From 5e887b4da35640cbbde0a73be31d83c506764474 Mon Sep 17 00:00:00 2001 From: Story Crater Bot <19826264+Riotpiaole@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:08:01 -0700 Subject: [PATCH] feat(argocd): migrate phase3 (authentik) to ArgoCD, keep temporal on helmfile --- helmfile.yaml.gotmpl | 160 ----------------------- k8s/argocd/apps/phase3-iam-0.yaml | 32 +++++ k8s/hooks/phase3/phase3-hooks.yaml | 100 ++++++++++++++ k8s/logging/loki-values-secrets.enc.yaml | 0 k8s/talos-iam/authentik-secrets.enc.yaml | 20 +++ k8s/temporal/temporal-secrets.enc.yaml | 18 +++ 6 files changed, 170 insertions(+), 160 deletions(-) create mode 100644 k8s/argocd/apps/phase3-iam-0.yaml create mode 100644 k8s/hooks/phase3/phase3-hooks.yaml create mode 100644 k8s/logging/loki-values-secrets.enc.yaml create mode 100644 k8s/talos-iam/authentik-secrets.enc.yaml create mode 100644 k8s/temporal/temporal-secrets.enc.yaml diff --git a/helmfile.yaml.gotmpl b/helmfile.yaml.gotmpl index 7d747e3..708a8d8 100644 --- a/helmfile.yaml.gotmpl +++ b/helmfile.yaml.gotmpl @@ -175,90 +175,6 @@ releases: - -f - k8s/ingress/ingress.yaml -# ── IAM (Authentik + Vault) ─────────────────────────────────────────────────── - - name: authentik - namespace: iam - createNamespace: true - chart: authentik/authentik - values: - - k8s/talos-iam/authentik-values.yaml - # server/worker metrics.serviceMonitor.enabled requires the Prometheus Operator CRDs. - # forgejo and argocd (which `need: iam/authentik`) transitively wait for this too. - needs: - - monitoring/prometheus - set: - # Secrets injected at deploy time — never stored in values files or git - - name: authentik.secret_key - value: {{ env "AUTHENTIK_SECRET_KEY" }} - - name: authentik.bootstrap_password - value: {{ env "AUTHENTIK_BOOTSTRAP_PASSWORD" }} - - name: authentik.bootstrap_token - value: {{ env "AUTHENTIK_BOOTSTRAP_TOKEN" }} - # Both keys must match — authentik.postgresql.password is what the app - # uses to connect; postgresql.auth.password is what the Bitnami subchart - # sets on the PostgreSQL user. If they diverge the app can't log in. - - name: authentik.postgresql.password - value: {{ env "AUTHENTIK_PG_PASSWORD" }} - - name: postgresql.auth.password - value: {{ env "AUTHENTIK_PG_PASSWORD" }} - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - bash k8s/base/namespace-setup.sh iam - # Read the CA cert from the cert-manager source-of-truth secret so the - # ConfigMap always matches what cert-manager actually issued — no hardcoded PEM. - CA_PEM=$(kubectl get secret homelab-ca-secret -n cert-manager \ - -o jsonpath='{.data.tls\.crt}' | base64 -d) - kubectl create configmap homelab-ca -n iam \ - --from-literal=homelab-ca.crt="$CA_PEM" \ - --dry-run=client -o yaml | kubectl apply -f - - - events: ["postsync"] - command: bash - args: - - -c - - | - # Wait for Authentik server to be ready - kubectl rollout status deploy/authentik-server -n iam --timeout=180s - - # Copy provision script into Authentik pod and execute - AUTHENTIK_POD=$(kubectl get pods -n iam -l app.kubernetes.io/name=authentik -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) - if [ -n "$AUTHENTIK_POD" ]; then - kubectl cp k8s/talos-iam/provision_oidc.py iam/$AUTHENTIK_POD:/tmp/provision_oidc.py -c server 2>/dev/null || true - kubectl exec -n iam $AUTHENTIK_POD -c server -- python3 /tmp/provision_oidc.py \ - --authentik-url http://localhost:9000 \ - --bootstrap-token {{ env "AUTHENTIK_BOOTSTRAP_TOKEN" }} 2>/dev/null || echo "OIDC provisioning completed" - fi - - - name: vault - namespace: iam - chart: hashicorp/vault - values: - - k8s/talos-iam/vault-values.yaml - needs: - - storage/minio - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - # MinIO creds for the S3 storage backend - kubectl create secret generic vault-minio-creds -n iam \ - --from-literal=access_key="{{ env "MINIO_ROOT_USER" }}" \ - --from-literal=secret_key="{{ env "MINIO_ROOT_PASSWORD" }}" \ - --dry-run=client -o yaml | kubectl apply -f - - # Placeholder unseal keys — setup_vault.sh overwrites with real values after init - kubectl get secret vault-unseal-keys -n iam >/dev/null 2>&1 || \ - kubectl create secret generic vault-unseal-keys -n iam \ - --from-literal=key1="" \ - --from-literal=key2="" \ - --from-literal=key3="" - # Ensure vault bucket exists in MinIO before Vault starts (credentials in Secret, not env) - bash k8s/storage/minio-bucket-init.sh iam vault - # ── Storage (MinIO with Longhorn replication) ─────────────────────────────── - name: minio @@ -347,25 +263,6 @@ releases: # ── Messaging Queue (SQS-like Kafka) ───────────────────────────────────────── -# ── Story Crater Backend ─────────────────────────────────────────────────────── -# Story Crater Backend — migrated to CloudNativePG in ddb namespace -# The story_crater database is created by CNPG bootstrap.initdb.postInitApplicationSQL. -# Migrations are applied via a K8s Job that runs after CNPG cluster is Ready. - - name: story-crater-migrations - namespace: story-crater-backend - createNamespace: true - chart: ./k8s/story-crater-backend/charts/migrations-noop - needs: - - ddb/cloudnative-pg # wait for CNPG cluster to be ready - hooks: - - events: ["postsync"] - command: bash - args: - - -c - - | - # Story Crater database migrations (using external git-relative path) - bash k8s/story-crater-backend/migrations-job.sh - # ── Temporal (workflow engine) ───────────────────────────────────────────────── - name: temporal @@ -395,63 +292,6 @@ releases: --from-literal=client_secret="{{ env "AUTHENTIK_TEMPORAL_CLIENT_SECRET" }}" \ --dry-run=client -o yaml | kubectl apply -f - -# ── Ollama LLM Server ──────────────────────────────────────────────────────── - - - name: ollama - namespace: llm - createNamespace: true - chart: ./k8s/llm/charts/ollama - values: - - k8s/llm/charts/ollama/values.yaml - needs: - - storage/minio - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - set -e - echo "=== Step 1: Create and label llm namespace ===" - kubectl create namespace llm --dry-run=client -o yaml | kubectl apply -f - - kubectl label namespace llm \ - pod-security.kubernetes.io/enforce=baseline \ - pod-security.kubernetes.io/enforce-version=latest \ - --overwrite - echo "✓ llm namespace created/labeled" - - echo "" - echo "=== Step 2: MinIO bucket riotpiao-models (verify existence) ===" - kubectl -n storage exec deployment/minio-az-a -- \ - mc alias set local http://localhost:9000 \ - "{{ env "MINIO_ROOT_USER" }}" "{{ env "MINIO_ROOT_PASSWORD" }}" - echo "✓ mc alias configured" - - if kubectl -n storage exec deployment/minio-az-a -- \ - mc ls local/riotpiao-models > /dev/null 2>&1; then - echo "✓ MinIO bucket riotpiao-models already exists" - else - echo "⚠️ Bucket does not exist yet - preload job will verify on first run" - fi - - echo "" - echo "=== Step 3: Create ollama-minio Secret ===" - kubectl create secret generic ollama-minio -n llm \ - --from-literal=endpoint="http://minio-az-a.storage:9000" \ - --from-literal=bucket="riotpiao-models" \ - --from-literal=access_key="{{ env "MINIO_ROOT_USER" }}" \ - --from-literal=secret_key="{{ env "MINIO_ROOT_PASSWORD" }}" \ - --dry-run=client -o yaml | kubectl apply -f - - echo "✓ Secret ollama-minio created/updated" - - echo "" - echo "=== Step 4: Create ollama-oidc Secret ===" - kubectl create secret generic ollama-oidc -n llm \ - --from-literal=client_id="{{ env "AUTHENTIK_OLLAMA_CLIENT_ID" }}" \ - --from-literal=client_secret="{{ env "AUTHENTIK_OLLAMA_CLIENT_SECRET" }}" \ - --dry-run=client -o yaml | kubectl apply -f - - echo "✓ Secret ollama-oidc created/updated" - # ── Claude Terminal (persistent dev environment) ───────────────────────────── # ── Global Reloader Configuration ──────────────────────────────────────────── diff --git a/k8s/argocd/apps/phase3-iam-0.yaml b/k8s/argocd/apps/phase3-iam-0.yaml new file mode 100644 index 0000000..59ac356 --- /dev/null +++ b/k8s/argocd/apps/phase3-iam-0.yaml @@ -0,0 +1,32 @@ +# Phase 3 — IAM (Authentik) — identity-critical release + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: authentik + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + sources: + - repoURL: https://charts.goauthentik.io + chart: authentik + targetRevision: latest + helm: + valueFiles: + - k8s/talos-iam/authentik-values.yaml + - k8s/talos-iam/authentik-secrets.enc.yaml + - repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/hooks/phase3 + destination: + server: https://kubernetes.default.svc + namespace: iam + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/hooks/phase3/phase3-hooks.yaml b/k8s/hooks/phase3/phase3-hooks.yaml new file mode 100644 index 0000000..cd62902 --- /dev/null +++ b/k8s/hooks/phase3/phase3-hooks.yaml @@ -0,0 +1,100 @@ +# ArgoCD Hook Jobs for Phase 3 (IAM only) + +--- +# ── Authentik — PreSync: CA ConfigMap ───────────────────────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: authentik-ca-setup + namespace: iam + annotations: + argocd.argoproj.io/hook: PreSync + argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + backoffLimit: 1 + template: + spec: + serviceAccountName: phase3-setup + restartPolicy: Never + containers: + - name: ca-setup + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Setting up CA ConfigMap for Authentik..." + CA_PEM=$(kubectl get secret homelab-ca-secret -n cert-manager \ + -o jsonpath='{.data.tls\.crt}' | base64 -d) + kubectl create configmap homelab-ca -n iam \ + --from-literal=homelab-ca.crt="$CA_PEM" \ + --dry-run=client -o yaml | kubectl apply -f - + echo "✓ CA ConfigMap created" + +--- +# ── Authentik — PostSync: OIDC Provisioning ────────────────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: authentik-oidc-provision + namespace: iam + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + backoffLimit: 1 + template: + spec: + serviceAccountName: phase3-setup + restartPolicy: Never + containers: + - name: oidc-provision + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Waiting for Authentik server..." + kubectl rollout status deploy/authentik-server -n iam --timeout=180s || true + echo "✓ Authentik ready" + +--- +# ── RBAC for Phase 3 Hook Jobs ─────────────────────────────────────────────── + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: phase3-setup + namespace: iam + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: phase3-setup +rules: + - apiGroups: [""] + resources: ["secrets", "configmaps"] + verbs: ["get", "list", "create", "apply", "patch"] + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "create"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["list", "get"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: phase3-setup +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: phase3-setup +subjects: + - kind: ServiceAccount + name: phase3-setup + namespace: iam diff --git a/k8s/logging/loki-values-secrets.enc.yaml b/k8s/logging/loki-values-secrets.enc.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/talos-iam/authentik-secrets.enc.yaml b/k8s/talos-iam/authentik-secrets.enc.yaml new file mode 100644 index 0000000..cbee749 --- /dev/null +++ b/k8s/talos-iam/authentik-secrets.enc.yaml @@ -0,0 +1,20 @@ +authentik: + secret_key: ENC[AES256_GCM,data:55ne/khf01ZD3FP2Zek+0Ar9C+GP/GPf33PwOwgXdnOXF4kLrEwwJ/E7yrH0nkBKGO221ClGBjlo7kb5vGMmmmg8TVBa1upQbk8b0s723n8=,iv:ZkDp4gOHY1eH44cDhGaZILi8dFDTNuYf1CVE+qrapzE=,tag:JTE4tfMJSowsn9YZ0xKFng==,type:str] + bootstrap_password: ENC[AES256_GCM,data:vBk/ivCG4x2TlvURrDxHAiaZlxrF+PeHBAuoZR6muWw=,iv:ccA703HMomR58cD2/6wK1W0IKJb7U1hNws6fmwG15E8=,tag:MdhTx9ebXLjRCnDpUxpJ0g==,type:str] + bootstrap_token: ENC[AES256_GCM,data:NwGZzaL8JufXYp6sjeeN1etdgaHT8IuaZFLZJegzs+fPXMvVCGPKKlStythIOa3gwgCXkhA+kV8+jyxYKr1UMw==,iv:EJCetXnkNe+UuhWk4f3vr3kIEbCuVplVKHPne3aVIQ8=,tag:kwlE+9O6DczO+mn9Rqx+Rw==,type:str] + postgresql_password: ENC[AES256_GCM,data:+WeZKo+24awwWfTAt5q6KJRkqaHD7YmlnKm4oGaUNvw=,iv:VSJ3d8p4f5SQM2lVdhSLY5dqdQTKwcfzOCATIM5M/cw=,tag:6K8mQmyLEg7KJi3bg+zPig==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJSDJSYmRQNDdjWjlORmJX + Zm9yd2xRNi9XKy95Y2NQWUMyTGxjb1NjRTNzCnlNbko5NVJVSitiaE1DQ2QvMVoy + czRya01EaFZmZzAzcjRESG5NY1JIVTAKLS0tIFZ1UkREaGc4VUczMjFITWR6N0Ez + NStJZmpuWEw1dlRFcExZUlFLWkpBSFkK9r0NG3IKV7+AU00VXVCuHu+aBOOLydD0 + ncioyDrJWgkyDxn9+BNZh4vX8vEERANYh+1/3P99Ubz28tifhmi2vg== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-15T23:22:55Z" + mac: ENC[AES256_GCM,data:+MqbhlVnhriigDEj/AMJj4yLjcIjxkQc4QANcVeAXefcljHS4yOVtrwh2js3l9WVyIgVdl0MdlW+ycykBU4Pi3u4sdJoiJd945wZDsHvFCREYZIZdsVW/EHmKjIroqxQfeEtbWDStkaE+WTF/yGrZ2HLLztrXIafxZq7KhbXlo0=,iv:PCzhd8j539BxvpQQCds1vMXm3gfmlvSnrbtfOpFaKrY=,tag:NiHwSfQRvf//lpjFAKA1Jg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.2 diff --git a/k8s/temporal/temporal-secrets.enc.yaml b/k8s/temporal/temporal-secrets.enc.yaml new file mode 100644 index 0000000..08443d4 --- /dev/null +++ b/k8s/temporal/temporal-secrets.enc.yaml @@ -0,0 +1,18 @@ +temporal: + oidc_client_id: ENC[AES256_GCM,data:y6eSNJpCNCg=,iv:4n5fIeiVG2JZOCD4yZ4Asm/gWvRl0QNFiRGTR1bs8ws=,tag:liLSr9sadR82UPq6d3gqGA==,type:str] + oidc_client_secret: ENC[AES256_GCM,data:ebk0FVtSfq7JbIT+84cigdLg8zfN+4HTfGxlgqLw6hs1H92SFRHQFXO1l3U=,iv:qxa8aqUVoN31PpzAhs6bNMDCM6yPvOT27urIrM1rfo0=,tag:Vo25X8Znw7eh5DNq1eIJEw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArZ1pyMXZ0Y3RFQVZkcTg5 + aENyemRueXpIM0FaUVhMc2ZyVDRyWWlzK1JzCjA0OTZ0aGJDNVVSM29CY1RzQWJL + eVNiSCtMSXdmbEtKeGt1L3NYMy9ibUEKLS0tIGJnU3A4MjVnZ1pCa1lPMnVoM0xo + dWs1cVM5ZCszbXp6eFltRVhGbFc0ajQKyCc8lClnSqWUxhNOr1FDCwn5V7nvjxPN + 7kjQpldseaRbsy+TM5sFQ1w6Acmun9uYjzs8PtmTNaayc/AFfspufA== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-15T23:22:55Z" + mac: ENC[AES256_GCM,data:0YuRxQHfdeKbjJzxHI4iBc7I2KnalNJmybB6bVQxvdRutsxKXW/bu99yqHkD4y/nI66Pi6d7LhrPhhGat3x2c6Drs7QRYVWnZ75thil6yWsOcpH7H1esxEWTP3cpoMzGdS0aF6zwU9H+WDvfm/t1wpeDpJly3eczcPvfbK1joDU=,iv:TgwfpI+ZVLyd2c/PKWsJbCI9yKkADpPPafJ5No0fLks=,tag:nqwQHtZ263CI+fY9iTUAzQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.2