Keycloak, when deployed on Kubernetes, isn’t just another application; it’s a distributed, stateful system that demands careful consideration of its internal workings, especially around persistence and clustering.
Let’s see Keycloak in action, not just as a set of Pods, but as a live, functioning identity provider. Imagine a simple web application that needs to authenticate users.
# client-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-client-app
spec:
replicas: 1
selector:
matchLabels:
app: my-client-app
template:
metadata:
labels:
app: my-client-app
spec:
containers:
- name: app
image: quay.io/keycloak/keycloak-quickstart-demo-app:latest
ports:
- containerPort: 8080
env:
- name: KEYCLOAK_URL
value: "http://keycloak.default.svc.cluster.local:8080/auth/" # Assuming Keycloak is in the 'default' namespace
- name: KEYCLOAK_REALM
value: "myrealm"
- name: KEYCLOAK_CLIENT_ID
value: "myclient"
When a user tries to access my-client-app, the app container will redirect them to the Keycloak service (keycloak.default.svc.cluster.local:8080/auth/). Keycloak then handles the authentication flow. If successful, it issues a JWT, which the my-client-app verifies, granting access. This entire dance, from redirect to token validation, is orchestrated by Keycloak’s internal logic.
The problem Keycloak solves is centralizing authentication and authorization for multiple applications. Instead of each app rolling its own login mechanism, they delegate this to a single, robust system. Keycloak acts as an OAuth 2.0 and OpenID Connect provider, a standard way for applications to securely delegate authentication.
Internally, Keycloak is a Java application running on WildFly. It exposes its functionality via REST APIs, which clients interact with. For a distributed deployment on Kubernetes, the critical components are:
- Statelessness (mostly): The Keycloak server instances themselves should ideally be stateless. All persistent state (user data, realm configurations, client secrets) must be stored externally.
- Clustering: To achieve high availability and scalability, Keycloak nodes need to communicate with each other. This is typically done using JGroups, which relies on multicast or unicast for node discovery and message passing. On Kubernetes, multicast is often problematic, so unicast is the preferred method.
- Persistence: User credentials, realm definitions, client configurations, and sessions must be stored durably. This is usually done with a relational database (PostgreSQL, MySQL, etc.).
The Helm chart for Keycloak abstracts away much of this complexity. When you deploy it, you’ll configure several key parameters:
image.tag: The specific Keycloak version to deploy.replicas: The number of Keycloak pods.extraEnv: Environment variables for the Keycloak container. Crucially,JGROUPS_DISCOVERY_PROTOCOL=dns.dns_pingis often used in Kubernetes for cluster discovery, andJGROUPS_DISCOVERY_PROPERTIES=dns.query=keycloak-service.keycloak.svc.cluster.local(adjustingkeycloak-serviceand namespace as needed) tells JGroups how to find other nodes.postgresql.enabled/mysql.enabled: Whether to deploy a managed database or use an external one.postgresql. Perempuan: For PostgreSQL, you’ll configurepostgresql.auth.username,postgresql.auth.password, andpostgresql.auth.databaseto set up the database Keycloak will use.args: Command-line arguments passed to the Keycloak entrypoint. This is where you often setstart-devfor development orstartfor production, and configure HTTP/HTTPS ports.
The most surprising truth about Keycloak on Kubernetes is how its clustering mechanism interacts with Kubernetes networking. While JGroups is designed for peer-to-peer discovery, in a Kubernetes environment, you don’t want nodes directly discovering each other via IP addresses that might change. Instead, you leverage Kubernetes DNS. When JGROUPS_DISCOVERY_PROTOCOL is set to dns.dns_ping, Keycloak pods query a specific Kubernetes Service (like keycloak-service.keycloak.svc.cluster.local) to find other healthy Keycloak pods. This Service acts as a stable rendezvous point, abstracting away the ephemeral nature of Pod IPs. The dns.query property then specifies the DNS name to resolve for discovering peers.
The next concept you’ll likely grapple with is managing Keycloak’s administrative interface and securing it, especially when using an external database or when you need to automate realm and client creation.