Table of contents
Securing access to a Kubernetes cluster is a fundamental aspect of maintaining its integrity. By integrating Keycloak, an open-source identity and access management solution, you can leverage its robust authentication mechanisms to control access to Kubernetes resources effectively. This guide outlines how to configure Keycloak as an OpenID Connect (OIDC) identity provider for Kubernetes.
Environment Setup
Operating System: Ubuntu 22
Kubernetes Cluster: Version 1.31
What is Kubernetes?
Kubernetes is an open-source container orchestration engine that automates the deployment, scaling, and management of containerized applications. It allows applications to be deployed as microservices, enabling easier updates, maintenance, and scalability. The Kubernetes API server, a critical component running on the master node, manages all API requests for the cluster. Authentication and authorization are essential to secure these requests and protect cluster resources.
Kubernetes API can be accessed via:
kubectl: CLI tool
Client libraries
REST API requests
Kubernetes supports multiple authentication modules, including client certificates, passwords, tokens, and JSON web tokens (JWTs).
Keycloak Integration Steps
Step 1: Generate Certificate Key Pair for Keycloak Server
Secure communication with Keycloak requires SSL certificates. Use Cert-Manager to generate self-signed certificates.
Install Cert-Manager using Helm
helm repo add jetstack https://charts.jetstack.io --force-update helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.16.2 \ --set crds.enabled=true
Create an Issuer
# issuer.yaml apiVersion: v1 kind: Namespace metadata: name: keycloak --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: selfsigned-issuer spec: selfSigned: {} --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: keycloak-ca namespace: keycloak spec: isCA: true commonName: keycloak-ca secretName: root-secret privateKey: algorithm: ECDSA size: 256 issuerRef: name: selfsigned-issuer kind: ClusterIssuer group: cert-manager.io
Generate Keycloak Certificate
# certificate.yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: keycloak namespace: keycloak spec: secretName: keycloak-tls duration: 2160h renewBefore: 360h subject: organizations: - home-k8s-lab isCA: false privateKey: algorithm: RSA encoding: PKCS1 size: 2048 usages: - server auth - client auth commonName: keycloak.devops.com dnsNames: - keycloak.devops.com issuerRef: name: keycloak-ca-issuer kind: Issuer
Apply the configurations:
kubectl apply -f issuer.yaml kubectl apply -f certificate.yaml
Step 2: Install Keycloak
Deploy Keycloak using the Bitnami Helm chart with the following configuration:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm upgrade --install keycloak --namespace keycloak bitnami/keycloak --reuse-values -f keycloak-values.yaml
keycloak-values.yaml
production: true auth: createAdminUser: true adminUser: admin adminPassword: admin12345 tls: enabled: true autoGenerated: true ingress: enabled: true hostname: keycloak.devops.com ingressClassName: nginx annotations: nginx.ingress.kubernetes.io/backend-protocol: HTTPS servicePort: https tls: true extraTls: - hosts: - keycloak.devops.com secretName: keycloak-tls postgresql: enabled: true postgresqlPassword: psqldbpass12345
Step 3: Configure Kubernetes API Server
Extract the Keycloak CA certificate:
kubectl get secret keycloak-tls -n keycloak -o yaml
Decode and save the
ca.crt
:echo "<base64-ca.crt>" | base64 -d > /etc/ssl/certs/keycloak-ca.crt
Edit the API server manifest:
vi /etc/kubernetes/manifests/kube-apiserver.yaml
Add the following flags:
- --oidc-issuer-url=https://keycloak.devops.com/realms/kubernetes - --oidc-client-id=kubernetes - --oidc-username-claim=email - --oidc-groups-claim=groups - --oidc-ca-file=/etc/ssl/certs/keycloak-ca.crt
Step 4: Configure Keycloak
Create a new realm and Client
First let’s setup a new realm named ‘kubernetes’ and create a clinet named kubernetes
inside it as shown below .
Once the client has been created, let’s create client scope named ‘groups’ and map the required claims (ie. name – user attribute and groups – group membership) as shown in the below screenshots. make sure group claim name matches the client scope name or the claim you wanted to claim. in our caese its groups
. disable full group path to make it work.
Now that we are completed the setup for client id and client scope we need to map the client scope to the client id that we created earlier so that the required mappers are mapped to the client id.
In realm settings
- login
- session
create user and group
Step 5: Configure RBAC in Kubernetes
Define roles and bindings for the developers
group:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: developer-role
rules:
- apiGroups: [""]
resources: ["namespaces", "pods"]
verbs: ["get", "watch", "list"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: developer-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: developer-role
subjects:
- kind: Group
name: "developers"
apiGroup: rbac.authorization.k8s.io
Apply the configuration:
kubectl apply -f devrole.yaml
Step 6: Configure User Context
Use the following script to create a user context in kubectl
:
#!/bin/bash
scope=openid
client_id=kubernetes
client_secret=<client-secret>
username=naveen
password=1234
oidc_url=https://keycloak.devops.com/auth/realms/kubernetes/protocol/openid-connect/token
realm_url=https://keycloak.devops.com/auth/realms/kubernetes
# Generate tokens
json_data=$(curl -k -d "grant_type=password" -d "scope=${scope}" -d "client_id=${client_id}" -d "client_secret=${client_secret}" -d "username=${username}" -d "password=${password}" ${oidc_url})
id_token=$(echo $json_data | jq '.id_token' | tr -d '"')
refresh_token=$(echo $json_data | jq '.refresh_token' | tr -d '"')
# Update kubectl config
kubectl config set-credentials ${username} \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=${realm_url} \
--auth-provider-arg=client-id=${client_id} \
--auth-provider-arg=client-secret=${client_secret} \
--auth-provider-arg=refresh-token=${refresh_token} \
--auth-provider-arg=id-token=${id_token}
kubectl config set-context ${username} --cluster=kubernetes --user=${username}
kubectl --context=${username} get pods
Conclusion
By integrating Keycloak with Kubernetes, you can streamline authentication and enhance cluster security. This setup leverages OIDC to provide centralized identity management and simplifies user access control through Kubernetes RBAC policies. With this integration, managing a secure and scalable Kubernetes environment becomes seamless and efficient.
Special Notes:
kubectl client will use a refresh token and ID token to generate an access token, so you need to configure the the duration of tokens in keycloak according to requirement.
If you face any issue during api-server restart , check its logs using crictl client
observe kubeconfig file it should have both refresh token and ID token and they should not be expired.
References: