K8s Access Control: Authentication with OIDC
Why it matters
Kubernetes does not have objects in the API sever which represent normal user accounts or groups. There are no objects called “User” or “Group.” It relies on external authentication mechanisms to identify users and grant them permissions. This means you'll need to integrate your cluster with an identity provider (IdP) to authenticate users and assign them roles. The specific method of authentication and authorization will depend on your chosen IdP and configuration.
OIDC authentication enhances Kubernetes security and streamlines external user and group management, making it a ideal choice to control access to your clusters.
The big picture
The K8s documentation Controlling Access to the Kubernetes API, does a great job introducing the stages a request traverses within the API server.
The interest here is the Authentication modules (or I've seen it referred as plugins as well) and how to enable a method for user authentication. Particularly the OpenID Connect (OIDC) Token authentication strategy.
OpenID Connect (OIDC - built on the OAuth 2.0 specification) allows seamless integration with identity providers for Kubernetes authentication. This means you can use your existing identity management system to control access to your Kubernetes resources.
The OIDC ID Token is a JSON Web Token that encapsulates the user identity, including a uique identifier, groups, and expiration information about the user that the API server can use to authorize their access. The JWT is signed by an identity provider’s certificate and can be verified by Kubernetes, simply by checking the JWT’s signature. This is the token passed to Kubernetes for each request to authenticate the external user.
Key components
To implement OIDC authentication in Kubernetes, you need to focus on three main areas:
- kube-apiserver oidc flags
- kubeconfig setup
- identity provider integration
How it works
Prerequisites
- Compute, in my case I'm playing with Iximiuz Labs - remote DevOps playgrounds
- Kind v0.25.0 single node cluster
- Kubectl v1.31.3
- An Auth0 (free) development instance as the Identity Provider
Kube-apiserver configuration
Add the OIDC flags to the API server and provide the OIDC certificate so that the API will trust the OIDC provider.
--oidc-issuer-url="https://amapiano-idp.us.auth0.com/"
--oidc-client-id="jLe7RD4MqaW6fFgRwOXa8B0n3OVFt4Z7"
--oidc-username-claim="email"
--oidc-groups-claim="groups"
--oidc-ca-file="/auth0/auth0-ca.crt"
One key technical detail is that the Kubernetes API server's built-in OpenID Connect authenticator supports the OIDC discovery mechanism, which helps the server find the configuration it needs to authenticate users.
For this exercise:
- I used the email claim for the OIDC username. However, since emails change, it's better to use the sub claim (subject, a standard unique identifier claim) or a custom identifier claim that your IdP uses.
- I configured the api oidc-groups-claim flag as
groups
however given this is not a standard OIDC claim, I have not yet setup the Auth0 IdP to add in a groups claim. I will look into this in a future post, likely one where I explore the Authorization module.
For the oidc-ca-file
, I obtained the certificate for the CA that signed Auth0 identity provider's web certificate by using the following tooling:
openssl s_client -showcerts -connect amapiano-idp.us.auth0.com:443 -servername amapiano-idp.us.auth0.com </dev/null | openssl x509 -out /tmp/auth0-ca.crt
Troubleshooting
Api server:
- enable the logging level to
--v=6
to see the athentication module logs. For example, when I was first setting up the OIDC IdP settings, I created a "fake" user within Auth0 and did not verify the user's email. Here were the messages I received and could see within the logs.
# Kubectl messaged received
$ kubectl --user=demo auth whoami
error: You must be logged in to the server (Unauthorized)
# Kube-apiserver error log
E1205 00:30:40.127319 1 authentication.go:73] "Unable to authenticate the request" err="[invalid bearer token, oidc: email not verified]
Kubeconfig configuration
I purposely focused on obtaining tokens using the Resource Owner Password Credentials grant type. While this grant type is not widely recommended due to its security implications, it's a straightforward way to acquire tokens without browser based flows, making it ideal for learning and demonstration purposes. I've packaged a bash script (k8s_user_auth_init.sh
) within the Iximiuz playground home directory to streamline this process.
The script will mint an ID token, configure a kubeconfig file with the token for user authentication, and then grant the user the cluster-admin role for simplicity.
One key detail when obtaining the id_token
is the scope to include in the OAuth 2.0 request. For example, in the bash script (available in the playground), it includes the openid
and email
scopes.
openid
: (Required) This indicates to the service provider that the client is making an OpenID Connect requestemail
: (Optional) This requests access to the user's e-mail address
curl -s --request POST \
--url 'https://amapiano-idp.us.auth0.com/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=password \
--data "username=${username}" \
--data "password=${password}" \
--data scope='openid email' \
--data "client_id=${client_id}" \
--data "client_secret=${client_secret}")
This Start Playground will fire up the custom Kind Cluster: OIDC AuthN playground. Playground initialization should take roughly one minute. Once fully initialized, execute the scripts below from the home directory. Once executed, the script's output will provide further instruction.
laborant@docker-01:~$ ./k8s_user_auth_init.sh
A note on Iximiuz Labs playgrounds:
- Free to signup and use
- Requires a github account to signup (if you happen to have a fresh github account during Iximiuz signup/signin, and extra "Discord" verification step is required
- Limited internet access and reduced cpu/memory resources
- There is an option to upgrade to Premium for larger VMs and unrestricted internet access (to defend from crypto bots and spam)
Feel free to explore the Kind configuration, makefile and script for more details on the playground setup.
OIDC identity provider integration
I ended up leveraging Auth0.com's free development IdP instance which provided enough of the necessary OAuth 2.0/OIDC and custom user management configuration.
Here is the well-known public endpoint for reference: