hashicorp/nomad · error

x5t assertion headers use SHA-1, which is forbidden in FIPS-

Error message

x5t assertion headers use SHA-1, which is forbidden in FIPS-140 mode

What it means

The classic x5t header derives the key thumbprint with SHA-1, which Go's FIPS-140 module forbids. When running in FIPS-140 mode, Nomad rejects OIDC client assertions configured with KeyIDHeader "x5t" and requires the SHA-256 variant "x5t#S256" instead.

Source

Thrown at nomad/structs/acl.go:1901

		if !path.IsAbs(k.PemCertFile) {
			return fmt.Errorf("%w: must be absolute; got: %s", ErrInvalidClientAssertionCertPath, k.PemCertFile)
		}
	}

	// only allow certain key id headers
	// only "kid" for KeyID
	if k.KeyID != "" && k.KeyIDHeader != OIDCClientAssertionHeaderKid {
		return fmt.Errorf("%w; key header for key ID must be %q",
			ErrInvalidKeyIDHeader, OIDCClientAssertionHeaderKid)
	}
	// only "x5t*" for certs
	if k.PemCert != "" || k.PemCertFile != "" {
		if k.KeyIDHeader != OIDCClientAssertionHeaderX5t && k.KeyIDHeader != OIDCClientAssertionHeaderX5tS256 {
			return fmt.Errorf("%w; certificate-derived key header must be one of: %q, %q",
				ErrInvalidKeyIDHeader, OIDCClientAssertionHeaderX5tS256, OIDCClientAssertionHeaderX5t)
		}
		if fips140.Enabled() && k.KeyIDHeader == OIDCClientAssertionHeaderX5t {
			return errors.New("x5t assertion headers use SHA-1, which is forbidden in FIPS-140 mode")
		}
	}

	return nil
}

// ACLAuthClaims is the claim mapping of the OIDC auth method in a format that
// can be used with go-bexpr. This structure is used during rule binding
// evaluation.
type ACLAuthClaims struct {
	Value map[string]string   `bexpr:"value"`
	List  map[string][]string `bexpr:"list"`
}

// ACLAuthMethodStub is used for listing ACL auth methods
type ACLAuthMethodStub struct {
	Name    string
	Type    string

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Switch KeyIDHeader to "x5t#S256" (OIDCClientAssertionHeaderX5tS256) and confirm your IdP accepts it
  2. If the IdP only supports x5t (SHA-1), run Nomad without FIPS-140 mode enabled
  3. Use a KeyID + "kid" header instead of a certificate-derived header if the IdP allows it

Example fix

// before
key := &structs.OIDCClientAssertionKey{
  PemCertFile: "/etc/nomad/tls/client.crt",
  KeyIDHeader: structs.OIDCClientAssertionHeaderX5t,
}
// after
key := &structs.OIDCClientAssertionKey{
  PemCertFile: "/etc/nomad/tls/client.crt",
  KeyIDHeader: structs.OIDCClientAssertionHeaderX5tS256,
}
Defensive patterns

Strategy: validation

Validate before calling

if fips140.Enabled() && key.KeyIDHeader == structs.OIDCClientAssertionHeaderX5t {
    key.KeyIDHeader = structs.OIDCClientAssertionHeaderX5tS256
}

Try / catch

if err := key.Validate(); err != nil {
    if strings.Contains(err.Error(), "forbidden in FIPS-140 mode") {
        // switch header to x5t#S256 or disable FIPS mode
    }
    return err
}

Prevention

When it happens

Trigger: Nomad built/run with FIPS-140 enabled (crypto/fips140.Enabled() true) and an OIDCClientAssertionKey has a cert (PemCert or PemCertFile) with KeyIDHeader == "x5t" during Validate().

Common situations: FedRAMP/FIPS-hardened deployments (often government) that copied an older auth-method config using x5t; migrating an existing OIDC setup onto a FIPS-enabled Nomad build.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/52b70c2542ccaa9c. Report an issue: GitHub.