Keycloak Helm vs Operator: Which to Use on Kubernetes
Last updated: March 2026
Deploying Keycloak on Kubernetes gives you the scalability and orchestration that production identity services demand. But Kubernetes offers two distinct deployment models for Keycloak: the Bitnami Helm chart (a traditional package manager approach) and the Keycloak Operator (a Kubernetes-native, CRD-driven approach). Each has tradeoffs in complexity, flexibility, and operational overhead.
This guide compares both approaches with real configuration examples, production-ready patterns, and a decision framework for choosing the right one for your team.
Quick Comparison
| Aspect | Bitnami Helm Chart | Keycloak Operator |
|---|---|---|
| Deployment model | Helm release | Custom Resources (CRDs) |
| Configuration | values.yaml |
Keycloak CR + KeycloakRealmImport CR |
| Realm management | Manual or external tooling | CRD-based (KeycloakRealmImport) |
| Auto-scaling | HPA (manual setup) | Built-in support |
| Certificate management | External (cert-manager) | Integrated |
| Database provisioning | Configurable in values | Separate (you manage) |
| Upgrade strategy | helm upgrade |
Operator-managed rolling update |
| Learning curve | Lower (Helm familiarity) | Higher (CRD concepts) |
| Community | Bitnami / VMware | Keycloak project (CNCF) |
Approach 1: Bitnami Helm Chart
The Bitnami Keycloak Helm chart packages Keycloak with sensible defaults, a bundled PostgreSQL database, and extensive configuration options. If your team already uses Helm for other services, this approach has the lowest adoption friction.
Installation
# Add the Bitnami repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Install with default settings (development)
helm install keycloak bitnami/keycloak
--namespace keycloak
--create-namespace
Production values.yaml
# values.yaml
replicaCount: 3
auth:
adminUser: admin
existingSecret: keycloak-admin-credentials
passwordSecretKey: admin-password
production: true
proxy: edge
# Resource limits
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
# PostgreSQL configuration
postgresql:
enabled: true
auth:
existingSecret: keycloak-db-credentials
secretKeys:
adminPasswordKey: postgres-password
userPasswordKey: password
primary:
persistence:
size: 20Gi
resources:
requests:
cpu: 250m
memory: 512Mi
# Or use an external database
# postgresql:
# enabled: false
# externalDatabase:
# host: my-rds-instance.abc123.us-east-1.rds.amazonaws.com
# port: 5432
# user: keycloak
# database: keycloak
# existingSecret: keycloak-external-db
# existingSecretPasswordKey: password
# Ingress
ingress:
enabled: true
ingressClassName: nginx
hostname: auth.example.com
tls: true
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
# Health checks
livenessProbe:
enabled: true
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
enabled: true
initialDelaySeconds: 30
periodSeconds: 10
# Keycloak configuration
extraEnvVars:
- name: KC_FEATURES
value: "token-exchange,admin-fine-grained-authz"
- name: KC_METRICS_ENABLED
value: "true"
- name: KC_HEALTH_ENABLED
value: "true"
- name: KC_CACHE
value: "ispn"
- name: KC_CACHE_STACK
value: "kubernetes"
- name: JAVA_OPTS_APPEND
value: >-
-Djgroups.dns.query=keycloak-headless.keycloak.svc.cluster.local
# Pod disruption budget
pdb:
create: true
minAvailable: 2
# Autoscaling
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPU: 70
targetMemory: 80
# Service monitor for Prometheus
metrics:
enabled: true
serviceMonitor:
enabled: true
namespace: monitoring
Deploy
helm install keycloak bitnami/keycloak
--namespace keycloak
--create-namespace
-f values.yaml
Upgrades
# Update chart version
helm repo update
# Upgrade with new values or chart version
helm upgrade keycloak bitnami/keycloak
--namespace keycloak
-f values.yaml
# Check rollout status
kubectl rollout status statefulset/keycloak -n keycloak
For detailed Keycloak upgrade strategies, see the best strategy to upgrade your Keycloak cluster.
Approach 2: Keycloak Operator
The Keycloak Operator is a Kubernetes-native way to manage Keycloak. It uses Custom Resource Definitions (CRDs) to declaratively define Keycloak instances and realm configurations. The operator watches for changes to these CRs and reconciles the cluster state automatically.
Install the Operator
# Install the operator (check for the latest version)
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/refs/heads/main/kubernetes/kubernetes.yml
-n keycloak
Or with OLM (Operator Lifecycle Manager):
# If OLM is installed
kubectl create -f https://operatorhub.io/install/keycloak-operator.yaml
Deploy Keycloak with a CR
# keycloak.yaml
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
namespace: keycloak
spec:
instances: 3
db:
vendor: postgres
host: postgres-service
usernameSecret:
name: keycloak-db-credentials
key: username
passwordSecret:
name: keycloak-db-credentials
key: password
hostname:
hostname: auth.example.com
http:
tlsSecret: keycloak-tls-secret
proxy:
headers: xforwarded
features:
enabled:
- token-exchange
- admin-fine-grained-authz
transaction:
xaEnabled: false
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
additionalOptions:
- name: metrics-enabled
value: "true"
- name: health-enabled
value: "true"
unsupported:
podTemplate:
spec:
containers:
- env:
- name: JAVA_OPTS_APPEND
value: >-
-Djgroups.dns.query=keycloak-discovery.keycloak.svc.cluster.local
kubectl apply -f keycloak.yaml -n keycloak
Realm Configuration with CRDs
The operator’s strongest feature is declarative realm management via KeycloakRealmImport:
# realm-import.yaml
apiVersion: k8s.keycloak.org/v2alpha1
kind: KeycloakRealmImport
metadata:
name: myrealm-import
namespace: keycloak
spec:
keycloakCRName: keycloak
realm:
realm: myrealm
enabled: true
sslRequired: external
registrationAllowed: false
loginWithEmailAllowed: true
duplicateEmailsAllowed: false
resetPasswordAllowed: true
bruteForceProtected: true
permanentLockout: false
maxFailureWaitSeconds: 900
minimumQuickLoginWaitSeconds: 60
waitIncrementSeconds: 60
maxDeltaTimeSeconds: 43200
failureFactor: 5
accessTokenLifespan: 300
ssoSessionIdleTimeout: 1800
ssoSessionMaxLifespan: 36000
clients:
- clientId: my-web-app
name: My Web Application
enabled: true
publicClient: false
clientAuthenticatorType: client-secret
secret: "$(env:MY_APP_SECRET:-changeme)"
redirectUris:
- "https://app.example.com/*"
webOrigins:
- "https://app.example.com"
protocol: openid-connect
defaultClientScopes:
- openid
- profile
- email
- clientId: my-mobile-app
name: My Mobile Application
enabled: true
publicClient: true
redirectUris:
- "myapp://auth/callback"
protocol: openid-connect
roles:
realm:
- name: app-admin
description: Application administrator
- name: app-user
description: Regular application user
client:
my-web-app:
- name: manage-users
- name: view-reports
identityProviders:
- alias: google
providerId: google
enabled: true
config:
clientId: "google-client-id"
clientSecret: "google-client-secret"
defaultScope: "openid profile email"
kubectl apply -f realm-import.yaml -n keycloak
The operator monitors this CR and applies the configuration to the running Keycloak instance. Changes to the CR trigger re-import. This is the CRD-based equivalent of what keycloak-config-cli does outside Kubernetes (see our realm export and import guide).
Certificate Management
The operator integrates with cert-manager for automatic TLS certificate provisioning:
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: keycloak-tls
namespace: keycloak
spec:
secretName: keycloak-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- auth.example.com
Reference the secret in your Keycloak CR under spec.http.tlsSecret.
Detailed Comparison
Configuration Management
Helm: Configuration lives in values.yaml. Changes require helm upgrade. You can use Helmfile or ArgoCD to manage values across environments. Realm configuration is not managed by Helm — you need external tools like keycloak-config-cli or the Admin API.
Operator: Configuration is split across Kubernetes CRs. The Keycloak CR manages the server, and KeycloakRealmImport CRs manage realm configuration. Changes are applied by updating the CRs. GitOps tools (ArgoCD, Flux) work naturally with CRs.
For a full ArgoCD-based deployment workflow, see how to deploy Keycloak in Kubernetes using ArgoCD.
High Availability
Helm: You set replicaCount and configure JGroups for cluster discovery. The Bitnami chart includes a headless service for DNS-based JGroups discovery. You manually configure PodDisruptionBudgets and anti-affinity rules.
Operator: You set instances in the Keycloak CR. The operator handles StatefulSet creation with proper discovery configuration. Pod disruption and rolling updates are managed by the operator’s reconciliation logic.
Both approaches require a shared database (PostgreSQL) and proper Infinispan/JGroups configuration for cache replication. For cluster tuning guidance, see top 7 Keycloak cluster configuration best practices.
Scaling
Helm: Use Kubernetes HPA with the autoscaling configuration in values.yaml. Scales based on CPU/memory metrics.
Operator: The operator can work with HPA, but you manage scaling by updating the instances field in the Keycloak CR. Custom metrics-based scaling requires additional configuration.
Monitoring
Both approaches expose the same Keycloak metrics at /metrics when metrics-enabled is set to true. The difference is in how you configure Prometheus scraping:
Helm: The Bitnami chart includes a ServiceMonitor resource when metrics.serviceMonitor.enabled is true.
Operator: You need to create the ServiceMonitor separately:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: keycloak-metrics
namespace: keycloak
spec:
selector:
matchLabels:
app: keycloak
endpoints:
- port: http
path: /metrics
interval: 30s
For production monitoring, Skycloak’s Insights dashboard provides pre-built metrics and alerting without the need to set up Prometheus yourself.
Upgrades
Helm: Run helm upgrade with a new chart version. The chart handles rolling updates through StatefulSet update strategies. You control the pace.
Operator: Update the operator version, then update the Keycloak CR’s image reference. The operator handles the rolling update, ensuring each pod is ready before proceeding.
Both methods require database migration awareness — Keycloak runs schema migrations on startup, and not all versions are backward-compatible. Always check the Keycloak release notes before upgrading.
Pros and Cons Summary
Helm Chart
Pros:
- Familiar to anyone who uses Helm
- Extensive configuration options in values.yaml
- Bundled PostgreSQL for simple deployments
- Large community with well-documented patterns
- Easy to integrate with existing Helm-based CI/CD
Cons:
- Realm configuration managed separately
- No built-in reconciliation (changes require manual
helm upgrade) - Bitnami chart may lag behind official Keycloak releases
- Less “Kubernetes-native” than CRD-based management
Keycloak Operator
Pros:
- Kubernetes-native CRD-based management
- Declarative realm configuration with
KeycloakRealmImport - Automatic reconciliation — the operator watches for drift
- Official project from the Keycloak team
- Natural fit for GitOps workflows (ArgoCD, Flux)
Cons:
- Operator itself needs management and updates
- The v2 operator is still maturing — some features are alpha
- Database is not bundled — you manage it separately
- Higher learning curve if team is unfamiliar with operators
- Fewer community examples compared to Helm
Decision Framework
Choose Helm When
- Your team already uses Helm extensively
- You want a quick, opinionated setup with bundled database
- You manage realm configuration through external tools (Terraform, keycloak-config-cli, Admin API)
- You need fine-grained control over every deployment parameter
- Your CI/CD pipeline is Helm-centric
Choose the Operator When
- You want Kubernetes-native, CRD-driven configuration
- You need declarative realm management alongside server management
- You use GitOps (ArgoCD, Flux) as your deployment model
- You want automatic reconciliation and drift detection
- Your team is comfortable with Kubernetes operators and CRD patterns
Choose Neither When
- You want to avoid the operational complexity of running Keycloak on Kubernetes entirely. Managed Keycloak hosting eliminates the need to manage infrastructure, regardless of the deployment method.
Production Checklist
Regardless of which approach you choose, ensure these items are addressed:
- [ ] External database with replication and automated backups
- [ ] TLS certificates with automatic renewal (cert-manager)
- [ ] Resource requests and limits configured
- [ ] PodDisruptionBudget set (minimum 2 available)
- [ ] Health checks configured (liveness and readiness probes)
- [ ] Metrics collection enabled (Prometheus + Grafana or similar)
- [ ] Audit logging enabled for security events
- [ ] Admin console access restricted (network policy or ingress rules). See path-based IP restriction for Keycloak admin console.
- [ ] Backup and restore procedures tested
- [ ] Upgrade runbook documented
For comprehensive cluster hardening, see securing your Keycloak master realm and 8 default configurations to adjust.
Further Reading
- Keycloak Operator Installation Guide
- Bitnami Keycloak Chart Documentation
- Keycloak on Kubernetes with ArgoCD
- Running Keycloak behind a reverse proxy
- Keycloak Docker Compose Generator — for local development before deploying to Kubernetes
Wrapping Up
Both the Helm chart and the Keycloak Operator are valid production deployment methods. Helm is more accessible and battle-tested. The operator is more Kubernetes-native and offers declarative realm management. The best choice depends on your team’s existing tooling, GitOps maturity, and comfort with CRD-based workflows.
If managing Kubernetes infrastructure for your identity platform is not where you want to invest engineering time, Skycloak runs Keycloak for you with built-in high availability, security features, and guaranteed SLA. Visit our pricing page to compare plans, or explore our documentation for integration details.
Ready to simplify your authentication?
Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.