DEV Community

Cover image for Install Keycloak with the Operator
Austin Cunningham
Austin Cunningham

Posted on

Install Keycloak with the Operator

Install the Keycloak via the operator

Create a project

oc new-project keycloak
Enter fullscreen mode Exit fullscreen mode

I am going to install the operator the OperatorHub in Openshift which uses OLM(Operator Lifecyecle Manager). Select Operator/OperatorHub from the side bar and search for keycloak and install it in the keycloak namespace

Install the keycloak operator via operatorhub

The install should finish
Keycloak operator install is finished

I will go through the requirements now. This will not be a production setup.

Install an DB

Going to install an Ephemeral PostgreSQL DB as this is just a demo, create a yaml file called example-postgres.yaml with the following content.

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
          env:
            - name: POSTGRES_PASSWORD
              value: postgres #<-- change this
            - name: POSTGRES_USER
              value: postgres #<-- change this
            - name: PGDATA
              value: /data/pgdata
            - name: POSTGRES_DB
              value: keycloak
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-db
spec:
  selector:
    app: postgresql-db
  ports:
  - port: 5432
    targetPort: 5432
Enter fullscreen mode Exit fullscreen mode

And then apply the file to the cluster

oc apply -f example-postgres.yaml
Enter fullscreen mode Exit fullscreen mode

The result

statefulset.apps/postgresql-db created
service/postgres-db created
Enter fullscreen mode Exit fullscreen mode

After checking the postgres pod logs I see the following error

mkdir: cannot create directory β€˜/data’: Permission denied
Enter fullscreen mode Exit fullscreen mode

Nothing is ever easy. This is because Openshift blocks containers being run as root. To get this to work we need to add a service account with the correct permissions and add that service account to the statefulset. This is a good reference blog for more details. Here are the commands I used

# create the service account
~ oc create sa postgres-sa
serviceaccount/postgres-sa created
# add policy
~ oc adm policy add-scc-to-user anyuid -z postgres-sa
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "postgres-sa"
# set the policy on the namespace
~ oc adm policy add-scc-to-user anyuid -z postgres-sa -n keycloak
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "postgres-sa"
# add the service account to the statefulset
~ oc set sa statefulset postgresql-db postgres-sa
statefulset.apps/postgresql-db serviceaccount updated
# delete the failing existing pod
oc delete po postgresql-db-0
# check the pods 
~ oc get po
NAME                                 READY   STATUS    RESTARTS   AGE
keycloak-operator-5659f58f4b-vtrm9   1/1     Running   0          29m
postgresql-db-0                      1/1     Running   0          8m55s
Enter fullscreen mode Exit fullscreen mode

Ok that's working

Hostname

We need a resolvable domain name. You can add any domain to your openshift cluster using a customDomain. As I couldn't be bothered setting up an actual domain name here or a valid cert this a quick hack for creating a resolvable domain name on Openshift.

# create a self signed cert 
openssl req -subj '/CN=apps.austin.me/O=Test Keycloak./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
# create cert project
oc new-project certs
# create a secret from that cert in the cert namespace
oc create secret tls austin-me-tls --cert=austin.me.crt --key=austin.me.key -n certs
# create a custom domain based on the cert
oc apply -f - <<EOF                                                      
---
apiVersion: managed.openshift.io/v1alpha1
kind: CustomDomain
metadata:
  name: cunningham
spec:
  domain: apps.austin.me
  scope: External
  certificate:
    name: austin-me-tls
    namespace: certs
EOF
# Wait for the custom domain to become ready 
oc get customdomains                                              
NAME         ENDPOINT                                          DOMAIN           STATUS
cunningham   oeffrs.cunningham.aucunnin.lpi0.s1.devshift.org   apps.austin.me   Ready
Enter fullscreen mode Exit fullscreen mode

All pretty standard a this point but the domain apps.austin.me doesn't exist. So here is the hack edit the custom domain oc edit customdomain cunningham and replace the spec.host with the endpoint.

apiVersion: managed.openshift.io/v1alpha1
kind: CustomDomain
metadata: 
  name: cunningham
spec:
  certificate:
    name: austin-me-tls
    namespace: certs
  domain: oeffrs.cunningham.aucunnin.lpi0.s1.devshift.org #<---- was apps.austin.me now points at the endpoint
  loadBalancerType: Classic
  scope: External
Enter fullscreen mode Exit fullscreen mode

So our domain going forward is the endpoint oeffrs.cunningham.aucunnin.lpi0.s1.devshift.org

Create a DB secret

oc project keycloak
# change these to match the secret used in your statefulset
kubectl create secret generic keycloak-db-secret \
  --from-literal=username=postgres \
  --from-literal=password=postgres
Enter fullscreen mode Exit fullscreen mode

Create the Keycloak CR

The CR(Custom Resource) creates a instance of the Keycloak UI. Create a yaml file called example-kc.yaml

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: austin-me-tls
  hostname:
    hostname: oeffrs.cunningham.aucunnin.lpi0.s1.devshift.org
Enter fullscreen mode Exit fullscreen mode

And then apply the file

kubectl apply -f example-kc.yaml
Enter fullscreen mode Exit fullscreen mode

We can check the CR status of keycloak, it will look like this when it is type: Ready status: "True"

# using https://mikefarah.gitbook.io/yq/
~ oc get keycloak example-kc -oyaml | yq '.status'
conditions:
  - lastTransitionTime: "2023-09-15T08:08:56.665783288Z"
    message: ""
    observedGeneration: 1
    status: "True"      #<------ This is what we are looking for I hate these condition to difficult to read a first glance
    type: Ready
  - lastTransitionTime: "2023-09-15T08:08:26.147242224Z"
    message: ""
    observedGeneration: 1
    status: "False"
    type: HasErrors
  - lastTransitionTime: "2023-09-15T08:08:26.147242224Z"
    message: ""
    observedGeneration: 1
    status: "False"
    type: RollingUpdate
instances: 1
observedGeneration: 1
selector: app=keycloak,app.kubernetes.io/managed-by=keycloak-operator,app.kubernetes.io/instance=example-kc

Enter fullscreen mode Exit fullscreen mode

That looks to have completed and if we port-forward the service it looks to be working

~ oc port-forward service/example-kc-service 8443:8443
Forwarding from 127.0.0.1:8443 -> 8443
Forwarding from [::1]:8443 -> 8443
Handling connection for 8443
Handling connection for 8443
Handling connection for 8443
Handling connection for 8443
Handling connection for 8443
Enter fullscreen mode Exit fullscreen mode

Keycloak landing page after port forward

And if we check the route we can open the keycloak landing page.

oc get routes --namespace keycloak
NAME                       HOST/PORT                                                    PATH   SERVICES             PORT    TERMINATION            WILDCARD
example-kc-ingress-76p8j   oeffrs.cunningham.aucunnin.lpi0.s1.devshift.org ... 1 more          example-kc-service   https   passthrough/Redirect   None
Enter fullscreen mode Exit fullscreen mode

Keycloak landing page using route

Top comments (0)