Secure Your Kubernetes Cluster with Keycloak: A Step-by-Step Guide

Secure Your Kubernetes Cluster with Keycloak: A Step-by-Step Guide

·

5 min read

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.

  1. 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
    
  2. 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
    
  3. 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

  1. 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
    
  2. 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 .

Screenshot 2024-12-06 154142

Screenshot 2024-12-06 154125

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.

Screenshot 2024-12-06 153942

Screenshot 2024-12-06 153913

Screenshot 2024-12-06 153855

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

Screenshot 2024-12-06 153432

  • session

Screenshot 2024-12-06 153523

create user and group

Screenshot 2024-12-06 153628


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: