kubernetes using OpenID Connect Tokens authentication

来源:互联网 发布:美国历史书籍推荐知乎 编辑:程序博客网 时间:2024/06/07 04:49

https://kubernetes.io/docs/admin/authentication/#openid-connect-tokens

OpenID Connect Tokens

OpenID Connect is a flavor of OAuth2 supported by some OAuth2 providers, notably Azure Active Directory, Salesforce, and Google. The protocol’s main extension of OAuth2 is an additional field returned with the access token called an ID Token. This token is a JSON Web Token (JWT) with well known fields, such as a user’s email, signed by the server.

To identify the user, the authenticator uses the id_token (not the access_token) from the OAuth2 token response as a bearer token. See above for how the token is included in a request.

Kubernetes OpenID Connect Flow

  1. Login to your identity provider
  2. Your identity provider will provide you with an access_tokenid_token and a refresh_token
  3. When using kubectl, use your id_token with the --token flag or add it directly to your kubeconfig
  4. kubectl sends your id_token in a header called Authorization to the API server
  5. The API server will make sure the JWT signature is valid by checking against the certificate named in the configuration
  6. Check to make sure the id_token hasn’t expired
  7. Make sure the user is authorized
  8. Once authorized the API server returns a response to kubectl
  9. kubectl provides feedback to the user

Since all of the data needed to validate who you are is in the id_token, Kubernetes doesn’t need to “phone home” to the identity provider. In a model where every request is stateless this provides a very 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 or interface to collect credentials which is why you need to authenticate to your identity provider first.
  2. The id_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. There’s no easy way to authenticate to the Kubernetes dashboard without using the kubectl proxy command or a reverse proxy that injects the id_token.

Configuring the API Server

To enable the plugin, configure the following flags on the API server:

ParameterDescriptionExampleRequired--oidc-issuer-urlURL of the provider which allows the API server to discover public signing keys. Only URLs which use the https:// scheme are accepted. This is typically the provider’s discovery URL without a path, for example “https://accounts.google.com” or “https://login.salesforce.com”. This URL should point to the level below .well-known/openid-configurationIf the discovery URL is https://accounts.google.com/.well-known/openid-configuration, the value should be https://accounts.google.comYes--oidc-client-idA client id that all tokens must be issued for.kubernetesYes--oidc-username-claimJWT claim to use as the user name. By default sub, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as email or name, depending on their provider. However, claims other than email will be prefixed with the issuer URL to prevent naming clashes with other plugins.subNo--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-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

If a claim other than email is chosen for --oidc-username-claim, the value will be prefixed with the --oidc-issuer-url to prevent clashes with existing Kubernetes names (such as the system: users). For example, if the provider URL is https://accounts.google.com and the username claim maps to jane, the plugin will authenticate the user as:

https://accounts.google.com#jane

Importantly, the API server is not an OAuth2 client, rather it can only be configured to trust a single issuer. This allows the use of public providers, such as Google, without trusting credentials issued to third parties. Admins who wish to utilize multiple OAuth clients should explore providers which support the azp (authorized party) claim, a mechanism for allowing one client to issue tokens on behalf of another.

Kubernetes does not provide an OpenID Connect Identity Provider. You can use an existing public OpenID Connect Identity Provider (such as Google, or others). Or, you can run your own Identity Provider, such as CoreOS dex, Keycloak, CloudFoundry UAA, or Tremolo Security’s OpenUnison.

For an identity provider to work with Kubernetes it must:

  1. Support OpenID connect discovery; not all do.
  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 own identity provider (as opposed to one of the cloud providers like Google or Microsoft) you MUST have your identity provider’s web server certificate signed by a certificate with the CAflag set to TRUE, even if it is self signed. This is due to GoLang’s TLS client implementation being very strict to the standards around certificate validation. If you don’t have a CA handy, you can use this script from the CoreOS team to create a simple CA and a signed certificate and key pair. Or you can use this similar script that generates SHA256 certs with a longer life and larger key size.

Setup instructions for specific systems:

  • UAA
  • Dex
  • OpenUnison

Using kubectl

Option 1 - OIDC Authenticator

The first option is to use the oidc authenticator. This authenticator takes your id_tokenrefresh_token and your OIDC client_secret and will refresh your token automatically. Once you have authenticated to your identity provider:

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 ) \   --auth-provider-arg=extra-scopes=( comma separated list of scopes to add to "openid email profile", optional )

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=extra-scopes=groups \        --auth-provider-arg=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw

Which would produce the below configuration:

users:- name: mmosley  user:    auth-provider:      config:        client-id: kubernetes        client-secret: 1db158f6-177d-4d9c-8a8b-d36869918ec5        extra-scopes: groups        id-token: eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw        idp-certificate-authority: /root/ca.pem        idp-issuer-url: https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP        refresh-token: q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXq      name: oidc

Once your id_token expires, kubectl will attempt to refresh your id_token using your refresh_token and client_secret storing the new values for the refresh_token and id_token in your kube/.config.

Option 2 - Use the --token Option

The kubectl command lets you pass in a token using the --token option. Simply copy and paste the id_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

Webhook authentication is a hook for verifying bearer tokens.

  • --authentication-token-webhook-config-file a kubeconfig file describing how to access the remote webhook service.
  • --authentication-token-webhook-cache-ttl how long to cache authentication decisions. Defaults to two minutes.

The configuration file uses the kubeconfig file format. Within the file “users” refers to the API server webhook and “clusters” refers to the remote service. An example would be:

# clusters refers to the remote service.clusters:  - name: name-of-remote-authn-service    cluster:      certificate-authority: /path/to/ca.pem         # CA for verifying the remote service.      server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'.# users refers to the API server's webhook configuration.users:  - name: name-of-api-server    user:      client-certificate: /path/to/cert.pem # cert for the webhook plugin to use      client-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-service    user: name-of-api-sever  name: webhook

When a client attempts to authenticate with the API server using a bearer token as discussed above, the authentication webhook queries the remote service with a review object containing the token. Kubernetes will not challenge a request that lacks such a header.

Note that webhook API objects are subject to the same versioning compatibility rules as other Kubernetes API objects. Implementers should be aware of looser compatibility promises for beta objects and check the “apiVersion” field of the request to ensure correct deserialization. Additionally, the API server must enable the authentication.k8s.io/v1beta1 API extensions group (--runtime-config=authentication.k8s.io/v1beta1=true).

The request body will be of the following format:

{  "apiVersion": "authentication.k8s.io/v1beta1",  "kind": "TokenReview",  "spec": {    "token": "(BEARERTOKEN)"  }}

The remote service is expected to fill the status field of the request to indicate the success of the login. The response body’s spec field is ignored and may be omitted. A successful validation of the bearer token would return:

{  "apiVersion": "authentication.k8s.io/v1beta1",  "kind": "TokenReview",  "status": {    "authenticated": true,    "user": {      "username": "janedoe@example.com",      "uid": "42",      "groups": [        "developers",        "qa"      ],      "extra": {        "extrafield1": [          "extravalue1",          "extravalue2"        ]      }    }  }}

An unsuccessful request would return:

{  "apiVersion": "authentication.k8s.io/v1beta1",  "kind": "TokenReview",  "status": {    "authenticated": false  }}

HTTP status codes can be used to supply additional error context.



阅读全文
0 0
原创粉丝点击