From 57c266af928186f45c8d346ce0f7c8c0baba01b1 Mon Sep 17 00:00:00 2001 From: Isman Firmansyah Date: Wed, 15 Jan 2025 01:58:14 +0700 Subject: [PATCH] feat(cloud-native): secure mounted configuration schema (#10577) * feat(cloud-native): secure mounted configuration schema Signed-off-by: iromli * feat(cloud-native): add support for configuration key file Signed-off-by: iromli * feat(cloud-native): implement obfuscated configuration schema in higher level setup Signed-off-by: iromli * chore(cloud-native): update JANS_SOURCE_VERSION Signed-off-by: iromli * docs(cloud-native): add missing configuration key docs Signed-off-by: iromli * feat(cloud-native): add support for secure configuration schema in janssen-all-in-one Signed-off-by: iromli * chore(cloud-native): cleanup unused template syntax Signed-off-by: iromli * refactor(jans-pycloudlib): revert temporary changes Signed-off-by: iromli * docs(charts): mention about empty configuration key Signed-off-by: iromli * chore(cloud-native): update JANS_SOURCE_VERSION * docs(kubernetes): fix example of using custom configuration schema Signed-off-by: iromli * chore(charts): specify allowed cnConfiguratorKey size Signed-off-by: iromli * docs(kubernetes): add how-to section for encrypted configuration schema Signed-off-by: iromli * docs: fix typos Signed-off-by: Amro Misbah * docs: fix wording in values.yaml Signed-off-by: Amro Misbah * docs: add the key used in custom schema Signed-off-by: Amro Misbah * chore(cloud-native): update JANS_SOURCE_VERSION Signed-off-by: iromli --------- Signed-off-by: iromli Signed-off-by: Amro Misbah Signed-off-by: Isman Firmansyah Co-authored-by: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com> Co-authored-by: Amro Misbah --- charts/janssen-all-in-one/README.md | 2 + .../janssen-all-in-one/templates/_helpers.tpl | 72 +++++++++++++- .../janssen-all-in-one/templates/secret.yaml | 70 ++++++-------- charts/janssen-all-in-one/values.yaml | 4 + charts/janssen/README.md | 4 +- .../charts/config/templates/_helpers.tpl | 59 +++++++++++- .../charts/config/templates/secrets.yaml | 72 ++++++-------- charts/janssen/templates/_helpers.tpl | 13 ++- charts/janssen/values.schema.json | 7 +- charts/janssen/values.yaml | 20 ++-- docker-jans-all-in-one/Dockerfile | 2 +- docker-jans-casa/Dockerfile | 2 +- docker-jans-certmanager/Dockerfile | 2 +- docker-jans-config-api/Dockerfile | 2 +- docker-jans-configurator/Dockerfile | 2 +- docker-jans-configurator/scripts/bootstrap.py | 21 ++++- docker-jans-fido2/Dockerfile | 2 +- docker-jans-kc-scheduler/Dockerfile | 2 +- docker-jans-keycloak-link/Dockerfile | 2 +- docker-jans-link/Dockerfile | 2 +- docker-jans-monolith/Dockerfile | 2 +- docker-jans-saml/Dockerfile | 2 +- docker-jans-scim/Dockerfile | 2 +- .../kubernetes/config-secret-keys.md | 93 +++++++++++++++---- 24 files changed, 329 insertions(+), 132 deletions(-) diff --git a/charts/janssen-all-in-one/README.md b/charts/janssen-all-in-one/README.md index b02f1bcf0ef..e331b0a1b71 100644 --- a/charts/janssen-all-in-one/README.md +++ b/charts/janssen-all-in-one/README.md @@ -134,6 +134,8 @@ Kubernetes: `>=v1.22.0-0` | cnConfiguratorCustomSchema | object | `{"secretName":""}` | Use custom configuration schema in existing secrets. Note, the secrets has to contain the key configuration.json or any basename as specified in cnConfiguratorConfigurationFile. | | cnConfiguratorCustomSchema.secretName | string | `""` | The name of the secrets used for storing custom configuration schema. | | cnConfiguratorDumpFile | string | `"/etc/jans/conf/configuration.out.json"` | Path to dumped configuration schema file | +| cnConfiguratorKey | string | `""` | Key to encrypt/decrypt configuration schema file using AES-256 CBC mode. Set the value to empty string to disable encryption/decryption, or 32 alphanumeric characters to enable it. | +| cnConfiguratorKeyFile | string | `"/etc/jans/conf/configuration.key"` | Path to file contains key to encrypt/decrypt configuration schema file. | | cnDocumentStoreType | string | `"DB"` | Document store type to use for shibboleth files DB. | | cnGoogleApplicationCredentials | string | `"/etc/jans/conf/google-credentials.json"` | Base64 encoded service account. The sa must have roles/secretmanager.admin to use Google secrets. Leave as this is a sensible default. | | cnPersistenceType | string | `"sql"` | Persistence backend to run Janssen with hybrid|sql. | diff --git a/charts/janssen-all-in-one/templates/_helpers.tpl b/charts/janssen-all-in-one/templates/_helpers.tpl index d30466ae7f9..135d37cbb03 100644 --- a/charts/janssen-all-in-one/templates/_helpers.tpl +++ b/charts/janssen-all-in-one/templates/_helpers.tpl @@ -73,10 +73,10 @@ Create optional scopes list {{- define "janssen-all-in-one.optionalScopes"}} {{ $newList := list }} {{- if eq .Values.configmap.cnCacheType "REDIS" }} -{{ $newList = append $newList ("redis" | quote ) }} +{{ $newList = append $newList "redis" }} {{- end}} {{ if eq .Values.cnPersistenceType "sql" }} -{{ $newList = append $newList ("sql" | quote) }} +{{ $newList = append $newList "sql" }} {{- end }} {{ toJson $newList }} {{- end }} @@ -178,12 +178,78 @@ Create configuration schema-related objects. {{- define "janssen-all-in-one.config.schema" -}} {{- $commonName := (printf "%s-configuration-file" .Release.Name) -}} {{- $secretName := .Values.cnConfiguratorCustomSchema.secretName | default $commonName -}} +{{- $keyName := (printf "%s-configuration-key-file" .Release.Name) -}} volumes: - name: {{ $commonName }} secret: secretName: {{ $secretName }} +{{- if .Values.cnConfiguratorKey }} + - name: {{ $keyName }} + secret: + secretName: {{ $keyName }} +{{- end }} volumeMounts: - name: {{ $commonName }} mountPath: {{ .Values.cnConfiguratorConfigurationFile }} subPath: {{ .Values.cnConfiguratorConfigurationFile | base }} -{{- end -}} +{{- if .Values.cnConfiguratorKey }} + - name: {{ $keyName }} + mountPath: {{ .Values.cnConfiguratorKeyFile }} + subPath: {{ .Values.cnConfiguratorKeyFile | base }} +{{- end }} +{{- end }} + +{{/* +Obfuscate configuration schema (only if configuration key is available) +*/}} +{{- define "janssen-all-in-one.config.prepareSchema" }} + +{{- $configmapSchema := dict }} +{{- $_ := set $configmapSchema "hostname" .Values.fqdn }} +{{- $_ := set $configmapSchema "country_code" .Values.countryCode }} +{{- $_ := set $configmapSchema "state" .Values.state }} +{{- $_ := set $configmapSchema "city" .Values.city }} +{{- $_ := set $configmapSchema "admin_email" .Values.email }} +{{- $_ := set $configmapSchema "orgName" .Values.orgName }} +{{- $_ := set $configmapSchema "auth_sig_keys" (index .Values "auth-server" "authSigKeys") }} +{{- $_ := set $configmapSchema "auth_enc_keys" (index .Values "auth-server" "authEncKeys") }} +{{- $_ := set $configmapSchema "optional_scopes" (include "janssen-all-in-one.optionalScopes" . | trim) }} +{{- if .Values.saml.enabled }} +{{- $_ := set $configmapSchema "kc_admin_username" .Values.configmap.kcAdminUsername }} +{{- end }} +{{- $_ := set $configmapSchema "init_keys_exp" (index .Values "auth-server-key-rotation" "initKeysLife") }} + +{{- $secretSchema := dict }} +{{- $_ := set $secretSchema "admin_password" .Values.adminPassword }} +{{- $_ := set $secretSchema "redis_password" .Values.redisPassword }} +{{- if or ( eq .Values.cnPersistenceType "sql" ) ( eq .Values.cnPersistenceType "hybrid" ) }} +{{- $_ := set $secretSchema "sql_password" .Values.configmap.cnSqldbUserPassword }} +{{- end }} +{{- if eq .Values.configSecretAdapter "vault" }} +{{- $_ := set $secretSchema "vault_role_id" .Values.configmap.cnVaultRoleId }} +{{- $_ := set $secretSchema "vault_secret_id" .Values.configmap.cnVaultSecretId }} +{{- end }} +{{- if or (eq .Values.configSecretAdapter "google") (eq .Values.configAdapterName "google") }} +{{- $_ := set $secretSchema "google_credentials" .Values.configmap.cnGoogleSecretManagerServiceAccount }} +{{- end }} +{{- if or (eq .Values.configAdapterName "aws") (eq .Values.configSecretAdapter "aws") }} +{{- $_ := set $secretSchema "aws_credentials" (include "config.aws-shared-credentials" . | b64enc) }} +{{- $_ := set $secretSchema "aws_config" (include "config.aws-config" . | b64enc) }} +{{- $_ := set $secretSchema "aws_replica_regions" (toJson .Values.configmap.cnAwsSecretsReplicaRegions | b64enc) }} +{{- end }} +{{- if .Values.saml.enabled }} +{{- $_ := set $secretSchema "kc_db_password" .Values.configmap.kcDbPassword }} +{{- $_ := set $secretSchema "kc_admin_password" .Values.configmap.kcAdminPassword }} +{{- end }} +{{- $_ := set $secretSchema "encoded_salt" .Values.salt }} + +{{- $schema := dict "_configmap" $configmapSchema "_secret" $secretSchema }} + +{{- if .Values.cnConfiguratorKey }} +{{- printf "%s" (encryptAES .Values.cnConfiguratorKey (toPrettyJson $schema)) }} +{{- else -}} +{{- toPrettyJson $schema }} +{{- end }} + +{{/* end of helpers */}} +{{- end }} diff --git a/charts/janssen-all-in-one/templates/secret.yaml b/charts/janssen-all-in-one/templates/secret.yaml index 9964d04a533..bcc2b62f50f 100644 --- a/charts/janssen-all-in-one/templates/secret.yaml +++ b/charts/janssen-all-in-one/templates/secret.yaml @@ -22,45 +22,33 @@ metadata: type: Opaque stringData: {{ .Values.cnConfiguratorConfigurationFile | base }}: |- - { - "_configmap": { - "hostname": {{ .Values.fqdn | quote }}, - "country_code": {{ .Values.countryCode | quote }}, - "state": {{ .Values.state | quote }}, - "city": {{ .Values.city | quote }}, - "admin_email": {{ .Values.email | quote }}, - "orgName": {{ .Values.orgName | quote }}, - "auth_sig_keys": {{ index .Values "auth-server" "authSigKeys" | quote }}, - "auth_enc_keys": {{ index .Values "auth-server" "authEncKeys" | quote }}, - "optional_scopes": {{ list (include "janssen-all-in-one.optionalScopes" . | fromJsonArray | join ",") | quote }}, - {{- if .Values.saml.enabled }} - "kc_admin_username": {{ .Values.configmap.kcAdminUsername | quote }}, - {{- end }} - "init_keys_exp": {{ index .Values "auth-server-key-rotation" "initKeysLife" }} - }, - "_secret": { - "admin_password": {{ .Values.adminPassword | quote }}, - "redis_password": {{ .Values.redisPassword | quote }}, - {{ if or ( eq .Values.cnPersistenceType "sql" ) ( eq .Values.cnPersistenceType "hybrid" ) }} - "sql_password": {{ .Values.configmap.cnSqldbUserPassword | quote }}, - {{- end }} - {{ if eq .Values.configSecretAdapter "vault" }} - "vault_role_id": {{ .Values.configmap.cnVaultRoleId | quote }}, - "vault_secret_id": {{ .Values.configmap.cnVaultSecretId | quote }}, - {{- end }} - {{ if or (eq .Values.configSecretAdapter "google") (eq .Values.configAdapterName "google") }} - "google_credentials": {{ .Values.configmap.cnGoogleSecretManagerServiceAccount | quote }}, - {{- end }} - {{ if or (eq .Values.configAdapterName "aws") (eq .Values.configSecretAdapter "aws") }} - "aws_credentials": {{ include "janssen-all-in-one.aws-shared-credentials" . | b64enc | quote }}, - "aws_config": {{ include "janssen-all-in-one.aws-config" . | b64enc | quote }}, - "aws_replica_regions": {{ .Values.configmap.cnAwsSecretsReplicaRegions | toJson | b64enc | quote }}, - {{- end }} - {{- if .Values.saml.enabled }} - "kc_db_password": {{ .Values.configmap.kcDbPassword | quote }}, - "kc_admin_password": {{ .Values.configmap.kcAdminPassword | quote }}, - {{- end }} - "encoded_salt": {{ .Values.salt | quote }} - } - } +{{ include "janssen-all-in-one.config.prepareSchema" . | indent 4 }} +{{- end }} + +--- + +{{- if .Values.cnConfiguratorKey -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-configuration-key-file + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-{{ include "janssen-all-in-one.name" . }}-aio +{{ include "janssen-all-in-one.labels" . | indent 4 }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | indent 4 }} +{{- end }} +{{- if or (.Values.additionalAnnotations) (.Values.customAnnotations.secret) }} + annotations: +{{- if .Values.additionalAnnotations }} +{{ toYaml .Values.additionalAnnotations | indent 4 }} +{{- end }} +{{- if .Values.customAnnotations.secret }} +{{ toYaml .Values.customAnnotations.secret | indent 4 }} +{{- end }} +{{- end }} +type: Opaque +data: + {{ .Values.cnConfiguratorKeyFile | base }}: {{ .Values.cnConfiguratorKey | b64enc }} {{- end }} diff --git a/charts/janssen-all-in-one/values.yaml b/charts/janssen-all-in-one/values.yaml index f446a4c50f4..616bd10f675 100644 --- a/charts/janssen-all-in-one/values.yaml +++ b/charts/janssen-all-in-one/values.yaml @@ -573,6 +573,10 @@ cnConfiguratorDumpFile: /etc/jans/conf/configuration.out.json cnConfiguratorCustomSchema: # -- The name of the secrets used for storing custom configuration schema. secretName: "" +# -- Key to encrypt/decrypt configuration schema file using AES-256 CBC mode. Set the value to empty string to disable encryption/decryption, or 32 alphanumeric characters to enable it. +cnConfiguratorKey: "" +# -- Path to file contains key to encrypt/decrypt configuration schema file. +cnConfiguratorKeyFile: /etc/jans/conf/configuration.key # ingress properties istio: diff --git a/charts/janssen/README.md b/charts/janssen/README.md index 56dace93960..4f015ece23e 100644 --- a/charts/janssen/README.md +++ b/charts/janssen/README.md @@ -265,7 +265,7 @@ Kubernetes: `>=v1.22.0-0` | fido2.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | fido2.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | fido2.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| global | object | `{"alb":{"ingress":false},"auth-server":{"appLoggers":{"auditStatsLogLevel":"INFO","auditStatsLogTarget":"FILE","authLogLevel":"INFO","authLogTarget":"STDOUT","enableStdoutLogPrefix":"true","httpLogLevel":"INFO","httpLogTarget":"FILE","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"authEncKeys":"RSA1_5 RSA-OAEP","authServerServiceName":"auth-server","authSigKeys":"RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512","cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"authServerAdditionalAnnotations":{},"authServerEnabled":true,"authServerLabels":{},"authzenAdditionalAnnotations":{},"authzenConfigEnabled":true,"authzenConfigLabels":{},"deviceCodeAdditionalAnnotations":{},"deviceCodeEnabled":true,"deviceCodeLabels":{},"firebaseMessagingAdditionalAnnotations":{},"firebaseMessagingEnabled":true,"firebaseMessagingLabels":{},"lockAdditionalAnnotations":{},"lockConfigAdditionalAnnotations":{},"lockConfigEnabled":false,"lockConfigLabels":{},"lockEnabled":false,"lockLabels":{},"openidAdditionalAnnotations":{},"openidConfigEnabled":true,"openidConfigLabels":{},"u2fAdditionalAnnotations":{},"u2fConfigEnabled":true,"u2fConfigLabels":{},"uma2AdditionalAnnotations":{},"uma2ConfigEnabled":true,"uma2ConfigLabels":{},"webdiscoveryAdditionalAnnotations":{},"webdiscoveryEnabled":true,"webdiscoveryLabels":{},"webfingerAdditionalAnnotations":{},"webfingerEnabled":true,"webfingerLabels":{}},"lockEnabled":false},"auth-server-key-rotation":{"customAnnotations":{"cronjob":{},"secret":{},"service":{}},"enabled":true,"initKeysLife":48},"awsStorageType":"io1","azureStorageAccountType":"Standard_LRS","azureStorageKind":"Managed","casa":{"appLoggers":{"casaLogLevel":"INFO","casaLogTarget":"STDOUT","enableStdoutLogPrefix":"true","timerLogLevel":"INFO","timerLogTarget":"FILE"},"casaServiceName":"casa","cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"casaAdditionalAnnotations":{},"casaEnabled":false,"casaLabels":{}}},"cloud":{"testEnviroment":false},"cnAwsConfigFile":"/etc/jans/conf/aws_config_file","cnAwsSecretsReplicaRegionsFile":"/etc/jans/conf/aws_secrets_replica_regions","cnAwsSharedCredentialsFile":"/etc/jans/conf/aws_shared_credential_file","cnConfiguratorConfigurationFile":"/etc/jans/conf/configuration.json","cnConfiguratorCustomSchema":{"secretName":""},"cnConfiguratorDumpFile":"/etc/jans/conf/configuration.out.json","cnDocumentStoreType":"DB","cnGoogleApplicationCredentials":"/etc/jans/conf/google-credentials.json","cnPersistenceType":"sql","cnPrometheusPort":"","cnSqlPasswordFile":"/etc/jans/conf/sql_password","config":{"customAnnotations":{"clusterRoleBinding":{},"configMap":{},"job":{},"role":{},"roleBinding":{},"secret":{},"service":{},"serviceAccount":{}},"enabled":true},"config-api":{"appLoggers":{"configApiLogLevel":"INFO","configApiLogTarget":"STDOUT","enableStdoutLogPrefix":"true","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","configApiServerServiceName":"config-api","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"configApiAdditionalAnnotations":{},"configApiEnabled":true,"configApiLabels":{}},"plugins":"fido2,scim,user-mgt"},"configAdapterName":"kubernetes","configSecretAdapter":"kubernetes","fido2":{"appLoggers":{"enableStdoutLogPrefix":"true","fido2LogLevel":"INFO","fido2LogTarget":"STDOUT","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"fido2ServiceName":"fido2","ingress":{"fido2AdditionalAnnotations":{},"fido2ConfigAdditionalAnnotations":{},"fido2ConfigEnabled":false,"fido2ConfigLabels":{},"fido2Enabled":false,"fido2Labels":{},"fido2WebauthnAdditionalAnnotations":{},"fido2WebauthnEnabled":false,"fido2WebauthnLabels":{}}},"fqdn":"demoexample.jans.io","gcePdStorageType":"pd-standard","isFqdnRegistered":false,"istio":{"additionalAnnotations":{},"additionalLabels":{},"enabled":false,"gateways":[],"ingress":false,"namespace":"istio-system"},"jobTtlSecondsAfterFinished":300,"kc-scheduler":{"enabled":false},"lbIp":"22.22.22.22","link":{"appLoggers":{"enableStdoutLogPrefix":"true","linkLogLevel":"INFO","linkLogTarget":"STDOUT","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"service":{},"virtualService":{}},"enabled":false,"ingress":{"linkAdditionalAnnotations":{},"linkEnabled":true,"linkLabels":{}},"linkServiceName":"link"},"nginx-ingress":{"enabled":true},"persistence":{"customAnnotations":{"job":{},"secret":{},"service":{}},"enabled":true},"saml":{"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":false,"ingress":{"samlAdditionalAnnotations":{},"samlEnabled":false,"samlLabels":{}},"samlServiceName":"saml"},"scim":{"appLoggers":{"enableStdoutLogPrefix":"true","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scimLogLevel":"INFO","scimLogTarget":"STDOUT","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"scimAdditionalAnnotations":{},"scimConfigAdditionalAnnotations":{},"scimConfigEnabled":false,"scimConfigLabels":{},"scimEnabled":false,"scimLabels":{}},"scimServiceName":"scim"},"serviceAccountName":"default","storageClass":{"allowVolumeExpansion":true,"allowedTopologies":[],"mountOptions":["debug"],"parameters":{},"provisioner":"microk8s.io/hostpath","reclaimPolicy":"Retain","volumeBindingMode":"WaitForFirstConsumer"},"usrEnvs":{"normal":{},"secret":{}}}` | Parameters used globally across all services helm charts. | +| global | object | `{"alb":{"ingress":false},"auth-server":{"appLoggers":{"auditStatsLogLevel":"INFO","auditStatsLogTarget":"FILE","authLogLevel":"INFO","authLogTarget":"STDOUT","enableStdoutLogPrefix":"true","httpLogLevel":"INFO","httpLogTarget":"FILE","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"authEncKeys":"RSA1_5 RSA-OAEP","authServerServiceName":"auth-server","authSigKeys":"RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512","cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"authServerAdditionalAnnotations":{},"authServerEnabled":true,"authServerLabels":{},"authzenAdditionalAnnotations":{},"authzenConfigEnabled":true,"authzenConfigLabels":{},"deviceCodeAdditionalAnnotations":{},"deviceCodeEnabled":true,"deviceCodeLabels":{},"firebaseMessagingAdditionalAnnotations":{},"firebaseMessagingEnabled":true,"firebaseMessagingLabels":{},"lockAdditionalAnnotations":{},"lockConfigAdditionalAnnotations":{},"lockConfigEnabled":false,"lockConfigLabels":{},"lockEnabled":false,"lockLabels":{},"openidAdditionalAnnotations":{},"openidConfigEnabled":true,"openidConfigLabels":{},"u2fAdditionalAnnotations":{},"u2fConfigEnabled":true,"u2fConfigLabels":{},"uma2AdditionalAnnotations":{},"uma2ConfigEnabled":true,"uma2ConfigLabels":{},"webdiscoveryAdditionalAnnotations":{},"webdiscoveryEnabled":true,"webdiscoveryLabels":{},"webfingerAdditionalAnnotations":{},"webfingerEnabled":true,"webfingerLabels":{}},"lockEnabled":false},"auth-server-key-rotation":{"customAnnotations":{"cronjob":{},"secret":{},"service":{}},"enabled":true,"initKeysLife":48},"awsStorageType":"io1","azureStorageAccountType":"Standard_LRS","azureStorageKind":"Managed","casa":{"appLoggers":{"casaLogLevel":"INFO","casaLogTarget":"STDOUT","enableStdoutLogPrefix":"true","timerLogLevel":"INFO","timerLogTarget":"FILE"},"casaServiceName":"casa","cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"casaAdditionalAnnotations":{},"casaEnabled":false,"casaLabels":{}}},"cloud":{"testEnviroment":false},"cnAwsConfigFile":"/etc/jans/conf/aws_config_file","cnAwsSecretsReplicaRegionsFile":"/etc/jans/conf/aws_secrets_replica_regions","cnAwsSharedCredentialsFile":"/etc/jans/conf/aws_shared_credential_file","cnConfiguratorConfigurationFile":"/etc/jans/conf/configuration.json","cnConfiguratorCustomSchema":{"secretName":""},"cnConfiguratorDumpFile":"/etc/jans/conf/configuration.out.json","cnConfiguratorKey":"","cnConfiguratorKeyFile":"/etc/jans/conf/configuration.key","cnDocumentStoreType":"DB","cnGoogleApplicationCredentials":"/etc/jans/conf/google-credentials.json","cnPersistenceType":"sql","cnPrometheusPort":"","cnSqlPasswordFile":"/etc/jans/conf/sql_password","config":{"customAnnotations":{"clusterRoleBinding":{},"configMap":{},"job":{},"role":{},"roleBinding":{},"secret":{},"service":{},"serviceAccount":{}},"enabled":true},"config-api":{"appLoggers":{"configApiLogLevel":"INFO","configApiLogTarget":"STDOUT","enableStdoutLogPrefix":"true","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","configApiServerServiceName":"config-api","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"configApiAdditionalAnnotations":{},"configApiEnabled":true,"configApiLabels":{}},"plugins":"fido2,scim,user-mgt"},"configAdapterName":"kubernetes","configSecretAdapter":"kubernetes","fido2":{"appLoggers":{"enableStdoutLogPrefix":"true","fido2LogLevel":"INFO","fido2LogTarget":"STDOUT","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"fido2ServiceName":"fido2","ingress":{"fido2AdditionalAnnotations":{},"fido2ConfigAdditionalAnnotations":{},"fido2ConfigEnabled":false,"fido2ConfigLabels":{},"fido2Enabled":false,"fido2Labels":{},"fido2WebauthnAdditionalAnnotations":{},"fido2WebauthnEnabled":false,"fido2WebauthnLabels":{}}},"fqdn":"demoexample.jans.io","gcePdStorageType":"pd-standard","isFqdnRegistered":false,"istio":{"additionalAnnotations":{},"additionalLabels":{},"enabled":false,"gateways":[],"ingress":false,"namespace":"istio-system"},"jobTtlSecondsAfterFinished":300,"kc-scheduler":{"enabled":false},"lbIp":"22.22.22.22","link":{"appLoggers":{"enableStdoutLogPrefix":"true","linkLogLevel":"INFO","linkLogTarget":"STDOUT","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"service":{},"virtualService":{}},"enabled":false,"ingress":{"linkAdditionalAnnotations":{},"linkEnabled":true,"linkLabels":{}},"linkServiceName":"link"},"nginx-ingress":{"enabled":true},"persistence":{"customAnnotations":{"job":{},"secret":{},"service":{}},"enabled":true},"saml":{"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":false,"ingress":{"samlAdditionalAnnotations":{},"samlEnabled":false,"samlLabels":{}},"samlServiceName":"saml"},"scim":{"appLoggers":{"enableStdoutLogPrefix":"true","persistenceDurationLogLevel":"INFO","persistenceDurationLogTarget":"FILE","persistenceLogLevel":"INFO","persistenceLogTarget":"FILE","scimLogLevel":"INFO","scimLogTarget":"STDOUT","scriptLogLevel":"INFO","scriptLogTarget":"FILE"},"cnCustomJavaOptions":"","customAnnotations":{"deployment":{},"destinationRule":{},"horizontalPodAutoscaler":{},"pod":{},"podDisruptionBudget":{},"secret":{},"service":{},"virtualService":{}},"enabled":true,"ingress":{"scimAdditionalAnnotations":{},"scimConfigAdditionalAnnotations":{},"scimConfigEnabled":false,"scimConfigLabels":{},"scimEnabled":false,"scimLabels":{}},"scimServiceName":"scim"},"serviceAccountName":"default","storageClass":{"allowVolumeExpansion":true,"allowedTopologies":[],"mountOptions":["debug"],"parameters":{},"provisioner":"microk8s.io/hostpath","reclaimPolicy":"Retain","volumeBindingMode":"WaitForFirstConsumer"},"usrEnvs":{"normal":{},"secret":{}}}` | Parameters used globally across all services helm charts. | | global.alb.ingress | bool | `false` | Activates ALB ingress | | global.auth-server-key-rotation.enabled | bool | `true` | Boolean flag to enable/disable the auth-server-key rotation cronjob chart. | | global.auth-server-key-rotation.initKeysLife | int | `48` | The initial auth server key rotation keys life in hours | @@ -344,6 +344,8 @@ Kubernetes: `>=v1.22.0-0` | global.cnConfiguratorCustomSchema | object | `{"secretName":""}` | Use custom configuration schema in existing secrets. Note, the secrets has to contain the key configuration.json or any basename as specified in cnConfiguratorConfigurationFile. | | global.cnConfiguratorCustomSchema.secretName | string | `""` | The name of the secrets used for storing custom configuration schema. | | global.cnConfiguratorDumpFile | string | `"/etc/jans/conf/configuration.out.json"` | Path to dumped configuration schema file | +| global.cnConfiguratorKey | string | `""` | Key to encrypt/decrypt configuration schema file using AES-256 CBC mode. Set the value to empty string to disable encryption/decryption, or 32 alphanumeric characters to enable it. | +| global.cnConfiguratorKeyFile | string | `"/etc/jans/conf/configuration.key"` | Path to file contains key to encrypt/decrypt configuration schema file. | | global.cnDocumentStoreType | string | `"DB"` | Document store type to use for shibboleth files DB. | | global.cnGoogleApplicationCredentials | string | `"/etc/jans/conf/google-credentials.json"` | Base64 encoded service account. The sa must have roles/secretmanager.admin to use Google secrets. Leave as this is a sensible default. | | global.cnPersistenceType | string | `"sql"` | Persistence backend to run Janssen with hybrid|sql | diff --git a/charts/janssen/charts/config/templates/_helpers.tpl b/charts/janssen/charts/config/templates/_helpers.tpl index c10074117bf..e03aae53613 100644 --- a/charts/janssen/charts/config/templates/_helpers.tpl +++ b/charts/janssen/charts/config/templates/_helpers.tpl @@ -73,10 +73,10 @@ Create optional scopes list {{- define "config.optionalScopes"}} {{ $newList := list }} {{- if eq .Values.configmap.cnCacheType "REDIS" }} -{{ $newList = append $newList ("redis" | quote ) }} +{{ $newList = append $newList "redis" }} {{- end}} {{ if eq .Values.global.cnPersistenceType "sql" }} -{{ $newList = append $newList ("sql" | quote) }} +{{ $newList = append $newList "sql" }} {{- end }} {{ toJson $newList }} {{- end }} @@ -105,3 +105,58 @@ Create AWS config. {{- end }} {{- printf "[%s]\nregion = %s\n" $profile .Values.configmap.cnAwsDefaultRegion }} {{- end }} + +{{/* +Obfuscate configuration schema (only if configuration key is available) +*/}} +{{- define "config.prepareSchema" }} + +{{- $configmapSchema := dict }} +{{- $_ := set $configmapSchema "hostname" .Values.global.fqdn }} +{{- $_ := set $configmapSchema "country_code" .Values.countryCode }} +{{- $_ := set $configmapSchema "state" .Values.state }} +{{- $_ := set $configmapSchema "city" .Values.city }} +{{- $_ := set $configmapSchema "admin_email" .Values.email }} +{{- $_ := set $configmapSchema "orgName" .Values.orgName }} +{{- $_ := set $configmapSchema "auth_sig_keys" (index .Values "global" "auth-server" "authSigKeys") }} +{{- $_ := set $configmapSchema "auth_enc_keys" (index .Values "global" "auth-server" "authEncKeys") }} +{{- $_ := set $configmapSchema "optional_scopes" (include "config.optionalScopes" . | trim) }} +{{- if .Values.global.saml.enabled }} +{{- $_ := set $configmapSchema "kc_admin_username" .Values.configmap.kcAdminUsername }} +{{- end }} +{{- $_ := set $configmapSchema "init_keys_exp" (index .Values "global" "auth-server-key-rotation" "initKeysLife") }} + +{{- $secretSchema := dict }} +{{- $_ := set $secretSchema "admin_password" .Values.adminPassword }} +{{- $_ := set $secretSchema "redis_password" .Values.redisPassword }} +{{- if or ( eq .Values.global.cnPersistenceType "sql" ) ( eq .Values.global.cnPersistenceType "hybrid" ) }} +{{- $_ := set $secretSchema "sql_password" .Values.configmap.cnSqldbUserPassword }} +{{- end }} +{{- if eq .Values.global.configSecretAdapter "vault" }} +{{- $_ := set $secretSchema "vault_role_id" .Values.configmap.cnVaultRoleId }} +{{- $_ := set $secretSchema "vault_secret_id" .Values.configmap.cnVaultSecretId }} +{{- end }} +{{- if or (eq .Values.global.configSecretAdapter "google") (eq .Values.global.configAdapterName "google") }} +{{- $_ := set $secretSchema "google_credentials" .Values.configmap.cnGoogleSecretManagerServiceAccount }} +{{- end }} +{{- if or (eq .Values.global.configAdapterName "aws") (eq .Values.global.configSecretAdapter "aws") }} +{{- $_ := set $secretSchema "aws_credentials" (include "config.aws-shared-credentials" . | b64enc) }} +{{- $_ := set $secretSchema "aws_config" (include "config.aws-config" . | b64enc) }} +{{- $_ := set $secretSchema "aws_replica_regions" (toJson .Values.configmap.cnAwsSecretsReplicaRegions | b64enc) }} +{{- end }} +{{- if .Values.global.saml.enabled }} +{{- $_ := set $secretSchema "kc_db_password" .Values.configmap.kcDbPassword }} +{{- $_ := set $secretSchema "kc_admin_password" .Values.configmap.kcAdminPassword }} +{{- end }} +{{- $_ := set $secretSchema "encoded_salt" .Values.salt }} + +{{- $schema := dict "_configmap" $configmapSchema "_secret" $secretSchema }} + +{{- if .Values.global.cnConfiguratorKey }} +{{- printf "%s" (encryptAES .Values.global.cnConfiguratorKey (toPrettyJson $schema)) }} +{{- else -}} +{{- toPrettyJson $schema }} +{{- end }} + +{{/* end of helpers */}} +{{- end }} diff --git a/charts/janssen/charts/config/templates/secrets.yaml b/charts/janssen/charts/config/templates/secrets.yaml index 3bc6dfee66d..dfca599dae0 100644 --- a/charts/janssen/charts/config/templates/secrets.yaml +++ b/charts/janssen/charts/config/templates/secrets.yaml @@ -22,45 +22,33 @@ metadata: type: Opaque stringData: {{ .Values.global.cnConfiguratorConfigurationFile | base }}: |- - { - "_configmap": { - "hostname": {{ .Values.global.fqdn | quote }}, - "country_code": {{ .Values.countryCode | quote }}, - "state": {{ .Values.state | quote }}, - "city": {{ .Values.city | quote }}, - "admin_email": {{ .Values.email | quote }}, - "orgName": {{ .Values.orgName | quote }}, - "auth_sig_keys": {{ index .Values "global" "auth-server" "authSigKeys" | quote }}, - "auth_enc_keys": {{ index .Values "global" "auth-server" "authEncKeys" | quote }}, - "optional_scopes": {{ list (include "config.optionalScopes" . | fromJsonArray | join ",") | quote }}, - {{- if .Values.global.saml.enabled }} - "kc_admin_username": {{ .Values.configmap.kcAdminUsername | quote }}, - {{- end }} - "init_keys_exp": {{ index .Values "global" "auth-server-key-rotation" "initKeysLife" }} - }, - "_secret": { - "admin_password": {{ .Values.adminPassword | quote }}, - "redis_password": {{ .Values.redisPassword | quote }}, - {{ if or ( eq .Values.global.cnPersistenceType "sql" ) ( eq .Values.global.cnPersistenceType "hybrid" ) }} - "sql_password": {{ .Values.configmap.cnSqldbUserPassword | quote }}, - {{- end }} - {{ if eq .Values.global.configSecretAdapter "vault" }} - "vault_role_id": {{ .Values.configmap.cnVaultRoleId | quote }}, - "vault_secret_id": {{ .Values.configmap.cnVaultSecretId | quote }}, - {{- end }} - {{ if or (eq .Values.global.configSecretAdapter "google") (eq .Values.global.configAdapterName "google") }} - "google_credentials": {{ .Values.configmap.cnGoogleSecretManagerServiceAccount | quote }}, - {{- end }} - {{ if or (eq .Values.global.configAdapterName "aws") (eq .Values.global.configSecretAdapter "aws") }} - "aws_credentials": {{ include "config.aws-shared-credentials" . | b64enc | quote }}, - "aws_config": {{ include "config.aws-config" . | b64enc | quote }}, - "aws_replica_regions": {{ .Values.configmap.cnAwsSecretsReplicaRegions | toJson | b64enc | quote }}, - {{- end }} - {{- if .Values.global.saml.enabled }} - "kc_db_password": {{ .Values.configmap.kcDbPassword | quote }}, - "kc_admin_password": {{ .Values.configmap.kcAdminPassword | quote }}, - {{- end }} - "encoded_salt": {{ .Values.salt | quote }} - } - } -{{- end -}} +{{ include "config.prepareSchema" . | indent 4 }} +{{- end }} + +--- + +{{- if .Values.global.cnConfiguratorKey -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-configuration-key-file + namespace: {{ .Release.Namespace }} + labels: + APP_NAME: configurator +{{ include "config.labels" . | indent 4 }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | indent 4 }} +{{- end }} +{{- if or (.Values.additionalAnnotations) (.Values.global.config.customAnnotations.secret) }} + annotations: +{{- if .Values.additionalAnnotations }} +{{ toYaml .Values.additionalAnnotations | indent 4 }} +{{- end }} +{{- if .Values.global.config.customAnnotations.secret }} +{{ toYaml .Values.global.config.customAnnotations.secret | indent 4 }} +{{- end }} +{{- end }} +type: Opaque +data: + {{ .Values.global.cnConfiguratorKeyFile | base }}: {{ .Values.global.cnConfiguratorKey | b64enc }} +{{- end }} diff --git a/charts/janssen/templates/_helpers.tpl b/charts/janssen/templates/_helpers.tpl index c284b5db6b0..8e2cc761e0c 100644 --- a/charts/janssen/templates/_helpers.tpl +++ b/charts/janssen/templates/_helpers.tpl @@ -37,12 +37,23 @@ Create configuration schema-related objects. {{- define "cn.config.schema" -}} {{- $commonName := (printf "%s-configuration-file" .Release.Name) -}} {{- $secretName := .Values.global.cnConfiguratorCustomSchema.secretName | default $commonName -}} +{{- $keyName := (printf "%s-configuration-key-file" .Release.Name) -}} volumes: - name: {{ $commonName }} secret: secretName: {{ $secretName }} +{{- if .Values.global.cnConfiguratorKey }} + - name: {{ $keyName }} + secret: + secretName: {{ $keyName }} +{{- end }} volumeMounts: - name: {{ $commonName }} mountPath: {{ .Values.global.cnConfiguratorConfigurationFile }} subPath: {{ .Values.global.cnConfiguratorConfigurationFile | base }} -{{- end -}} +{{- if .Values.global.cnConfiguratorKey }} + - name: {{ $keyName }} + mountPath: {{ .Values.global.cnConfiguratorKeyFile }} + subPath: {{ .Values.global.cnConfiguratorKeyFile | base }} +{{- end }} +{{- end }} diff --git a/charts/janssen/values.schema.json b/charts/janssen/values.schema.json index ea4fc5db7a8..2b571dd738f 100644 --- a/charts/janssen/values.schema.json +++ b/charts/janssen/values.schema.json @@ -1254,6 +1254,11 @@ "description": "The location of file contains password for the SQL user config.configmap.cnSqlDbUser. The file path must end with sql_password.", "type": "string", "pattern": ".*sql_password\\b.*" + }, + "cnConfiguratorKey": { + "description": "Key to encrypt/decrypt configuration schema file using AES-256 CBC mode. Set the value to empty string to disable encryption/decryption, or 32 alphanumeric characters to enable it.", + "type": "string", + "pattern": "^(?:[a-zA-Z0-9]{32})?$" } } }, @@ -2643,4 +2648,4 @@ "else": true } } -} \ No newline at end of file +} diff --git a/charts/janssen/values.yaml b/charts/janssen/values.yaml index 6f6ee66f33c..edecfe88d4f 100644 --- a/charts/janssen/values.yaml +++ b/charts/janssen/values.yaml @@ -249,9 +249,9 @@ config: cnVaultAddr: http://localhost:8200 # -- Verify connection to Vault. cnVaultVerify: false - # -- Path to file contains Vault AppRole role ID. + # -- Path to the file that contains Vault AppRole role ID. cnVaultRoleIdFile: /etc/certs/vault_role_id - # -- Path to file contains Vault AppRole secret ID. + # -- Path to the file that contains Vault AppRole secret ID. cnVaultSecretIdFile: /etc/certs/vault_secret_id # -- Vault namespace used to access the secrets. cnVaultNamespace: "" @@ -259,7 +259,7 @@ config: cnVaultKvPath: secret # -- Base prefix name used to access secrets. cnVaultPrefix: jans - # -- Path to Vault AppRole. + # -- Path to the Vault AppRole. cnVaultAppRolePath: approle # [vault_envs] END # -- Value passed to Java option -XX:MaxRAMPercentage @@ -1190,19 +1190,23 @@ global: samlAdditionalAnnotations: { } # -- passing custom java options to saml. DO NOT PASS JAVA_OPTIONS in envs. cnCustomJavaOptions: "" - # -- Path to SQL password file + # -- Path to the SQL password file cnSqlPasswordFile: /etc/jans/conf/sql_password kc-scheduler: # -- Boolean flag to enable/disable the kc-scheduler cronjob chart. enabled: false - # -- Path to configuration schema file + # -- Path to the configuration schema file cnConfiguratorConfigurationFile: /etc/jans/conf/configuration.json - # -- Path to dumped configuration schema file + # -- Path to the dumped configuration schema file cnConfiguratorDumpFile: /etc/jans/conf/configuration.out.json - # -- Use custom configuration schema in existing secrets. Note, the secrets has to contain the key configuration.json or any basename as specified in cnConfiguratorConfigurationFile. + # -- Use custom configuration schema in existing Kubernetes secret. Note that the secret has to contain the configuration.json key or any basename as specified in cnConfiguratorConfigurationFile. cnConfiguratorCustomSchema: - # -- The name of the secrets used for storing custom configuration schema. + # -- The name of the Kubernetes secret used for storing custom configuration schema. secretName: "" + # -- Key to encrypt/decrypt configuration schema file using AES-256 CBC mode. Set the value to empty string to disable encryption/decryption, or 32 alphanumeric characters to enable it. + cnConfiguratorKey: "" + # -- Path to the file that contains the key to encrypt/decrypt the configuration schema file. + cnConfiguratorKeyFile: /etc/jans/conf/configuration.key # -- Nginx ingress definitions chart nginx-ingress: diff --git a/docker-jans-all-in-one/Dockerfile b/docker-jans-all-in-one/Dockerfile index 6591e7a7424..86dbca99f41 100644 --- a/docker-jans-all-in-one/Dockerfile +++ b/docker-jans-all-in-one/Dockerfile @@ -58,7 +58,7 @@ RUN apk update \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 # note that as we're pulling from a monorepo (with multiple project in it) # we are using partial-clone and sparse-checkout to get the assets diff --git a/docker-jans-casa/Dockerfile b/docker-jans-casa/Dockerfile index 9f4beb98f2d..a143751e3f1 100644 --- a/docker-jans-casa/Dockerfile +++ b/docker-jans-casa/Dockerfile @@ -60,7 +60,7 @@ RUN mkdir -p /usr/share/java \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup # note that as we're pulling from a monorepo (with multiple project in it) diff --git a/docker-jans-certmanager/Dockerfile b/docker-jans-certmanager/Dockerfile index d14f8d2f8b8..aef95351f42 100644 --- a/docker-jans-certmanager/Dockerfile +++ b/docker-jans-certmanager/Dockerfile @@ -25,7 +25,7 @@ RUN wget -q ${CN_SOURCE_URL} -P /app/javalibs/ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 # note that as we're pulling from a monorepo (with multiple project in it) # we are using partial-clone and sparse-checkout to get the assets diff --git a/docker-jans-config-api/Dockerfile b/docker-jans-config-api/Dockerfile index ece0aef0c42..e69aac884ef 100644 --- a/docker-jans-config-api/Dockerfile +++ b/docker-jans-config-api/Dockerfile @@ -70,7 +70,7 @@ RUN mkdir -p ${JETTY_BASE}/jans-config-api/_plugins \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup ARG JANS_CONFIG_API_RESOURCES=jans-config-api/server/src/main/resources diff --git a/docker-jans-configurator/Dockerfile b/docker-jans-configurator/Dockerfile index 3b9acd83810..e59453273f0 100644 --- a/docker-jans-configurator/Dockerfile +++ b/docker-jans-configurator/Dockerfile @@ -27,7 +27,7 @@ RUN mkdir -p /opt/jans/configurator/javalibs \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG GIT_CLONE_DEPTH=100 RUN git clone --depth ${GIT_CLONE_DEPTH} --filter blob:none --no-checkout https://github.com/janssenproject/jans /tmp/jans \ diff --git a/docker-jans-configurator/scripts/bootstrap.py b/docker-jans-configurator/scripts/bootstrap.py index 95b8637276b..5c1f9a7c25c 100644 --- a/docker-jans-configurator/scripts/bootstrap.py +++ b/docker-jans-configurator/scripts/bootstrap.py @@ -476,6 +476,16 @@ def get_dump_file(): return f"{DB_DIR}/configuration.out.json" +def get_configuration_key_file(): + path = os.environ.get("CN_CONFIGURATOR_CONFIGURATION_KEY_FILE", "/etc/jans/conf/configuration.key") + + if os.path.isfile(path): + return path + + # backward-compat + return f"{DB_DIR}/configuration.key" + + # ============ # CLI commands # ============ @@ -501,7 +511,14 @@ def cli(): default=get_dump_file(), show_default=True, ) -def load(configuration_file, dump_file): +@click.option( + "--key-file", + type=click.Path(exists=False), + help="Absolute path to file contains key to decrypt configmaps and secrets (if applicable)", + default=get_configuration_key_file(), + show_default=True, +) +def load(configuration_file, dump_file, key_file): """Loads configmaps and secrets from JSON file (generate if not exist). """ deps = ["config_conn", "secret_conn"] @@ -517,7 +534,7 @@ def load(configuration_file, dump_file): with manager.create_lock("configurator-load"): logger.info(f"Loading configmaps and secrets from {configuration_file}") - params, err, code = load_schema_from_file(configuration_file) + params, err, code = load_schema_from_file(configuration_file, key_file=key_file) if code != 0: logger.error(f"Unable to load configmaps and secrets; reason={err}") raise click.Abort() diff --git a/docker-jans-fido2/Dockerfile b/docker-jans-fido2/Dockerfile index c5aad76a3b6..bab86f7852d 100644 --- a/docker-jans-fido2/Dockerfile +++ b/docker-jans-fido2/Dockerfile @@ -61,7 +61,7 @@ RUN mkdir -p ${JETTY_BASE}/jans-fido2/webapps \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup # note that as we're pulling from a monorepo (with multiple project in it) diff --git a/docker-jans-kc-scheduler/Dockerfile b/docker-jans-kc-scheduler/Dockerfile index 686d061ed6b..79e977cd36c 100644 --- a/docker-jans-kc-scheduler/Dockerfile +++ b/docker-jans-kc-scheduler/Dockerfile @@ -38,7 +38,7 @@ RUN wget -q https://repo1.maven.org/maven2/org/codehaus/janino/janino/3.1.9/jani # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 # note that as we're pulling from a monorepo (with multiple project in it) # we are using partial-clone and sparse-checkout to get the assets diff --git a/docker-jans-keycloak-link/Dockerfile b/docker-jans-keycloak-link/Dockerfile index c8663bbedb4..bd77b7f94b1 100644 --- a/docker-jans-keycloak-link/Dockerfile +++ b/docker-jans-keycloak-link/Dockerfile @@ -61,7 +61,7 @@ RUN mkdir -p ${JETTY_BASE}/jans-keycloak-link/webapps \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup # note that as we're pulling from a monorepo (with multiple project in it) diff --git a/docker-jans-link/Dockerfile b/docker-jans-link/Dockerfile index fb7381450bc..e24f91d95c5 100644 --- a/docker-jans-link/Dockerfile +++ b/docker-jans-link/Dockerfile @@ -61,7 +61,7 @@ RUN mkdir -p ${JETTY_BASE}/jans-link/webapps \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup # note that as we're pulling from a monorepo (with multiple project in it) diff --git a/docker-jans-monolith/Dockerfile b/docker-jans-monolith/Dockerfile index 069e406c4fc..4e0f74da233 100644 --- a/docker-jans-monolith/Dockerfile +++ b/docker-jans-monolith/Dockerfile @@ -42,7 +42,7 @@ EXPOSE 443 8080 1636 # jans-linux-setup # ===================== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 # cleanup RUN rm -rf /tmp/jans diff --git a/docker-jans-saml/Dockerfile b/docker-jans-saml/Dockerfile index 222834ca2bc..38859e83419 100644 --- a/docker-jans-saml/Dockerfile +++ b/docker-jans-saml/Dockerfile @@ -35,7 +35,7 @@ RUN wget -q https://jenkins.jans.io/maven/io/jans/kc-jans-spi/${CN_VERSION}/kc-j # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup # note that as we're pulling from a monorepo (with multiple project in it) diff --git a/docker-jans-scim/Dockerfile b/docker-jans-scim/Dockerfile index 5a3d48c1857..46b2e549272 100644 --- a/docker-jans-scim/Dockerfile +++ b/docker-jans-scim/Dockerfile @@ -60,7 +60,7 @@ RUN mkdir -p ${JETTY_BASE}/jans-scim/webapps \ # Assets sync # =========== -ENV JANS_SOURCE_VERSION=aa1b2edaa8d7e3413bd57a7bd7cc86206086768b +ENV JANS_SOURCE_VERSION=856f9fed1d58a6d41503a0459bbe04f52b0bb8e7 ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup ARG JANS_SCIM_RESOURCE_DIR=jans-scim/server/src/main/resources diff --git a/docs/janssen-server/reference/kubernetes/config-secret-keys.md b/docs/janssen-server/reference/kubernetes/config-secret-keys.md index d6a91c77504..e24d4e504b5 100644 --- a/docs/janssen-server/reference/kubernetes/config-secret-keys.md +++ b/docs/janssen-server/reference/kubernetes/config-secret-keys.md @@ -9,7 +9,10 @@ tags: ## Overview -The `config` job creates a set of configuration (contains `secrets` and `configmaps`) used by all Janssen services. +The `config` job creates a set of configurations (contains `secrets` and `configmaps`) used by all Janssen services. + +!!! Note + We assume Janssen is installed in a namespace called `jans` ## Configmaps @@ -27,7 +30,7 @@ Note that each key in configmaps is based on the schema below: { "city": { "type": "string", - "description": "Locality name (.e.g city)", + "description": "Locality name (e.g. city)", "example": "Austin" }, "country_code": { @@ -502,10 +505,8 @@ Note that each key in secrets is based on the schema below: ## Example decoding secrets ### Opening `base64-decoded` secrets -!!! Note - We assume Jans is installed in a namespace called `jans` -1. Get the `tls-certificate` from backend secret +1. Get the `tls-certificate` from the backend secret ```bash kubectl get secret tls-certificate -n jans -o yaml @@ -525,17 +526,22 @@ Note that each key in secrets is based on the schema below: ## Using Configuration Schema -As mentioned earlier, the `config` job creates configuration. Behind the scene, a Kubernetes' Secret object is created during the deployment to pre-populate `secrets` and `configmaps`. +As mentioned earlier, the `config` job creates a set of configurations. -### Default configuration +This happens by using a Kubernetes secret named `-configuration-file` that gets created during the helm chart installation. + +It contains a JSON schema with the necessary `secrets` and `configmaps` to install Janssen services. + +This secret is then mounted by the `config` job. -By default, the configuration only contains necessary `secrets` and `configmaps` to install Jans services. + +### Default configuration ```yaml apiVersion: v1 kind: Secret metadata: - name: jans-configuration-file + name: janssen-configuration-file namespace: jans labels: APP_NAME: configurator @@ -563,7 +569,7 @@ stringData: } ``` -Note that `_secret` may contain other keys depending on persistence, secrets/configmaps backend, etc. See examples below: +Note that `_secret` may contain other keys depending on the persistence used, the backend of the secrets/configmaps, etc. For example: 1. Secrets/configmaps backend is set to `google`: @@ -594,23 +600,22 @@ Note that `_secret` may contain other keys depending on persistence, secrets/con ### Custom configuration -The default configuration is sufficient for most of the time. If there's a requirement to use custom or reusing existing configuration, user may create a custom Kubernetes object. +The default configuration schema is sufficient for most of the time. However, if there's a requirement to use a custom configuration or reusing an existing configuration, you can create a Kubernetes secret with the custom configuration schema. !!! Warning The custom configuration schema is a BETA feature. -1. Prepare YAML file: +1. Prepare the YAML file containing the custom configuration schema. We will name it `custom-configuration-schema.yaml`: ```yaml - # custom-configuration-schema.yaml apiVersion: v1 kind: Secret metadata: - name: custom-configuration-file + name: custom-configuration-schema namespace: jans type: Opaque stringData: - custom-configuration.json: |- + configuration.json: |- { "_configmap": { "hostname": "demoexample.jans.io", @@ -628,19 +633,69 @@ The default configuration is sufficient for most of the time. If there's a requi } ``` -1. Create Kubernetes secrets: +1. Create the Kubernetes secret: ```bash - kubernetes -n jans create secret generic custom-configuration-schema --from-file=custom-configuration.json + kubectl -n jans apply -f custom-configuration-schema.yaml ``` 1. Specify the secret in `values.yaml`: ```yaml global: - cnConfiguratorConfigurationFile: /etc/jans/conf/custom-configuration.json cnConfiguratorCustomSchema: secretName: custom-configuration-schema ``` -1. Install the Jans charts. +1. Install the Janssen helm chart. + +## Encrypting Configuration Schema + +The encryption uses [Helm-specific](https://helm.sh/docs/chart_template_guide/function_list/#encryptaes) implementation of AES-256 CBC mode. + +### Default configuration + +The [default configuration](#default-configuration) schema can be encrypted by specifying 32 alphanumeric characters to `cnConfiguratorKey` attribute (the default value is an empty string). + +```yaml +global: + cnConfiguratorKey: "VMtVyFha8CfppdDGQSw8zEnfKXRvksAD" +``` + +The following example is what an encrypted default configuration looks like: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: janssen-configuration-file + namespace: jans +stringData: + configuration.json: |- + sxySo+redacted+generated+by+helm/TNpE5PoUR2+JxXiHiLq8X5ibexJcfjAN0fKlqRvU= +``` + +### Custom configuration + +If you are using a [custom configuration](#custom-configuration) schema, you will need to generate the string using [sprig-aes](https://pypi.org/project/sprig-aes/) CLI and paste it into a YAML manifest. + +```yaml +# custom-configuration-schema.yaml +apiVersion: v1 +kind: Secret +metadata: + name: custom-configuration-schema + namespace: jans +type: Opaque +stringData: + configuration.json: |- + sxySo+redacted+generated+by+sprigaes+JxXiHiLq8X5ibexJcfjAN0fKlqRvU= +``` + +Add the `key` used when encrypting using sprig-aes. + +```yaml +global: + cnConfiguratorKey: "VMtVyFha8CfppdDGQSw8zEnfKXRvksAD" +``` +