diff --git a/automation/dbildungs-iam-keycloak/Chart.yaml b/automation/dbildungs-iam-keycloak/Chart.yaml index 35fd584a9..e23fc195a 100644 --- a/automation/dbildungs-iam-keycloak/Chart.yaml +++ b/automation/dbildungs-iam-keycloak/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -appVersion: testbranch-1234-1234 +appVersion: SPSH-1648 description: A Helm Chart for the dbildungs-iam-keycloak name: dbildungs-iam-keycloak type: application -version: 0.0.0-testbranch-1234-1234-20241216-1520 +version: 0.0.0-spsh-1648-20241216-1808 diff --git a/automation/dbildungs-iam-keycloak/dev-realm-spsh.json b/automation/dbildungs-iam-keycloak/dev-realm-spsh.json index dfabf8403..898e2ee19 100644 --- a/automation/dbildungs-iam-keycloak/dev-realm-spsh.json +++ b/automation/dbildungs-iam-keycloak/dev-realm-spsh.json @@ -853,7 +853,7 @@ "oidc.ciba.grant.enabled": "false", "client.secret.creation.time": "1727357679", "backchannel.logout.session.required": "true", - "jwt.credential.certificate": "MIICpzCCAY8CBgGSudz1xDANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxzcHNoLXNlcnZpY2UwHhcNMjQxMDIzMTQ1MDE4WhcNMzQxMDIzMTQ1MTU4WjAXMRUwEwYDVQQDDAxzcHNoLXNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4+xc3VFrYv+1A5Eoa+7firuYN/+3FwoLKSYAe68FQrPTDA27qyTdtPwbZfYe33lxREq7YgAF0T9qGVShXQrQqv+vvf0IDBdsTWd2UbEnJ02vj0CvDKV+1bFBWQt2Ead7MF6Wsw0HbK1tWMlvdZZl7YwypH8uHmXtGvdnnYNCLzJYPEWU4so6CPVAB89cTdspceYGg9HUnoWKv7IklAL/fJfJ/IWO/D/tEmPqM5taONuQmnwmYFhXMFAVRu32uixIYXNzr8Tw9w5naHIjENib83OtiqwidZrGbL7djNidIIs0XOzTxRlOzJ/+ajvUUQJLEQPEpjyd0QFEk2RshtcD9AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGsR/rbVu+Yf0rvYsfz59etjNoEtTq8l4jbDMChJRnanLHJvAxqHl0co1m+MbxTYB+l2cnqS6tpwea0LfKICXAamMScxe8dcq86DHV8RFOpWLszZgxFuPNplVxZxWde2AhwxCTz/wF2bPllJGc8mxJK0DJkuC50zh9yXQ6XFfwT9qTVAvqv3aEEKidmY3uDxRYFnzmLzqu7ac+Q3e/AWtP+PCQ+vmSJaSK4Uyn21wu3VN+1Gb8clPVI2pkNypSExq/OeS6g1BZy6Sng9mxG42602RLQj7QwK4GQHxYqMCEagf2W1OzC9pt+kGGg0JlN1kxeodiKLvU/Q8zWGCURWY30=", + "jwt.credential.certificate": "${KC_SERVICE_CLIENT_CERTIFICATE}", "oauth2.device.authorization.grant.enabled": "false", "display.on.consent.screen": "false", "backchannel.logout.revoke.offline.tokens": "false" @@ -1445,6 +1445,72 @@ "configure": true, "manage": true } + }, + { + "id": "dd986a17-44c7-4ec9-87f6-addf1646ecf0", + "clientId": "${KC_SCHOOLSH_CLIENT_ID}", + "name": "School-SH", + "description": "", + "rootUrl": "${KC_SCHOOLSH_CLIENT_ROOT_URL}", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "${KC_SCHOOLSH_CLIENT_SECRET}", + "redirectUris": [ + "/cgi/samlauth" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "saml", + "attributes": { + "saml.assertion.signature": "true", + "saml_assertion_consumer_url_redirect": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/samlauth", + "saml_single_logout_service_url_post": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/tmlogout", + "saml.force.post.binding": "true", + "saml.encrypt": "true", + "saml_assertion_consumer_url_post": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/samlauth", + "saml.server.signature": "true", + "saml.server.signature.keyinfo.ext": "false", + "saml.signing.certificate": "${KC_SCHOOLSH_CLIENT_SIGNING_CERTIFICATE}", + "saml_single_logout_service_url_redirect": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/tmlogout", + "saml.artifact.binding": "false", + "saml.signature.algorithm": "RSA_SHA256", + "saml_force_name_id_format": "false", + "saml.client.signature": "true", + "saml.encryption.certificate": "${KC_SCHOOLSH_CLIENT_ENCRYPTION_CERTIFICATE}", + "saml.authnstatement": "true", + "display.on.consent.screen": "false", + "saml_name_id_format": "username", + "saml.allow.ecp.flow": "false", + "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#", + "saml.onetimeuse.condition": "false", + "saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer": "NONE" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "role_list" + ], + "optionalClientScopes": [], + "access": { + "view": true, + "configure": true, + "manage": true + } } ], "clientScopes": [ @@ -2126,12 +2192,27 @@ }, { "id": "d47622d7-8d04-4d38-b7f0-d80eb182f80d", - "name": "rsa-generated", - "providerId": "rsa-generated", + "name": "rsa", + "providerId": "rsa", "subComponents": {}, "config": { + "privateKey": [ + "${KC_RS256_PRIVATE_KEY}" + ], + "certificate": [ + "${KC_RS256_CERTIFICATE}" + ], + "active": [ + "true" + ], + "enabled": [ + "true" + ], "priority": [ "100" + ], + "algorithm": [ + "RS256" ] } }, diff --git a/automation/dbildungs-iam-keycloak/prod-realm-spsh.json b/automation/dbildungs-iam-keycloak/prod-realm-spsh.json index 88148773c..4043b4a0f 100644 --- a/automation/dbildungs-iam-keycloak/prod-realm-spsh.json +++ b/automation/dbildungs-iam-keycloak/prod-realm-spsh.json @@ -851,7 +851,7 @@ "oidc.ciba.grant.enabled": "false", "client.secret.creation.time": "1727357679", "backchannel.logout.session.required": "true", - "jwt.credential.certificate": "MIICpzCCAY8CBgGSudz1xDANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxzcHNoLXNlcnZpY2UwHhcNMjQxMDIzMTQ1MDE4WhcNMzQxMDIzMTQ1MTU4WjAXMRUwEwYDVQQDDAxzcHNoLXNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4+xc3VFrYv+1A5Eoa+7firuYN/+3FwoLKSYAe68FQrPTDA27qyTdtPwbZfYe33lxREq7YgAF0T9qGVShXQrQqv+vvf0IDBdsTWd2UbEnJ02vj0CvDKV+1bFBWQt2Ead7MF6Wsw0HbK1tWMlvdZZl7YwypH8uHmXtGvdnnYNCLzJYPEWU4so6CPVAB89cTdspceYGg9HUnoWKv7IklAL/fJfJ/IWO/D/tEmPqM5taONuQmnwmYFhXMFAVRu32uixIYXNzr8Tw9w5naHIjENib83OtiqwidZrGbL7djNidIIs0XOzTxRlOzJ/+ajvUUQJLEQPEpjyd0QFEk2RshtcD9AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGsR/rbVu+Yf0rvYsfz59etjNoEtTq8l4jbDMChJRnanLHJvAxqHl0co1m+MbxTYB+l2cnqS6tpwea0LfKICXAamMScxe8dcq86DHV8RFOpWLszZgxFuPNplVxZxWde2AhwxCTz/wF2bPllJGc8mxJK0DJkuC50zh9yXQ6XFfwT9qTVAvqv3aEEKidmY3uDxRYFnzmLzqu7ac+Q3e/AWtP+PCQ+vmSJaSK4Uyn21wu3VN+1Gb8clPVI2pkNypSExq/OeS6g1BZy6Sng9mxG42602RLQj7QwK4GQHxYqMCEagf2W1OzC9pt+kGGg0JlN1kxeodiKLvU/Q8zWGCURWY30=", + "jwt.credential.certificate": "${KC_SERVICE_CLIENT_CERTIFICATE}", "oauth2.device.authorization.grant.enabled": "false", "display.on.consent.screen": "false", "backchannel.logout.revoke.offline.tokens": "false" @@ -1282,6 +1282,72 @@ "configure": true, "manage": true } + }, + { + "id": "dd986a17-44c7-4ec9-87f6-addf1646ecf0", + "clientId": "${KC_SCHOOLSH_CLIENT_ID}", + "name": "School-SH", + "description": "", + "rootUrl": "${KC_SCHOOLSH_CLIENT_ROOT_URL}", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "${KC_SCHOOLSH_CLIENT_SECRET}", + "redirectUris": [ + "/cgi/samlauth" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "saml", + "attributes": { + "saml.assertion.signature": "true", + "saml_assertion_consumer_url_redirect": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/samlauth", + "saml_single_logout_service_url_post": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/tmlogout", + "saml.force.post.binding": "true", + "saml.encrypt": "true", + "saml_assertion_consumer_url_post": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/samlauth", + "saml.server.signature": "true", + "saml.server.signature.keyinfo.ext": "false", + "saml.signing.certificate": "${KC_SCHOOLSH_CLIENT_SIGNING_CERTIFICATE}", + "saml_single_logout_service_url_redirect": "${KC_SCHOOLSH_CLIENT_ROOT_URL}/cgi/tmlogout", + "saml.artifact.binding": "false", + "saml.signature.algorithm": "RSA_SHA256", + "saml_force_name_id_format": "false", + "saml.client.signature": "true", + "saml.encryption.certificate": "${KC_SCHOOLSH_CLIENT_ENCRYPTION_CERTIFICATE}", + "saml.authnstatement": "true", + "display.on.consent.screen": "false", + "saml_name_id_format": "username", + "saml.allow.ecp.flow": "false", + "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#", + "saml.onetimeuse.condition": "false", + "saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer": "NONE" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "role_list" + ], + "optionalClientScopes": [], + "access": { + "view": true, + "configure": true, + "manage": true + } } ], "clientScopes": [ @@ -1963,12 +2029,27 @@ }, { "id": "d47622d7-8d04-4d38-b7f0-d80eb182f80d", - "name": "rsa-generated", - "providerId": "rsa-generated", + "name": "rsa", + "providerId": "rsa", "subComponents": {}, "config": { + "privateKey": [ + "${KC_RS256_PRIVATE_KEY}" + ], + "certificate": [ + "${KC_RS256_CERTIFICATE}" + ], + "active": [ + "true" + ], + "enabled": [ + "true" + ], "priority": [ "100" + ], + "algorithm": [ + "RS256" ] } }, diff --git a/automation/dbildungs-iam-keycloak/templates/configmap.yaml b/automation/dbildungs-iam-keycloak/templates/configmap.yaml index 4fbaf3eb2..e6596fee5 100644 --- a/automation/dbildungs-iam-keycloak/templates/configmap.yaml +++ b/automation/dbildungs-iam-keycloak/templates/configmap.yaml @@ -11,5 +11,7 @@ data: KC_ROOT_URL: "https://{{ .Values.frontendHostname }}" KC_PROXY: "edge" KEYCLOAK_ADMIN: admin + KC_SCHOOLSH_CLIENT_ID: "{{ .Values.schoolsh.clientId }}" + KC_SCHOOLSH_CLIENT_ROOT_URL: "{{ .Values.schoolsh.rootUrl }}" KC_HTTP_MANAGEMENT_PORT: "8090" STATUS_URL: "{{ .Values.status.url }}" \ No newline at end of file diff --git a/automation/dbildungs-iam-keycloak/templates/deployment.yaml b/automation/dbildungs-iam-keycloak/templates/deployment.yaml index 50d66b5f6..2face79cb 100644 --- a/automation/dbildungs-iam-keycloak/templates/deployment.yaml +++ b/automation/dbildungs-iam-keycloak/templates/deployment.yaml @@ -70,6 +70,16 @@ spec: secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} key: db-password + - name: KC_RS256_PRIVATE_KEY + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-rs256-privateKey + - name: KC_RS256_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-rs256-certificate - name: KC_CLIENT_SECRET valueFrom: secretKeyRef: @@ -80,6 +90,11 @@ spec: secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} key: keycloak-adminSecret + - name: KC_SERVICE_CLIENT_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-serviceClientCertificate - name: KC_ITSLEARNING_CLIENT_SECRET valueFrom: secretKeyRef: @@ -127,6 +142,21 @@ spec: key: keycloak-nextcloud-clientSecret - name: KC_DB_URL value: "jdbc:postgresql://$(DB_HOST)/$(DB_NAME)" + - name: KC_SCHOOLSH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-schoolsh-clientSecret + - name: KC_SCHOOLSH_CLIENT_SIGNING_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-schoolsh-signingCertificate + - name: KC_SCHOOLSH_CLIENT_ENCRYPTION_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: keycloak-schoolsh-encryptionCertificate {{- if .Values.extraEnvVars }} {{ toYaml .Values.extraEnvVars | nindent 12 }} {{- end }} diff --git a/automation/dbildungs-iam-keycloak/templates/ingress2nd.yaml b/automation/dbildungs-iam-keycloak/templates/ingress2nd.yaml new file mode 100644 index 000000000..bb594edc1 --- /dev/null +++ b/automation/dbildungs-iam-keycloak/templates/ingress2nd.yaml @@ -0,0 +1,29 @@ +{{if .Values.ingress.enabled2nd }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ template "common.names.name" . }}-2nd + namespace: {{ template "common.names.namespace" . }} + labels: + {{- include "common.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + tls: + - hosts: + - {{ .Values.keycloak2ndHostname }} + ingressClassName: {{ .Values.ingress.ingressClassName }} + rules: + - host: {{ .Values.keycloak2ndHostname }} + http: + paths: + - path: {{ .Values.ingress.path }} + pathType: {{ .Values.ingress.pathType }} + backend: + service: + name: {{ template "common.names.name" . }} + port: + number: {{ .Values.service.ports.http }} +{{- end }} \ No newline at end of file diff --git a/automation/dbildungs-iam-keycloak/templates/keycloak-servicemonitor.yaml b/automation/dbildungs-iam-keycloak/templates/keycloak-servicemonitor.yaml new file mode 100644 index 000000000..85a83f34d --- /dev/null +++ b/automation/dbildungs-iam-keycloak/templates/keycloak-servicemonitor.yaml @@ -0,0 +1,21 @@ +{{- if .Values.keycloak.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "common.names.name" . }} + namespace: {{ template "common.names.namespace" . }} + labels: + {{- include "common.labels" . | nindent 4 }} + app.kubernetes.io/component: keycloak +spec: + namespaceSelector: + matchNames: + - {{ include "common.names.namespace" . | quote }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "common.names.name" . }} + endpoints: + - port: {{ .Values.keycloak.serviceMonitor.port }} + path: {{ .Values.keycloak.serviceMonitor.path }} + interval: {{ .Values.keycloak.serviceMonitor.interval | default "30s" }} +{{- end }} diff --git a/automation/dbildungs-iam-keycloak/templates/pdb.yaml b/automation/dbildungs-iam-keycloak/templates/pdb.yaml new file mode 100644 index 000000000..7bedbc8f0 --- /dev/null +++ b/automation/dbildungs-iam-keycloak/templates/pdb.yaml @@ -0,0 +1,17 @@ +{{- if .Values.podDisruptionBudget.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "common.names.name" . }}-pdb + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "common.names.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + selector: + matchLabels: + app.kubernetes.io/name: dbildungs-iam-keycloak +{{- end }} \ No newline at end of file diff --git a/automation/dbildungs-iam-keycloak/templates/secret.yaml b/automation/dbildungs-iam-keycloak/templates/secret.yaml index fa32c7e33..ea0ff8cde 100644 --- a/automation/dbildungs-iam-keycloak/templates/secret.yaml +++ b/automation/dbildungs-iam-keycloak/templates/secret.yaml @@ -9,8 +9,11 @@ data: admin-password: {{ .Values.auth.admin_password }} db-host: {{ .Values.database.host }} db-password: {{ .Values.database.password }} + keycloak-rs256-privateKey: {{ .Values.auth.keycloak_rs256_privateKey }} + keycloak-rs256-certificate: {{ .Values.auth.keycloak_rs256_certificate }} keycloak-adminSecret: {{ .Values.auth.keycloak_adminSecret }} keycloak-clientSecret: {{ .Values.auth.keycloak_clientSecret }} + keycloak-serviceClientCertificate: {{ .Values.auth.keycloak_serviceClientCertificate }} keycloak-itslearning-clientSecret: {{ .Values.auth.keycloak_itslearning_clientSecret }} keycloak-ox-clientSecret: {{ .Values.auth.keycloak_ox_clientSecret }} pi-admin-password: {{ .Values.auth.pi_admin_password }} @@ -20,5 +23,8 @@ data: pi-user-realm: {{ .Values.auth.pi_user_realm }} keycloak-nextcloud-clientId: {{ .Values.auth.keycloak_nextcloud_clientId }} keycloak-nextcloud-clientSecret: {{ .Values.auth.keycloak_nextcloud_clientSecret }} + keycloak-schoolsh-clientSecret: {{ .Values.auth.keycloak_schoolsh_clientSecret }} + keycloak-schoolsh-signingCertificate: {{ .Values.auth.keycloak_schoolsh_signingCertificate }} + keycloak-schoolsh-encryptionCertificate: {{ .Values.auth.keycloak_schoolsh_encryptionCertificate }} {{- end }} \ No newline at end of file diff --git a/automation/dbildungs-iam-keycloak/values.yaml b/automation/dbildungs-iam-keycloak/values.yaml index e79fbf64c..988b235f8 100644 --- a/automation/dbildungs-iam-keycloak/values.yaml +++ b/automation/dbildungs-iam-keycloak/values.yaml @@ -8,14 +8,21 @@ image: tag: "" pullPolicy: Always +schoolsh: + clientId: https://school-sh.invalid + rootUrl: https://school-sh.invalid + auth: # existingSecret: Refers to a secret already present in the cluster, which is required for the authentication and configuration of the database setup tasks. existingSecret: "" secretName: dbildungs-iam-keycloak admin_password: "" admin_user: "" + keycloak_rs256_privateKey: "" + keycloak_rs256_certificate: "" keycloak_adminSecret: "" keycloak_clientSecret: "" + keycloak_serviceClientCertificate: "" keycloak_itslearning_clientSecret: "" keycloak_ox_clientSecret: "" keycloak_nextcloud_clientId: "" @@ -25,6 +32,10 @@ auth: pi_admin_password: "" pi_user_resolver: "" pi_user_realm: "" + schoolsh_clientSecret: "" + schoolsh_signingCertificate: "" + schoolsh_encryptionCertificate: "" + command: [] @@ -46,6 +57,7 @@ restartPolicy: Always keycloakHostname: "" frontendHostname: "" +keycloak2ndHostname: "" containerSecurityContext: enabled: true @@ -88,6 +100,8 @@ readinessProbe: port: mgmt ingress: + # Only enable if 2nd host name is defined + enabled2nd: false ingressClassName: nginx path: / pathType: Prefix @@ -110,6 +124,12 @@ service: ports: http: 80 +keycloak: + serviceMonitor: + enabled: true + path: "/metrics" + port: 'mgmt' + autoscaling: enabled: false minReplicas: 1 @@ -118,3 +138,7 @@ autoscaling: status: url: "https://status.dev.spsh.dbildungsplattform.de/" + +podDisruptionBudget: + enabled: true + minAvailable: "80%"