Skip to content

Keycloak Realm Configuration

This content is not available in your language yet.

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.

  1. Export Required Shell Variables

    There are two sets of variables required for this configuration.

    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 Domains
    export 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 Variables
    export KEYCLOAK_REALM="opstella"

    Then make sure you have loaded global variables:

    Terminal window
    source $HOME/opstella-installation/shell-values/global.vars.sh

    Export these additional variables specific to the realm and admin setup:

    Terminal window
    # Realm Display Information
    export KEYCLOAK_DISPLAY_NAME="Opstella Platform"
    # Realm Opstella Group
    export 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"
  2. 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-06
    realm: "${KEYCLOAK_REALM}"
    displayName: "${KEYCLOAK_DISPLAY_NAME}"
    displayNameHtml: <div class="kc-logo-text"><span>${KEYCLOAK_DISPLAY_NAME}</span></div>
    loginTheme: opstella-v5
    enabled: 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: admin
    email: "opstella-admin@${BASE_DOMAIN}"
    enabled: true
    emailVerified: true
    firstName: Opstella
    lastName: Administrator
    # Assign to Group
    groups:
    - "/${KEYCLOAK_REALM_OPSTELLA_GROUP_PATH}"
    # Credentials
    credentials:
    - type: password
    value: "${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: argocd
    name: ArgoCD
    description: "ArgoCD Application"
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 2. DefectDojo
    - clientId: defectdojo
    name: DefectDojo
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: false
    rootUrl: "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: audience
    protocol: openid-connect
    protocolMapper: oidc-audience-mapper
    config:
    "included.client.audience": "defectdojo"
    "id.token.claim": "true"
    "access.token.claim": "true"
    # 3. SonarQube
    - clientId: sonarqube
    name: SonarQube
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 4. GitLab
    - clientId: gitlab
    name: GitLab
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 5. Harbor
    - clientId: harbor
    name: Harbor
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 6. Grafana
    - clientId: grafana
    name: Grafana
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 7. Kubernetes API
    - clientId: kubernetes
    name: Kubernetes API
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    redirectUris:
    - "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 8. Vault
    - clientId: vault
    name: HashiCorp Vault
    enabled: true
    clientAuthenticatorType: client-secret
    publicClient: false
    serviceAccountsEnabled: true
    authorizationServicesEnabled: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    # 9. Opstella
    - clientId: opstella
    name: Opstella
    enabled: true
    publicClient: true
    standardFlowEnabled: true
    directAccessGrantsEnabled: true
    fullScopeAllowed: true
    rootUrl: "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 Groups
    protocol: openid-connect
    protocolMapper: oidc-group-membership-mapper
    config:
    "full.path": "false"
    "id.token.claim": "true"
    "access.token.claim": "true"
    "userinfo.token.claim": "true"
    "claim.name": "groups"
    EOF
  3. 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