Skip to content

Commit

Permalink
dbildungs-iam-server
Browse files Browse the repository at this point in the history
  • Loading branch information
dbildungs-iam-server-gha committed Nov 8, 2024
1 parent 194a2cd commit 8708ac2
Show file tree
Hide file tree
Showing 13 changed files with 371 additions and 19 deletions.
2 changes: 1 addition & 1 deletion automation/dbildungs-iam-server/Chart.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ dependencies:
repository: https://charts.bitnami.com/bitnami
version: 11.0.6
digest: sha256:790bafa04fe9c1cc9f772dc12fada16eb847c282f738fd23df09f665af93ec74
generated: "2024-11-08T15:47:20.334302258Z"
generated: "2024-11-08T15:47:56.436299898Z"
4 changes: 2 additions & 2 deletions automation/dbildungs-iam-server/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: sha-665c83c
appVersion: DBP-1022
dependencies:
- condition: redis-cluster.enabled
name: redis-cluster
Expand All @@ -8,4 +8,4 @@ dependencies:
description: dBildungs-IAM-server
name: dbildungs-iam-server
type: application
version: 0.0.1-20241108-1547
version: 0.0.0-dbp-1022-20241108-1547
24 changes: 24 additions & 0 deletions automation/dbildungs-iam-server/cron/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM alpine:latest

# Install necessary packages
RUN apk update && \
apk add --no-cache bash openssl curl cronie jq vim

# Copy scripts into the image
COPY scripts/ /scripts/

# Set execute permissions for all .sh scripts in /scripts/
RUN chmod +x /scripts/*.sh

# Copy crontab into the image
COPY crontab /etc/crontabs/root

# Set correct permissions for crontab
RUN chmod 600 /etc/crontabs/root

# Create a log file if your scripts write to a file
RUN touch /var/log/cron.log && \
chmod 644 /var/log/cron.log

# Start the cron service in foreground
CMD ["/usr/sbin/crond", "-f"]
1 change: 1 addition & 0 deletions automation/dbildungs-iam-server/cron/crontab
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* * * * * /scripts/trigger_xyz.sh >> /var/log/cron.log
15 changes: 15 additions & 0 deletions automation/dbildungs-iam-server/cron/keys/dummy_jwks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"keys": [
{
"kty": "RSA",
"n": "m7yAgb97yHR9AhKgeIQ2rV3aqOeUuUId9yETShol7F2A1W71E6Srt_iI1osfytCj1LKTLCSxFhMLvKXXAQBOj2VZMKa0xSYjoyy_7N6QqKBxtreeP8mW8IkEbd2ioqbbRvk-SuFmRI-nkgux2ZRdP5P9J8rBkQeAWADwayqsGSYJZ_Ok4D0CpR4mIXaXWVuHmqmjEegKNPoll-XTp2fR2X0u_fK0n2bm-0HdkG-wrlDrIZ4eaMYqZcE327_1AUxi6BIFymECZJzMIhpGoDbMwGIv60jkbqzlwqhbxSHcqv_6mexrAYHtm1v4iVM82WpQPR28eQFmHGlJdR0wCMDW6H-zN08PlCaRa6bRoR2ca_GRCvIVITioUqPzWLFAAe9VXvJ1cWOQVLK4oB40WoomDMgJDH5IcfRLNrGF4r-QskP34i04jobASQn6puBymkn-c-HJe1uEHxE6w22UVZqONses9SqYVaFP2AbptPQNuYktqrONKm-Plavo4ijPA-D2AE2ltQL7jfXK-XQGjSk7PxJ7prK6khLpbk2Snn4B5bgWrD8QTa784SM10fMMCzr6xKvjr5ZZYItTAID6kZ2k5x8cXUCede8IRvqweBdeIOYv7KIP4IvukxIbBlcfM59wF1sqtEiLwd5r2RARxscl1-_FF6i7kXTdY2F4N3nik70",
"e": "AQAB",
"d": "FUl4z0NbKhUyGRxurspzptLTVo8A9ymgau0sc86LLHnDaGkYOq0hg64HFjxCBjjqi-I0163UPs4vpoOMlehy1Irn3AyNXP1PlbhCK6BoaYQ0xuLmUJW_efVgk5vd5Rmlk1fyOc4BapGwN_g9QR5UeKJD0jKWrro1wtGuCxf0GiPm2TymZrgwKl2qnJxXJ7GpIWzai1IKQx-GD_MsMQ-x0WaZC8EnCzrHi8R_AoUhw1HwMdIpGe0sUmhMuE7OsHS-eDYucHE-IH6GMIsi6DdVWV6Saji2cKJVbXwRvypXvU_r8yornjMiRUAXAr5L7PPpL9Fmt6uHR47kqYtpy2iAd2SWNa6yvDzYGnV3N-Eq_7tRvsr8IiWVWqpH7NpDDMHseVobtm0gzLtgrUDhlGkGid0Mt2pCBnYMiECtiE4zcz0u9OifEcyUgbuKKdTZs1F24u6MCUJF-N2s6juNL-iE3cK3QAXPLmsXGy0rr3P7q5N9i_4x1Ha2XOSbyU_gb-EAaXEUTRgQdLSmj85H2UIudqwS63MYVTDpFmHZraVN-jxsBPISN6EAcRvBFbqUpq7rwHJrbQECKbuB12xm9iv4gpabUl_RaempTJNodDQNY5hc3i4e2Vr0FpY_yThbQ1vn444TexdSCJ1Sp2wjI10hwpr4zV5k-7KKDmqBEND8VAk",
"p": "yiMeDN349vQgClqAaUI2j2Wv_SUR9VW33Y6ftkMaxz67nsA0X621Y4e41V_npd3YRM5rQr4hTWfovn-Te1N3R57zmfF3z5RyzdKflNgQAe9cryNoa5s5AUP4MYnlkZE740UlNTV5VUeVp_3HoB83lvnVAT2mmKLa4cgBKzT6i97HtotBT6in7tdkeQQmqM4T9dX7G_9v9AjOwXJVqLJlxsVwplm-_2sBoFutlpBkcL46SeNIQm1aGvF2A7Vgfc1qlVG_PDu8UuxFZ_p_Onl52Cwx6-p_hAosiA44o6KJIet2jTa28hjT516nmDaO1juMGWPw-rDpx3VrD_mhRglk3w",
"q": "xTwhHr7PnBYHJq1F2DiTR_MrCh2x0lcc3x_9OAhrVGfvGUO2Rn5gFxTDzbFgIJx7-Anc4AzWghvD_4xBGX5nYKZgCo_kmZzwWpDtUVUl_0tDn7srgVXrRgodd9eVpuMUn8o2lGp0qoYqW4ZX_V2wGDxsQHYwxuXEl7KgweGaLkYTdCGmC0yW5GSuDDkcipurLqmvTbE8uDfORhvXPKieVohZUJtNfltX7rMBVZ0NKv0PCT4XTCwwknU7qi7_xb643NdVvWeIp2Q-exN9ZGu4qm-uR85nNZNPUw4_YStI1cmwAkcswQMT70ydWvoKJtaHJN7_fnpkP1TaS63uVcQe4w",
"dp": "Bs9oE8bmvGs9KRwjd2hjrjEe3MiC8mEQ8MX9W4anQE88wvx2x0Jy-gd4krfIdi4jOy45LuZ4-MKndMOXlHAbdK5GRsl73-KAe6688abV4zrNRJlMy1NPeFtx4TlkIqNiASYzOreyfs0Knb5PG3XxyYRhSMlq83mJJlI2t93xEwVOdTf721MzVTisiec55jYLNh0feLICc5ZYYOwZNrXL-AZu5Svg43oXc--iyY_T0niWPicKKDLG9mFsOHPD7HkfPiii6MSac7DCJd6qqq2tDTtv8yLTaP9uwKa6AclYFWx5cgiF4WI0wXbO7rHn3g_jiHd1hvyu46lxEfi3FkT6wQ",
"dq": "Nh7Eu8oB78N_nNZI5wbHKyQHeFQjmiL7MiJ1-i0dPmDyk80ns_ozZcH15Hg6d1hZD_us1vHO3o693l5e8p7jwPqGOf-364rLzR4dcIbb0UyWtrrGOkwYLfTSlzLZxpxi6WG0Tk9TygLclpariENv8YaK8bk8sycTJckHIYxFIVNrPR-Kj2kpsmwJ8iKtuT7z3u8Cwl_S2H2_pS84hVWDdR0e3OZwgi6QV1hZEmPw3A3qVU_rVqR9g4KVp6IT3u_xi--ugDVrovr3xg_YBXklh-bzPJLfcS0FxDWRoJke-ELKgCWFm0S78JrmRrN7m6KcHLrwAoWVAmfHKqMEVhZlnw",
"qi": "Qp55BbUd_Ef34ykWalS-NE9TzHgQ7XbSnSfaJ7Xs0uRcoP6EDF2-QhhTKkN55xu5LVTSbrzwmQNOGymL7ZQ6J_nXbrtviD2gzDLSyqAZ7lfBdXw8pCgf0r3EVhA16uq6EsmNQzj4Ec1RLe4taD9EXPgJvwQpvyFNZJ76RkVpzzadhGMD192645ElgdsiBegbJLI0iOMBI4dJHhvJ5on96WohUY5FBVnmibvA_sIAJfyyuoHYPxJYRkRVx18NoQR9eYrUsJOWNYM7GYL4zbi0iev14BuDhUg1b-PlTAnZTleuY-eTrkFrW99TkVU1M3DOQJ0pUcFjqE1x29xVGRJJuA"
}
]
}
179 changes: 179 additions & 0 deletions automation/dbildungs-iam-server/cron/scripts/get_access_token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#!/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}"
backend_hostname="${BACKEND_HOSTNAME}"

echo "BACKEND_HOSTNAME is $backend_hostname"
echo "KC_CLIENT_ID is $clientId"
echo "KC_TOKEN_URL is $kc_token_url"
echo "JWKS_FILE_PATH is $JWKS_FILE_PATH"

# 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" <<EOF
asn1=SEQUENCE:private_key
[private_key]
version=INTEGER:0
n=INTEGER:0x$n_dec
e=INTEGER:0x$e_dec
d=INTEGER:0x$d_dec
p=INTEGER:0x$p_dec
q=INTEGER:0x$q_dec
dp=INTEGER:0x$dp_dec
dq=INTEGER:0x$dq_dec
qi=INTEGER:0x$qi_dec
EOF

echo "Starting to generate PEM-formatted private key" >> /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 <<EOF
{
"iss": "$clientId",
"sub": "$clientId",
"aud": "$kc_token_url",
"jti": "$jti",
"exp": $exp_time
}
EOF
)
payload_base64=$(base64url_encode "$payload")

# Combine header and payload
header_payload="$header_base64.$payload_base64"

echo "Payload created" >> /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=$(curl -s -X POST "$kc_token_url" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$clientId" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=$jwt_assertion")

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
8 changes: 8 additions & 0 deletions automation/dbildungs-iam-server/cron/scripts/trigger_xyz.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
echo "Trigger XYZ executed at $(date)" >> /var/log/cron.log

# Call get_access_token.sh and capture the access token
access_token=$(./get_access_token.sh)

# Use the access token as needed
echo "Access token obtained: $access_token"
2 changes: 1 addition & 1 deletion automation/dbildungs-iam-server/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +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_BIND_DN: "{{ .Values.ldap.bindDN }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
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 }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
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 }}
trigger_xyz.sh: |-
{{ .Files.Get "cron/scripts/trigger_xyz.sh" | nindent 4 }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: onepassword.com/v1
kind: OnePasswordItem
metadata:
name: cronjob-secret-service-acc-jwks
namespace: {{ template "common.names.namespace" . }}
labels:
app.kubernetes.io/managed-by: helm
spec:
itemPath: "vaults/spsh-dev-schulportal/items/dbildungs-iam-server"

70 changes: 70 additions & 0 deletions automation/dbildungs-iam-server/templates/cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{{- range $job_name, $job_options := .Values.cronjobs.jobs }}
apiVersion: batch/v1
kind: CronJob
metadata:
name: dbp-1022-cronjob-dev-{{ $job_name}}
#name: {{ template "common.names.namespace" $ }}-{{ $job_name}}
namespace: {{ template "common.names.namespace" $ }}
spec:
schedule: {{ $job_options.schedule }}
startingDeadlineSeconds: 300
suspend: true
jobTemplate:
spec:
backoffLimit: 0
template:
metadata:
labels:
test: dbildungs-iam-server-{{ $job_name }}
pod: {{ $job_name }}
spec:
automountServiceAccountToken: false
containers:
- name: {{ $job_name }}
image: alpine:{{ $.Values.cronjobs.imageTag }}
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
envFrom:
- configMapRef:
name: cronjob-envs-configmap
env:
- name: BACKEND_HOSTNAME
value: "{{ $.Values.backendHostname }}{{ $job_options.endpoint }}"
command:
- "sh"
- "-c"
- |
apk update &&
apk add --no-cache bash openssl curl cronie jq vim &&
mkdir /scripts &&
cp /scripts_tmp/*.sh /scripts/ &&
chmod +x /scripts/*.sh &&
chmod 600 /etc/crontabs/root &&
touch /var/log/cron.log &&
chmod 644 /var/log/cron.log &&
cd {{ $.Values.cronjobs.scriptDir}} &&
./{{ $job_options.script}}
volumeMounts:
- name: secret-volume-jwks
mountPath: /keys
readOnly: true
- name: script-volume
mountPath: /scripts_tmp
readOnly: false
ports:
- containerPort: {{ $.Values.cronjobs.port }}
name: trigger-xyz-pod
volumes:
- name: script-volume
configMap:
name: cronjob-scripts-configmap
- name: secret-volume-jwks
secret:
secretName: cronjob-secret-service-acc-jwks
items:
- key: service-account-private-jwks
path: jwks.json
restartPolicy: Never
---
{{- end}}
Loading

0 comments on commit 8708ac2

Please sign in to comment.