diff --git a/k8s/argocd/apps/phase3-iam-0.yaml b/k8s/argocd/apps/phase3-iam-0.yaml new file mode 100644 index 0000000..9bd837a --- /dev/null +++ b/k8s/argocd/apps/phase3-iam-0.yaml @@ -0,0 +1,63 @@ +# Phase 3 — IAM (Authentik + Vault) — identity/secret-critical releases + +--- +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 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: vault + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + sources: + - repoURL: https://helm.releases.hashicorp.com + chart: vault + targetRevision: latest + helm: + valueFiles: + - k8s/talos-iam/vault-values.yaml + - k8s/talos-iam/vault-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/argocd/apps/phase3-llm.yaml b/k8s/argocd/apps/phase3-llm.yaml new file mode 100644 index 0000000..a4421a9 --- /dev/null +++ b/k8s/argocd/apps/phase3-llm.yaml @@ -0,0 +1,32 @@ +# Phase 3 — LLM (Ollama with OIDC) + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ollama + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + project: homelab + sources: + - repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/llm/charts/ollama + helm: + valueFiles: + - values.yaml + - k8s/llm/ollama-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: llm + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/argocd/apps/phase3-workflows.yaml b/k8s/argocd/apps/phase3-workflows.yaml new file mode 100644 index 0000000..42bc9eb --- /dev/null +++ b/k8s/argocd/apps/phase3-workflows.yaml @@ -0,0 +1,59 @@ +# Phase 3 — Workflows (Temporal + Story Crater Migrations) + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: temporal + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + sources: + - repoURL: https://go.temporal.io/helm-charts + chart: temporal + targetRevision: "~0.55" + helm: + valueFiles: + - k8s/temporal/temporal-values.yaml + - k8s/temporal/temporal-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: temporal + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: story-crater-migrations + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + project: homelab + source: + repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/story-crater-backend/charts/migrations-noop + helm: + valueFiles: + - values.yaml + destination: + server: https://kubernetes.default.svc + namespace: story-crater-backend + 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..606f1f5 --- /dev/null +++ b/k8s/hooks/phase3/phase3-hooks.yaml @@ -0,0 +1,224 @@ +# ArgoCD Hook Jobs for Phase 3 releases + +--- +# ── 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 (OIDC provisioning requires bootstrap token from secrets)" + echo "✓ OIDC provisioning placeholder" + +--- +# ── Vault — PreSync: MinIO Creds & Bucket ──────────────────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: vault-minio-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: minio-setup + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Creating Vault MinIO secrets..." + # Note: MinIO creds from secrets.enc.yaml should be available + echo "Vault MinIO setup (credentials from SOPS secrets)" + echo "✓ Vault MinIO placeholder" + +--- +# ── Temporal — PreSync: Elasticsearch & Secrets ─────────────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: temporal-elasticsearch-setup + namespace: temporal + 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: es-setup + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Setting up Temporal Elasticsearch..." + kubectl create namespace temporal --dry-run=client -o yaml | kubectl apply -f - + kubectl apply -f k8s/temporal/elasticsearch.yaml || echo "ES already exists" + echo "✓ Elasticsearch setup" + +--- +# ── Ollama — PreSync: Namespace & Secrets ──────────────────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: ollama-namespace-setup + namespace: llm + 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: ns-setup + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Setting up Ollama 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 2>/dev/null || true + echo "✓ Ollama namespace setup" + +--- +# ── Story Crater Migrations — PostSync: Run Migrations ──────────────────────── + +apiVersion: batch/v1 +kind: Job +metadata: + name: story-crater-migrations-run + namespace: story-crater-backend + 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: migrations + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + echo "Running Story Crater migrations..." + # Note: actual migrations require CNPG cluster to be ready + echo "Migrations placeholder (requires CNPG + Vault secrets)" + echo "✓ Migrations setup" + +--- +# ── 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"] + - apiGroups: ["batch"] + resources: ["jobs"] + verbs: ["get", "list", "create"] + +--- +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/llm/ollama-secrets.enc.yaml b/k8s/llm/ollama-secrets.enc.yaml new file mode 100644 index 0000000..4b432fa --- /dev/null +++ b/k8s/llm/ollama-secrets.enc.yaml @@ -0,0 +1,20 @@ +ollama: + minio_access_key: ENC[AES256_GCM,data:8GM6GyPNs1SfTQ==,iv:D03MJ5BbmgkQZXreDb8ZdwG7Jc+FBPOPVUezHrdahQU=,tag:7BAugt9R+d5QdMtJsUFYnQ==,type:str] + minio_secret_key: ENC[AES256_GCM,data:IEJ2WoG6mOXNWtdPFrkd2DPNilLE0mL+pHDhD24sLjhV+b+I5vhclArrqX4=,iv:z9LeIP/CWv9MACvve22ioNZIc7oD12y0jMwYO4Zv+o8=,tag:PrK7BKTHeo9c4+QSdSO9Ww==,type:str] + oidc_client_id: ENC[AES256_GCM,data:r0UT39bX,iv:bOlH3El5VrFyyGFnV3m9XEGhKoxpqWbwX0Aoh9jEq0E=,tag:9yZnVGhMn5MsKvlRrYS02Q==,type:str] + oidc_client_secret: ENC[AES256_GCM,data:6DcQW8t9SvRgc95jQa04sfv9vTE=,iv:RmYLyXG+SbQUmir5j40r3KK2enA9YzJPnlW5Z1Vtkzo=,tag:MVka9N+FU0OLp9dkcYehZA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5OHMzZmtNOXp0L3h4Y3Zl + LzBxaHkrSDl6eVJ6b1JqTXdNZzdGSHI3M0VJCmwwYStjSXhOR2orRFJQYy94aXBn + clpxV1ZSdko4UFl1OUM2QW5uTmZKcGMKLS0tIG9lMnFTanpicDJRTDY4K1pjOEpm + NnV3TS9rZzdGd0tmZXNuOUVPbXBVbU0KRoWu536ZUSDg+a5XiLbP8TpVlEcpolo1 + Gtj3sjaRTdWwguiNlhmxIzpdb+88mYbDJIerotDIknnc1oWvcOgq6Q== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-15T23:22:55Z" + mac: ENC[AES256_GCM,data:4bGmma4shLOaZZ7VJB9JIQ8x3qZrrGR3b6FBE5/J7GBwxVdu/mg9xi/VlgFwDd1axrQ/DuFczJdnK4YtYe9tVLpJzoWXJt93T4BXEmthhIDzn+G2bWqogqAwqVncMwz6PXrrP8TI0pgZz2KvGBU03FESN8ymU54X9uPc63YZPjI=,iv:ZBPy2GzEKMq66Lh/4vhhGf0PVpdyR4EhpkOtWRQRcPg=,tag:a37rAAM+lglbexcwM5lrKQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.2 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/talos-iam/vault-secrets.enc.yaml b/k8s/talos-iam/vault-secrets.enc.yaml new file mode 100644 index 0000000..8f2fd7a --- /dev/null +++ b/k8s/talos-iam/vault-secrets.enc.yaml @@ -0,0 +1,18 @@ +vault: + minio_access_key: ENC[AES256_GCM,data:9xlDx4SYgo/ziA==,iv:M2ZTUgTwpF6XIIAYV6fl/uJDkWDx3BNq1AAB8cwHlTc=,tag:L6SeSdzkYsZeNiZSLyIABQ==,type:str] + minio_secret_key: ENC[AES256_GCM,data:SqR1gnc2w0ojHBQWKlHbtl/8CxvVRZYuo/4/Y1Ywo3L1YqjBJJ3kaBgImN4=,iv:+OPeOUeofyotnTOX3VbN69KX7sudxulzDW6hcyy3aX0=,tag:AyODMQmENoMxoaTANeBlCA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnVFdBNkVNdWxiRVloRVFh + WmJsYWxyQkxWTDQrd094QkR1c0VjbHZkYVdNCmtwNitJeTFFR0FzVTBCOFppdnM5 + bjJMQzNvWnVzU0hINkdGenBJcUI3SWcKLS0tIFRESlBrY0JiQ3JIOEhxNUZ5bFpD + M2JFcVJmYUdjVEo4SzNDSHZLRnJKSjAKA6IgXmTVf1D0sWl3TaM+8Aa/zOFrJmOv + u3jxLXNczAUxO1YeDcmfaztyV0GW0cNwlk2yZoGlcqU/vqCL0Thxvw== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-15T23:22:55Z" + mac: ENC[AES256_GCM,data:Jk9xbLYxXyAeOky2yqDfmYcvIxUGQ45aiWAnUXu9mOZAprjtVxm2meqxqietn8q4fL1t4WLY+Rp19K+zmdX4qDgiMb0qpz0bdm3JurP8L3UYVld9nGxoqk5hZPmnvG3Iv8mwCL9L/GZFUYSGxUHEZMZXqfKw0K+MoU6CEx8mC14=,iv:BGxZ/pB5kz3js00lYfYU9Cuby1IHZX6FiINkLS1EJ+w=,tag:HHa7qCUBYxCUlglUEZBBUg==,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