DEV Community

Scott Molinari for m8a.io

Posted on

m8a scenario #1 - Using Coder to Develop Keycloak Templates Live (almost)...

Keycloak Custom Theming

This article will be one of many posts about the trials and tribulations, the learnings and sharings of information as we build out the m8a.io platform (in POC).

The goal of these scenario articles will be to highlight one or more technologies and explain what we did with them.

We want to share these learnings and experiences, because we do believe we are making some cutting edge decisions for our new platform and/ or are coming up with alternative ways to do things that haven't yet been discovered before. And the publication of this knowledge is all in the name of giving back to those technologies that are helping us with our very lofty endeavour. It's a start.

In this article, two of the technologies being highlighting are:

Coder and Keycloak

From their websites:

Coder

Coder offloads development from local workstations to your on-prem and public cloud infrastructure. Boost developer productivity with instant onboarding and powerful server resources. Keep code and data under control within your network.

spacerKeycloak

Add authentication to applications and secure services with minimum effort. No need to deal with storing users or authenticating users.
Keycloak provides user federation, strong authentication, user management, fine-grained authorization, and more.

As you can imagine, these are two pretty powerful sounding applications, right?

Scenario Description

Above and beyond these two great applications, we are also using Kubernetes.

Note: This article will assume you have some fairly good knowledge of Kubernetes and Helm and how they both work together. You should also be familiar with Terraform.

As you hopefully know, Kubernetes (k8s) is a very powerful platform for orchestrating container workloads. If are still reading this and you don't know about k8s, I highly recommend learning about.

Getting back to our two main technologies....we have implemented Keycloak as our Identification and Authorization Management system (IAM). However, as these things go, Keycloak has its own tech stack. One of the technologies, of course, is the language they used, which is Java. And being it is Java, they chose to use a templating engine called Freemarker.

To keep this article as short as possible and because it isn't the intention of this article, we won't go into the deeper details of Keycloak's templating system and how to use it. Instead, I'll refer you to two good articles that explain it all well:

Customizing Themes for Keycloak
How to Customize Keycloak Themes

That being said, if you are familiar with any other templating system for the backend, you'll understand Freemarker fairly quickly too.

And, because Keycloak uses this template system, setting up your Corporate Identity within Keycloak is very much possible and not entirely difficult.

However, despite knowing about templating and Keycloak you'll quickly understand the first hurdle of having Keycloak in k8s.

Above and beyond designing the templates, how can we even get those new templates into the Keycloak pods for use by the application?

There are two suggested ways to get customized templates into the Keycloak pod or pods.

  1. using an init container to "load" the new templates over a shared volume.

  2. using a secret to load in a tarballed archive of the files.

Why won't this work?

Both require a number of steps to make the template contents usable by Keycloak and as you can imagine, are miles away from any kind of live development.

With either of these two steps, you'd need to have a local version of Keycloak to design on, then create a container with the files or create a tarball and load it into a secret and then restart Keycloak. Restarting Keycloak alone takes about a minute until it is ready to go. And if you happen to see a mistake, as it always happen, it's wash, rinse and repeat (pulling out hair or getting grey from the process).

Coder to the Rescue!

Coder is going to be an integral part of the m8a platform. And as it may be, we can also use it for the purpose of (almost) live development of custom templates in a running Keycloak pod.

Point #1 above of getting a template set into Keycloak via a shared volume gave us the initial idea. Why not just use another pod, a Coder agent/ workspace pod in parallel and share the volume between them? That way you can develop on the files in the volume and Keycloak would use them directly. Yes!

So, off we went looking to resolve this challenge.

Installing and Setting up Coder

To get going with Coder, you'll need to install Coder into your k8s cluster via Helm. Follow the instructions carefully and you should have Coder up and running in cluster in no time.

Next, you'll need a workspace template to be able to create a workspace. Again, the Coder's docs explain how to do this well and there is an example k8s template you can start from.

You'll also need to install the Coder CLI onto your local machine for working on the templates.

Coder's templates are basically Terraform modules. So, you'll need knowledge of how Terraform works and the config language itself, to develop them. If you know k8s though, it's fairly easy to pick up.

Getting Everything Set Up

Coder's service account permissions

In order to have Coder work with k8s objects outside its own workspace, we have to give the Coder service account (which should have been installed while installing Coder's Helm chart) enough permissions to work across namespaces. We did this by creating an admin cluster role and binding it to the service account via kubectl.

Keycloak setup

This was the trickier part. And of course, this will require a development environment, and not your production Keycloak. Setting up a complete development environment in k8s is way beyond the scope of this article, but if you are a good with k8s, you'll know what to do, if you haven't done it already (i.e. you really should!).

Ok. So, with Keycloak in a dev environment, you'll need to have only one Keycloak pod running, to not run into caching issues. And, you'll be setting this up in the Helm chart (we are using the Bitnami chart):


extraStartupArgs: >-
  --spi-theme-static-max-age=-1 --spi-theme-cache-themes=false --spi-theme-cache-templates=false

...

replicaCount: 1
Enter fullscreen mode Exit fullscreen mode

These startup args will turn off the Keycloak caching process for templates.

Or, you can also do this:


extraEnvVars:
  - name: KEYCLOAK_PRODUCTION
    value: 'false'
Enter fullscreen mode Exit fullscreen mode

This will start the pod in dev-mode, which should also mean template caching is turned off.

Set up the volume

We are using Longhorn as a more capable storage system inside our k8s clusters. To set up the volume with Longhorn, you can go into the UI and create a new Persistent Volume Claim (pvc)/ Volume.

Longhorn

You can also do this via kubectl, and with any other storage system in k8s.

Once you have the pvc created (making sure it is in the keycloak namespace) you are halfway there.

As a next step, you'll need to bind the pvc to the Keycloak pod via a Persistent Volume (pv). To do this, add the following to the Helm chart and upgrade it:

extraVolumeMounts:
  - mountPath: /opt/bitnami/keycloak/themes/m8a-theme
    name: theme
extraVolumes:
  - name: theme
    persistentVolumeClaim:
      claimName: pvc-keycloak-theme
Enter fullscreen mode Exit fullscreen mode

The mountPath is dependent on where Keycloak is installed in the pod. The path above it where the Bitnami chart puts it.

The claimName is the name of your pvc. Ours is pvc-keycloak-theme. Keep that in mind.

Now you have the Keycloak instance working with a volume that can be attached to other pods. Let's do that now with a Coder workspace.

Setting up the Coder workspace (the pod)

As mentioned above, you can use the example Coder template to create the workspace. The only difference is now, you'll need to have the volume also bind to the workspace pod. To make that happen, you'll need to add this to the template:

resource "kubernetes_pod" "main" {
  count = data.coder_workspace.me.start_count

   ...


      env {
        name  = "CODER_AGENT_TOKEN"
        value = coder_agent.main.token
      }
      volume_mount {
        mount_path = "/home/template-dev/my-theme"
        name       = "theme"
        read_only  = false
      }
    }

    volume {
      name = "theme"
      persistent_volume_claim {
        claim_name = "pvc-keycloak-theme"
        read_only  = false
      }
    }
  }
Enter fullscreen mode Exit fullscreen mode

The volume_mount and volume entries are the important additions. volume_mount is the location of the files you'll be working on. volume is the binding of the pvc to the pod.

Push up or add your template to your Coder instance via the Coder CLI and you are almost ready for development.

The new development workflow

Ok. Now that we have pretty much everything set up. Go into your Coder installation (either via port forward or if you set everything up properly, via the URL), go to the Templates tab and fire up a new workspace.

Coder Template Tab

I like to use my local VSCode, so I press on the button, which will open the workspace in VSCode.

Coder Workspace

Coder will also let you work directly in the browser too, if that is what you want. We removed that feature from our template and why you don't see the option above.

Remember, this is a pod working inside a k8s cluster. It's true remote development in a just-like-production dev environment.

Once you've clicked on the button shown above, you'll be greeted with this a few seconds later:

VSCode editor

With the workspace running, you can add your files as necessary and start developing directly on your Keycloak templates.

Note1: In the image above, the login folder is the one I was working in. You'll need to add the different folders yourself for the different areas you want to customize Keycloak's templates.

Note2: In the future, you'll be able to determine which folder the Workspace should open up in. The suggestion wasn't yet implemented in Coder at the time of writing.

Note3: Don't make the same mistake as I did and have browser caching turned on (and have forgotten about it). If you aren't seeing changes made directly after refreshing the Keycloak page you are customizing, see if it works with Ctrl + F5. Or turn off your browser's cache.

So, that is it. I searched very hard to find something like this and couldn't find anything remotely similar. I hope this will help others, at least those wanting to customize their Keycloak instance more efficiently inside k8s.

Happy Coding!!!! 😁

Top comments (0)