Note
This follows from my blog post located here. There are a series of three posts covering OAAuth and OIDC that are helpful in understanding the steps below.
https://developer.okta.com/signup/
- From the
Directorylink in the left gutter, use theGroupandPeoplelinks to create a group calledk8s-cluster-adminsand a user. Set the user password to not require change on first login. Place the user in the group.
Tip
For the flow of this guide, preface your group names with k8s- (e.g. k8s-cluster-admins).
- From the
Applicationslink in the left gutter, selectCreate App Integration
- Select
OIDC - OpenID ConnectandNative Application, clickNext
- Give it an App Integration name ok K8s. In the Sign-in and Sign-out redirect URIs specify
http://localhost:8000. SelectAllow everyone in your organization to access. ClickSave.
- Copy the
Client IDand save for later. Make sureRequire PKCE as additional verificationis selected.
- From the
Securitylink in the left gutter, select sub menuAPI. ClickAdd Authorization Server
- Give it the name
K8s. Specifyhttp://localhost:8000forAudience. (You may need to clickSaveand thenEditto complete the rest of thsi step) SelectOkta URLforIssuer. ClickSave. Copy theIssuer URL(In parenthesis afterOkta URL) for later.
- Select the
Claimstab and click onAdd Claim.
- Specify
groupsforName.Include in token typeID Token Always.Value typeGroups.FilterStarts with k8s. ClickCreate
- Click on the
Access Policytab and thenAdd Policy
- Name and Description is
K8s.Assign to the following clientsisK8s. ClickCreate Policy.
- Click
Add Rule
- Set config to image below and click
Create Rule
That does it for setting up your OIDC enabled Authorization Server. We can now authenticate to it and receive access and ID tokens.
We've defined a group that will be used in our cluster RBAC. We've setup an Authorization Server and copied the issuer URL to configure our Client. We've defined an auth flow for OIDC with System grant type (System is a Public Cient config that allows redirect to localhost).
We've said we want to generate ID tokens and include only groups from the Directory service that begin with k8s- within the token Scope fields (This reduces the group membership information to only those needed and reduces the chance of group name collisions). Next we configure kube-api server and kubectl.
These two links provide further background on the grant type we've selected to use:
https://www.oauth.com/oauth2-servers/oauth-native-apps/
https://www.oauth.com/oauth2-servers/oauth-native-apps/redirect-urls-for-native-apps/
This step will vary based on your K8s cluster. I will show the steps for a cluster deployed by Kubeadm. If you are using a different deployment method for K8s, refer to your docs on how to configure the kube-apiserver.
- Edit
/etc/kubernetes/manifests/kube-apiserver.yamlon each control plane node. Add the following lines to the kube-apiserver commands:
spec:
containers:
- command:
- kube-apiserver
- --oidc-issuer-url=<The Issuer URL we saved earlier (just the url)>
- --oidc-client-id=<The Client ID we saved earlier>
- --oidc-username-claim=email
- --oidc-groups-claim=groupsIn this step, we create a ClusterRoleBinding to the default cluster-admin role with the group name we created in our Directory Service. The group name that is subsequently added to our ID Token as a Scope. kube-apiserver has no concept of groups beyond RBAC. If your token or certificate (regardless of what valid way it was created) says you belong to a group, then kube-apiserver will consider that against ClusterRoleBindigns and RoleBindings.
kubectl apply -f - <<EOF
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: oidc-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: Group
name: k8s-cluster-admins #<-- This is the group membership we present in our OIDC ID Token
EOFThis config must be performed on a client with a web browser. It will not work for hosts you are SSH connected to. There is an Authorization code flow with a keyboard that is similar to how you enter a code in a browser when you sign-in to smart tv streaming apps. I'm not covering it here, but it's in the kubelogin docs.
The installation steps vary based on your OS. Rather than recreate the docs for it, I'll point you to the repo where you can perform the task. I find the easiest way across OS platforms is to use the kubectl krew plugin manager.
https://github.com/int128/kubelogin
- Add the following under users section (Add the correct issuer url and client id):
users:
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=<issuer url>
- --oidc-client-id=<client id>
- --oidc-extra-scope="email offline_access profile openid"- Use the
kubectlcommand with the --user=oidc flag.
kubectl get nodes --user=oidc
This will pop you to your browser with a login page. Sign in as your user and that's it!
You can use an online tool to decode your ID Token if you'd like to see what it contains:
- Print contents of the token file
cat ~/.kube/cache/oidc-login/<should be only one file here to choose>-
Copy everything between quotes after
{"id_token":to your clipboard. -
Paste them into the
JWT Stringinput form at https://token.dev/
Within the Payload output, you should see your username/email and groups you are a member of.
Certificate and SA token based authentication will still work. But you can now craft and distribute kube config files without including security sensitive certificates with keys.
You can use the same Authorization server for as many clusters as you'd like. Simply configure the cluster RBAC to grant privileges based on group names from your IdP Directory Service. A good next step would be creating additional groups and users, assigning RBAC to various groups based on namespaces. I personally don't like the fantasy of namespace tenanting K8s control planes, but you can play around with cluster admins vs. namespaced users which is a valid security task. In my next blog post, I cover vCluster which I consider a better method of multi-tenanting a K8s control plane.
There is a now abandoned project called Gangway that aimed at making the config on the kubectl client side easier. I don't know where that ended up. But you could check it out.
A newer project named Pinniped (I think that is a seal) exists to make it 'easy' to setup auth. But in my few brief reviews of it, there are so many moving parts that I didn't get the 'easy button' sense at all. Worth keeping an eye on though.
Net/net, this three part series was on OIDC more than K8s. While I've used K8s as a working example, I was aiming at conveying an understanding of how OAuth/OIDC JWTs are trusted and applied by Resource Servers.














