From f24fa56d0efbe1ae85a13be11ea8e77b48772bdc Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Fri, 31 Oct 2025 12:25:58 +0000 Subject: [PATCH 1/3] feat: use native bitnami-keycloak chart --- root/values.yaml | 12 +- root/values_cf.yaml | 1 + root/values_dev.yaml | 3 +- root/values_ha.yaml | 1 + sbom/components.yaml | 6 +- ....yaml => keycloak-airm-realm-secrets.yaml} | 37 +- .../templates/keycloak-cluster.yaml | 99 --- .../templates/keycloak-cnpg-cluster.yaml | 49 ++ .../templates/keycloak-cnpg-secrets.yaml | 46 + .../templates/keycloak-credentials.yaml | 21 + .../templates/keycloak-httproute.yaml | 2 +- .../keycloak-realm-templates-cm.yaml | 785 +++++++++++++----- ...cloak-cm.yaml => keycloak-scripts-cm.yaml} | 0 sources/keycloak/values_cf.yaml | 120 ++- 14 files changed, 805 insertions(+), 377 deletions(-) rename sources/keycloak-config/templates/{keycloak-secrets.yaml => keycloak-airm-realm-secrets.yaml} (66%) delete mode 100644 sources/keycloak-config/templates/keycloak-cluster.yaml create mode 100644 sources/keycloak-config/templates/keycloak-cnpg-cluster.yaml create mode 100644 sources/keycloak-config/templates/keycloak-cnpg-secrets.yaml create mode 100644 sources/keycloak-config/templates/keycloak-credentials.yaml rename sources/keycloak-config/templates/{keycloak-cm.yaml => keycloak-scripts-cm.yaml} (100%) diff --git a/root/values.yaml b/root/values.yaml index 9cdf78ba..c1310068 100644 --- a/root/values.yaml +++ b/root/values.yaml @@ -33,6 +33,7 @@ enabledApps: - cluster-auth - cluster-auth-config - keycloak + - keycloak-config - kyverno - kyverno-config - amd-gpu-operator @@ -197,7 +198,16 @@ apps: - ".spec.data[].remoteRef.decodingStrategy" - ".spec.data[].remoteRef.metadataPolicy" keycloak: - path: keycloak-old + path: keycloak/25.2.0 + namespace: keycloak + valuesFile: ../values_cf.yaml + helmParameters: + - name: domain + value: "{{ .Values.global.domain }}" + syncWave: -1 + + keycloak-config: + path: keycloak-config namespace: keycloak valuesFile: values.yaml helmParameters: diff --git a/root/values_cf.yaml b/root/values_cf.yaml index be596968..8a096bb7 100644 --- a/root/values_cf.yaml +++ b/root/values_cf.yaml @@ -31,6 +31,7 @@ enabledApps: - cluster-auth - cluster-auth-config - keycloak + - keycloak-config - kyverno - kyverno-config - amd-gpu-operator diff --git a/root/values_dev.yaml b/root/values_dev.yaml index 28c9496c..e4bbfe00 100644 --- a/root/values_dev.yaml +++ b/root/values_dev.yaml @@ -17,8 +17,6 @@ enabledApps: - openbao-config - external-secrets - external-secrets-config - - gitea - - gitea-config - gateway-api - metallb - kgateway-crds @@ -31,6 +29,7 @@ enabledApps: - cluster-auth - cluster-auth-config - keycloak + - keycloak-config - kyverno - kyverno-config - amd-gpu-operator diff --git a/root/values_ha.yaml b/root/values_ha.yaml index 6453dc61..4ffd7335 100644 --- a/root/values_ha.yaml +++ b/root/values_ha.yaml @@ -31,6 +31,7 @@ enabledApps: - cluster-auth - cluster-auth-config - keycloak + - keycloak-config - kyverno - kyverno-config - amd-gpu-operator diff --git a/sbom/components.yaml b/sbom/components.yaml index 236cc828..9baafcd4 100644 --- a/sbom/components.yaml +++ b/sbom/components.yaml @@ -99,9 +99,9 @@ components: license: Apache License 2.0 licenseUrl: https://github.com/silogen/cluster-forge/blob/main/LICENSE keycloak: - path: keycloak-old - valuesFile: values.yaml - sourceUrl: https://codecentric.github.io/helm-charts + path: keycloak/25.2.0 + valuesFile: ../values_cf.yaml + sourceUrl: oci://registry-1.docker.io/bitnamicharts/keycloak projectUrl: https://github.com/keycloak/keycloak license: Apache License 2.0 licenseUrl: https://github.com/keycloak/keycloak/blob/main/LICENSE.txt diff --git a/sources/keycloak-config/templates/keycloak-secrets.yaml b/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml similarity index 66% rename from sources/keycloak-config/templates/keycloak-secrets.yaml rename to sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml index a53cbebb..b9ddc2c3 100644 --- a/sources/keycloak-config/templates/keycloak-secrets.yaml +++ b/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml @@ -1,5 +1,5 @@ --- -apiVersion: external-secrets.io/v1 +apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: airm-realm-credentials @@ -24,31 +24,26 @@ spec: key: airm-ci-client-secret property: value secretKey: CI_CLIENT_SECRET - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: openbao-secret-store - target: - creationPolicy: Owner - name: airm-realm-credentials ---- -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: keycloak-credentials - namespace: keycloak - annotations: - argocd.argoproj.io/hook: PreSync -spec: - data: - remoteRef: - key: keycloak-initial-admin-password + key: k8s-client-secret + property: value + secretKey: K8S_CLIENT_SECRET + - remoteRef: + key: minio-client-secret + property: value + secretKey: MINIO_CLIENT_SECRET + - remoteRef: + key: gitea-client-secret property: value - secretKey: KEYCLOAK_INITIAL_ADMIN_PASSWORD + secretKey: GITEA_CLIENT_SECRET + - remoteRef: + key: argocd-client-secret + property: value + secretKey: ARGOCD_CLIENT_SECRET refreshInterval: 1h secretStoreRef: kind: ClusterSecretStore name: openbao-secret-store target: creationPolicy: Owner - name: keycloak-credentials + name: airm-realm-credentials diff --git a/sources/keycloak-config/templates/keycloak-cluster.yaml b/sources/keycloak-config/templates/keycloak-cluster.yaml deleted file mode 100644 index 0421fda3..00000000 --- a/sources/keycloak-config/templates/keycloak-cluster.yaml +++ /dev/null @@ -1,99 +0,0 @@ ---- -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: keycloak-cnpg-superuser-credentials - namespace: keycloak -spec: - secretStoreRef: - kind: ClusterSecretStore - name: openbao-secret-store - target: - creationPolicy: Owner - name: keycloak-cnpg-superuser - data: - - remoteRef: - key: keycloak-cnpg-superuser-username - property: value - secretKey: username - - remoteRef: - key: keycloak-cnpg-superuser-password - property: value - secretKey: password - ---- -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: keycloak-cnpg-user-credentials - namespace: keycloak -spec: - data: - - remoteRef: - key: keycloak-cnpg-user-username - property: value - secretKey: username - - remoteRef: - key: keycloak-cnpg-user-password - property: value - secretKey: password - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: openbao-secret-store - target: - creationPolicy: Owner - name: keycloak-cnpg-user ---- -apiVersion: postgresql.cnpg.io/v1 -kind: Cluster -metadata: - name: keycloak-cnpg - namespace: keycloak -spec: - affinity: - enablePodAntiAffinity: true - topologyKey: topology.kubernetes.io/zone - bootstrap: - initdb: - database: keycloak - owner: keycloak - postInitSQL: - - GRANT CREATE ON SCHEMA public TO keycloak - secret: - name: keycloak-cnpg-user - imageName: ghcr.io/cloudnative-pg/postgresql:17 - instances: 1 - nodeMaintenanceWindow: - inProgress: false - reusePVC: true - postgresql: - parameters: - auto_explain.log_min_duration: 10s - pg_stat_statements.max: "10000" - pg_stat_statements.track: all - shared_buffers: 256MB - pg_hba: - - host all all 10.244.0.0/16 md5 - primaryUpdateStrategy: unsupervised - resources: - limits: - cpu: "2" - memory: 1Gi - requests: - cpu: "1" - memory: 512Mi - serviceAccountTemplate: - metadata: - annotations: - iam.gke.io/gcp-service-account: dev-gke-sa@silogen-dev.iam.gserviceaccount.com - startDelay: 300 - stopDelay: 300 - storage: - size: 50Gi - storageClass: default - superuserSecret: - name: keycloak-cnpg-superuser - walStorage: - size: 50Gi - storageClass: default diff --git a/sources/keycloak-config/templates/keycloak-cnpg-cluster.yaml b/sources/keycloak-config/templates/keycloak-cnpg-cluster.yaml new file mode 100644 index 00000000..bceb5ad6 --- /dev/null +++ b/sources/keycloak-config/templates/keycloak-cnpg-cluster.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: keycloak-cnpg + namespace: keycloak +spec: + affinity: + enablePodAntiAffinity: true + topologyKey: topology.kubernetes.io/zone + bootstrap: + initdb: + database: keycloak + owner: keycloak + postInitSQL: + - GRANT CREATE ON SCHEMA public TO keycloak + secret: + name: keycloak-cnpg-user + imageName: ghcr.io/cloudnative-pg/postgresql:17 + instances: 1 + nodeMaintenanceWindow: + inProgress: false + reusePVC: true + postgresql: + parameters: + auto_explain.log_min_duration: 10s + pg_stat_statements.max: "10000" + pg_stat_statements.track: all + shared_buffers: 256MB + pg_hba: + - host all all 10.244.0.0/16 md5 + primaryUpdateStrategy: unsupervised + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: "1" + memory: 512Mi + startDelay: 300 + stopDelay: 300 + storage: + size: 50Gi + storageClass: default + superuserSecret: + name: keycloak-cnpg-superuser + walStorage: + size: 50Gi + storageClass: default diff --git a/sources/keycloak-config/templates/keycloak-cnpg-secrets.yaml b/sources/keycloak-config/templates/keycloak-cnpg-secrets.yaml new file mode 100644 index 00000000..53fea973 --- /dev/null +++ b/sources/keycloak-config/templates/keycloak-cnpg-secrets.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: keycloak-cnpg-superuser-credentials + namespace: keycloak +spec: + secretStoreRef: + kind: ClusterSecretStore + name: openbao-secret-store + target: + creationPolicy: Owner + name: keycloak-cnpg-superuser + data: + - remoteRef: + key: keycloak-cnpg-superuser-username + property: value + secretKey: username + - remoteRef: + key: keycloak-cnpg-superuser-password + property: value + secretKey: password + +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: keycloak-cnpg-user-credentials + namespace: keycloak +spec: + data: + - remoteRef: + key: keycloak-cnpg-user-username + property: value + secretKey: username + - remoteRef: + key: keycloak-cnpg-user-password + property: value + secretKey: password + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: openbao-secret-store + target: + creationPolicy: Owner + name: keycloak-cnpg-user \ No newline at end of file diff --git a/sources/keycloak-config/templates/keycloak-credentials.yaml b/sources/keycloak-config/templates/keycloak-credentials.yaml new file mode 100644 index 00000000..46dd6ebf --- /dev/null +++ b/sources/keycloak-config/templates/keycloak-credentials.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: keycloak-credentials + namespace: keycloak + annotations: + argocd.argoproj.io/hook: PreSync +spec: + data: + - remoteRef: + key: keycloak-initial-admin-password + property: value + secretKey: KEYCLOAK_INITIAL_ADMIN_PASSWORD + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: openbao-secret-store + target: + creationPolicy: Owner + name: keycloak-credentials diff --git a/sources/keycloak-config/templates/keycloak-httproute.yaml b/sources/keycloak-config/templates/keycloak-httproute.yaml index 93c65f43..1fa444ec 100644 --- a/sources/keycloak-config/templates/keycloak-httproute.yaml +++ b/sources/keycloak-config/templates/keycloak-httproute.yaml @@ -16,7 +16,7 @@ spec: kind: Service name: keycloak namespace: keycloak - port: 80 + port: 8080 weight: 1 matches: - headers: diff --git a/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml b/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml index 1f8f9cfa..d9c65c90 100644 --- a/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml +++ b/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml @@ -252,8 +252,8 @@ data: "view-realm", "query-users", "manage-realm", - "manage-users", "create-client", + "manage-users", "view-authorization", "impersonation", "manage-identity-providers", @@ -339,9 +339,12 @@ data: ], "security-admin-console": [], "__AIRM_ADMIN_CLIENT_ID__": [], - "admin-cli": [], + "argocd": [], "k8s": [], + "admin-cli": [], "minio": [], + "gitea": [], + "ci-service-account": [], "account-console": [], "broker": [ { @@ -445,6 +448,15 @@ data: } }, "groups": [ + { + "id": "36795a36-68fd-46b6-b194-64e788500360", + "name": "argocd-users", + "path": "/argocd-users", + "subGroups": [], + "attributes": {}, + "realmRoles": [], + "clientRoles": {} + }, { "id": "edbe36d4-aea0-4ff3-a8db-a3c9843e8a46", "name": "minio-users", @@ -457,6 +469,19 @@ data: }, "realmRoles": [], "clientRoles": {} + }, + { + "id": "edbe36d4-bfe2-4ff3-a8db-a3c9843e8a46", + "name": "gitea-users", + "path": "/gitea-users", + "subGroups": [], + "attributes": { + "policy": [ + "readwrite" + ] + }, + "realmRoles": [], + "clientRoles": {} } ], "defaultRole": { @@ -512,27 +537,6 @@ data: "webAuthnPolicyPasswordlessAcceptableAaguids": [], "webAuthnPolicyPasswordlessExtraOrigins": [], "users": [ - { - "id": "393cb680-d521-4c02-839d-7366076398d1", - "username": "service-account-__AIRM_ADMIN_CLIENT_ID__", - "emailVerified": false, - "createdTimestamp": 1737315816555, - "enabled": true, - "totp": false, - "serviceAccountClientId": "__AIRM_ADMIN_CLIENT_ID__", - "disableableCredentialTypes": [], - "requiredActions": [], - "realmRoles": [ - "default-roles-airm" - ], - "clientRoles": { - "realm-management": [ - "realm-admin" - ] - }, - "notBefore": 0, - "groups": [] - }, { "id": "487590ed-165c-44d5-b686-1aff81cca298", "username": "devuser@{{ .Values.domain }}", @@ -562,9 +566,32 @@ data: ], "notBefore": 0, "groups": [ - "/minio-users" + "/minio-users", + "/argocd-users", + "/gitea-users" ] }, + { + "id": "393cb680-d521-4c02-839d-7366076398d1", + "username": "service-account-__AIRM_ADMIN_CLIENT_ID__", + "emailVerified": false, + "createdTimestamp": 1737315816555, + "enabled": true, + "totp": false, + "serviceAccountClientId": "__AIRM_ADMIN_CLIENT_ID__", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-airm" + ], + "clientRoles": { + "realm-management": [ + "realm-admin" + ] + }, + "notBefore": 0, + "groups": [] + }, { "id": "b2cbd302-17bf-4865-9591-96845376dc7b", "username": "service-account-minio", @@ -573,6 +600,22 @@ data: "enabled": true, "totp": false, "serviceAccountClientId": "minio", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-airm" + ], + "notBefore": 0, + "groups": [] + }, + { + "id": "e5714500-2153-4c0e-9f2e-b9d4681f33c5", + "username": "service-account-ci-service-account", + "emailVerified": false, + "createdTimestamp": 1759383882000, + "enabled": true, + "totp": false, + "serviceAccountClientId": "ci-service-account", "credentials": [], "disableableCredentialTypes": [], "requiredActions": [], @@ -684,6 +727,216 @@ data: "microprofile-jwt" ] }, + { + "id": "ceeab688-00ab-4d0f-b0e2-0b5b0f1facbe", + "clientId": "354a0fa1-35ac-4a6d-9c4d-d661129c2cd0", + "name": "AIRM UI Client", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "__AIRM_FRONTEND_CLIENT_SECRET__", + "redirectUris": [ + "https://airmapi.{{ .Values.domain }}/*", + "https://airmui.{{ .Values.domain }}/*", + "https://{{ .Values.domain }}/*" + ], + "webOrigins": [ + "*" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1737564832", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "organization", + "profile", + "groups", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4829f38b-ed60-40d2-ad3d-b71c6406433d", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/airm/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/airm/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "d4eeae5e-578f-43cc-9759-b4cc7f10e7bd", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/airm/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/airm/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "e16c13e4-dd66-4a2b-b740-cdfd73e1ca6b", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "64f7bd64-cf2b-4e43-9b41-8b5045da884a", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, { "id": "9f46dcf2-2d4a-434e-bec6-718bdb300367", "clientId": "__AIRM_ADMIN_CLIENT_ID__", @@ -698,9 +951,10 @@ data: "clientAuthenticatorType": "client-secret", "secret": "__AIRM_ADMIN_CLIENT_SECRET__", "redirectUris": [ - "https://{{ .Values.domain }}/*", + "https://airmapi.{{ .Values.domain }}/*", "https://airmui.{{ .Values.domain }}/*", - "https://*.{{ .Values.domain }}/*" + "https://*.{{ .Values.domain }}/*", + "https://{{ .Values.domain }}/*" ], "webOrigins": [ "*" @@ -796,22 +1050,20 @@ data: ] }, { - "id": "ceeab688-00ab-4d0f-b0e2-0b5b0f1facbe", - "clientId": "354a0fa1-35ac-4a6d-9c4d-d661129c2cd0", - "name": "AIRM UI Client", + "id": "cb138b4d-8f15-45c1-8c1d-f1db394a17e3", + "clientId": "argocd", + "name": "argocd", "description": "", - "rootUrl": "", - "adminUrl": "", - "baseUrl": "", + "rootUrl": "https://argocd.{{ .Values.domain }}", + "adminUrl": "https://argocd.{{ .Values.domain }}", + "baseUrl": "/applications", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "__AIRM_FRONTEND_CLIENT_SECRET__", + "secret": "__ARGOCD_CLIENT_SECRET__", "redirectUris": [ - "https://{{ .Values.domain }}/*", - "https://airmui.{{ .Values.domain }}/*", - "https://airmapi.{{ .Values.domain }}/*" + "https://argocd.{{ .Values.domain }}/auth/callback" ], "webOrigins": [ "*" @@ -820,7 +1072,7 @@ data: "bearerOnly": false, "consentRequired": false, "standardFlowEnabled": true, - "implicitFlowEnabled": true, + "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, "serviceAccountsEnabled": false, "publicClient": false, @@ -829,11 +1081,10 @@ data: "attributes": { "realm_client": "false", "oidc.ciba.grant.enabled": "false", - "client.secret.creation.time": "1737564832", + "client.secret.creation.time": "1759834455", "backchannel.logout.session.required": "true", - "post.logout.redirect.uris": "+", + "post.logout.redirect.uris": "https://argocd.{{ .Values.domain }}/auth/callback", "oauth2.device.authorization.grant.enabled": "false", - "display.on.consent.screen": "false", "backchannel.logout.revoke.offline.tokens": "false" }, "authenticationFlowBindingOverrides": {}, @@ -843,45 +1094,42 @@ data: "web-origins", "acr", "roles", - "organization", "profile", + "groups", "basic", "email", - "groups" + "policy" ], "optionalClientScopes": [ "address", "phone", + "organization", "offline_access", "microprofile-jwt" ] }, { - "id": "4829f38b-ed60-40d2-ad3d-b71c6406433d", - "clientId": "account", - "name": "${client_account}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/airm/account/", + "id": "f8ce533a-7ebc-431b-89f5-28f386164ccf", + "clientId": "broker", + "name": "${client_broker}", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "redirectUris": [ - "/realms/airm/account/*" - ], + "redirectUris": [], "webOrigins": [], "notBefore": 0, - "bearerOnly": false, + "bearerOnly": true, "consentRequired": false, "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, "serviceAccountsEnabled": false, - "publicClient": true, + "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", "attributes": { - "realm_client": "false", + "realm_client": "true", "post.logout.redirect.uris": "+" }, "authenticationFlowBindingOverrides": {}, @@ -904,141 +1152,104 @@ data: ] }, { - "id": "d4eeae5e-578f-43cc-9759-b4cc7f10e7bd", - "clientId": "account-console", - "name": "${client_account-console}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/airm/account/", + "id": "efb12ee0-a2dc-4c7a-a032-74ce4730c425", + "clientId": "minio", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", + "secret": "__MINIO_CLIENT_SECRET__", "redirectUris": [ - "/realms/airm/account/*" + "", + "https://minio.{{ .Values.domain }}/*" + ], + "webOrigins": [ + "*" ], - "webOrigins": [], "notBefore": 0, "bearerOnly": false, "consentRequired": false, "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": true, "protocol": "openid-connect", "attributes": { "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1756901765", + "backchannel.logout.session.required": "true", "post.logout.redirect.uris": "+", - "pkce.code.challenge.method": "S256" + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" }, "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, "protocolMappers": [ { - "id": "e16c13e4-dd66-4a2b-b740-cdfd73e1ca6b", - "name": "audience resolve", + "id": "aa7debbf-865b-5eqs-b990-7e23304f7a46", + "name": "Client ID", "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", + "protocolMapper": "oidc-usersessionmodel-note-mapper", "consentRequired": false, - "config": {} - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "basic", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "organization", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "64f7bd64-cf2b-4e43-9b41-8b5045da884a", - "clientId": "admin-cli", - "name": "${client_admin-cli}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": false, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "realm_client": "false", - "client.use.lightweight.access.token.enabled": "true", - "post.logout.redirect.uris": "+" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "basic", - "email" + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "74d68184-yre3-40a7-a7ed-b0e8cb8bdcc5", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "1539a7f8-a01a-8ike-8815-98ee03396d8c", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + } ], - "optionalClientScopes": [ - "address", - "phone", - "organization", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "f8ce533a-7ebc-431b-89f5-28f386164ccf", - "clientId": "broker", - "name": "${client_broker}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "realm_client": "true", - "post.logout.redirect.uris": "+" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, "defaultClientScopes": [ "web-origins", "acr", "roles", "profile", + "groups", "basic", - "email" + "email", + "policy" ], "optionalClientScopes": [ "address", @@ -1049,8 +1260,8 @@ data: ] }, { - "id": "efb12ee0-a2dc-4c7a-a032-74ce4730c425", - "clientId": "minio", + "id": "efb12ee0-b3yw-4c7a-a032-74ce4730c425", + "clientId": "gitea", "name": "", "description": "", "rootUrl": "", @@ -1060,10 +1271,10 @@ data: "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "__MINIO_KEYCLOAK_CLIENT_SECRET__", + "secret": "__GITEA_CLIENT_SECRET__", "redirectUris": [ "", - "https://minio.{{ .Values.domain }}/*" + "https://gitea.{{ .Values.domain }}/*" ], "webOrigins": [ "*" @@ -1167,12 +1378,12 @@ data: "redirectUris": [], "webOrigins": [], "notBefore": 0, - "bearerOnly": true, + "bearerOnly": false, "consentRequired": false, "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, + "serviceAccountsEnabled": true, "authorizationServicesEnabled": true, "publicClient": false, "frontchannelLogout": false, @@ -1236,6 +1447,111 @@ data: "decisionStrategy": "UNANIMOUS" } }, + { + "id": "185c5af6-9b04-4463-83db-2923dfc75b72", + "clientId": "ci-service-account", + "name": "CI Service Account", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "__AIRM_CI_CLIENT_SECRET__", + "redirectUris": [ + "/*" + ], + "webOrigins": [ + "/*" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1759383882", + "backchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "8cbf3b39-4ba0-4353-84f4-80ffeac6eee3", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "7dda77a1-17cd-4969-b093-2ce396ac8ebd", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "69603ff4-0252-4cc5-9c6d-b2f1357e5931", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "organization", + "profile", + "groups", + "basic", + "email", + "policy" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, { "id": "2bb550ef-6d62-4c4a-ad46-bbaeb2e32ab8", "clientId": "security-admin-console", @@ -1376,36 +1692,6 @@ data: } ] }, - { - "id": "ca910203-028f-426e-b8bd-44881302e47b", - "name": "groups", - "description": "User group memberships", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "c44766cf-7ee5-484d-b147-ef112f0cf573", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-group-membership-mapper", - "consentRequired": false, - "config": { - "full.path": "false", - "introspection.token.claim": "true", - "multivalued": "true", - "userinfo.token.claim": "true", - "id.token.claim": "true", - "lightweight.claim": "false", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - } - ] - }, { "id": "dfce246f-f69b-4a33-82cf-f222bffabaf8", "name": "policy", @@ -1525,6 +1811,36 @@ data: } ] }, + { + "id": "ca910203-028f-426e-b8bd-44881302e47b", + "name": "groups", + "description": "User group memberships", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "c44766cf-7ee5-484d-b147-ef112f0cf573", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": false, + "config": { + "full.path": "false", + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "lightweight.claim": "false", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, { "id": "198bd7af-34c0-45bf-9c36-7be521db7433", "name": "saml_organization", @@ -2042,8 +2358,7 @@ data: "xXSSProtection": "1; mode=block", "strictTransportSecurity": "max-age=31536000; includeSubDomains" }, - "smtpServer": { - }, + "smtpServer": {}, "eventsEnabled": false, "eventsListeners": [ "jboss-logging" @@ -2063,14 +2378,14 @@ data: "subComponents": {}, "config": { "allowed-protocol-mapper-types": [ - "saml-user-attribute-mapper", - "oidc-full-name-mapper", - "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", - "oidc-address-mapper", - "saml-user-property-mapper" + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-full-name-mapper" ] } }, @@ -2134,14 +2449,14 @@ data: "subComponents": {}, "config": { "allowed-protocol-mapper-types": [ + "oidc-address-mapper", "saml-user-attribute-mapper", - "oidc-full-name-mapper", - "saml-role-list-mapper", - "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", - "oidc-address-mapper" + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper" ] } }, @@ -2174,7 +2489,57 @@ data: } ], "org.keycloak.keys.KeyProvider": [ -] + { + "id": "95c6bb56-1e9c-48d3-93b2-9b181c984246", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + }, + { + "id": "314bcf12-2efb-4843-9504-bd4c38971b18", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "e069eb06-b3d3-46ad-961b-3762ce21882e", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "e58345e2-b092-4462-88e9-37f4a5be78f4", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + } + ] }, "internationalizationEnabled": false, "supportedLocales": [], @@ -2911,8 +3276,8 @@ data: "attributes": { "cibaBackchannelTokenDeliveryMode": "poll", "cibaAuthRequestedUserHint": "login_hint", - "oauth2DevicePollingInterval": "5", "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", "clientSessionIdleTimeout": "0", "clientOfflineSessionIdleTimeout": "0", "cibaInterval": "5", diff --git a/sources/keycloak-config/templates/keycloak-cm.yaml b/sources/keycloak-config/templates/keycloak-scripts-cm.yaml similarity index 100% rename from sources/keycloak-config/templates/keycloak-cm.yaml rename to sources/keycloak-config/templates/keycloak-scripts-cm.yaml diff --git a/sources/keycloak/values_cf.yaml b/sources/keycloak/values_cf.yaml index 4a1dddf8..a5a3b172 100644 --- a/sources/keycloak/values_cf.yaml +++ b/sources/keycloak/values_cf.yaml @@ -1,48 +1,84 @@ +image: + registry: docker.io + repository: bitnamilegacy/keycloak + +extraEnvVars: + - name: KC_HOSTNAME + value: "https://kc.{{ .Values.domain }}" + - name: KC_PROXY + value: edge + - name: KC_HOSTNAME_STRICT + value: "false" + - name: KC_PROXY_HEADERS + value: xforwarded + +httpEnabled: true + +service: + ports: + http: 8080 + resources: requests: memory: "512Mi" cpu: "500m" limits: - memory: "1Gi" + memory: "2Gi" cpu: "1000m" podLabels: app: keycloak auth: - adminUser: admin + adminUser: silogen-admin existingSecret: "keycloak-credentials" passwordSecretKey: "KEYCLOAK_INITIAL_ADMIN_PASSWORD" extraStartupArgs: "--cache=ispn --features=scripts,admin-fine-grained-authz,token-exchange --import-realm" +logging: + output: default + level: DEBUG + initContainers: - - command: + - name: init-auth-extensions + command: - /bin/sh - -c - | cd /opt/scripts - zip -r /opt/keycloak/providers/SilogenExtensionPackage.jar . + zip -r /opt/bitnami/keycloak/providers/SilogenExtensionPackage.jar . image: ghcr.io/silogen/keycloak-init:0.1 - name: init-auth-extensions volumeMounts: - - mountPath: /opt/keycloak/providers - name: keycloak-package-volume + - mountPath: /opt/bitnami/keycloak/providers + name: empty-dir + subPath: app-providers-dir - mountPath: /opt/scripts name: keycloak-script-volume - - command: + - name: init-realm-scripts + command: - /bin/sh - -c - - | - if [ -f "/opt/realm_templates/airm/airm-realm.json" ]; then - cp /opt/realm_templates/airm/airm-realm.json /opt/realms/airm-realm.json - sed -i -e "s/__AIRM_FRONTEND_CLIENT_SECRET__/$AIRM_FRONTEND_CLIENT_SECRET/g" /opt/realms/airm-realm.json - sed -i -e "s/__AIRM_ADMIN_CLIENT_ID__/$AIRM_ADMIN_CLIENT_ID/g" /opt/realms/airm-realm.json - sed -i -e "s/__AIRM_ADMIN_CLIENT_SECRET__/$AIRM_ADMIN_CLIENT_SECRET/g" /opt/realms/airm-realm.json - sed -i -e "s/__AIRM_CI_CLIENT_SECRET__/$AIRM_CI_CLIENT_SECRET/g" /opt/realms/airm-realm.json + - | + if [ -f "/opt/realm_templates/airm-realm.json" ]; then + cp /opt/realm_templates/airm-realm.json /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__AIRM_FRONTEND_CLIENT_SECRET__/$AIRM_FRONTEND_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__AIRM_ADMIN_CLIENT_ID__/$AIRM_ADMIN_CLIENT_ID/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__AIRM_ADMIN_CLIENT_SECRET__/$AIRM_ADMIN_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__AIRM_CI_CLIENT_SECRET__/$AIRM_CI_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__K8S_CLIENT_SECRET__/$K8S_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__MINIO_CLIENT_SECRET__/$MINIO_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__GITEA_CLIENT_SECRET__/$GITEA_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__ARGOCD_CLIENT_SECRET__/$ARGOCD_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json else - echo "Warning: /opt/realm_templates/airm/airm-realm.json not found, skipping airm realm setup" + echo "Warning: /opt/realm_templates/airm-realm.json not found, skipping airm realm setup" fi + image: ghcr.io/silogen/keycloak-init:0.1 + volumeMounts: + - mountPath: /opt/realm_templates + name: keycloak-realm-template-volume + - mountPath: /opt/bitnami/keycloak/data/import + name: keycloak-realm-volume env: - name: AIRM_FRONTEND_CLIENT_SECRET valueFrom: @@ -64,40 +100,44 @@ initContainers: secretKeyRef: key: CI_CLIENT_SECRET name: airm-realm-credentials - image: ghcr.io/silogen/keycloak-init:0.1 - name: init-realm-scripts - volumeMounts: - - mountPath: /opt/realm_templates/airm - name: keycloak-airm-realm-template-volume - - mountPath: /opt/realm_templates/k8s - name: keycloak-k8s-realm-template-volume - - mountPath: /opt/realms - name: keycloak-realm-volume + - name: K8S_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: K8S_CLIENT_SECRET + name: airm-realm-credentials + - name: MINIO_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: MINIO_CLIENT_SECRET + name: airm-realm-credentials + - name: GITEA_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: GITEA_CLIENT_SECRET + name: airm-realm-credentials + - name: ARGOCD_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: ARGOCD_CLIENT_SECRET + name: airm-realm-credentials extraVolumes: - - configMap: + - name: keycloak-script-volume + configMap: name: keycloak-scripts items: - key: keycloak-scripts.json path: META-INF/keycloak-scripts.json - key: domain-group-authenticator.js path: domain-group-authenticator.js - name: keycloak-script-volume - - emptyDir: {} - name: keycloak-package-volume - - configMap: - name: keycloak-realm-templates-7kgh2hc6b2 - name: keycloak-airm-realm-template-volume - - emptyDir: {} - name: keycloak-realm-volume - - configMap: - name: keycloak-realm-templates-k8s - name: keycloak-k8s-realm-template-volume + - name: keycloak-realm-template-volume + configMap: + name: keycloak-realm-templates + - name: keycloak-realm-volume + emptyDir: {} extraVolumeMounts: - - mountPath: /opt/keycloak/providers - name: keycloak-package-volume - - mountPath: /opt/keycloak/data/import + - mountPath: /opt/bitnami/keycloak/data/import name: keycloak-realm-volume postgresql: From 9989e5433ccb2b7a52c646ccf812d9ebcb3f83cb Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Wed, 7 Jan 2026 17:00:54 +0000 Subject: [PATCH 2/3] feat: random initial keycloak passwords --- scripts/bootstrap.md | 10 +++++++++ .../templates/cf-init-openbao-cm.yaml | 5 +++-- .../keycloak-airm-realm-secrets.yaml | 4 ++++ .../templates/keycloak-credentials.yaml | 21 +++++++++++++++++++ .../keycloak-realm-templates-cm.yaml | 7 ++----- sources/keycloak/values_cf.yaml | 6 ++++++ 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/scripts/bootstrap.md b/scripts/bootstrap.md index 2cfe36b4..d63b0aa4 100644 --- a/scripts/bootstrap.md +++ b/scripts/bootstrap.md @@ -90,6 +90,16 @@ Creates three namespaces for core components: kubectl -n cf-openbao get secret openbao-keys -o jsonpath='{.data.root_token}' | base64 -d ``` +4. **Devuser:** + ```bash + kubectl -n airm get secret airm-devuser-credentials -o jsonpath="{.data.KEYCLOAK_INITIAL_DEVUSER_PASSWORD}"| base64 -d + ``` + +5. **Keycloak admin:** + ```bash + kubectl -n keycloak get secret keycloak-credentials -o jsonpath="{.data.KEYCLOAK_INITIAL_ADMIN_PASSWORD}"| base64 -d + ``` + ## Development For development purposes there is a way to sync all apps directly from cluster-forge GitHub repo bypassing gitea. Here is the possible development flow: diff --git a/scripts/init-openbao-job/templates/cf-init-openbao-cm.yaml b/scripts/init-openbao-job/templates/cf-init-openbao-cm.yaml index 0be51d8a..20060a4c 100644 --- a/scripts/init-openbao-job/templates/cf-init-openbao-cm.yaml +++ b/scripts/init-openbao-job/templates/cf-init-openbao-cm.yaml @@ -139,8 +139,9 @@ data: bao kv put secrets/airm-keycloak-admin-client-id value="admin-client-id-value" bao kv put secrets/airm-keycloak-admin-client-secret value="$(bao write -field=random_bytes sys/tools/random bytes=16 format=hex)"; - - bao kv put secrets/keycloak-initial-admin-password value=admin; + + bao kv put secrets/keycloak-initial-admin-password value="$(bao write -field=random_bytes sys/tools/random bytes=16 format=hex)"; + bao kv put secrets/keycloak-initial-devuser-password value="$(bao write -field=random_bytes sys/tools/random bytes=16 format=hex)"; bao kv put secrets/keycloak-cnpg-user-username value=keycloak; bao kv put secrets/keycloak-cnpg-user-password value=keycloak; bao kv put secrets/keycloak-cnpg-superuser-username value="$(bao write -field=random_bytes sys/tools/random bytes=16 format=hex)"; diff --git a/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml b/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml index b9ddc2c3..7bed7ccb 100644 --- a/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml +++ b/sources/keycloak-config/templates/keycloak-airm-realm-secrets.yaml @@ -40,6 +40,10 @@ spec: key: argocd-client-secret property: value secretKey: ARGOCD_CLIENT_SECRET + - remoteRef: + key: keycloak-initial-devuser-password + property: value + secretKey: KEYCLOAK_INITIAL_DEVUSER_PASSWORD refreshInterval: 1h secretStoreRef: kind: ClusterSecretStore diff --git a/sources/keycloak-config/templates/keycloak-credentials.yaml b/sources/keycloak-config/templates/keycloak-credentials.yaml index 46dd6ebf..8c72a331 100644 --- a/sources/keycloak-config/templates/keycloak-credentials.yaml +++ b/sources/keycloak-config/templates/keycloak-credentials.yaml @@ -19,3 +19,24 @@ spec: target: creationPolicy: Owner name: keycloak-credentials +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: airm-devuser-credentials + namespace: keycloak + annotations: + argocd.argoproj.io/hook: PreSync +spec: + data: + - remoteRef: + key: keycloak-initial-devuser-password + property: value + secretKey: KEYCLOAK_INITIAL_DEVUSER_PASSWORD + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: openbao-secret-store + target: + creationPolicy: Owner + name: airm-devuser-credentials diff --git a/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml b/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml index d9c65c90..15a269fc 100644 --- a/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml +++ b/sources/keycloak-config/templates/keycloak-realm-templates-cm.yaml @@ -549,12 +549,9 @@ data: "totp": false, "credentials": [ { - "id": "596f57d5-41d0-4dd8-bd6f-bb16db235be2", "type": "password", - "userLabel": "My password", - "createdDate": 1746628471958, - "secretData": "{\"value\":\"15oUl8X/o/maH7BWBI4mGDj7WFXPXSc+BbPsIBTcqHE=\",\"salt\":\"RDnI5bojai0rUPa5j7T1rQ==\",\"additionalParameters\":{}}", - "credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + "value": "__DEVUSER_INITIAL_PASSWORD__", + "temporary": false } ], "disableableCredentialTypes": [], diff --git a/sources/keycloak/values_cf.yaml b/sources/keycloak/values_cf.yaml index a5a3b172..915fe748 100644 --- a/sources/keycloak/values_cf.yaml +++ b/sources/keycloak/values_cf.yaml @@ -70,6 +70,7 @@ initContainers: sed -i -e "s/__MINIO_CLIENT_SECRET__/$MINIO_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json sed -i -e "s/__GITEA_CLIENT_SECRET__/$GITEA_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json sed -i -e "s/__ARGOCD_CLIENT_SECRET__/$ARGOCD_CLIENT_SECRET/g" /opt/bitnami/keycloak/data/import/airm-realm.json + sed -i -e "s/__DEVUSER_INITIAL_PASSWORD__/$DEVUSER_INITIAL_PASSWORD/g" /opt/bitnami/keycloak/data/import/airm-realm.json else echo "Warning: /opt/realm_templates/airm-realm.json not found, skipping airm realm setup" fi @@ -120,6 +121,11 @@ initContainers: secretKeyRef: key: ARGOCD_CLIENT_SECRET name: airm-realm-credentials + - name: DEVUSER_INITIAL_PASSWORD + valueFrom: + secretKeyRef: + key: KEYCLOAK_INITIAL_DEVUSER_PASSWORD + name: airm-realm-credentials extraVolumes: - name: keycloak-script-volume From 77d3c40eb1d4d6904f6c46838f53db7d284b34fc Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Wed, 7 Jan 2026 17:21:04 +0000 Subject: [PATCH 3/3] fix: support for random initial devuser password --- .../0.3.1/charts/airm-api/files/configure.sh | 3 ++- .../templates/airm-configure-job.yaml | 5 +++++ .../charts/airm-api/templates/airm-es.yaml | 21 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/sources/airm/0.3.1/charts/airm-api/files/configure.sh b/sources/airm/0.3.1/charts/airm-api/files/configure.sh index a26c4425..45670fc6 100644 --- a/sources/airm/0.3.1/charts/airm-api/files/configure.sh +++ b/sources/airm/0.3.1/charts/airm-api/files/configure.sh @@ -53,9 +53,10 @@ check_env_variable "KEYCLOAK_CLIENT_SECRET" check_env_variable "KEYCLOAK_CLIENT_ID" check_env_variable "KEYCLOAK_ADMIN_CLIENT_ID" check_env_variable "KEYCLOAK_ADMIN_CLIENT_SECRET" +check_env_variable "INITIAL_USER_PASSWORD" function refresh_token() { - TOKEN=$(curl -s -d "client_id=${KEYCLOAK_CLIENT_ID}" -d "username=${USER_EMAIL}" -d 'password=password' -d 'grant_type=password' -d "client_secret=${KEYCLOAK_CLIENT_SECRET}" "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token" | jq -r '.access_token') + TOKEN=$(curl -s -d "client_id=${KEYCLOAK_CLIENT_ID}" -d "username=${USER_EMAIL}" -d "password=${INITIAL_USER_PASSWORD}" -d 'grant_type=password' -d "client_secret=${KEYCLOAK_CLIENT_SECRET}" "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token" | jq -r '.access_token') if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then echo "ERROR: Failed to obtain access token from Keycloak." exit 1 diff --git a/sources/airm/0.3.1/charts/airm-api/templates/airm-configure-job.yaml b/sources/airm/0.3.1/charts/airm-api/templates/airm-configure-job.yaml index 2cd24c46..0d85ded6 100644 --- a/sources/airm/0.3.1/charts/airm-api/templates/airm-configure-job.yaml +++ b/sources/airm/0.3.1/charts/airm-api/templates/airm-configure-job.yaml @@ -137,6 +137,11 @@ spec: secretKeyRef: key: client-secret name: "{{ .Release.Name }}-keycloak-admin-client" + - name: INITIAL_USER_PASSWORD + valueFrom: + secretKeyRef: + key: KEYCLOAK_INITIAL_DEVUSER_PASSWORD + name: "{{ .Release.Name }}-devuser-credentials" - name: AIRM_API_URL value: "http://{{ .Release.Name }}-api.{{ .Release.Namespace }}.svc.cluster.local" volumeMounts: diff --git a/sources/airm/0.3.1/charts/airm-api/templates/airm-es.yaml b/sources/airm/0.3.1/charts/airm-api/templates/airm-es.yaml index 80cc1057..88afa95f 100644 --- a/sources/airm/0.3.1/charts/airm-api/templates/airm-es.yaml +++ b/sources/airm/0.3.1/charts/airm-api/templates/airm-es.yaml @@ -192,3 +192,24 @@ spec: remoteRef: key: cluster-auth-admin-token property: value +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: "{{ .Release.Name }}-devuser-credentials" + namespace: "{{ .Release.Namespace }}" + annotations: + helm.sh/hook: pre-install +spec: + data: + - remoteRef: + key: keycloak-initial-devuser-password + property: value + secretKey: KEYCLOAK_INITIAL_DEVUSER_PASSWORD + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: openbao-secret-store + target: + creationPolicy: Owner + name: airm-devuser-credentials