-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
dbildungs-iam-server-gha
committed
Nov 20, 2024
1 parent
1f5bf66
commit db9e784
Showing
11 changed files
with
397 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
FROM alpine:3.19 | ||
|
||
# Install necessary packages | ||
RUN apk update && \ | ||
apk add --no-cache bash cronie curl jq openssl vim | ||
|
||
# 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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} | ||
] | ||
} |
40 changes: 40 additions & 0 deletions
40
automation/dbildungs-iam-server/cron/scripts/cron_trigger.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#!/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=$(curl -s -w "\n%{http_code}" -X "$HTTP_METHOD" "$endpoint_url" \ | ||
-H "Authorization: Bearer $access_token" \ | ||
-H "Content-Type: application/json") | ||
|
||
# Split the response into body and status code | ||
response_body=$(echo "$response" | sed '$d') | ||
http_status=$(echo "$response" | tail -n1) | ||
|
||
# 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 |
172 changes: 172 additions & 0 deletions
172
automation/dbildungs-iam-server/cron/scripts/get_access_token.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
#!/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" <<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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
automation/dbildungs-iam-server/templates/cronjob-envs-configmap.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }}" |
13 changes: 13 additions & 0 deletions
13
automation/dbildungs-iam-server/templates/cronjob-scripts-configmap.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
{{- 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 && | ||
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/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 }} |
Oops, something went wrong.