Authenticating

This page provides an overview of authentication in Kubernetes, with a focus onauthentication to theKubernetes API.

Users in Kubernetes

All Kubernetes clusters have two categories of users: service accounts managedby Kubernetes, and normal users.

It is assumed that a cluster-independent service manages normal users in the following ways:

  • an administrator distributing private keys
  • a user store like Keystone or Google Accounts
  • a file with a list of usernames and passwords

In this regard,Kubernetes does not have objects which represent normal user accounts.Normal users cannot be added to a cluster through an API call.

Even though a normal user cannot be added via an API call, any user thatpresents a valid certificate signed by the cluster's certificate authority(CA) is considered authenticated. In this configuration, Kubernetes determinesthe username from the common name field in the 'subject' of the cert (e.g.,"/CN=bob"). From there, the role based access control (RBAC) sub-system woulddetermine whether the user is authorized to perform a specific operation on aresource.

In contrast, service accounts are users managed by the Kubernetes API. They arebound to specific namespaces, and created automatically by the API server ormanually through API calls. Service accounts are tied to a set of credentialsstored asSecrets, which are mounted into pods allowing in-cluster processesto talk to the Kubernetes API.

API requests are tied to either a normal user or a service account, or are treatedasanonymous requests. This means every process inside or outside the cluster, froma human user typingkubectl on a workstation, tokubelets on nodes, to membersof the control plane, must authenticate when making requests to the API server,or be treated as an anonymous user.

Authentication strategies

Kubernetes uses client certificates, bearer tokens, or an authenticating proxy toauthenticate API requests through authentication plugins. As HTTP requests aremade to the API server, plugins attempt to associate the following attributeswith the request:

  • Username: a string which identifies the end user. Common values might bekube-admin orjane@example.com.
  • UID: a string which identifies the end user and attempts to be more consistent and unique than username.
  • Groups: a set of strings, each of which indicates the user's membership in a named logical collection of users.Common values might besystem:masters ordevops-team.
  • Extra fields: a map of strings to list of strings which holds additional information authorizers may find useful.

Note:

All values are opaque to the authentication system and only hold significancewhen interpreted by anauthorizer.

Anonymous requests

When enabled, requests that are not rejected by other configured authentication methods aretreated as anonymous requests, and given a username ofsystem:anonymous and a group ofsystem:unauthenticated.

For example, on a server with token authentication configured, and anonymous access enabled,a request providing an invalid bearer token would receive a401 Unauthorized error.A request providing no bearer token would be treated as an anonymous request.

Anonymous access is enabled by default if anauthorization modeother thanAlwaysAllow is used; you can disable it by passing the--anonymous-auth=falsecommand line option to the API server.The built-in ABAC and RBAC authorizers require explicit authorization of thesystem:anonymous user or thesystem:unauthenticated group; if you have legacy policy rules(from Kubernetes version 1.5 or earlier), those legacy rulesthat grant access to the* user or* group do not automatically allow access to anonymous users.

Anonymous authenticator configuration

FEATURE STATE:Kubernetes v1.34 [stable](enabled by default)

TheAuthenticationConfiguration can be used to configure the anonymousauthenticator. If you set the anonymous field in theAuthenticationConfigurationfile then you cannot set the--anonymous-auth command line option.

The main advantage of configuring anonymous authenticator using the authenticationconfiguration file is that in addition to enabling and disabling anonymous authenticationyou can also configure which endpoints support anonymous authentication.

A sample authentication configuration file is below:

---## CAUTION: this is an example configuration.#          Do not use this as-is for your own cluster!#apiVersion:apiserver.config.k8s.io/v1kind:AuthenticationConfigurationanonymous:enabled:trueconditions:-path:/livez-path:/readyz-path:/healthz

In the configuration above, only the/livez,/readyz and/healthz endpointsare reachable by anonymous requests. Any other endpoints will not be reachableanonymously, even if your authorization configuration would allow it.

Authentication methods

You can enable multiple authentication methods at once. You should usually use at least two methods:

  • service account tokens for service accounts
  • at least one other method for user authentication.

When multiple authenticator modules are enabled, the first moduleto successfully authenticate the request short-circuits evaluation.The API server does not guarantee the order authenticators run in.

Thesystem:authenticated group is included in the list of groups for all authenticated users.

Integrations with other authentication protocols (LDAP, SAML, Kerberos, alternate x509 schemes, etc)are available; for example using anauthenticating proxy or theauthentication webhook.

X.509 client certificates

Client certificate authentication is enabled by passing the--client-ca-file=SOMEFILEoption to API server. The referenced file must contain one or more certificate authoritiesto use to validate client certificates presented to the API server. If a client certificateis presented and verified, the common name of the subject is used as the user name for therequest. As of Kubernetes 1.4, client certificates can also indicate a user's group membershipsusing the certificate's organization fields. To include multiple group memberships for a user,include multiple organization fields in the certificate.

For example, using theopenssl command line tool to generate a certificate signing request:

openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj"/CN=jbeda/O=app1/O=app2"

This would create a CSR for the username "jbeda", belonging to two groups, "app1" and "app2".

SeeManaging Certificates for how to generate a client cert.

Putting a bearer token in a request

When using bearer token authentication from an http client, the APIserver expects anAuthorization header with a value ofBearer <token>. The bearer token must be a character sequence that can beput in an HTTP header value using no more than the encoding andquoting facilities of HTTP. For example: if the bearer token is31ada4fd-adec-460c-809a-9e56ceb75269 then it would appear in an HTTPheader as shown below.

Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

Bootstrap tokens

FEATURE STATE:Kubernetes v1.18 [stable]

To allow for streamlined bootstrapping for new clusters, Kubernetes includes adynamically-managed Bearer token type called aBootstrap Token. These tokensare stored as Secrets in thekube-system namespace, where they can bedynamically managed and created. Controller Manager contains a TokenCleanercontroller that deletes bootstrap tokens as they expire.

The tokens are of the form[a-z0-9]{6}.[a-z0-9]{16}. The first component is aToken ID and the second component is the Token Secret. You specify the tokenin an HTTP header as follows:

Authorization: Bearer 781292.db7bc3a58fc5f07e

You must enable the Bootstrap Token Authenticator with the--enable-bootstrap-token-auth flag on the API Server. You must enablethe TokenCleaner controller via the--controllers command line argumentfor kube-controller-manager.This is done with something like--controllers=*,tokencleaner.Thekubeadm tool will do this for you if you are using it to bootstrap a cluster.

The authenticator authenticates assystem:bootstrap:<Token ID>. It isincluded in thesystem:bootstrappers group. The naming and groups areintentionally limited to discourage users from using these tokens pastbootstrapping. The user names and group can be used (and are used bykubeadm)to craft the appropriate authorization policies to support bootstrapping acluster.

Please seeBootstrap Tokens for in depthdocumentation on the Bootstrap Token authenticator and controllers along withhow to manage these tokens withkubeadm.

Service account tokens

A service account is an automatically enabled authenticator that uses signedbearer tokens to verify requests. The plugin takes two optional flags:

  • --service-account-key-file File containing PEM-encoded x509 RSA or ECDSAprivate or public keys, used to verify ServiceAccount tokens. The specified filecan contain multiple keys, and the flag can be specified multiple times withdifferent files. If unspecified, --tls-private-key-file is used.
  • --service-account-lookup If enabled, tokens which are deleted from the API will be revoked.

Service accounts are usually created automatically by the API server andassociated with pods running in the cluster through theServiceAccountAdmission Controller. Bearer tokens aremounted into pods at well-known locations, and allow in-cluster processes totalk to the API server. Accounts may be explicitly associated with pods using theserviceAccountName field of aPodSpec.

Note:

serviceAccountName is usually omitted because this is done automatically.
apiVersion:apps/v1# this apiVersion is relevant as of Kubernetes 1.9kind:Deploymentmetadata:name:nginx-deploymentnamespace:defaultspec:replicas:3template:metadata:# ...spec:serviceAccountName:bob-the-botcontainers:-name:nginximage:nginx:1.14.2

Service account bearer tokens are perfectly valid to use outside the cluster andcan be used to create identities for long standing jobs that wish to talk to theKubernetes API. To manually create a service account, use thekubectl create serviceaccount (NAME) command. This creates a service account in the currentnamespace.

kubectl create serviceaccount jenkins
serviceaccount/jenkins created

You can manually create an associated token:

kubectl create token jenkins
eyJhbGciOiJSUzI1NiIsImtp...

The created token is a signedJSON Web Token (JWT).

The signed JWT can be used as a bearer token to authenticate as the given serviceaccount. Seeabove for how the token is includedin a request. Normally these tokens are mounted into pods for in-cluster access tothe API server, but can be used from outside the cluster as well.

Service accounts authenticate with the usernamesystem:serviceaccount:(NAMESPACE):(SERVICEACCOUNT),and are assigned to the groupssystem:serviceaccounts andsystem:serviceaccounts:(NAMESPACE).

Warning:

Because service account tokens can also be stored in Secret API objects, any user withwrite access to Secrets can request a token, and any user with read access to thoseSecrets can authenticate as the service account. Be cautious when granting permissionsto service accounts and read or write capabilities for Secrets.

External integrations

Kubernetes has native support for JWT and for OpenID Connect (OIDC); seeJSON Web Token authentication.

Integrations with other authentication protocols (for example: LDAP, SAML, Kerberos, alternate X.509 schemes)can be accomplished using anauthenticating proxy or by integrating with anauthentication webhook.

You can also use any custom method that issuesclient X.509 certificates to clients,provided that the API server will trust the valid certificates.ReadX.509 client certificates to learn about how to generate acertificate.

If you do issue certificates to clients, it is up to you (as a cloud platform administrator)to make sure that the certificate validity period, and other design choices you make, provide asuitable level of security.

JSON Web Token authentication

You can configure Kubernetes to authenticate users usingJSON Web Token(JWT) compliant tokens. JWT authentication mechanism is used for the ServiceAccount tokens that Kubernetes itself issues,and you can also use it to integrate with other identity sources.

The authenticator attempts to parse a raw ID token, verify it's been signed by the configured issuer.For externally issued tokens, the public key to verify the signature is discovered from the issuer's public endpoint using OIDC discovery.

The minimum valid JWT payloadmust contain the following claims:

{"iss":"https://example.com",// must match the issuer.url"aud": ["my-app"],// at least one of the entries in issuer.audiences must match the "aud" claim in presented JWTs."exp":1234567890,// token expiration as Unix time (the number of seconds elapsed since January 1, 1970 UTC)"<username-claim>":"user"// this is the username claim configured in the claimMappings.username.claim or claimMappings.username.expression}

JWT egress selector type

FEATURE STATE:Kubernetes v1.34 [beta](enabled by default)

TheegressSelectorType field in the JWT issuer configuration allows you to specify whichegress selectorshould be used for sending all traffic related to the issuer (discovery, JWKS, distributed claims, etc).This feature requires theStructuredAuthenticationConfigurationEgressSelector feature gate to be enabled.

OpenID Connect tokens

OpenID Connect is a flavor of OAuth2 supported bysome OAuth2 providers, notably Microsoft Entra ID, Salesforce, and Google.The protocol's main extension of OAuth2 is an additional field returned withthe access token called anID Token.This token is a JSON Web Token (JWT) with well known fields, such as a user'semail, signed by the server.

To identify the user, the authenticator uses theid_token (not theaccess_token)from the OAuth2token responseas a bearer token. Seeabove for how the tokenis included in a request.

sequenceDiagramparticipant user as Userparticipant idp as Identity Providerparticipant kube as kubectlparticipant api as API Serveruser ->> idp: 1. Log in to IdPactivate idpidp -->> user: 2. Provide access_token,
id_token, and refresh_tokendeactivate idpactivate useruser ->> kube: 3. Call kubectl
with --token being the id_token
OR add tokens to .kube/configdeactivate useractivate kubekube ->> api: 4. Authorization: Bearer...deactivate kubeactivate apiapi ->> api: 5. Is JWT signature valid?api ->> api: 6. Has the JWT expired? (iat+exp)api ->> api: 7. User authorized?api -->> kube: 8. Authorized: Perform
action and return resultdeactivate apiactivate kubekube --x user: 9. Return resultdeactivate kube
  1. Log in to your identity provider

  2. Your identity provider will provide you with anaccess_token,id_token and arefresh_token

  3. When usingkubectl, use yourid_token with the--token command line argument or add it directly to yourkubeconfig

  4. kubectl sends yourid_token in a header called Authorization to the API server

  5. The API server will make sure the JWT signature is valid

  6. Check to make sure theid_token hasn't expired

    Perform claim and/or user validation if CEL expressions are configured withAuthenticationConfiguration.

  7. Make sure the user is authorized

  8. Once authorized the API server returns a response tokubectl

  9. kubectl provides feedback to the user

Since all of the data needed to validate who you are is in theid_token, Kubernetes doesn't need to"phone home" to the identity provider. In a model where every request is stateless this provides avery scalable solution for authentication. It does offer a few challenges:

  1. Kubernetes has no "web interface" to trigger the authentication process. There is no browser orinterface to collect credentials which is why you need to authenticate to your identity provider first.
  2. Theid_token can't be revoked, it's like a certificate so it should be short-lived (only a few minutes)so it can be very annoying to have to get a new token every few minutes.
  3. To authenticate to the Kubernetes dashboard, you must use thekubectl proxy command or a reverse proxythat injects theid_token.

Configuring the API Server

Using command line arguments

To enable the plugin, configure the following command line arguments for the API server:

ParameterDescriptionExampleRequired
--oidc-issuer-urlURL of the provider that allows the API server to discover public signing keys. Only URLs that use thehttps:// scheme are accepted. This is typically the provider's discovery URL, changed to have an empty path.If the issuer's OIDC discovery URL ishttps://accounts.provider.example/.well-known/openid-configuration, the value should behttps://accounts.provider.exampleYes
--oidc-client-idA client id that all tokens must be issued for.kubernetesYes
--oidc-username-claimJWT claim to use as the user name. By defaultsub, which is expected to be a unique identifier of the end user. Admins can choose other claims, such asemail orname, depending on their provider. However, claims other thanemail will be prefixed with the issuer URL to prevent naming clashes with other plugins.subNo
--oidc-username-prefixPrefix prepended to username claims to prevent clashes with existing names (such assystem: users). For example, the valueoidc: will create usernames likeoidc:jane.doe. If this argument isn't provided and--oidc-username-claim is a value other thanemail the prefix defaults to( Issuer URL )# where( Issuer URL ) is the value of--oidc-issuer-url. The value- can be used to disable all prefixing.oidc:No
--oidc-groups-claimJWT claim to use as the user's group. If the claim is present it must be an array of strings.groupsNo
--oidc-groups-prefixPrefix prepended to group claims to prevent clashes with existing names (such assystem: groups). For example, the valueoidc: will create group names likeoidc:engineering andoidc:infra.oidc:No
--oidc-required-claimA key=value pair that describes a required claim in the ID Token. If set, the claim is verified to be present in the ID Token with a matching value. Repeat this argument to specify multiple claims.claim=valueNo
--oidc-ca-fileThe path to the certificate for the CA that signed your identity provider's web certificate. Defaults to the host's root CAs./etc/kubernetes/ssl/kc-ca.pemNo
--oidc-signing-algsThe signing algorithms accepted. Default is RS256. Allowed values are: RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512. Values are defined by RFC 7518https://tools.ietf.org/html/rfc7518#section-3.1.RS512No
Authentication configuration from a file
FEATURE STATE:Kubernetes v1.34 [stable](enabled by default)

The configuration file approach allows you to configure multiple JWT authenticators, each with a uniqueissuer.url andissuer.discoveryURL. The configuration file even allows you to specifyCELexpressions to map claims to user attributes, and to validate claims and user information.The API server also automatically reloads the authenticators when the configuration file is modified.You can useapiserver_authentication_config_controller_automatic_reload_last_timestamp_seconds metricto monitor the last time the configuration was reloaded by the API server.

You must specify the path to the authentication configuration using the--authentication-config command line argument to the API server. If you want to use command line arguments instead of the configuration file, those willcontinue to work as-is. To access the new capabilities like configuring multiple authenticators,setting multiple audiences for an issuer, switch to using the configuration file.

To use structured authentication, specify the--authentication-config command lineargument to the kube-apiserver. An example of the structured authentication configuration file is shown below.

Note:

If you specify--authentication-config along with any of the--oidc-* command line arguments, this isa misconfiguration. In this situation, the API server reports an error and then immediately exits.If you want to switch to using structured authentication configuration, you have to remove the--oidc-*command line arguments, and use the configuration file instead.
---## CAUTION: this is an example configuration.#          Do not use this for your own cluster!#apiVersion:apiserver.config.k8s.io/v1kind:AuthenticationConfiguration# list of authenticators to authenticate Kubernetes users using JWT compliant tokens.# the maximum number of allowed authenticators is 64.jwt:-issuer:# url must be unique across all authenticators.# url must not conflict with issuer configured in --service-account-issuer.url:https://example.com# Same as --oidc-issuer-url.# discoveryURL, if specified, overrides the URL used to fetch discovery# information instead of using "{url}/.well-known/openid-configuration".# The exact value specified is used, so "/.well-known/openid-configuration"# must be included in discoveryURL if needed.## The "issuer" field in the fetched discovery information must match the "issuer.url" field# in the AuthenticationConfiguration and will be used to validate the "iss" claim in the presented JWT.# This is for scenarios where the well-known and jwks endpoints are hosted at a different# location than the issuer (such as locally in the cluster).# discoveryURL must be different from url if specified and must be unique across all authenticators.discoveryURL:https://discovery.example.com/.well-known/openid-configuration# PEM encoded CA certificates used to validate the connection when fetching# discovery information. If not set, the system verifier will be used.# Same value as the content of the file referenced by the --oidc-ca-file command line argument.certificateAuthority:<PEM encoded CA certificates># audiences is the set of acceptable audiences the JWT must be issued to.# At least one of the entries must match the "aud" claim in presented JWTs.audiences:- my-app# Same as --oidc-client-id.- my-other-app# this is required to be set to "MatchAny" when multiple audiences are specified.audienceMatchPolicy:MatchAny# egressSelectorType is an indicator of which egress selection should be used for sending all traffic related# to this issuer (discovery, JWKS, distributed claims, etc).  If unspecified, no custom dialer is used.# The StructuredAuthenticationConfigurationEgressSelector feature gate must be enabled# before you can use the egressSelectorType field.# When specified, the valid choices are "controlplane" and "cluster".  These correspond to the associated# values in the --egress-selector-config-file.# - controlplane: for traffic intended to go to the control plane.# - cluster: for traffic intended to go to the system being managed by Kubernetes.egressSelectorType:<egress-selector-type># rules applied to validate token claims to authenticate users.claimValidationRules:# Same as --oidc-required-claim key=value.-claim:hdrequiredValue:example.com# Instead of claim and requiredValue, you can use expression to validate the claim.# expression is a CEL expression that evaluates to a boolean.# all the expressions must evaluate to true for validation to succeed.-expression:'claims.hd == "example.com"'# Message customizes the error message seen in the API server logs when the validation fails.message:the hd claim must be set to example.com-expression:'claims.exp - claims.nbf <= 86400'message:total token lifetime must not exceed 24 hoursclaimMappings:# username represents an option for the username attribute.# This is the only required attribute.username:# Same as --oidc-username-claim. Mutually exclusive with username.expression.claim:"sub"# Same as --oidc-username-prefix. Mutually exclusive with username.expression.# if username.claim is set, username.prefix is required.# Explicitly set it to "" if no prefix is desired.prefix:""# Mutually exclusive with username.claim and username.prefix.# expression is a CEL expression that evaluates to a string.## 1.  If username.expression uses 'claims.email', then 'claims.email_verified' must be used in#     username.expression or extra[*].valueExpression or claimValidationRules[*].expression.#     An example claim validation rule expression that matches the validation automatically#     applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'.#     By explicitly comparing the value to true, we let type-checking see the result will be a boolean, and#     to make sure a non-boolean email_verified claim will be caught at runtime.# 2.  If the username asserted based on username.expression is the empty string, the authentication#     request will fail.expression:'claims.username + ":external-user"'# groups represents an option for the groups attribute.groups:# Same as --oidc-groups-claim. Mutually exclusive with groups.expression.claim:"sub"# Same as --oidc-groups-prefix. Mutually exclusive with groups.expression.# if groups.claim is set, groups.prefix is required.# Explicitly set it to "" if no prefix is desired.prefix:""# Mutually exclusive with groups.claim and groups.prefix.# expression is a CEL expression that evaluates to a string or a list of strings.expression:'claims.roles.split(",")'# uid represents an option for the uid attribute.uid:# Mutually exclusive with uid.expression.claim:'sub'# Mutually exclusive with uid.claim# expression is a CEL expression that evaluates to a string.expression:'claims.sub'# extra attributes to be added to the UserInfo object. Keys must be domain-prefix path and must be unique.extra:# key is a string to use as the extra attribute key.# key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid# subdomain as defined by RFC 1123. All characters trailing the first "/" must# be valid HTTP Path characters as defined by RFC 3986.# k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use and cannot be used.# key must be lowercase and unique across all extra attributes.-key:'example.com/tenant'# valueExpression is a CEL expression that evaluates to a string or a list of strings.valueExpression:'claims.tenant'# validation rules applied to the final user object.userValidationRules:# expression is a CEL expression that evaluates to a boolean.# all the expressions must evaluate to true for the user to be valid.-expression:"!user.username.startsWith('system:')"# Message customizes the error message seen in the API server logs when the validation fails.message: 'username cannot used reserved system:prefix'-expression:"user.groups.all(group, !group.startsWith('system:'))"message: 'groups cannot used reserved system:prefix'
  • Claim validation rule expression

    jwt.claimValidationRules[i].expression represents the expression which will be evaluated by CEL.CEL expressions have access to the contents of the token payload, organized intoclaims CEL variable.claims is a map of claim names (as strings) to claim values (of any type).

  • User validation rule expression

    jwt.userValidationRules[i].expression represents the expression which will be evaluated by CEL.CEL expressions have access to the contents ofuserInfo, organized intouser CEL variable.Refer to theUserInfoAPI documentation for the schema ofuser.

  • Claim mapping expression

    jwt.claimMappings.username.expression,jwt.claimMappings.groups.expression,jwt.claimMappings.uid.expressionjwt.claimMappings.extra[i].valueExpression represents the expression which will be evaluated by CEL.CEL expressions have access to the contents of the token payload, organized intoclaims CEL variable.claims is a map of claim names (as strings) to claim values (of any type).

    To learn more, see theDocumentation on CEL

    Here are examples of theAuthenticationConfiguration with different token payloads.

    apiVersion:apiserver.config.k8s.io/v1kind:AuthenticationConfigurationjwt:-issuer:url:https://example.comaudiences:- my-appclaimMappings:username:expression:'claims.username + ":external-user"'groups:expression:'claims.roles.split(",")'uid:expression:'claims.sub'extra:-key:'example.com/tenant'valueExpression:'claims.tenant'userValidationRules:-expression:"!user.username.startsWith('system:')"# the expression will evaluate to true, so validation will succeed.message: 'username cannot used reserved system:prefix'
    TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJpYXQiOjE3MDExMDcyMzMsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJqdGkiOiI3YzMzNzk0MjgwN2U3M2NhYTJjMzBjODY4YWMwY2U5MTBiY2UwMmRkY2JmZWJlOGMyM2I4YjVmMjdhZDYyODczIiwibmJmIjoxNzAxMTA3MjMzLCJyb2xlcyI6InVzZXIsYWRtaW4iLCJzdWIiOiJhdXRoIiwidGVuYW50IjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjRhIiwidXNlcm5hbWUiOiJmb28ifQ.TBWF2RkQHm4QQz85AYPcwLxSk-VLvQW-mNDHx7SEOSv9LVwcPYPuPajJpuQn9C_gKq1R94QKSQ5F6UgHMILz8OfmPKmX_00wpwwNVGeevJ79ieX2V-__W56iNR5gJ-i9nn6FYk5pwfVREB0l4HSlpTOmu80gbPWAXY5hLW0ZtcE1JTEEmefORHV2ge8e3jp1xGafNy6LdJWabYuKiw8d7Qga__HxtKB-t0kRMNzLRS7rka_SfQg0dSYektuxhLbiDkqhmRffGlQKXGVzUsuvFw7IGM5ZWnZgEMDzCI357obHeM3tRqpn5WRjtB8oM7JgnCymaJi-P3iCd88iu1xnzA

    where the token payload is:

      {"aud":"kubernetes","exp":1703232949,"iat":1701107233,"iss":"https://example.com","jti":"7c337942807e73caa2c30c868ac0ce910bce02ddcbfebe8c23b8b5f27ad62873","nbf":1701107233,"roles":"user,admin","sub":"auth","tenant":"72f988bf-86f1-41af-91ab-2d7cd011db4a","username":"foo"  }

    The token with the aboveAuthenticationConfiguration will produce the followingUserInfo object and successfully authenticate the user.

    {"username":"foo:external-user","uid":"auth","groups": ["user","admin"    ],"extra": {"example.com/tenant": ["72f988bf-86f1-41af-91ab-2d7cd011db4a"]    }}

    apiVersion:apiserver.config.k8s.io/v1kind:AuthenticationConfigurationjwt:-issuer:url:https://example.comaudiences:- my-appclaimValidationRules:-expression:'claims.hd == "example.com"'# the token below does not have this claim, so validation will fail.message:the hd claim must be set to example.comclaimMappings:username:expression:'claims.username + ":external-user"'groups:expression:'claims.roles.split(",")'uid:expression:'claims.sub'extra:-key:'example.com/tenant'valueExpression:'claims.tenant'userValidationRules:-expression:"!user.username.startsWith('system:')"# the expression will evaluate to true, so validation will succeed.message: 'username cannot used reserved system:prefix'
    TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJpYXQiOjE3MDExMDcyMzMsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJqdGkiOiI3YzMzNzk0MjgwN2U3M2NhYTJjMzBjODY4YWMwY2U5MTBiY2UwMmRkY2JmZWJlOGMyM2I4YjVmMjdhZDYyODczIiwibmJmIjoxNzAxMTA3MjMzLCJyb2xlcyI6InVzZXIsYWRtaW4iLCJzdWIiOiJhdXRoIiwidGVuYW50IjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjRhIiwidXNlcm5hbWUiOiJmb28ifQ.TBWF2RkQHm4QQz85AYPcwLxSk-VLvQW-mNDHx7SEOSv9LVwcPYPuPajJpuQn9C_gKq1R94QKSQ5F6UgHMILz8OfmPKmX_00wpwwNVGeevJ79ieX2V-__W56iNR5gJ-i9nn6FYk5pwfVREB0l4HSlpTOmu80gbPWAXY5hLW0ZtcE1JTEEmefORHV2ge8e3jp1xGafNy6LdJWabYuKiw8d7Qga__HxtKB-t0kRMNzLRS7rka_SfQg0dSYektuxhLbiDkqhmRffGlQKXGVzUsuvFw7IGM5ZWnZgEMDzCI357obHeM3tRqpn5WRjtB8oM7JgnCymaJi-P3iCd88iu1xnzA

    where the token payload is:

      {"aud":"kubernetes","exp":1703232949,"iat":1701107233,"iss":"https://example.com","jti":"7c337942807e73caa2c30c868ac0ce910bce02ddcbfebe8c23b8b5f27ad62873","nbf":1701107233,"roles":"user,admin","sub":"auth","tenant":"72f988bf-86f1-41af-91ab-2d7cd011db4a","username":"foo"  }

    The token with the aboveAuthenticationConfiguration will fail to authenticate because thehd claim is not set toexample.com. The API server will return401 Unauthorized error.

    apiVersion:apiserver.config.k8s.io/v1kind:AuthenticationConfigurationjwt:-issuer:url:https://example.comaudiences:- my-appclaimValidationRules:-expression:'claims.hd == "example.com"'message:the hd claim must be set to example.comclaimMappings:username:expression:'"system:" + claims.username'# this will prefix the username with "system:" and will fail user validation.groups:expression:'claims.roles.split(",")'uid:expression:'claims.sub'extra:-key:'example.com/tenant'valueExpression:'claims.tenant'userValidationRules:-expression:"!user.username.startsWith('system:')"# the username will be system:foo and expression will evaluate to false, so validation will fail.message: 'username cannot used reserved system:prefix'
    TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJoZCI6ImV4YW1wbGUuY29tIiwiaWF0IjoxNzAxMTEzMTAxLCJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwianRpIjoiYjViMDY1MjM3MmNkMjBlMzQ1YjZmZGZmY2RjMjE4MWY0YWZkNmYyNTlhYWI0YjdlMzU4ODEyMzdkMjkyMjBiYyIsIm5iZiI6MTcwMTExMzEwMSwicm9sZXMiOiJ1c2VyLGFkbWluIiwic3ViIjoiYXV0aCIsInRlbmFudCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0YSIsInVzZXJuYW1lIjoiZm9vIn0.FgPJBYLobo9jnbHreooBlvpgEcSPWnKfX6dc0IvdlRB-F0dCcgy91oCJeK_aBk-8zH5AKUXoFTlInfLCkPivMOJqMECA1YTrMUwt_IVqwb116AqihfByUYIIqzMjvUbthtbpIeHQm2fF0HbrUqa_Q0uaYwgy8mD807h7sBcUMjNd215ff_nFIHss-9zegH8GI1d9fiBf-g6zjkR1j987EP748khpQh9IxPjMJbSgG_uH5x80YFuqgEWwq-aYJPQxXX6FatP96a2EAn7wfPpGlPRt0HcBOvq5pCnudgCgfVgiOJiLr_7robQu4T1bis0W75VPEvwWtgFcLnvcQx0JWg

    where the token payload is:

      {"aud":"kubernetes","exp":1703232949,"hd":"example.com","iat":1701113101,"iss":"https://example.com","jti":"b5b0652372cd20e345b6fdffcdc2181f4afd6f259aab4b7e35881237d29220bc","nbf":1701113101,"roles":"user,admin","sub":"auth","tenant":"72f988bf-86f1-41af-91ab-2d7cd011db4a","username":"foo"  }

    The token with the aboveAuthenticationConfiguration will produce the followingUserInfo object:

    {"username":"system:foo","uid":"auth","groups": ["user","admin"    ],"extra": {"example.com/tenant": ["72f988bf-86f1-41af-91ab-2d7cd011db4a"]    }}

    which will fail user validation because the username starts withsystem:.The API server will return401 Unauthorized error.

Limitations
  1. Distributed claims do not work viaCEL expressions.

Kubernetes does not provide an OpenID Connect Identity Provider.You can use an existing public OpenID Connect Identity Provider or run your own Identity Providerthat supports the OpenID Connect protocol.

For an identity provider to work with Kubernetes it must:

  1. SupportOpenID connect discovery

    The public key to verify the signature is discovered from the issuer's public endpoint using OIDC discovery.If you're using the authentication configuration file, the identity provider doesn't need to publicly expose the discovery endpoint.You can host the discovery endpoint at a different location than the issuer (such as locally in the cluster) and specify theissuer.discoveryURL in the configuration file.

  2. Run in TLS with non-obsolete ciphers

  3. Have a CA signed certificate (even if the CA is not a commercial CA or is self signed)

A note about requirement #3 above, requiring a CA signed certificate. If you deploy your ownidentity provider you MUST have your identity provider's web server certificate signed by acertificate with theCA flag set toTRUE, even if it is self signed. This is due to GoLang'sTLS client implementation being very strict to the standards around certificate validation. If youdon't have a CA handy, you can create a simple CA and a signed certificate and key pair usingstandard certificate generation tools.

Using kubectl

Option 1 - OIDC authenticator

The first option is to use the kubectloidc authenticator, which sets theid_token as a bearer tokenfor all requests and refreshes the token once it expires. After you've logged into your provider, usekubectl to add yourid_token,refresh_token,client_id, andclient_secret to configure the plugin.

Providers that don't return anid_token as part of their refresh token response aren't supportedby this plugin and should useOption 2 (specifying--token).

kubectl config set-credentials USER_NAME\   --auth-provider=oidc\   --auth-provider-arg=idp-issuer-url=( issuer url)\   --auth-provider-arg=client-id=( your client id)\   --auth-provider-arg=client-secret=( your client secret)\   --auth-provider-arg=refresh-token=( your refresh token)\   --auth-provider-arg=idp-certificate-authority=( path to your ca certificate)\   --auth-provider-arg=id-token=( your id_token)

As an example, running the below command after authenticating to your identity provider:

kubectl config set-credentials mmosley\        --auth-provider=oidc\        --auth-provider-arg=idp-issuer-url=https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP\        --auth-provider-arg=client-id=kubernetes\        --auth-provider-arg=client-secret=1db158f6-177d-4d9c-8a8b-d36869918ec5\        --auth-provider-arg=refresh-token=q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqHega4GAXlF+ma+vmYpFcHe5eZR+slBFpZKtQA=\        --auth-provider-arg=idp-certificate-authority=/root/ca.pem\        --auth-provider-arg=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw

Which would produce the below configuration:

users:-name:mmosleyuser:auth-provider:config:client-id:kubernetesclient-secret:1db158f6-177d-4d9c-8a8b-d36869918ec5id-token:eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knwidp-certificate-authority:/root/ca.pemidp-issuer-url:https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdPrefresh-token:q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqname:oidc

Once yourid_token expires,kubectl will attempt to refresh yourid_token using yourrefresh_tokenandclient_secret storing the new values for therefresh_token andid_token in your.kube/config.

Option 2 - Use the--token command line argument

Thekubectl command lets you pass in a token using the--token command line argument.Copy and paste theid_token into this option:

kubectl --token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL21sYi50cmVtb2xvLmxhbjo4MDQzL2F1dGgvaWRwL29pZGMiLCJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNDc0NTk2NjY5LCJqdGkiOiI2RDUzNXoxUEpFNjJOR3QxaWVyYm9RIiwiaWF0IjoxNDc0NTk2MzY5LCJuYmYiOjE0NzQ1OTYyNDksInN1YiI6Im13aW5kdSIsInVzZXJfcm9sZSI6WyJ1c2VycyIsIm5ldy1uYW1lc3BhY2Utdmlld2VyIl0sImVtYWlsIjoibXdpbmR1QG5vbW9yZWplZGkuY29tIn0.f2As579n9VNoaKzoF-dOQGmXkFKf1FMyNV0-va_B63jn-_n9LGSCca_6IVMP8pO-Zb4KvRqGyTP0r3HkHxYy5c81AnIh8ijarruczl-TK_yF5akjSTHFZD-0gRzlevBDiH8Q79NAr-ky0P4iIXS8lY9Vnjch5MF74Zx0c3alKJHJUnnpjIACByfF2SCaYzbWFMUNat-K1PaUk5-ujMBG7yYnr95xD-63n8CO8teGUAAEMx6zRjzfhnhbzX-ajwZLGwGUBT4WqjMs70-6a7_8gZmLZb2az1cZynkFRj2BaCkVT3A2RrjeEwZEtGXlMqKJ1_I2ulrOVsYx01_yD35-rw get nodes

Webhook token authentication

Kuberneteswebhook authentication is a mechanism to make an HTTP callout for verifying bearer tokens.

In terms of how you configure the API server:

  • --authentication-token-webhook-config-file a configuration file describing how to access the remote webhook service.
  • --authentication-token-webhook-cache-ttl how long to cache authentication decisions. Defaults to two minutes.
  • --authentication-token-webhook-version determines whether to useauthentication.k8s.io/v1beta1 orauthentication.k8s.io/v1TokenReview objects to send/receive information from the webhook. Defaults tov1beta1.

The configuration file uses thekubeconfigfile format. Within the file,clusters refers to the remote service andusers refers to the API server webhook. An example would be:

# Kubernetes API versionapiVersion:v1# kind of the API objectkind:Config# clusters refers to the remote service.clusters:-name:name-of-remote-authn-servicecluster:certificate-authority:/path/to/ca.pem# CA for verifying the remote service.server:https://authn.example.com/authenticate# URL of remote service to query. 'https' recommended for production.# users refers to the API server's webhook configuration.users:-name:name-of-api-serveruser:client-certificate:/path/to/cert.pem# cert for the webhook plugin to useclient-key:/path/to/key.pem# key matching the cert# kubeconfig files require a context. Provide one for the API server.current-context:webhookcontexts:-context:cluster:name-of-remote-authn-serviceuser:name-of-api-servername:webhook

When a client attempts to authenticate with the API server using a bearer token as discussedabove, the authentication webhook POSTs a JSON-serializedTokenReview object containing the token to the remote service.

Note that webhook API objects are subject to the sameversioning compatibility rulesas other Kubernetes API objects. Implementers should check theapiVersion field of the request to ensure correct deserialization,andmust respond with aTokenReview object of the same version as the request.

Note:

The Kubernetes API server defaults to sendingauthentication.k8s.io/v1beta1 token reviews for backwards compatibility.To opt into receivingauthentication.k8s.io/v1 token reviews, the API server must be started with--authentication-token-webhook-version=v1.
{"apiVersion":"authentication.k8s.io/v1","kind":"TokenReview","spec":{# Opaque bearer token sent to the API server"token":"014fbff9a07c...",# Optional list of the audience identifiers for the server the token was presented to.# Audience-aware token authenticators (for example, OIDC token authenticators)# should verify the token was intended for at least one of the audiences in this list,# and return the intersection of this list and the valid audiences for the token in the response status.# This ensures the token is valid to authenticate to the server it was presented to.# If no audiences are provided, the token should be validated to authenticate to the Kubernetes API server."audiences":["https://myserver.example.com","https://myserver.internal.example.com"]}}

{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","spec":{# Opaque bearer token sent to the API server"token":"014fbff9a07c...",# Optional list of the audience identifiers for the server the token was presented to.# Audience-aware token authenticators (for example, OIDC token authenticators)# should verify the token was intended for at least one of the audiences in this list,# and return the intersection of this list and the valid audiences for the token in the response status.# This ensures the token is valid to authenticate to the server it was presented to.# If no audiences are provided, the token should be validated to authenticate to the Kubernetes API server."audiences":["https://myserver.example.com","https://myserver.internal.example.com"]}}

The remote service is expected to fill thestatus field of the request to indicate the success of the login.The response body'sspec field is ignored and may be omitted.The remote service must return a response using the sameTokenReview API version that it received.A successful validation of the bearer token would return:

{"apiVersion":"authentication.k8s.io/v1","kind":"TokenReview","status":{"authenticated":true,"user":{# Required"username":"janedoe@example.com",# Optional"uid":"42",# Optional group memberships"groups":["developers","qa"],# Optional additional information provided by the authenticator.# This should not contain confidential data, as it can be recorded in logs# or API objects, and is made available to admission webhooks."extra":{"extrafield1":["extravalue1","extravalue2"]}},# Optional list audience-aware token authenticators can return,# containing the audiences from the `spec.audiences` list for which the provided token was valid.# If this is omitted, the token is considered to be valid to authenticate to the Kubernetes API server."audiences":["https://myserver.example.com"]}}

{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","status":{"authenticated":true,"user":{# Required"username":"janedoe@example.com",# Optional"uid":"42",# Optional group memberships"groups":["developers","qa"],# Optional additional information provided by the authenticator.# This should not contain confidential data, as it can be recorded in logs# or API objects, and is made available to admission webhooks."extra":{"extrafield1":["extravalue1","extravalue2"]}},# Optional list audience-aware token authenticators can return,# containing the audiences from the `spec.audiences` list for which the provided token was valid.# If this is omitted, the token is considered to be valid to authenticate to the Kubernetes API server."audiences":["https://myserver.example.com"]}}

An unsuccessful request would return:

{"apiVersion":"authentication.k8s.io/v1","kind":"TokenReview","status":{"authenticated":false,# Optionally include details about why authentication failed.# If no error is provided, the API will return a generic Unauthorized message.# The error field is ignored when authenticated=true."error":"Credentials are expired"}}

{"apiVersion":"authentication.k8s.io/v1beta1","kind":"TokenReview","status":{"authenticated":false,# Optionally include details about why authentication failed.# If no error is provided, the API will return a generic Unauthorized message.# The error field is ignored when authenticated=true."error":"Credentials are expired"}}

Authenticating reverse proxy

Warning:

If you have a certificate authority (CA) that is also used in a different context,do not trustthat certificate authority to identify authenticating proxy clients, unless you understand therisks and the mechanisms to protect that CA's usage.

The API server can be configured to identify users from request header values, such asX-Remote-User.It is designed for use in combination with anauthenticating proxy that sets these headers.

The command line arguments to configure this mode are:

--requestheader-client-ca-file
Required.Path to a PEM-encoded certificate bundle.
A validclient certificatemust be presented and validated against the certificate authorities in the specified file before therequest headers are checked for user names.
--requestheader-allowed-names
Optional. Comma-separated list of Common Name values (CNs).
If set, a valid clientcertificate with a CN in the specified list must be presented before the request headers are checkedfor user names. If empty, any CN is allowed.
--requestheader-username-headers
Required; case-insensitive. Header names to check, in order, for the user identity.
The first header containing a value is used as the username.
--requestheader-group-headers
Optional; case-insensitive.Header names to check, in order, for the user's groups.
X-Remote-Group is suggested.All values in all specified headers are used as group names.
--requestheader-extra-headers-prefix
Optional; case-insensitive.Header prefixes to look for to determine extra information about the user.
X-Remote-Extra- is suggested.Extra data is typically used by the configured authorization plugin(s).Any headers beginning with any of the specified prefixes have the prefix removed.The remainder of the header name is lowercased andpercent-decodedand becomes the extra key, and the header value is the extra value.

For example, with this configuration:

--requestheader-username-headers=X-Remote-User--requestheader-group-headers=X-Remote-Group--requestheader-extra-headers-prefix=X-Remote-Extra-

this request:

GET/HTTP/1.1X-Remote-User: fidoX-Remote-Group: dogsX-Remote-Group: dachshundsX-Remote-Extra-Acme.com%2Fproject: some-projectX-Remote-Extra-Scopes: openidX-Remote-Extra-Scopes: profile

would result in this user info:

name:fidogroups:- dogs- dachshundsextra:acme.com/project:- some-projectscopes:- openid- profile

Note:

Prior to Kubernetes 1.11.3 (and 1.10.7, 1.9.11), theextra key could only contain characters thatwerelegal in HTTP header labels.

Client certificate

In order to prevent header spoofing, the authenticating proxy is required to present a valid clientcertificate to the API server for validation against the specified CA before the request headers arechecked.

Donot reuse a CA that is used in a different context unless you understandthe risks and the mechanisms to protect the CA's usage.

Static token file integration

The API server reads static bearer tokens from a file when given the--token-auth-file=<SOMEFILE>option on the command line.In Kubernetes 1.35, tokens last indefinitely, and the token list cannot bechanged without restarting the API server.

The token file is a CSV file with a minimum of 3 columns: token, user name, user uid,followed by a comma-separated list of optional group names.

Note:

If you have more than one group, the column must be double quoted e.g.

token,user,uid,"group1,group2,group3"

Using a static token file is appropriate for tokens that by their natureare long-lived, static, and perhaps may never be rotated. It is also usefulwhen the client is local to a particular API server within the control plane,such as a monitoring agent.

If you use this method during cluster provisioning, and then transition toa different authentication method that will be used longer term, youshould deactivate the token that was used for bootstrapping (this requiresa restart of each API server.

For other circumstances, and especially where very prompt token rotation isimportant, the Kubernetes project recommends using awebhook token authenticator instead of this mechanism.

User impersonation

User impersonation providesa method that a user can act as another user through impersonation headers

client-go credential plugins

FEATURE STATE:Kubernetes v1.22 [stable]

k8s.io/client-go and tools using it such askubectl andkubelet are able to execute anexternal command to receive user credentials.

This feature is intended for client side integrations with authentication protocols not nativelysupported byk8s.io/client-go (LDAP, Kerberos, OAuth2, SAML, etc.). The plugin implements theprotocol specific logic, then returns opaque credentials to use. Almost all credential pluginuse cases require a server side component with support for thewebhook token authenticatorto interpret the credential format produced by the client plugin.

Note:

Earlier versions ofkubectl included built-in support for authenticating to AKS and GKE, but this is no longer present.

Example use case

In a hypothetical use case, an organization would run an external service that exchanges LDAP credentialsfor user specific, signed tokens. The service would also be capable of responding towebhook tokenauthenticator requests to validate the tokens. Users would be requiredto install a credential plugin on their workstation.

To authenticate against the API:

  • The user issues akubectl command.
  • Credential plugin prompts the user for LDAP credentials, exchanges credentials with external service for a token.
  • Credential plugin returns token to client-go, which uses it as a bearer token against the API server.
  • API server uses thewebhook token authenticator to submit aTokenReview to the external service.
  • External service verifies the signature on the token and returns the user's username and groups.

Configuration

Credential plugins are configured throughkubectl config filesas part of the user fields.

apiVersion:v1kind:Configusers:-name:my-useruser:exec:# Command to execute. Required.command:"example-client-go-exec-plugin"# API version to use when decoding the ExecCredentials resource. Required.## The API version returned by the plugin MUST match the version listed here.## To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1beta1),# set an environment variable, pass an argument to the tool that indicates which version the exec plugin expects,# or read the version from the ExecCredential object in the KUBERNETES_EXEC_INFO environment variable.apiVersion:"client.authentication.k8s.io/v1"# Environment variables to set when executing the plugin. Optional.env:-name:"FOO"value:"bar"# Arguments to pass when executing the plugin. Optional.args:-"arg1"-"arg2"# Text shown to the user when the executable doesn't seem to be present. Optional.installHint:|        example-client-go-exec-plugin is required to authenticate        to the current cluster.  It can be installed:        On macOS: brew install example-client-go-exec-plugin        On Ubuntu: apt-get install example-client-go-exec-plugin        On Fedora: dnf install example-client-go-exec-plugin        ...# Whether or not to provide cluster information, which could potentially contain# very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO# environment variable.provideClusterInfo:true# The contract between the exec plugin and the standard input I/O stream. If the# contract cannot be satisfied, this plugin will not be run and an error will be# returned. Valid values are "Never" (this exec plugin never uses standard input),# "IfAvailable" (this exec plugin wants to use standard input if it is available),# or "Always" (this exec plugin requires standard input to function). Required.interactiveMode:Neverclusters:-name:my-clustercluster:server:"https://172.17.4.100:6443"certificate-authority:"/etc/kubernetes/ca.pem"extensions:-name:client.authentication.k8s.io/exec# reserved extension name for per cluster exec configextension:arbitrary:configthis:can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfoyou:["can","put","anything","here"]contexts:-name:my-clustercontext:cluster:my-clusteruser:my-usercurrent-context:my-cluster

apiVersion:v1kind:Configusers:-name:my-useruser:exec:# Command to execute. Required.command:"example-client-go-exec-plugin"# API version to use when decoding the ExecCredentials resource. Required.## The API version returned by the plugin MUST match the version listed here.## To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1),# set an environment variable, pass an argument to the tool that indicates which version the exec plugin expects,# or read the version from the ExecCredential object in the KUBERNETES_EXEC_INFO environment variable.apiVersion:"client.authentication.k8s.io/v1beta1"# Environment variables to set when executing the plugin. Optional.env:-name:"FOO"value:"bar"# Arguments to pass when executing the plugin. Optional.args:-"arg1"-"arg2"# Text shown to the user when the executable doesn't seem to be present. Optional.installHint:|        example-client-go-exec-plugin is required to authenticate        to the current cluster.  It can be installed:        On macOS: brew install example-client-go-exec-plugin        On Ubuntu: apt-get install example-client-go-exec-plugin        On Fedora: dnf install example-client-go-exec-plugin        ...# Whether or not to provide cluster information, which could potentially contain# very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO# environment variable.provideClusterInfo:true# The contract between the exec plugin and the standard input I/O stream. If the# contract cannot be satisfied, this plugin will not be run and an error will be# returned. Valid values are "Never" (this exec plugin never uses standard input),# "IfAvailable" (this exec plugin wants to use standard input if it is available),# or "Always" (this exec plugin requires standard input to function). Optional.# Defaults to "IfAvailable".interactiveMode:Neverclusters:-name:my-clustercluster:server:"https://172.17.4.100:6443"certificate-authority:"/etc/kubernetes/ca.pem"extensions:-name:client.authentication.k8s.io/exec# reserved extension name for per cluster exec configextension:arbitrary:configthis:can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfoyou:["can","put","anything","here"]contexts:-name:my-clustercontext:cluster:my-clusteruser:my-usercurrent-context:my-cluster

Relative command paths are interpreted as relative to the directory of the config file. IfKUBECONFIG is set to/home/jane/kubeconfig and the exec command is./bin/example-client-go-exec-plugin,the binary/home/jane/bin/example-client-go-exec-plugin is executed.

-name:my-useruser:exec:# Path relative to the directory of the kubeconfigcommand:"./bin/example-client-go-exec-plugin"apiVersion:"client.authentication.k8s.io/v1"interactiveMode:Never

Input and output formats

The executed command prints anExecCredential object tostdout.k8s.io/client-goauthenticates against the Kubernetes API using the returned credentials in thestatus.The executed command is passed anExecCredential object as input via theKUBERNETES_EXEC_INFOenvironment variable. This input contains helpful information like the expected API versionof the returnedExecCredential object and whether or not the plugin can usestdin to interactwith the user.

When run from an interactive session (i.e., a terminal),stdin can be exposed directlyto the plugin. Plugins should use thespec.interactive field of the inputExecCredential object from theKUBERNETES_EXEC_INFO environment variable in order todetermine ifstdin has been provided. A plugin'sstdin requirements (i.e., whetherstdin is optional, strictly required, or never used in order for the pluginto run successfully) is declared via theuser.exec.interactiveMode field in thekubeconfig(see table below for valid values). Theuser.exec.interactiveMode field is optionalinclient.authentication.k8s.io/v1beta1 and required inclient.authentication.k8s.io/v1.

interactiveMode values
interactiveMode ValueMeaning
NeverThis exec plugin never needs to use standard input, and therefore the exec plugin will be run regardless of whether standard input is available for user input.
IfAvailableThis exec plugin would like to use standard input if it is available, but can still operate if standard input is not available. Therefore, the exec plugin will be run regardless of whether stdin is available for user input. If standard input is available for user input, then it will be provided to this exec plugin.
AlwaysThis exec plugin requires standard input in order to run, and therefore the exec plugin will only be run if standard input is available for user input. If standard input is not available for user input, then the exec plugin will not be run and an error will be returned by the exec plugin runner.

To use bearer token credentials, the plugin returns a token in the status of theExecCredential

{"apiVersion":"client.authentication.k8s.io/v1","kind":"ExecCredential","status": {"token":"my-bearer-token"  }}

{"apiVersion":"client.authentication.k8s.io/v1beta1","kind":"ExecCredential","status": {"token":"my-bearer-token"  }}

Alternatively, a PEM-encoded client certificate and key can be returned to use TLS client auth.If the plugin returns a different certificate and key on a subsequent call,k8s.io/client-gowill close existing connections with the server to force a new TLS handshake.

If specified,clientKeyData andclientCertificateData must both must be present.

clientCertificateData may contain additional intermediate certificates to send to the server.

{"apiVersion":"client.authentication.k8s.io/v1","kind":"ExecCredential","status": {"clientCertificateData":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----","clientKeyData":"-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"  }}

{"apiVersion":"client.authentication.k8s.io/v1beta1","kind":"ExecCredential","status": {"clientCertificateData":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----","clientKeyData":"-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"  }}

Optionally, the response can include the expiry of the credential formatted as aRFC 3339 timestamp.

Presence or absence of an expiry has the following impact:

  • If an expiry is included, the bearer token and TLS credentials are cached untilthe expiry time is reached, or if the server responds with a 401 HTTP status code,or when the process exits.
  • If an expiry is omitted, the bearer token and TLS credentials are cached untilthe server responds with a 401 HTTP status code or until the process exits.

{"apiVersion":"client.authentication.k8s.io/v1","kind":"ExecCredential","status": {"token":"my-bearer-token","expirationTimestamp":"2018-03-05T17:30:20-08:00"  }}

{"apiVersion":"client.authentication.k8s.io/v1beta1","kind":"ExecCredential","status": {"token":"my-bearer-token","expirationTimestamp":"2018-03-05T17:30:20-08:00"  }}

To enable the exec plugin to obtain cluster-specific information, setprovideClusterInfo on theuser.execfield in thekubeconfig.The plugin will then be supplied this cluster-specific information in theKUBERNETES_EXEC_INFO environment variable.Information from this environment variable can be used to perform cluster-specificcredential acquisition logic.The followingExecCredential manifest describes a cluster information sample.

{"apiVersion":"client.authentication.k8s.io/v1","kind":"ExecCredential","spec": {"cluster": {"server":"https://172.17.4.100:6443","certificate-authority-data":"LS0t...","config": {"arbitrary":"config","this":"can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo","you": ["can","put","anything","here"]      }    },"interactive":true  }}

{"apiVersion":"client.authentication.k8s.io/v1beta1","kind":"ExecCredential","spec": {"cluster": {"server":"https://172.17.4.100:6443","certificate-authority-data":"LS0t...","config": {"arbitrary":"config","this":"can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo","you": ["can","put","anything","here"]      }    },"interactive":true  }}

API access to authentication information for a client

FEATURE STATE:Kubernetes v1.28 [stable]

If your cluster has the API enabled, you can use the SelfSubjectReview API to find outhow your Kubernetes cluster maps your authentication information to identify you as a client.This works whether you are authenticating as a user (typically representinga real person) or as a ServiceAccount.

SelfSubjectReview objects do not have any configurable fields. On receiving a request,the Kubernetes API server fills the status with the user attributes and returns it to the user.

Request example (the body would be a SelfSubjectReview):

POST /apis/authentication.k8s.io/v1/selfsubjectreviews
{"apiVersion":"authentication.k8s.io/v1","kind":"SelfSubjectReview"}

Response example:

{"apiVersion":"authentication.k8s.io/v1","kind":"SelfSubjectReview","status": {"userInfo": {"name":"jane.doe","uid":"b6c7cfd4-f166-11ec-8ea0-0242ac120002","groups": ["viewers","editors","system:authenticated"      ],"extra": {"provider_id": ["token.company.example"]      }    }  }}

For convenience, thekubectl auth whoami command is present. Executing this command willproduce the following output (yet different user attributes will be shown):

  • Simple output example

    ATTRIBUTE         VALUEUsername          jane.doeGroups            [system:authenticated]
  • Complex example including extra attributes

    ATTRIBUTE         VALUEUsername          jane.doeUID               b79dbf30-0c6a-11ed-861d-0242ac120002Groups            [students teachers system:authenticated]Extra: skills     [reading learning]Extra: subjects   [math sports]

By providing the output flag, it is also possible to print the JSON or YAML representation of the result:

{"apiVersion":"authentication.k8s.io/v1","kind":"SelfSubjectReview","status": {"userInfo": {"username":"jane.doe","uid":"b79dbf30-0c6a-11ed-861d-0242ac120002","groups": ["students","teachers","system:authenticated"      ],"extra": {"skills": ["reading","learning"        ],"subjects": ["math","sports"        ]      }    }  }}

apiVersion:authentication.k8s.io/v1kind:SelfSubjectReviewstatus:userInfo:username:jane.doeuid:b79dbf30-0c6a-11ed-861d-0242ac120002groups:- students- teachers- system:authenticatedextra:skills:- reading- learningsubjects:- math- sports

This feature is extremely useful when a complicated authentication flow is used in a Kubernetes cluster,for example, if you usewebhook token authenticationorauthenticating proxy.

Note:

The Kubernetes API server fills theuserInfo after all authentication mechanisms are applied,includingimpersonation.If you, or an authentication proxy, make a SelfSubjectReview using impersonation,you see the user details and properties for the user that was impersonated.

By default, all authenticated users can createSelfSubjectReview objects when theAPISelfSubjectReviewfeature is enabled. It is allowed by thesystem:basic-user cluster role.

Note:

You can only makeSelfSubjectReview requests if:

  • theAPISelfSubjectReviewfeature gateis enabled for your cluster (not needed for Kubernetes 1.35, but olderKubernetes versions might not offer this feature gate, or might default it to be off)
  • (if you are running a version of Kubernetes older than v1.28) the API server for yourcluster has theauthentication.k8s.io/v1alpha1 orauthentication.k8s.io/v1beta1API groupenabled.

What's next

Last modified September 20, 2025 at 3:13 PM PST:Revise authn reference mentions of JWT (01fc1f6e90)