Keycloak Realm Configuration
After installing Keycloak, you need to configure the Opstella realm, groups, users, and clients (ArgoCD, GitLab, etc.). This is performed using the keycloak-config-cli tool.
Configuration
Section titled “Configuration”-
Export Required Shell Variables
There are two sets of variables required for this configuration.
Previously Set Variables
Section titled “Previously Set Variables”Ensure you have defined and loaded your Global Shell Variables as described in Shell Variables.
The following variables should already be defined if you followed the Shell Variables guide:
Terminal window # Global & Tenant Domainsexport BASE_DOMAIN="example.com"export KEYCLOAK_DOMAIN="idp.${BASE_DOMAIN}"export ARGOCD_DOMAIN="argocd.${BASE_DOMAIN}"export GITLAB_DOMAIN="gitlab.${BASE_DOMAIN}"export HARBOR_DOMAIN="harbor.${BASE_DOMAIN}"# ... and others (SonarQube, DefectDojo, Vault, Grafana)# Core Keycloak Variablesexport KEYCLOAK_REALM="opstella"Then make sure you have loaded global variables:
Terminal window source $HOME/opstella-installation/shell-values/global.vars.shNew Configuration Variables
Section titled “New Configuration Variables”Export these additional variables specific to the realm and admin setup:
Terminal window # Realm Display Informationexport KEYCLOAK_DISPLAY_NAME="Opstella Platform"# Realm Opstella Groupexport KEYCLOAK_REALM_OPSTELLA_GROUP="opstella-group"export KEYCLOAK_REALM_OPSTELLA_GROUP_PATH="opstella-group"export KEYCLOAK_REALM_ADMIN_PASSWORD="CHANGEME"# Core Keycloak Admin (Set during installation)export KEYCLOAK_ADMIN_PASSWORD="CHANGEME" -
Prepare Realm Configuration File
The following file defines the Opstella realm structure, including all OIDC clients for the platform.
Terminal window cat <<EOF > $HOME/opstella-installation/kc-opstella-realm.yaml# Forced update 2026-02-06realm: "${KEYCLOAK_REALM}"displayName: "${KEYCLOAK_DISPLAY_NAME}"displayNameHtml: <div class="kc-logo-text"><span>${KEYCLOAK_DISPLAY_NAME}</span></div>loginTheme: opstella-v5enabled: true# --- GROUPS (Fully Managed) ---# Supported: "import.managed.group"groups:- name: "${KEYCLOAK_REALM_OPSTELLA_GROUP}"path: "/${KEYCLOAK_REALM_OPSTELLA_GROUP_PATH}"# --- USERS (Update Only) ---# FACT: 'Users' are NOT supported for full management/deletion.# This section will Create/Update 'admin', but will NOT delete other users.users:- username: adminemail: "opstella-admin@${BASE_DOMAIN}"enabled: trueemailVerified: truefirstName: OpstellalastName: Administrator# Assign to Groupgroups:- "/${KEYCLOAK_REALM_OPSTELLA_GROUP_PATH}"# Credentialscredentials:- type: passwordvalue: "${KEYCLOAK_REALM_ADMIN_PASSWORD}"temporary: false# Client Roles (Map Structure)clientRoles:realm-management:- realm-admin# --- CLIENTS (Fully Managed) ---# Supported: "import.managed.client"clients:# 1. ArgoCD- clientId: argocdname: ArgoCDdescription: "ArgoCD Application"enabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${ARGOCD_DOMAIN}"baseUrl: "https://${ARGOCD_DOMAIN}"adminUrl: "https://${ARGOCD_DOMAIN}"redirectUris:- "https://${ARGOCD_DOMAIN}/auth/callback"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "true""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 2. DefectDojo- clientId: defectdojoname: DefectDojoenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: falserootUrl: "https://${DEFECTDOJO_DOMAIN}"baseUrl: "https://${DEFECTDOJO_DOMAIN}"adminUrl: "https://${DEFECTDOJO_DOMAIN}"redirectUris:- "https://${DEFECTDOJO_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "false"protocolMappers:- name: audienceprotocol: openid-connectprotocolMapper: oidc-audience-mapperconfig:"included.client.audience": "defectdojo""id.token.claim": "true""access.token.claim": "true"# 3. SonarQube- clientId: sonarqubename: SonarQubeenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${SONARQUBE_DOMAIN}"baseUrl: "https://${SONARQUBE_DOMAIN}"adminUrl: "https://${SONARQUBE_DOMAIN}"redirectUris:- "https://${SONARQUBE_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 4. GitLab- clientId: gitlabname: GitLabenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${GITLAB_DOMAIN}"baseUrl: "https://${GITLAB_DOMAIN}"adminUrl: "https://${GITLAB_DOMAIN}"redirectUris:- "https://${GITLAB_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 5. Harbor- clientId: harborname: Harborenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${HARBOR_DOMAIN}"baseUrl: "https://${HARBOR_DOMAIN}"adminUrl: "https://${HARBOR_DOMAIN}"redirectUris:- "https://${HARBOR_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "true""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 6. Grafana- clientId: grafananame: Grafanaenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${GRAFANA_DASHBOARD_DOMAIN}"baseUrl: "https://${GRAFANA_DASHBOARD_DOMAIN}"adminUrl: "https://${GRAFANA_DASHBOARD_DOMAIN}"redirectUris:- "https://${GRAFANA_DASHBOARD_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 7. Kubernetes API- clientId: kubernetesname: Kubernetes APIenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: trueredirectUris:- "http://localhost:8000"- "http://localhost:18000"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 8. Vault- clientId: vaultname: HashiCorp Vaultenabled: trueclientAuthenticatorType: client-secretpublicClient: falseserviceAccountsEnabled: trueauthorizationServicesEnabled: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${VAULT_DOMAIN}"baseUrl: "https://${VAULT_DOMAIN}"adminUrl: "https://${VAULT_DOMAIN}"redirectUris:- "https://${VAULT_DOMAIN}/*"- "https://${VAULT_DOMAIN}/ui/vault/auth/oidc/oidc/callback"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "true""exclude.issuer.from.auth.response": "false"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"# 9. Opstella- clientId: opstellaname: Opstellaenabled: truepublicClient: truestandardFlowEnabled: truedirectAccessGrantsEnabled: truefullScopeAllowed: truerootUrl: "https://${OPSTELLA_DOMAIN}"baseUrl: "https://${OPSTELLA_DOMAIN}"adminUrl: "https://${OPSTELLA_DOMAIN}"redirectUris:- "https://${OPSTELLA_DOMAIN}/*"webOrigins:- "+"attributes:"backchannel.logout.session.required": "true""backchannel.logout.revoke.offline.tokens": "false""exclude.issuer.from.auth.response": "true"protocolMappers:- name: Opstella Groupsprotocol: openid-connectprotocolMapper: oidc-group-membership-mapperconfig:"full.path": "false""id.token.claim": "true""access.token.claim": "true""userinfo.token.claim": "true""claim.name": "groups"EOF -
Apply Configuration with keycloak-config-cli
Use the following Docker command to apply the configuration. This tool connects to your Keycloak instance and synchronizes the realm state.
Terminal window docker run --rm \-v "$HOME/opstella-installation/kc-opstella-realm.yaml:/config/realm-config.yaml" \--env KEYCLOAK_URL="https://${KEYCLOAK_DOMAIN}" \--env KEYCLOAK_USER="admin" \--env KEYCLOAK_PASSWORD="${KEYCLOAK_ADMIN_PASSWORD}" \--env KEYCLOAK_AVAILABILITYCHECK_ENABLED=true \--env KEYCLOAK_AVAILABILITYCHECK_TIMEOUT=120s \--env LOGGING_LEVEL_ROOT=DEBUG \--env IMPORT_FILES_LOCATIONS="/config/realm-config.yaml" \--env IMPORT_MANAGED_CLIENT=full \--env IMPORT_MANAGED_GROUP=full \--env IMPORT_MANAGED_ROLE=no-delete \--env IMPORT_MANAGED_COMPONENT=no-delete \--env IMPORT_MANAGED_AUTHENTICATION_FLOW=no-delete \--env IMPORT_MANAGED_REQUIRED_ACTION=no-delete \--env IMPORT_MANAGED_CLIENT_SCOPE=no-delete \--env IMPORT_MANAGED_SCOPE_MAPPING=no-delete \adorsys/keycloak-config-cli:6.4.1-24
Finished?
Use the below navigation to proceed