Keycloak Operator for Kubernetes - a Basic Tutorial

Posted by Shaaf's blog on Thursday, September 7, 2023

The Keycloak team announced that they were going to move to a new Operator framework that will effictevely manage Keycloak installatons on a Kubernetes cluster. So what is an Operator in the Kubernetes context. Simplyfying it a bit here… Its basically a component that takes over the operational aspects of your application. So rather then managing all of the lifecycle and state in scripts and in our minds in someways is coded into an operator. For us Keycloak Operator does exactly that and in this blog I will cover how to setup a very simple Keycloak installation and get ready for development. If you are interested in knowing more about Operators you will likely find some good info here.

If you arent familiar with Keycloak; its an opensource identity and access management software. Current version is 22, its used alot already in the wild. It provides single sign on capabitlity with OAuth/OIDC, AD, LDAP and SAML v2 as well. If you aren’t very familiar with Keycloak, I have also written a small self-paced Keycloak tutorial that goes through all the basics and some advance configs too.

Let’s get cracking on installing a basic keycloak instance backed by a PostgreSQL database.

So heres the plan

  • Install Operator on OpenShift cluster (a distribution of Kubernetes by Red Hat)
  • Install database for the Keycloak backend.
  • Create SSL certificate for use with keycloak backend.
  • Install the first Keycloak instance.
  • Importing a realm

Installing the Operator

To install the Keycloak operator I am choosing to install it via the webconsole which is an easy way to do it. Its also possible to do it via CLI.

Simply search for keycloak and press install. e.g.

alt_text
OpenShift Operator Install

Once you press install the installer will ask which namespace you would like to install to. In my case it the rhbk.

alt_text
OpenShift Operator Install

This could take a couple of seconds or minutes depending on your cluster.

Installing the database

For the Keycloak server to store its state and data it should have a database. For this I will use Crunchy.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-db
spec:
  serviceName: postgresql-db-service
  selector:
    matchLabels:
      app: postgresql-db
  replicas: 1
  template:
    metadata:
      labels:
        app: postgresql-db
    spec:
      containers:
        - name: postgresql-db
          image: postgres:latest
          volumeMounts:
            - mountPath: /data
              name: cache-volume
          env:
            - name: POSTGRES_PASSWORD
              value: testpassword
            - name: PGDATA
              value: /data/pgdata
            - name: POSTGRES_DB
              value: keycloak
      volumes:
        - name: cache-volume
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-db
spec:
  selector:
    app: postgresql-db
  type: LoadBalancer
  ports:
  - port: 5432
    targetPort: 5432

Create SSL certificate for use with keycloak backend.

Okay time to create a self-signed certificate, incase it was production assuming that would be via a certificate autority instead. But here since I am just testing this out we an just use the self-signed certificate. On a linux machine I can create a self-signed certificate like this where keycloak.rhbk.apps.green.demoshift.com is the address to my keyclaok instance and O is Test demoshift. it could be anything you want to denote here in my case its a test Org.

openssl req -subj '/CN=keycloak.rhbk.apps.green.demoshift.com/O=Test demoshift./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

Generating a 2048 bit RSA private key
.....................+++++
.....................+++++
writing new private key to 'key.pem'

Lets load this certificate into our Kubernetes environment by usng the following command. Make sure the path for the cert is correct, in my case I am in the same dir as my cert.

kubectl create secret tls example-tls-secret --cert certificate.pem --key key.pem 

Also a good practise is to load the database password as a secret rather then it littering around different yaml files.

kubectl create secret generic keycloak-db-secret \ 
            --from-literal=username=postgres \
            --from-literal=password=testpassword

Install the first Keycloak instance

apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: example-kc
spec:
  instances: 1
  db:
    vendor: postgres
    host: postgres-db
    usernameSecret:
      name: keycloak-db-secret
      key: username
    passwordSecret:
      name: keycloak-db-secret
      key: password
  http:
    tlsSecret: example-tls-secret
  hostname:
    hostname: keycloak.rhbk.apps.green.demoshift.com

Now if we go back to the webconsole you should be able to see.

    1. Keycloak operator pod
    1. PG database pod
    1. Keycloak server pod.

OpenShift has this nice feature that you can see the route once you click your application. also visible in the image below. Head over to your instance and login.

alt_text
Keycloak server Install

To login obviously one needs the admin password which in this case has been autogenerated by the operator. Lets get that by running the following command.

kubectl get secret example-kc-initial-admin -o jsonpath='{.data.password}' | base64 --decode

Assuming we have the password, lets go back to the route and click on Adminstration console. Username is admin and password should be what we retrieved from the command above.

Login and Viola! we have landed on our freshly installed Keycloak server.

Importing a realm

At this moment we only have the master realm. Typically one should leave the master realm intact without much changes. The logic behind that would be not to lock ourselves out. How about we import a realm. And here the power of Operator comes into play. We will create a RealmImportCR and that will add a new realm to Keycloak. Imagine if the Keycloak pod goes down at some point, the operator will ensure that its brought back to the same state it was and where is that state going to be? in the CRs and the database.

Okay lets test this out further, how about adding a new realm via the KCImportRealmCR

Let’s go back to the Operator view

Click on KeycloakRealmImport -> Create instance

alt_text
Keycloak server realm import

I had a realm json file. And obviously operators and most of the stuff in K8s expects yaml so I had to make a conversion. I used the following yq for conversion. There are also online tools available, but given the sensitive nature of realms I wouldnt suggest using a random online tool to convert to yaml.

So here is the resultant CR

Load the yaml and press create

alt_text
Keycloak server realm import

It can take a couple of seconds to that it will come up. As soon as we create the CR, the Keycloak Operator will pick it up and add it to the running Keycloak instance. If you log back into the admin console it should look like this.

alt_text
Keycloak server realm import

And if we explore further and look into the clients there is a backend-service. Its a Client config for a Quarkus based REST service written in Java. Thats for another post. There is alot more that can be done with Operators.

If you are looking for more in depth details the Keycloak docs is a great resource. If you are looking to explore more and try this installation you can also use the following Keycloak tutorial

More to come on Keycloak in later posts.