Exporting Keycloak Resources
The Keycloak Operator includes an export command that extracts resources from an existing Keycloak instance and generates Kubernetes CRD manifests. This is useful for:
- Migration: Moving from manual Keycloak configuration to operator-managed resources
- Discovery: Generating manifests from an existing Keycloak setup
- Backup: Creating declarative representations of your Keycloak configuration
Quick Start
Export a realm to stdout:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm
Running the Export Command
The export command is included in the operator container image. Run it via Docker:
Direct Connection Mode
Connect directly to a Keycloak instance using URL and credentials:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--target-namespace production \
--instance-ref keycloak-prod
From Existing KeycloakInstance CR
If you already have the operator deployed with a KeycloakInstance configured, you can reuse those connection details:
docker run --rm -v ~/.kube:/root/.kube ghcr.io/hostzero-gmbh/keycloak-operator export \
--from-instance my-keycloak \
--namespace keycloak-operator \
--realm my-realm
This reads the connection URL and credentials from the existing KeycloakInstance CR and its associated Secret.
For cluster-scoped instances:
docker run --rm -v ~/.kube:/root/.kube ghcr.io/hostzero-gmbh/keycloak-operator export \
--from-cluster-instance my-cluster-keycloak \
--realm my-realm
Output Options
Stdout (Default)
Output all manifests as multi-document YAML, suitable for piping:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
> manifests.yaml
Or apply directly:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
| kubectl apply -f -
Single File
Write all manifests to a single file:
docker run --rm -v $(pwd):/output ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--output /output/manifests.yaml
Directory Structure
Create an organized directory hierarchy:
docker run --rm -v $(pwd)/manifests:/output ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--output-dir /output
This creates:
manifests/
realm.yaml
clients/
my-app.yaml
another-client.yaml
users/
john-doe.yaml
groups/
admin-group.yaml
roles/
custom-role.yaml
...
Filtering Resources
Include Specific Types
Export only certain resource types:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--include clients,users,groups
Exclude Types
Skip certain resource types:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--exclude role-mappings,protocol-mappers
Resource Types
Available resource types for filtering:
| Type | Description |
|---|---|
realm | The realm itself |
clients | OAuth2/OIDC clients |
client-scopes | Client scopes |
users | User accounts |
groups | User groups |
roles | Realm and client roles |
role-mappings | Role assignments to users/groups |
identity-providers | External identity providers (SAML, OIDC, etc.). Org-linked IdPs emit spec.organizationRef instead of definition.organizationId. |
components | LDAP federation, key providers, etc. |
protocol-mappers | Token claim mappers |
organizations | Organizations (Keycloak 26+) |
Identity providers linked to an organization are exported with spec.organizationRef pointing at the generated KeycloakOrganization (named from the organization name). The Keycloak organizationId UUID is stripped from definition so the exported manifest applies without being rejected. If the organization cannot be resolved (for example it was deleted), the field is dropped and a warning is logged.
Skip Built-in Resources
By default, Keycloak’s built-in resources are skipped (--skip-defaults=true). These include:
- Default clients:
account,account-console,admin-cli,broker,realm-management,security-admin-console - Default client scopes:
address,email,offline_access,phone,profile,roles,web-origins, etc. - Default roles:
offline_access,uma_authorization,default-roles-{realm} - Service account users (prefixed with
service-account-)
To include built-in resources:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--skip-defaults=false
Manifest Generation Options
Target Namespace
Set the namespace for generated manifests:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--target-namespace production
Instance Reference
Set the KeycloakInstance reference for all generated resources:
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--instance-ref keycloak-prod
Realm Reference
Override the realm reference name (defaults to the sanitized realm name):
docker run --rm ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm \
--realm-ref production-realm
Security Considerations
Secrets Are Never Exported
The export command never exports secrets. This includes:
- Client secrets
- User passwords
- Identity provider client secrets
- LDAP bind credentials (
config.bindCredential)
You must create these secrets separately and set the matching reference on the CR (clientSecretRef, configSecretRef, userSecret). Export does not emit configSecretRef; wire it after creating the Secret. See Secret references.
Password Handling
Pass passwords via environment variable instead of command line:
export KEYCLOAK_PASSWORD="your-password"
docker run --rm -e KEYCLOAK_PASSWORD ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm my-realm
Example Workflow: Migrating to the Operator
- Export existing configuration:
docker run --rm -v $(pwd)/manifests:/output ghcr.io/hostzero-gmbh/keycloak-operator export \
--url https://keycloak.example.com \
--username admin \
--password "$KEYCLOAK_PASSWORD" \
--realm production \
--target-namespace keycloak \
--instance-ref keycloak-prod \
--output-dir /output
- Review and customize manifests:
# Review generated files
ls -la manifests/
# Edit as needed (add client secrets, customize settings)
vim manifests/clients/my-app.yaml
- Create required secrets:
# Create client secrets referenced by the manifests
kubectl create secret generic my-app-credentials \
--namespace keycloak \
--from-literal=client-secret=your-client-secret
# LDAP bind credentials (then set spec.configSecretRef on the exported Component)
kubectl create secret generic ldap-credentials \
--namespace keycloak \
--from-literal=bindCredential=your-ldap-password
- Deploy the operator (if not already installed):
helm install keycloak-operator oci://ghcr.io/hostzero-gmbh/charts/keycloak-operator \
--namespace keycloak-operator \
--create-namespace
- Create the KeycloakInstance:
# Create credentials secret
kubectl create secret generic keycloak-admin \
--namespace keycloak \
--from-literal=username=admin \
--from-literal=password=your-admin-password
# Apply instance configuration
kubectl apply -f - <<EOF
apiVersion: keycloak.hostzero.com/v1beta1
kind: KeycloakInstance
metadata:
name: keycloak-prod
namespace: keycloak
spec:
baseUrl: https://keycloak.example.com
auth:
passwordGrant:
secretRef:
name: keycloak-admin
EOF
- Apply the exported manifests:
kubectl apply -f manifests/
Command Reference
Usage: keycloak-operator export [options]
Connection Options (choose one mode):
--url Keycloak server URL
--username Admin username
--password Admin password (or use KEYCLOAK_PASSWORD env var)
--from-instance Name of KeycloakInstance CR
--from-cluster-instance Name of ClusterKeycloakInstance CR
--namespace Namespace of KeycloakInstance
Export Options:
--realm Realm to export (required)
Output Options:
--output Output file path (default: stdout)
--output-dir Output directory (creates file structure)
Manifest Options:
--target-namespace Namespace for generated manifests (default: "default")
--instance-ref KeycloakInstance name to reference
--realm-ref KeycloakRealm name to reference
Filtering Options:
--include Resource types to include (comma-separated)
--exclude Resource types to exclude (comma-separated)
--skip-defaults Skip built-in Keycloak resources (default: true)
General Options:
--verbose Enable verbose output