From 88924a931879d52caaf7119d1c46a5943bd4a998 Mon Sep 17 00:00:00 2001 From: dbildungs-iam-server-gha Date: Wed, 20 Nov 2024 15:10:04 +0000 Subject: [PATCH] dbildungs-iam-server --- automation/dbildungs-iam-server/Chart.lock | 2 +- automation/dbildungs-iam-server/Chart.yaml | 4 +- .../dbildungs-iam-server/cron/Dockerfile | 23 +++ .../cron/keys/dummy_jwks.json | 15 ++ .../cron/scripts/cron_trigger.sh | 38 ++++ .../cron/scripts/get_access_token.sh | 169 ++++++++++++++++++ .../templates/_dbildungs-iam-server-envs.tpl | 33 +++- .../templates/backend-deployment.yaml | 12 +- .../templates/configmap.yaml | 12 +- .../templates/cronjob-envs-configmap.yaml | 11 ++ .../templates/cronjob-scripts-configmap.yaml | 13 ++ .../templates/cronjob.yaml | 86 +++++++++ .../templates/secret.yaml | 7 +- automation/dbildungs-iam-server/values.yaml | 59 +++--- 14 files changed, 435 insertions(+), 49 deletions(-) create mode 100644 automation/dbildungs-iam-server/cron/Dockerfile create mode 100644 automation/dbildungs-iam-server/cron/keys/dummy_jwks.json create mode 100644 automation/dbildungs-iam-server/cron/scripts/cron_trigger.sh create mode 100644 automation/dbildungs-iam-server/cron/scripts/get_access_token.sh create mode 100644 automation/dbildungs-iam-server/templates/cronjob-envs-configmap.yaml create mode 100644 automation/dbildungs-iam-server/templates/cronjob-scripts-configmap.yaml create mode 100644 automation/dbildungs-iam-server/templates/cronjob.yaml diff --git a/automation/dbildungs-iam-server/Chart.lock b/automation/dbildungs-iam-server/Chart.lock index 5db4713cc..459012f9e 100644 --- a/automation/dbildungs-iam-server/Chart.lock +++ b/automation/dbildungs-iam-server/Chart.lock @@ -3,4 +3,4 @@ dependencies: repository: https://charts.bitnami.com/bitnami version: 11.0.6 digest: sha256:790bafa04fe9c1cc9f772dc12fada16eb847c282f738fd23df09f665af93ec74 -generated: "2024-11-20T15:03:02.334662439Z" +generated: "2024-11-20T15:09:27.026824035Z" diff --git a/automation/dbildungs-iam-server/Chart.yaml b/automation/dbildungs-iam-server/Chart.yaml index e98fe1215..91fa71395 100644 --- a/automation/dbildungs-iam-server/Chart.yaml +++ b/automation/dbildungs-iam-server/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: DBP-1066 +appVersion: DBP-1022 dependencies: - condition: redis-cluster.enabled name: redis-cluster @@ -8,4 +8,4 @@ dependencies: description: dBildungs-IAM-server name: dbildungs-iam-server type: application -version: 0.0.0-dbp-1066-20241120-1502 +version: 0.0.0-dbp-1022-20241120-1509 diff --git a/automation/dbildungs-iam-server/cron/Dockerfile b/automation/dbildungs-iam-server/cron/Dockerfile new file mode 100644 index 000000000..a05b37677 --- /dev/null +++ b/automation/dbildungs-iam-server/cron/Dockerfile @@ -0,0 +1,23 @@ +FROM alpine:3.19 + +# Install necessary packages +RUN apk update && \ + apk add --no-cache bash cronie jq openssl vim wget + +# Create a new user and group +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# Copy scripts into the image +COPY scripts/ /scripts/ + +# Set execute permissions for all .sh scripts in /scripts/ and create a log file +RUN chmod +x /scripts/*.sh \ + && touch /var/log/cron.log \ + && chmod 644 /var/log/cron.log \ + && chown -R appuser:appgroup /scripts /var/log/cron.log + +# Switch to the new user +USER appuser + +# Start the cron service in foreground +CMD ["/usr/sbin/crond", "-f"] diff --git a/automation/dbildungs-iam-server/cron/keys/dummy_jwks.json b/automation/dbildungs-iam-server/cron/keys/dummy_jwks.json new file mode 100644 index 000000000..85b1e9d25 --- /dev/null +++ b/automation/dbildungs-iam-server/cron/keys/dummy_jwks.json @@ -0,0 +1,15 @@ +{ + "keys": [ + { + "kty": "RSA", + "n": "23mzd3v4YjgWMzO7XYYwD92NqCm436ErU1-NPTVok9aaVXx5mjZKfh_Xoyp5BEgjQU042MKOhl1Ri17HfOOf6k4cpBpvBQhENp0yfNPv_-kSy4OgdA3qk9-kZyvuRX1-0LKvJMwlrCLCLEfiv_yn8YQLpQeqgdIj1AlX37fcnSxxL3qukM_-Hm8dCB2mbUzANT_uRkSCHFQWVDxcbocKAmhr0808CmpiINWEIVv7AhS_HVSliaeB-iteAKN3W9Am3tCtGZaWKUlioKueQux7OTKxHm5fM-jZ9ZPnb7_RQlOGV9vu-TTMO8pKYkqn15LcnYuBKKHmFEBO8vRxI9_8Lw", + "e": "AQAB", + "d": "CdcSByhlbC9BkjgejW89FmkDjJJE-gR63HkV7F70T7SOejNjga4vdtTXUTclR94yyR8SORMNWtQyRMJnb_UGBXZNGG_K9yR2EntyeQrzjBDCHqJ0fjTlheMVYZQkUbSdC_RcSpUQl1V-STKhOvmz-e3Gq-Evxt70wPFOTEyCYAA5zTSgF7vwoxtKChfOb3NvkLUmD4JrBEb0vzapTgVvoyB158glUGEibpHBaVvVnA98qEI5hqJE2jhhtaoGyvErIkWDOummb1WPN2D0Nqsvr-sfwH3mxKFLDogHIfjMLxDaP9Y3I7Wwie9pbpsg6zK66s6EB27hkZnbRLlwaK4ImQ", + "p": "_KCzohdV8BpnvfDxyL-Zjj8paJB5RBLkewf7xl-sqLHykjn-_nR1OGfEr8Gc0zwYD6FtTAJ9JN-h730vBacUVZDrgnKOW0NbQPIwNXCSisyChhbkSVXLBi94r_-t92ieJ8wPbchynF6Z1UyH0m4rieKnAPcxuio9iLuXdQrRNEs", + "q": "3me1bHQ_GO5mPKwUf-kSZDguninq98ERMOAYdr__yUM1fc8QJ_3FSkZsSFr91Fi5kPvP9gthPRYhlfKeix61ibypLnLpyx6A298VIdG8VFjPrXzlme5CGSPYN9-YRSQq31e-xSdkn3lKiJlqPZzlRARyHveJlSWu07LuS91AgS0", + "dp": "--U1GEOSchWyKaeNPrElaLu8C0I7WFBKOA7u0o9ldtPwXjOr-Yaftz1o1iMEv29lQnigpbC5ncHLEyRMdaNyWBtnaSvWnFNeMzUKMs7rn7Bp2VAMEr-T77f36-3SRiavxFjpbXr4JMkDNLbZm0405Yj1IrZYhBtIPgVm8NJ3ZV8", + "dq": "ofqgbKvBZLQEq_2cNIiYh3tPoIvhAK6Riao8xwgREBEt_UH4f1fY_76IkK4MnkI8bHapwIYLPQVIUsBQbfxgtT89bIHu-qttqDUyW944Lqo8HxuO0WxwoYS0rgTgDsNHokByxX5qT6dz_EbX1KXXaJFgWGNqxcCbMr3nxkMO_sU", + "qi": "r8ZslmjXzZJUv6IoN6nUT12UpzmhbriRXxjTcLNSwZBuSXz8QV_7F8ViNyEcot20aDo35t8IssLnDD9nxDAGTCL68FkXTJaAsUE2beGfkX9Sz5r_Gzlcer_Gjhl5aNHeZYgIMsYciPhM4laBzKD3d51xQuDFMMX1RQUvyDHDIog" + } + ] +} diff --git a/automation/dbildungs-iam-server/cron/scripts/cron_trigger.sh b/automation/dbildungs-iam-server/cron/scripts/cron_trigger.sh new file mode 100644 index 000000000..50d6e147e --- /dev/null +++ b/automation/dbildungs-iam-server/cron/scripts/cron_trigger.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Check if BACKEND_ENDPOINT_URL is set +if [ -z "$BACKEND_ENDPOINT_URL" ]; then + echo "Error: BACKEND_ENDPOINT_URL is not set." + exit 1 +fi + +# Check if HTTP_METHOD is set +if [ -z "$HTTP_METHOD" ]; then + echo "Error: HTTP_METHOD is not set." + exit 1 +fi + +endpoint_url="${BACKEND_ENDPOINT_URL}" + +echo "Triggering $endpoint_url with $HTTP_METHOD at $(date)" + +# Call get_access_token.sh and capture the access token +access_token=$(./get_access_token.sh) + +# Make the request with JWT authorization and capture the HTTP status code and response body +response=$(wget --quiet --output-document=- --server-response --header="Authorization: Bearer $access_token" --header="Content-Type: application/json" --method="$HTTP_METHOD" "$endpoint_url" 2>&1) + +# Split the response into body and status code +response_body=$(echo "$response" | sed -n '/^ HTTP\//q;p') +http_status=$(echo "$response" | awk '/^ HTTP\// {print $2; exit}') + +# Output the response details +echo "Finished triggering $endpoint_url with $HTTP_METHOD at $(date) +HTTP Status: $http_status +Response Body: $response_body" + +# Exit with status 1 if the HTTP status code is not 200 +if [ "$http_status" -ne 200 ]; then + echo "Error: HTTP request failed with status code $http_status" + exit 1 +fi diff --git a/automation/dbildungs-iam-server/cron/scripts/get_access_token.sh b/automation/dbildungs-iam-server/cron/scripts/get_access_token.sh new file mode 100644 index 000000000..b3e35e6ed --- /dev/null +++ b/automation/dbildungs-iam-server/cron/scripts/get_access_token.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +# Ensure the script exits on any error +set -e + +# Function to perform base64 URL encoding +base64url_encode() { + # Base64 encode the input, replace '+' with '-', '/' with '_', and remove padding '=' + echo -n "$1" | openssl enc -base64 -A | tr '+/' '-_' | tr -d '=' +} + +base64url_decode() { + local input=$1 + # Replace '-' with '+', '_' with '/' + input=$(echo "$input" | sed 's/-/+/g; s/_/\//g') + # Calculate the required padding + local padding=$(( (4 - ${#input} % 4) % 4 )) + # Add padding if necessary + input="$input$(printf '=%.0s' $(seq 1 $padding))" + echo "$input" | base64 -d +} + +# Function to decode base64url and convert to hex, preserving leading zeros +decode_to_hex() { + base64url_decode "$1" | hexdump -v -e '/1 "%02x"' +} + +# Generate a random string for 'jti' claim +generate_jti() { + head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 +} + +# Load environment variables +clientId="${KC_CLIENT_ID}" +kc_token_url="${KC_TOKEN_URL}" + +# Load JWKS from environment variable or file +if [ -n "$JWKS" ]; then + # JWKS is set in the environment, use it directly + jwks="$JWKS" +elif [ -n "$JWKS_FILE_PATH" ] && [ -f "$JWKS_FILE_PATH" ]; then + # JWKS_FILE_PATH is set, use the file + jwks=$(cat "$JWKS_FILE_PATH") +else + echo "Error: No JWKS environment variable or JWKS file found." >> /var/log/cron.log + exit 1 +fi + +# Check if environment variables are set +if [[ -z "$clientId" || -z "$kc_token_url" || -z "$jwks" ]]; then + echo "Error: CLIENT_ID, TOKEN_URL, and JWKS environment variables must be set." >> /var/log/cron.log + exit 1 +fi + +# Extract the first key from the JWKS +key_json=$(echo "$jwks" | jq -c '.keys[0]') + +# Check if key_json is empty +if [[ -z "$key_json" ]]; then + echo "Error: No keys found in JWKS." >> /var/log/cron.log + exit 1 +fi + +# Extract RSA components from JWK +n=$(echo "$key_json" | jq -r '.n') +e=$(echo "$key_json" | jq -r '.e') +d=$(echo "$key_json" | jq -r '.d') +p=$(echo "$key_json" | jq -r '.p') +q=$(echo "$key_json" | jq -r '.q') +dp=$(echo "$key_json" | jq -r '.dp') +dq=$(echo "$key_json" | jq -r '.dq') +qi=$(echo "$key_json" | jq -r '.qi') + +# Decode the base64url-encoded components and convert to hex +n_dec=$(decode_to_hex "$n") +e_dec=$(decode_to_hex "$e") +d_dec=$(decode_to_hex "$d") +p_dec=$(decode_to_hex "$p") +q_dec=$(decode_to_hex "$q") +dp_dec=$(decode_to_hex "$dp") +dq_dec=$(decode_to_hex "$dq") +qi_dec=$(decode_to_hex "$qi") + +# Create an ASN.1 structure for the RSA private key +asn1_structure=$(mktemp) + +cat > "$asn1_structure" <> /var/log/cron.log + +# Generate the PEM-formatted private key +temp_key_file=$(mktemp) +openssl asn1parse -genconf "$asn1_structure" -out "$temp_key_file" > /dev/null 2>&1 +openssl rsa -in "$temp_key_file" -inform DER -outform PEM -out "$temp_key_file.pem" > /dev/null 2>&1 + +echo "Ending to generate PEM-formatted private key" >> /var/log/cron.log + +# Remove temporary files +rm "$asn1_structure" "$temp_key_file" + +# Create JWT header +header='{"alg":"RS256","typ":"JWT"}' +header_base64=$(base64url_encode "$header") + +# Create JWT payload +current_time=$(date +%s) +exp_time=$((current_time + 300)) # Token valid for 5 minutes +jti=$(generate_jti) + +payload=$(cat <> /var/log/cron.log + +# Sign the JWT +signature=$(echo -n "$header_payload" | \ + openssl dgst -sha256 -sign "$temp_key_file.pem" | \ + openssl enc -base64 -A | tr '+/' '-_' | tr -d '=') + +echo "Signed the JWT" >> /var/log/cron.log + +# Remove the temporary PEM key file +rm "$temp_key_file.pem" + +# Create the JWT assertion +jwt_assertion="$header_payload.$signature" + +# Make the POST request to Keycloak to get the access token +response=$(wget -qO- --post-data "grant_type=client_credentials&client_id=$clientId&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=$jwt_assertion" \ + --header "Content-Type: application/x-www-form-urlencoded" \ + "$kc_token_url") + +echo "Access token requested" >> /var/log/cron.log + +# Check if the response contains an access token +if echo "$response" | grep -q '"access_token"'; then + # Extract the access token from the response + access_token=$(echo "$response" | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') + echo "$access_token" +else + echo "Failed to retrieve access token. Response:" >> /var/log/cron.log + echo "$response" >> /var/log/cron.log + exit 1 +fi diff --git a/automation/dbildungs-iam-server/templates/_dbildungs-iam-server-envs.tpl b/automation/dbildungs-iam-server/templates/_dbildungs-iam-server-envs.tpl index 995dc13fd..e6b03a7fd 100644 --- a/automation/dbildungs-iam-server/templates/_dbildungs-iam-server-envs.tpl +++ b/automation/dbildungs-iam-server/templates/_dbildungs-iam-server-envs.tpl @@ -36,6 +36,16 @@ secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} key: frontend-sessionSecret + - name: ITSLEARNING_ENABLED + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: itslearning-enabled + - name: ITSLEARNING_ENDPOINT + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: itslearning-endpoint - name: ITSLEARNING_USERNAME valueFrom: secretKeyRef: @@ -46,16 +56,16 @@ secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} key: itslearning-password - - name: LDAP_BIND_DN + - name: LDAP_ADMIN_PASSWORD valueFrom: secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} - key: ldap-bind-dn - - name: LDAP_ADMIN_PASSWORD + key: ldap-admin-password + - name: PI_BASE_URL valueFrom: secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} - key: ldap-admin-password + key: pi-base-url - name: PI_ADMIN_USER valueFrom: secretKeyRef: @@ -66,6 +76,21 @@ secretKeyRef: name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} key: pi-admin-password + - name: PI_USER_RESOLVER + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: pi-user-resolver + - name: PI_REALM + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: pi-user-realm + - name: PI_RENAME_WAITING_TIME + valueFrom: + secretKeyRef: + name: {{ default .Values.auth.existingSecret .Values.auth.secretName }} + key: pi-rename-waiting-time - name: REDIS_PASSWORD valueFrom: secretKeyRef: diff --git a/automation/dbildungs-iam-server/templates/backend-deployment.yaml b/automation/dbildungs-iam-server/templates/backend-deployment.yaml index 7d5405891..0c5b14b06 100644 --- a/automation/dbildungs-iam-server/templates/backend-deployment.yaml +++ b/automation/dbildungs-iam-server/templates/backend-deployment.yaml @@ -22,12 +22,11 @@ spec: spec: automountServiceAccountToken: false initContainers: - {{- if .Values.backend.dbmigration.enabled }} - name: "{{ template "common.names.name" . }}-db-migration-apply" image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.backend.image.pullPolicy | default "Always" }} securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - command: {{ .Values.backend.dbmigration.command }} + command: [ "node", "dist/src/console/main.js", "db", "migration-apply" ] env: {{- include "dbildungs-iam-server-backend-envs" . | indent 12 }} {{- if .Values.backend.extraEnvVars }} @@ -39,13 +38,11 @@ spec: volumeMounts: {{- toYaml .Values.backend.volumeMounts | nindent 12 }} resources: {{- toYaml .Values.backend.resources | nindent 12 }} - {{ end }} - {{- if .Values.backend.keycloakdatamigration.enabled }} - name: "{{ template "common.names.name" . }}-keycloak-data-migration" image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.backend.image.pullPolicy | default "Always" }} securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - command: {{ .Values.backend.keycloakdatamigration.command }} + command: [ "node", "dist/src/console/main.js", "keycloak", "update-clients", "dev" ] env: {{- include "dbildungs-iam-server-backend-envs" . | indent 12 }} {{- if .Values.backend.extraEnvVars }} @@ -57,13 +54,12 @@ spec: volumeMounts: {{- toYaml .Values.backend.volumeMounts | nindent 12 }} resources: {{- toYaml .Values.backend.resources | nindent 12 }} - {{ end }} {{- if .Values.backend.dbseeding.enabled }} - name: db-seeding image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{.Values.imagePullPolicy | default "Always"}} securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - command: {{ .Values.backend.dbseeding.command }} + command: [ "node", "dist/src/console/main.js", "db", "seed", "dev" ] envFrom: - configMapRef: name: {{ template "common.names.name" . }} @@ -71,7 +67,7 @@ spec: volumeMounts: {{- toYaml .Values.backend.volumeMounts | nindent 12 }} resources: {{- toYaml .Values.backend.resources | nindent 12 }} - {{ end }} + {{end}} containers: - name: "{{ template "common.names.name" . }}-backend" image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}" diff --git a/automation/dbildungs-iam-server/templates/configmap.yaml b/automation/dbildungs-iam-server/templates/configmap.yaml index 8a2abcfd3..d98ee1a8d 100644 --- a/automation/dbildungs-iam-server/templates/configmap.yaml +++ b/automation/dbildungs-iam-server/templates/configmap.yaml @@ -8,7 +8,6 @@ metadata: data: config-json: |- {{ .Files.Get "config/config.json" | nindent 4 }} - # why is this node env NODE_ENV: "prod" DEPLOY_STAGE: {{ .Values.environment | quote }} DB_NAME: {{ .Values.database.name | quote }} @@ -18,13 +17,4 @@ data: FRONTEND_LOGOUT_REDIRECT: "https://{{ .Values.backendHostname }}/" BACKEND_HOSTNAME: "{{ .Values.backendHostname }}" LDAP_URL: '{{ .Values.ldap.url | replace "spsh-xxx" .Release.Namespace }}' - LDAP_BIND_DN: "{{ .Values.ldap.bindDN }}" - LDAP_OEFFENTLICHE_SCHULEN_DOMAIN: "{{ .Values.ldap.oeffentlicheSchulenDomain }}" - LDAP_ERSATZSCHULEN_DOMAIN: "{{ .Values.ldap.ersatzschulenDomain }}" - ITSLEARNING_ENABLED: "{{ .Values.itslearning.enabled }}" - ITSLEARNING_ENDPOINT: "{{ .Values.itslearning.endpoint }}" - PI_BASE_URL: "{{ .Values.privacyidea.url }}" - PI_RENAME_WAITING_TIME: "{{ .Values.privacyidea.renameWaitingTime }}" - PI_REALM: "{{ .Values.privacyidea.realm }}" - PI_USER_RESOLVER: "{{ .Values.privacyidea.userResolver }}" - + LDAP_BIND_DN: "{{ .Values.ldap.bindDN }}" \ No newline at end of file diff --git a/automation/dbildungs-iam-server/templates/cronjob-envs-configmap.yaml b/automation/dbildungs-iam-server/templates/cronjob-envs-configmap.yaml new file mode 100644 index 000000000..2d7158c75 --- /dev/null +++ b/automation/dbildungs-iam-server/templates/cronjob-envs-configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.name" . }}-cronjob-envs-configmap + namespace: {{ template "common.names.namespace" . }} + labels: + {{- include "common.labels" . | nindent 4 }} +data: + KC_TOKEN_URL: "https://{{ $.Values.keycloakHostname }}{{ $.Values.cronjobs.keycloakTokenUrl }}" + JWKS_FILE_PATH: "{{ $.Values.cronjobs.jwksFilePath }}" + KC_CLIENT_ID: "{{ $.Values.cronjobs.keycloakClientId }}" \ No newline at end of file diff --git a/automation/dbildungs-iam-server/templates/cronjob-scripts-configmap.yaml b/automation/dbildungs-iam-server/templates/cronjob-scripts-configmap.yaml new file mode 100644 index 000000000..4c2278c5c --- /dev/null +++ b/automation/dbildungs-iam-server/templates/cronjob-scripts-configmap.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.name" . }}-cronjob-scripts-configmap + namespace: {{ template "common.names.namespace" . }} + labels: {{- include "common.labels" . | nindent 4 }} +type: Opaque +data: + get_access_token.sh: |- + {{ .Files.Get "cron/scripts/get_access_token.sh" | nindent 4 }} + cron_trigger.sh: |- + {{ .Files.Get "cron/scripts/cron_trigger.sh" | nindent 4 }} diff --git a/automation/dbildungs-iam-server/templates/cronjob.yaml b/automation/dbildungs-iam-server/templates/cronjob.yaml new file mode 100644 index 000000000..b2b72b23f --- /dev/null +++ b/automation/dbildungs-iam-server/templates/cronjob.yaml @@ -0,0 +1,86 @@ +{{- if .Values.cronjobs.enabled }} +{{- range $job_name, $job_options := .Values.cronjobs.jobs }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ template "common.names.name" $ }}-{{ $job_name}} + namespace: {{ template "common.names.namespace" $ }} +spec: + schedule: {{ $job_options.schedule }} + startingDeadlineSeconds: 300 + jobTemplate: + spec: + backoffLimit: 0 + template: + metadata: + labels: + cron: {{ $job_name }} + spec: + automountServiceAccountToken: false + containers: + - name: {{ $job_name }} + image: "{{ $.Values.cronjobs.image.repository }}:{{ $.Values.cronjobs.image.tag }}" + imagePullPolicy: {{ $.Values.cronjobs.image.pullPolicy | default "Always"}} + securityContext: + # not yet possible since we need to install some tools + # privileged: false + # runAsUser: 1000 + # runAsNonRoot: true + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + envFrom: + - configMapRef: + name: {{ template "common.names.name" $ }}-cronjob-envs-configmap + env: + - name: BACKEND_ENDPOINT_URL + value: "https://{{ $.Values.backendHostname }}{{ $job_options.endpoint }}" + - name: HTTP_METHOD + value: "{{ $job_options.httpMethod }}" + resources: + limits: + memory: "128Mi" + cpu: "200m" + requests: + memory: "64Mi" + cpu: "50m" + command: + - "sh" + - "-c" + - | + mkdir /scripts && + cp /scripts_tmp/*.sh /scripts/ && + chmod +x /scripts/*.sh && + touch /var/log/cron.log && + chmod 644 /var/log/cron.log && + cd {{ $.Values.cronjobs.scriptDir }} && + bash {{ $job_options.script }} + volumeMounts: + - name: secret-volume-jwks + mountPath: /keys/jwks.json + subPath: jwks.json + readOnly: true + - name: script-volume + mountPath: /scripts_tmp + readOnly: false + ports: + - containerPort: {{ $.Values.cronjobs.port }} + name: cron-pod + volumes: + - name: script-volume + configMap: + name: {{ template "common.names.name" $ }}-cronjob-scripts-configmap + - name: secret-volume-jwks + secret: + secretName: dbildungs-iam-server + items: + - key: service-account-private-jwks + path: jwks.json + restartPolicy: Never +--- +{{- end}} +{{- end }} \ No newline at end of file diff --git a/automation/dbildungs-iam-server/templates/secret.yaml b/automation/dbildungs-iam-server/templates/secret.yaml index 677d8f793..51e46f34b 100644 --- a/automation/dbildungs-iam-server/templates/secret.yaml +++ b/automation/dbildungs-iam-server/templates/secret.yaml @@ -12,12 +12,17 @@ data: db-username: {{ .Values.database.username }} keycloak-adminSecret: {{ .Values.auth.keycloak_adminSecret }} keycloak-clientSecret: {{ .Values.auth.keycloak_clientSecret }} - ldap-bind-dn: {{ .Values.auth.ldap_bind_dn }} ldap-admin-password: {{ .Values.auth.ldap_admin_password }} + itslearning-enabled: {{ .Values.auth.itslearning_enabled }} + itslearning-endpoint: {{ .Values.auth.itslearning_endpoint }} itslearning-username: {{ .Values.auth.itslearning_username }} itslearning-password: {{ .Values.auth.itslearning_password }} + pi-base-url: {{ .Values.auth.pi_base_url }} pi-admin-user: {{ .Values.auth.pi_admin_user }} pi-admin-password: {{ .Values.auth.pi_admin_password }} + pi-user-resolver: {{ .Values.auth.pi_user_resolver }} + pi-user-realm: {{ .Values.auth.pi_user_realm }} + pi-rename-waiting-time: {{ .Values.auth.pi_rename_waiting_time }} secrets-json: {{ .Values.auth.secrets_json }} redis-password: {{ .Values.auth.redis_password }} {{- end }} diff --git a/automation/dbildungs-iam-server/values.yaml b/automation/dbildungs-iam-server/values.yaml index 3b297197a..4f95439b4 100644 --- a/automation/dbildungs-iam-server/values.yaml +++ b/automation/dbildungs-iam-server/values.yaml @@ -29,19 +29,6 @@ database: ldap: url: ldap://dbildungs-iam-ldap.spsh-xxx.svc.cluster.local bindDN: cn=admin,dc=schule-sh,dc=de - oeffentlicheSchulenDomain: schule-sh.de - ersatzschulenDomain: ersatzschule-sh.de - -itslearning: - enabled: false - endpoint: https://enterprise.itslintegrations.com/WCFServiceLibrary/ImsEnterpriseServicesPort.svc - -privacyidea: - url: https://privacyidea.dev.spsh.dbildungsplattform.de - renameWaitingTime: 5 - realm: ucs_users - userResolver: ucs_users - auth: # existingSecret: Refers to a secret already present in the cluster, which is required. @@ -49,14 +36,19 @@ auth: secretName: dbildungs-iam-server keycloak_adminSecret: '' keycloak_clientSecret: '' - ldap_bind_dn: '' ldap_admin_password: '' secrets_json: '' frontend_sessionSecret: '' + itslearning_enabled: '' + itslearning_endpoint: '' itslearning_username: '' itslearning_password: '' + pi_base_url: '' pi_admin_user: '' pi_admin_password: '' + pi_user_resolver: '' + pi_user_realm: '' + pi_rename_waiting_time: '' redis_password: '' backend: @@ -99,13 +91,7 @@ backend: path: '/health' dbseeding: enabled: true - command: [ "node", "dist/src/console/main.js", "db", "seed", "dev" ] - dbmigration: - enabled: true - command: [ "node", "dist/src/console/main.js", "db", "migration-apply" ] - keycloakdatamigration: - enabled: true - command: [ "node", "dist/src/console/main.js", "keycloak", "update-clients", "dev" ] + command: ['node', 'dist/src/console/main.js', 'db', 'seed', 'dev', ''] ingress: enabled: true ingressClassName: nginx @@ -186,4 +172,33 @@ autoscaling: enabled: false minReplicas: 1 maxReplicas: 5 - targetCPUUtilizationPercentage: 60 \ No newline at end of file + targetCPUUtilizationPercentage: 60 + +cronjobs: + enabled: true + image: + tag: latest + repository: ghcr.io/hpi-schul-cloud/cron-tools + pullPolicy: IfNotPresent + port: 5656 + keycloakTokenUrl: '/realms/SPSH/protocol/openid-connect/token' + keycloakClientId: spsh-service + jwksFilePath: /keys/jwks.json + backendHostname: '{{ $.Values.frontendHostname }}' + scriptDir: scripts + jobs: + cron-trigger-1: + schedule: 20 0 * * * + endpoint: '/api/cron/kopers-lock' + httpMethod: 'PUT' + script: 'cron_trigger.sh' + cron-trigger-2: + schedule: 40 0 * * * + endpoint: '/api/cron/kontext-expired' + httpMethod: 'PUT' + script: 'cron_trigger.sh' + cron-trigger-3: + schedule: 50 0 * * * + endpoint: '/api/cron/person-without-org' + httpMethod: 'PUT' + script: 'cron_trigger.sh' \ No newline at end of file