Repository: hashicorp/nomad
File: nomad/auth/auth.go (Go)

Code before:
	VerifyTLS      bool
	Region         string
	Encrypter      Encrypter
}

func NewAuthenticator(cfg *AuthenticatorConfig) *Authenticator {
	return &Authenticator{
		aclsEnabled:          cfg.AclsEnabled,
		verifyTLS:            cfg.VerifyTLS,
		logger:               cfg.Logger.With("auth"),
		getState:             cfg.StateFn,
		getLeaderACL:         cfg.GetLeaderACLFn,
		region:               cfg.Region,
		aclCache:             structs.NewACLCache[*acl.ACL](aclCacheSize),
		encrypter:            cfg.Encrypter,
		validServerCertNames: []string{"server." + cfg.Region + ".nomad"},
		validClientCertNames: []string{
			"client." + cfg.Region + ".nomad",
			"server." + cfg.Region + ".nomad",
		},
	}
}

// SetVerifyTLS is a helper method to set the verifyTLS field. This is used in
// when the server TLS configuration is updated.
func (s *Authenticator) SetVerifyTLS(verifyTLS bool) { s.verifyTLS = verifyTLS }

// Authenticate extracts an AuthenticatedIdentity from the request context or
// provided token and sets the identity on the request. The caller can extract
// an acl.ACL, WorkloadIdentity, or other identifying tokens to use for
// authorization. Keeping these fields independent rather than merging them into
// an ephemeral ACLToken makes the original of the credential clear to RPC
// handlers, who may have different behavior for internal vs external origins.
//
// Note: when making a server-to-server RPC that authenticates with this method,
// the RPC *must* include the leader's ACL token. Use AuthenticateServerOnly for
// requests that don't have access to the leader's ACL token.
//
// Note: when called on the follower we'll be making stale queries, so it's
// possible if the follower is behind that the leader will get a different value
// if an ACL token or allocation's WI has just been created.
//
// This method returns errors that are used for testing diagnostics. RPC callers
// should always return ErrPermissionDenied after checking forwarding when one
// of these errors is received.
func (s *Authenticator) Authenticate(ctx RPCContext, args structs.RequestWithIdentity) error {

	// get the user ACLToken or anonymous token
	secretID := args.GetAuthToken()
	aclToken, err := s.resolveSecretToken(secretID)


Review comment (bug):
I think we've got a data race here, right? The methods on this struct read the value concurrently. Would be nice if we can do this without introducing a lock everywhere though (i.e. we only have this one boolean value to update so could we do it with an atomic load/store? Or reconfigure and swap out the whole `Authenticator` atomically?)

Code after:

type AuthenticatorConfig struct {
	StateFn        StateGetter
	Logger         hclog.Logger
	GetLeaderACLFn LeaderACLGetter
	AclsEnabled    bool
	VerifyTLS      bool
	Region         string
	Encrypter      Encrypter
}

func NewAuthenticator(cfg *AuthenticatorConfig) *Authenticator {
	a := Authenticator{
		aclsEnabled:          cfg.AclsEnabled,
		verifyTLS:            &atomic.Bool{},
		logger:               cfg.Logger.With("auth"),
		getState:             cfg.StateFn,
		getLeaderACL:         cfg.GetLeaderACLFn,
		region:               cfg.Region,
		aclCache:             structs.NewACLCache[*acl.ACL](aclCacheSize),
		encrypter:            cfg.Encrypter,
		validServerCertNames: []string{"server." + cfg.Region + ".nomad"},
		validClientCertNames: []string{
			"client." + cfg.Region + ".nomad",
			"server." + cfg.Region + ".nomad",
		},
	}

	a.verifyTLS.Store(cfg.VerifyTLS)
	return &a
}

// SetVerifyTLS is a helper method to set the verifyTLS field. This is used in
// when the server TLS configuration is updated.
func (s *Authenticator) SetVerifyTLS(verifyTLS bool) { s.verifyTLS.Store(verifyTLS) }

// Authenticate extracts an AuthenticatedIdentity from the request context or
// provided token and sets the identity on the request. The caller can extract
// an acl.ACL, WorkloadIdentity, or other identifying tokens to use for
// authorization. Keeping these fields independent rather than merging them into
// an ephemeral ACLToken makes the original of the credential clear to RPC
// handlers, who may have different behavior for internal vs external origins.
//
// Note: when making a server-to-server RPC that authenticates with this method,
// the RPC *must* include the leader's ACL token. Use AuthenticateServerOnly for
// requests that don't have access to the leader's ACL token.
//
// Note: when called on the follower we'll be making stale queries, so it's
// possible if the follower is behind that the leader will get a different value
// if an ACL token or allocation's WI has just been created.
//