Deploy Keycloak on Thalassa Cloud Kubernetes

Keycloak is an open-source identity and access management solution that provides single sign-on (SSO), social login, user federation, and fine-grained authorization. By deploying Keycloak on Thalassa Cloud Kubernetes using FluxCD and Cloud Native PostgreSQL, you can run a production-ready identity management platform with high availability, automated deployments, and seamless integration with Kubernetes features.

This guide walks you through deploying Keycloak using FluxCD for GitOps-based deployment, configuring it to use Cloud Native PostgreSQL for the database, and setting up ingress with TLS certificates.

Understanding Keycloak on Kubernetes

On Kubernetes, Keycloak benefits from the platform’s orchestration features like automatic scaling, health checks, and persistent storage. The use of the Helm chart makes deploying Keycloak straightforward and repeatable. Keycloak requires a database for storing user and configuration data, and PostgreSQL is recommended for its reliability and strong integration with Kubernetes.

Cloud Native PostgreSQL provides high availability, automated backups, and seamless database operation within your cluster. To manage Keycloak deployment in a version-controlled and automated way, FluxCD enables GitOps workflows—so every change to your configuration goes through Git and can be automatically applied to your cluster. To learn more about using FluxCD for GitOps, see the Installing FluxCD guide.

Prerequisites

Before deploying Keycloak, ensure you have a few things in place.

  1. First, you need a running Kubernetes cluster in Thalassa Cloud. Keycloak works with Kubernetes 1.24 or later, and Thalassa Cloud clusters meet this requirement. If you’re new to Thalassa Cloud Kubernetes, see the Getting Started guide for cluster creation and basic setup.
  2. You’ll also need cluster access configured using kubectl. Use tcloud kubernetes connect to configure access, or set up kubeconfig manually. You’ll need cluster administrator permissions to install FluxCD and create namespaces.
  3. FluxCD must be installed in your cluster. If you haven’t installed it yet, follow the Installing FluxCD guide to set it up. This guide assumes you have FluxCD installed and configured with access to a Git repository where you’ll store your Keycloak configuration.
  4. For the database, you’ll need Cloud Native PostgreSQL installed in your cluster. If you haven’t installed it yet, follow the Cloud Native PostgreSQL guide to set it up. This guide assumes you have Cloud Native PostgreSQL installed and ready to use.
  5. For TLS certificates, you’ll need Cert Manager installed with Let’s Encrypt configured. See the Cert Manager and Let’s Encrypt guide for installation and configuration instructions.

Finally, ensure your cluster has sufficient resources. Keycloak requires CPU, memory, and storage for the application and database. Plan for at least one node with adequate resources, and consider using dedicated node pools for database instances. For information about storage options, see the Storage documentation and Persistent Volumes documentation.

Setting Up PostgreSQL Database

Before deploying Keycloak, set up a PostgreSQL database cluster using Cloud Native PostgreSQL. This provides a reliable, high-availability database for your Keycloak instance. This section provides a quick setup; for PostgreSQL configuration options, high availability setup, and backup configuration, see the Cloud Native PostgreSQL guide.

Step 1: Create Namespace

Create a namespace for Keycloak resources with pod security labels:

apiVersion: v1
kind: Namespace
metadata:
  name: keycloak
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/warn: restricted

Apply the namespace:

kubectl apply -f namespace.yaml

Alternatively, you can create the namespace using kubectl:

kubectl create namespace keycloak
kubectl label namespace keycloak pod-security.kubernetes.io/enforce=baseline pod-security.kubernetes.io/warn=restricted

Step 2: Create Database Credentials Secret

Create a Kubernetes Secret for the database user credentials. CloudNativePG will use this secret to set the password for the database user:

apiVersion: v1
kind: Secret
metadata:
  name: keycloak-database-app
  namespace: keycloak
type: Opaque
stringData:
  username: keycloak
  password: your-secure-password

Apply the secret:

kubectl apply -f db-credentials-secret.yaml

Secure Password Management

Use a strong, unique password for the database user. Store the password in a Kubernetes Secret rather than hardcoding it. CloudNativePG will use this secret to set up the database user automatically.

Create a PostgreSQL cluster for Keycloak. This example creates a cluster with 2 instances for high availability:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: keycloak-database
  namespace: keycloak
spec:
  instances: 2
  imageName: ghcr.io/cloudnative-pg/postgresql:16
  primaryUpdateStrategy: unsupervised
  postgresql:
    parameters:
      max_connections: "100"
  bootstrap:
    initdb:
      database: keycloak
      owner: keycloak
      dataChecksums: true
      secret:
        name: keycloak-database-app
  storage:
    size: 5Gi
    storageClass: tc-block
  resources:
    requests:
      memory: "512Mi"
      cpu: "50m"
    limits:
      memory: "1Gi"
      cpu: "1000m"
  monitoring:
    enablePodMonitor: false

The bootstrap.initdb section tells CloudNativePG to automatically create a database named keycloak with an owner keycloak, using the credentials from the secret. CloudNativePG will create the database and user during cluster initialization, so you don’t need to run SQL commands manually.

Save this to postgres-cluster.yaml and apply it:

kubectl apply -f postgres-cluster.yaml

Step 4: Wait for Cluster to be Ready

Wait for the cluster to be ready:

kubectl wait --for=condition=Ready cluster/keycloak-database -n keycloak --timeout=300s

CloudNativePG automatically creates the database and user during cluster initialization. The credentials are stored in the secret you created, and CloudNativePG uses them to set up the database owner.

Automatic Database and User Creation

CloudNativePG’s bootstrap configuration automatically creates the database and user specified in the bootstrap.initdb section. This eliminates the need to manually run SQL commands to create the database, user, and grant privileges. The database and user are ready to use once the cluster is ready.

Deploying Keycloak with FluxCD

Using FluxCD for Keycloak deployment provides GitOps-based management, allowing you to version control your configuration and automate deployments. This approach is recommended for production deployments as it provides better control, audit trails, and consistency.

Step 1: Create HelmRepository

Create a HelmRepository resource that tells FluxCD where to find the Keycloak Helm chart:

apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: keycloakx
  namespace: keycloak
spec:
  type: oci
  interval: 60m
  url: oci://ghcr.io/codecentric/helm-charts

This creates a HelmRepository that points to the Codecentric Helm charts repository, which contains the Keycloak chart. The interval specifies how often FluxCD should check for chart updates.

Save this to helm-repository.yaml and apply it, or commit it to your Git repository if you’re using FluxCD with Git:

kubectl apply -f helm-repository.yaml

If using FluxCD with Git, commit this file to your repository and FluxCD will automatically apply it.

Step 2: Create HelmRelease

Create a HelmRelease resource that defines how Keycloak should be deployed:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: keycloakx
  namespace: keycloak
spec:
  releaseName: keycloakx
  chart:
    spec:
      chart: keycloakx
      version: 7.1.5
      sourceRef:
        kind: HelmRepository
        name: keycloakx
        namespace: keycloak
  interval: 30m
  values:
    command:
      - "/opt/keycloak/bin/kc.sh"
      - "start"
      - "--http-port=8080"
      - "--hostname-strict=false"

    replicas: 2
    ingress:
      enabled: false

    database:
      vendor: postgres
      hostname: keycloak-database-rw
      port: "5432"
      username: keycloak
      existingSecret: keycloak-database-app
      existingSecretKey: password

    proxy:
      enabled: false
      mode: edge
    http:
      relativePath: "/"

    cache:
      stack: jdbc-ping

    serviceMonitor:
      enabled: false

    externalDatabase:
      host: keycloak-database-rw
      database: keycloak
      port: "5432"
      existingSecret: keycloak-database-app
      existingSecretUserKey: username
      existingSecretPasswordKey: password

    proxyHeaders: "xforwarded"

    extraEnv: |
      - name: KC_BOOTSTRAP_ADMIN_USERNAME
        value: admin
      - name: KC_BOOTSTRAP_ADMIN_PASSWORD
        valueFrom:
          secretKeyRef:
            name: keycloak
            key: admin-password
      - name: KC_PROXY
        value: edge
      - name: KC_HTTP_ENABLED
        value: "true"
      - name: KC_HOSTNAME_STRICT
        value: "false"
      - name: KC_HOSTNAME_STRICT_HTTPS
        value: "false"
      - name: KC_PROXY_HEADERS
        value: xforwarded
      - name: KEYCLOAK_PRODUCTION
        value: "false"

    resources:
      requests:
        cpu: 20m
        memory: 1536M
      limits:
        cpu: 4
        memory: 1536M

This HelmRelease configures Keycloak with:

  • 2 replicas for high availability
  • PostgreSQL database connection using the CloudNativePG cluster
  • Edge proxy mode for use behind a reverse proxy
  • JDBC-Ping cache for clustering
  • Resource limits and requests

Step 3: Create Admin Password Secret

Create a Secret for the Keycloak admin password:

apiVersion: v1
kind: Secret
metadata:
  name: keycloak
  namespace: keycloak
type: Opaque
stringData:
  admin-password: your-secure-admin-password

Step 4: Apply Resources

Apply the HelmRelease and secret:

kubectl apply -f helm-release.yaml
kubectl apply -f keycloak-secret.yaml

If using FluxCD with Git, commit these files to your repository and FluxCD will automatically apply them.

Step 5: Verify Deployment

Verify that Keycloak is deploying:

kubectl get helmrelease -n keycloak
kubectl get pods -n keycloak

FluxCD will automatically install and manage the Keycloak Helm release based on your configuration. Wait for the pods to be in the Running state before proceeding.

Configuring Ingress and TLS

Keycloak needs to be accessible from outside the cluster. Configure ingress resources to expose Keycloak, and use Cert Manager to automatically provision TLS certificates.

Creating TLS Certificate

First, create a Certificate resource for TLS:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: login-ingress-tls
  namespace: keycloak
spec:
  secretName: login-ingress-tls
  dnsNames:
  - account.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Replace account.example.com with your actual domain name. Cert Manager will automatically create and manage the TLS certificate. For more information about Cert Manager, see the Cert Manager and Let’s Encrypt guide.

Creating Ingress Resources

Create ingress resources to expose Keycloak. This example creates two ingress resources: one for general access and one for the admin console with IP whitelisting:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: login-keycloak
  namespace: keycloak
  labels:
    app.kubernetes.io/name: keycloak
    app.kubernetes.io/component: app
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "20k"
    nginx.ingress.kubernetes.io/client-body-buffer-size: 1M
spec:
  ingressClassName: nginx
  rules:
  - host: account.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: keycloakx-http
            port:
              name: http
  tls:
  - hosts:
    - account.example.com
    secretName: login-ingress-tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: login-admin
  namespace: keycloak
  labels:
    app.kubernetes.io/name: keycloak
    app.kubernetes.io/component: app
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "<example-ip/32>"
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "20k"
    nginx.ingress.kubernetes.io/client-body-buffer-size: 1M
spec:
  ingressClassName: nginx
  rules:
  - host: account.example.com
    http:
      paths:
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: keycloakx-http
            port:
              name: http
      - path: /realms/master
        pathType: Prefix
        backend:
          service:
            name: keycloakx-http
            port:
              name: http
  tls:
  - hosts:
    - account.example.com
    secretName: login-ingress-tls

The first ingress exposes Keycloak for general access. The second ingress exposes the admin console and master realm with IP whitelisting for additional security.

Admin Console Security

The admin console ingress includes IP whitelisting to restrict access to trusted IP addresses. Update the whitelist-source-range annotation with your trusted IP addresses. For production deployments, consider using additional security measures such as VPN access or network policies.

Apply the ingress resources:

kubectl apply -f ingress.yaml

Verify that the ingress is configured correctly:

kubectl get ingress -n keycloak

Once Cert Manager has issued the certificate, you can access Keycloak at your configured domain.

Initial Setup

Once Keycloak is accessible, complete the initial setup through the web interface. Navigate to your configured domain in a web browser.

You can log in to the admin console using the credentials you configured:

  • Username: admin (or the value from KC_BOOTSTRAP_ADMIN_USERNAME)
  • Password: The password from the keycloak secret

The admin console allows you to:

  1. Create realms for different applications or organizations
  2. Configure identity providers for social login
  3. Set up clients for OAuth2 and OpenID Connect
  4. Configure user federation
  5. Manage users and roles

First Login

On first login, Keycloak may prompt you to set up additional security features such as two-factor authentication for the admin account. This is recommended for production deployments.

Backup Configuration

Regular backups are essential for production Keycloak deployments. Cloud Native PostgreSQL handles database backups automatically when configured. For Keycloak file storage, implement a backup strategy.

Database Backups

Configure automated backups for the PostgreSQL cluster. See the Cloud Native PostgreSQL guide for detailed backup configuration, including automated backup schedules, retention policies, and restore procedures.

Configuration Backups

Keycloak configuration is stored in the database, so database backups include your Keycloak configuration. However, consider exporting realm configurations regularly for additional safety:

kubectl exec -it sts/keycloakx -n keycloak -- \
  /opt/keycloak/bin/kc.sh export --dir /tmp/export

This exports realm configurations that you can import later if needed.

Upgrading Keycloak

To upgrade Keycloak to a newer version, update the HelmRelease with the new chart version:

spec:
  chart:
    spec:
      chart: keycloakx
      version: 7.2.0  # Updated version

Commit the change to your Git repository, and FluxCD will automatically upgrade Keycloak. For more information about FluxCD upgrades, see the Installing FluxCD guide.

Backup Before Upgrades

Always create backups of both the database and configuration before upgrading Keycloak. This ensures you can roll back if the upgrade causes issues.

Conclusion

Deploying Keycloak on Thalassa Cloud Kubernetes using FluxCD and Cloud Native PostgreSQL provides a production-ready identity and access management platform. FluxCD provides GitOps-based deployment management, Cloud Native PostgreSQL provides reliable database management, and Thalassa Cloud’s infrastructure features ensure high performance and availability. By following this guide, you’ve set up Keycloak with persistent storage, high-availability database, GitOps-based deployment, and proper ingress configuration with TLS.

For more information about Keycloak features and configuration, see the official Keycloak documentation. For details about the Helm chart, see the Keycloak Helm chart repository.