Add User Authentication to Applications with a Scalable Keycloak Deployment on Kubernetes

Introduction

Keycloak is an open source application for centralized identity and access management. It allows users to authenticate themselves across multiple applications and supports many popular protocols (such as OpenID Connect, OAuth 2.0, LDAP and SAML 2.0) and social networks (such as Google, Twitter and Facebook). Keycloak also provides integration libraries for common programming languages and server applications, including Java, Node.js, Apache, Tomcat and Wildfly.

For developers looking to quickly add authentication and identity management to their applications, Keycloak provides a powerful and flexible set of features. The quickest way to get started with it is with Bitnami's Keycloak Helm chart. This chart deploys the most recent and secure version of Keycloak on a Kubernetes cluster using the Helm package manager. Once deployed, Keycloak can be easily configured as an authentication service provider for other applications.

This article walks you through the process of deploying Keycloak on Kubernetes using the Bitnami Keycloak Helm chart. It also shows you how to configure a Keycloak realm, user and client and walks you through the process of developing a simple Express application that integrates with the Keycloak deployment for authentication.

Assumptions and prerequisites

This article assumes that:

Step 1: Deploy Keycloak on Kubernetes

Follow the steps below to deploy Keycloak on Kubernetes with Bitnami's Keycloak Helm chart:

  • Add the Bitnami chart repository to Helm:

    helm repo add bitnami https://charts.bitnami.com/bitnami
    
  • Execute the following command to deploy Keycloak. Replace the ADMIN-PASSWORD placeholder with a custom password for the Keycloak administrator account.

    helm install keycloak bitnami/keycloak \
      --set auth.adminPassword=ADMIN-PASSWORD
    

    Wait for a few minutes until the chart is deployed. You can also use the command below to check the status of the deployment:

    kubectl rollout status sts keycloak
    
  • By default, a load balancer service is created for the Keycloak deployment. Obtain the public URL for the deployment using the commands shown in the deployment notes. Exmple commands are provided below.

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services keycloak)
    export SERVICE_IP=$(kubectl get svc --namespace default keycloak -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "http://${SERVICE_IP}:${SERVICE_PORT}/auth"
    

Step 2: Create a Keycloak realm and user

The next step is to create a Keycloak realm. Follow these steps:

  • Browse to the Keycloak URL obtained at the end of the previous step. This displays the Keycloak welcome page, as shown below:
Keycloak welcome page
  • Click the link for the "Administration Console". This displays the Keycloak login page, as shown below:
Keycloak login page
  • Log in to Keycloak with the username user and the password defined in the ADMIN-PASSWORD placeholder in the previous step.
  • Navigate to the "Master -> Add Realm" page.
  • Enter a name for the new realm.
  • Click "Create" once done.
Keycloak realm creation

The new realm is created.

Next, create at least one user account within the new realm, as follows:

  • Ensure that the new realm is the active realm, by selecting it in the top left corner of the navigation bar.
  • Navigate to the "Manage -> Users" page.
  • Click the "Add user" button.
  • Enter a username for the new user.
  • Click "Save" to save the record.
Keycloak user creation

The new user is created.

  • On the resulting user details page, select the "Credentials" tab.
  • Configure the credentials as follows:
    • Enter a password for the user account.
    • Repeat the password entry to confirm it.
    • Set the "Temporary" slider to "Off".
  • Click "Set Password" once done to save the new password. Confirm the operation when prompted.
Keycloak password creation

The password for the new user account is now configured.

Step 3: Create a Keycloak client

Every application that uses Keycloak for authentication must use a registered Keycloak client. Fortunately, creating and registering a new Keycloak client is simple.

Follow the steps below to create a client for the Express example application:

  • In the Keycloak administration console, ensure that the correct realm is selected.
  • Navigate to the "Manage -> Clients" page.
  • Click the "Create" button.
  • Create a new client using the following parameters:
    • Client ID: node
    • Client Protocol: openid-connect
    • Root URL: http://localhost:3000. If the application is running on a different host, replace localhost with the IP address of the host
  • Click "Save" to save the record.
Keycloak client creation
  • On the resulting client details page, select the "Installation" tab.
  • Select the "Keycloak OIDC JSON" format.
  • Note the JSON block displayed on the screen, as you will need it in Step 4.
Keycloak client JSON
Tip

Learn more about configuring clients in Keycloak.

Step 4: Integrate an Express application with Keycloak

Keycloak comes with client adapters for many popular programming languages, including Java, Python, Node.js, C# and Android. This tutorial uses the Node.js client adapter and creates a skeleton Express application with a single endpoint. Access to that endpoint will be protected with Keycloak authentication.

This article will use the Bitnami Node.js container image to create the Express application. However, if you already have a Node.js development environment, you can use that instead and skip the Docker commands below.

  • Begin by creating a directory for your application and making it the current working directory:

    mkdir myapp
    cd myapp
    
  • Use the following Docker commands to create and start a Bitnami Node.js container on your host:

    docker create -v $(pwd):/app -t --net="host" --name node -p 3000:3000 bitnami/node:14
    docker start node
    

    The -v argument to the first command tells Docker to mount the host's current directory into the container's /app path, so that the effects of commands run in the container are seen on the host. The --net="host" parameter tells Docker to use the host's network stack for the container. The container is named node. The -p 3000:3000 parameter maps container port 3000 to host port 3000, so that it is easier to access the application from the Docker host.

  • Once the container is running, connect to the container console with the command below. This will give you a command shell and allow you to use the Node.js tools available in the image for subsequent tasks.

    docker exec -it node /bin/bash
    
  • Install Express, the Keycloak adapter for Node.js and the Express session manager:

    npm install --save express keycloak-connect express-session
    
  • Create a new file named server.js and fill it with the following code for a skeleton Express application:

    var express = require('express');
    var app = express();
    
    app.get('/', function(req, res){
      res.send("Secure page");
    });
    
    app.listen(3000);
    
  • Update the skeleton application with additional code to integrate the Keycloak Node.js adapter. The revised server.js file looks like this. Replace the CLIENT-JSON-BLOCK placeholder with the JSON block (including curly braces) obtained at the end of Step 3.

    var express = require('express');
    var session = require('express-session');
    var Keycloak = require('keycloak-connect');
    var memoryStore = new session.MemoryStore();
    
    var app = express();
    
    var config = CLIENT-JSON-BLOCK
    
    app.use(session({
      secret: 'guessme',
      resave: false,
      saveUninitialized: true,
      store: memoryStore
    }));
    
    var keycloak = new Keycloak({ store: memoryStore }, config);
    app.use(keycloak.middleware());
    
    app.get('/', keycloak.protect(), function(req, res){
      res.send("Secure page");
    });
    
    app.listen(3000);
    

    These changes add the Keycloak adapter to the Express application as middleware and use its protect() method to secure the root URL of the application.

Step 5: Test the Keycloak integration

You can now proceed to test the integration with Keycloak, by starting the Node.js application and attempting to access the protected URL.

  • Start the application:

    node server.js
    
  • Browse to the application root URL on the Docker host, such as http://localhost:3000. If the application is running on a different host, replace localhost with the IP address of the host. You are redirected to a Keycloak login page. This page displays the name of your custom realm.

Keycloak authentication
  • Log in with the user credentials created in Step 2 to see the contents of the protected URL.
Secure page display

This demonstrates that the Keycloak service is running and able to authenticate requests from registered clients.

Security improvements

It is important to note that the approach outlined in this tutorial is illustrative and not recommended for production environments. The steps described above take various liberties with application and cluster security, in the interests of creating a simpler and more focused tutorial. For example:

  • The Keycloak service is exposed at a public IP address.
  • A non-HTTPS connection is permitted between the Express application and the Keycloak service.

To improve security, the following enhancements are recommended in production environments:

  • The Keycloak service should only be available at a cluster IP address (exposed using a ClusterIP service).
  • The Keycloak service endpoints should be secured with HTTPS.
  • Client connections should only be permitted over HTTPS.
  • Client access should only be permitted from "known good" web origins.
  • Applications wishing to use the Keycloak service for authentication should be deployed within the cluster using immutable container images. If these applications are public-facing, a LoadBalancer service can be used to expose them using public IP addresses.

Useful links

To learn more about the topics discussed in this article, use the links below: