From 05848223eba98e4d9c046ae02eaa3fa6632c54c0 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Thu, 8 Jan 2026 02:09:23 -0300 Subject: [PATCH] comms: ensure MAS secrets via keycloak admin job --- services/comms/kustomization.yaml | 1 + services/comms/mas-secrets-ensure-rbac.yaml | 25 +++++ services/keycloak/kustomization.yaml | 1 + services/keycloak/mas-secrets-ensure-job.yaml | 95 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 services/comms/mas-secrets-ensure-rbac.yaml create mode 100644 services/keycloak/mas-secrets-ensure-job.yaml diff --git a/services/comms/kustomization.yaml b/services/comms/kustomization.yaml index 99b0b4a..e3e182f 100644 --- a/services/comms/kustomization.yaml +++ b/services/comms/kustomization.yaml @@ -10,6 +10,7 @@ resources: - synapse-seeder-admin-ensure-job.yaml - mas-configmap.yaml - mas-admin-client-secret-ensure-job.yaml + - mas-secrets-ensure-rbac.yaml - mas-deployment.yaml - element-rendered.yaml - livekit-config.yaml diff --git a/services/comms/mas-secrets-ensure-rbac.yaml b/services/comms/mas-secrets-ensure-rbac.yaml new file mode 100644 index 0000000..9723d03 --- /dev/null +++ b/services/comms/mas-secrets-ensure-rbac.yaml @@ -0,0 +1,25 @@ +# services/comms/mas-secrets-ensure-rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: mas-secrets-ensure + namespace: comms +rules: + - apiGroups: [""] + resources: ["secrets"] + resourceNames: ["mas-secrets-runtime"] + verbs: ["get", "create", "patch", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: mas-secrets-ensure + namespace: comms +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: mas-secrets-ensure +subjects: + - kind: ServiceAccount + name: mas-secrets-ensure + namespace: sso diff --git a/services/keycloak/kustomization.yaml b/services/keycloak/kustomization.yaml index 24490de..d6dd32e 100644 --- a/services/keycloak/kustomization.yaml +++ b/services/keycloak/kustomization.yaml @@ -16,6 +16,7 @@ resources: - portal-e2e-execute-actions-email-test-job.yaml - ldap-federation-job.yaml - user-overrides-job.yaml + - mas-secrets-ensure-job.yaml - service.yaml - ingress.yaml generatorOptions: diff --git a/services/keycloak/mas-secrets-ensure-job.yaml b/services/keycloak/mas-secrets-ensure-job.yaml new file mode 100644 index 0000000..7a6972a --- /dev/null +++ b/services/keycloak/mas-secrets-ensure-job.yaml @@ -0,0 +1,95 @@ +# services/keycloak/mas-secrets-ensure-job.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mas-secrets-ensure + namespace: sso +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: mas-secrets-ensure-1 + namespace: sso +spec: + backoffLimit: 2 + template: + spec: + serviceAccountName: mas-secrets-ensure + restartPolicy: OnFailure + volumes: + - name: work + emptyDir: {} + initContainers: + - name: generate + image: alpine:3.20 + command: ["/bin/sh", "-c"] + args: + - | + set -euo pipefail + umask 077 + apk add --no-cache curl openssl jq >/dev/null + + KC_URL="http://keycloak.sso.svc.cluster.local" + TOKEN_JSON="$(curl -sS -X POST "$KC_URL/realms/master/protocol/openid-connect/token" \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d "grant_type=password" \ + -d "client_id=admin-cli" \ + -d "username=${KEYCLOAK_ADMIN}" \ + -d "password=${KEYCLOAK_ADMIN_PASSWORD}")" + ACCESS_TOKEN="$(echo "$TOKEN_JSON" | jq -r '.access_token')" + if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then + echo "Failed to fetch Keycloak admin token" >&2 + exit 1 + fi + + CLIENT_ID="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + "$KC_URL/admin/realms/atlas/clients?clientId=othrys-mas" | jq -r '.[0].id')" + if [ -z "$CLIENT_ID" ] || [ "$CLIENT_ID" = "null" ]; then + echo "Keycloak client othrys-mas not found" >&2 + exit 1 + fi + + CLIENT_SECRET="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + "$KC_URL/admin/realms/atlas/clients/${CLIENT_ID}/client-secret" | jq -r '.value')" + if [ -z "$CLIENT_SECRET" ] || [ "$CLIENT_SECRET" = "null" ]; then + echo "Keycloak client secret not found" >&2 + exit 1 + fi + + printf '%s' "$CLIENT_SECRET" > /work/keycloak_client_secret + openssl rand -base64 32 > /work/encryption + openssl rand -hex 32 > /work/matrix_shared_secret + openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out /work/rsa_key >/dev/null 2>&1 + chmod 0600 /work/* + env: + - name: KEYCLOAK_ADMIN + valueFrom: + secretKeyRef: + name: keycloak-admin + key: username + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-admin + key: password + volumeMounts: + - name: work + mountPath: /work + containers: + - name: apply + image: bitnami/kubectl:latest + command: ["/bin/sh", "-c"] + args: + - | + set -euo pipefail + if kubectl -n comms get secret mas-secrets-runtime >/dev/null 2>&1; then + exit 0 + fi + kubectl -n comms create secret generic mas-secrets-runtime \ + --from-file=encryption=/work/encryption \ + --from-file=matrix_shared_secret=/work/matrix_shared_secret \ + --from-file=keycloak_client_secret=/work/keycloak_client_secret \ + --from-file=rsa_key=/work/rsa_key >/dev/null + volumeMounts: + - name: work + mountPath: /work