When deploying Keycloak in a Kubernetes environment, you often need to customize the login interface to match the brand identity of your company/customer. While Keycloak supports custom themes out of the box, deploying and managing these themes in a containerized environment presents unique challenges. This article explores a elegant solution using Kubernetes init containers to dynamically inject custom themes during deployment.

Custom Keycloak Themes

Here Come Init Containers

Kubernetes init containers provide a clean solution to this problem. They run before the main container starts and can prepare the environment, including downloading and setting up theme files. This approach offers several advantages:

  • themes can be version controlled separately from the Keycloak deployment
  • we don’t need to build and maintain custom Keycloak images
  • themes can be updated without rebuilding containers - you just push to the theme repository and restart your deployment!
    • in more complex scenarios, you can even manage release candidates on separate feature / RC branches so that you don’t mess your production before testing / QA

Implementation Using Helm

The official Keycloak Helm chart makes this implementation straightforward by supporting custom init containers. Here’s how to set it up:

initContainers:
  - name: init-theme
    image: alpine/git:latest
    command:
      - sh
      - -c
    args:
      - |
        git clone https://.../my-keycloak-theme repository && \
        cp -r repository/themes/beehive-theme /themes && \
        chown -R 1001:1001 /themes/* && \
        chmod -R g+rwX /themes/*
    volumeMounts:
      - name: theme-volume
        mountPath: /themes
    securityContext:
      runAsUser: 0

Volume Configuration

You’ll also need to configure the volume in your Helm values:

extraVolumes:
  - name: theme-volume
    emptyDir: {}

extraVolumeMounts:
  - name: theme-volume
    mountPath: /opt/bitnami/keycloak/themes
    readOnly: true

This configuration ensures the theme volume is properly mounted in the main Keycloak container.

A very important note: be aware that the mount path /opt/bitnami/keycloak/themes is specific to the Helm Keycloak chart. For standard Keycloak deployments using different deployment methods, the correct path is typically /opt/keycloak/themes.

Alternative k8s Approaches

While init containers provide an elegant solution, these alternatives might also be very useful:

  1. Sidecar Containers: might be useful for development purposes but I haven’t explored this option
  2. ConfigMap Mounting: Suitable for simple themes with few files

Of course, you could also build a custom Keycloak Docker image which injects your theme beforehand, but this requires maintaining separate builds which you need to continuously rebase towards upstream. Nevertheless, a custom image might still be a viable and perfect solution for those who need to manage themes for many customers.