Coexistence wiring for the Authentik replacement: ZITADEL gets its own CNPG cluster, SOPS masterkey, Helm values and ArgoCD Application in namespace iam. Authentik keeps serving; no consumer is moved and no Authentik object changes. - k8s/infra/databases/zitadel-db.yaml: CNPG Postgres 16.2, 3 instances - k8s/infra/iam/zitadel-values.yaml: chart 10.4.0 pinned, DSN from the CNPG secret, masterkey from a Secret, metrics ServiceMonitor, second-sync caveat - k8s/argocd/apps/30-security.yaml: Application named zitadel, wave 3, automated sync deliberately absent for the first sync (chart PreSync hook re-run risk) - k8s/argocd/secrets/zitadel-masterkey.enc.yaml: 32-byte masterkey, SOPS - k8s/infra/monitoring/alerts/svc-zitadel-rules.yaml: target-down, login-UI, crash-loop and PreSync-job-failed rules - terraform/files/coredns/Corefile: in-cluster rewrite for the zitadel host Not applied. The cluster is mid-incident: vault-0 and authentik-server are 0/1, authentik-db-2 has 14 restarts, prometheus-0 is 1/2 CrashLoopBackOff and kube-state-metrics has 1925 restarts. Two manual steps still gate the first sync: the Cloudflare Tunnel public hostname plus a proxied CNAME, and terraform apply + make apply-cp for the CoreDNS rewrite (Talos-owned). The offline masterkey copy is at ~/zitadel-masterkey.offline (mode 600). Move it to sealed storage and delete it before the first sync. Losing it makes every encrypted ZITADEL value unreadable.
271 lines
8.8 KiB
YAML
271 lines
8.8 KiB
YAML
# Wave 3 — Vault + Authentik (identity), plus IAM raw jobs and the Forgejo
|
|
# runner. Authentik/Vault values reference SOPS-managed secrets (see *.enc.yaml
|
|
# in k8s/infra/iam) resolved by the ArgoCD SOPS plugin at sync time.
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: vault
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
spec:
|
|
project: homelab
|
|
sources:
|
|
- repoURL: https://helm.releases.hashicorp.com
|
|
chart: vault
|
|
targetRevision: "*"
|
|
helm:
|
|
valueFiles:
|
|
- $values/k8s/infra/iam/vault-values.yaml
|
|
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
ref: values
|
|
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: authentik
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
spec:
|
|
project: homelab
|
|
sources:
|
|
- repoURL: https://charts.goauthentik.io
|
|
chart: authentik
|
|
targetRevision: "*"
|
|
helm:
|
|
valueFiles:
|
|
- $values/k8s/infra/iam/authentik-values.yaml
|
|
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
ref: values
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: iam
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
---
|
|
# ZITADEL — the Authentik replacement. Coexistence, not cutover: Authentik keeps
|
|
# serving in the same `iam` namespace until the last consumer moves, then this
|
|
# becomes the only IdP. Migration plan (outside git):
|
|
# ~/workplace/homelab-doc/ZITADEL_MIGRATION.html
|
|
#
|
|
# Wave 3 ordering: sops-secrets (wave 0) creates the `zitadel-masterkey` Secret,
|
|
# databases (wave 2) creates the `zitadel-db` CNPG cluster and its
|
|
# `zitadel-db-app` DSN secret. Both must exist before the init job starts.
|
|
#
|
|
# automated sync is deliberately absent for the first sync — same reason as
|
|
# forgejo. The chart ships `pre-install,pre-upgrade` Helm hooks (zitadel-init,
|
|
# zitadel-setup), which ArgoCD maps to PreSync and re-runs on every sync, manual
|
|
# or automated. A human reads the first sync's hook output before any repeat can
|
|
# run. The init job runs `init zitadel` only (CNPG owns the database and the app
|
|
# user), and the setup job creates the first org and the `iam-admin` machine key
|
|
# that Terraform consumes. Read the SECOND-SYNC HAZARD block at the top of
|
|
# k8s/infra/iam/zitadel-values.yaml before enabling automated sync.
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: zitadel
|
|
namespace: argocd
|
|
finalizers:
|
|
- resources-finalizer.argocd.argoproj.io
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
spec:
|
|
project: homelab
|
|
revisionHistoryLimit: 3
|
|
sources:
|
|
- repoURL: https://charts.zitadel.com
|
|
chart: zitadel
|
|
# Pinned: the chart trails the upstream app release, and the verified
|
|
# masterkey/passwap facts were read at v4.19.x. A floating tag would
|
|
# change the app version without a diff anyone reviews.
|
|
targetRevision: 10.4.0
|
|
helm:
|
|
valueFiles:
|
|
- $values/k8s/infra/iam/zitadel-values.yaml
|
|
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
ref: values
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: iam
|
|
syncPolicy:
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
---
|
|
# Raw IAM manifests: key-rotation cronjob + authentik migration job.
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: iam-jobs
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
spec:
|
|
project: homelab
|
|
source:
|
|
repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
path: k8s/infra/iam
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: iam
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
---
|
|
# Forgejo itself. Was a bootstrap Helm release (phase 3) until it was brought
|
|
# under Argo, because values changes there were inert — a proxy-body-size fix
|
|
# sat committed while the live Ingress kept nginx's 1m default and rejected
|
|
# every OCI push with 413.
|
|
#
|
|
# Wave 3: after databases (wave 2) — Forgejo needs CNPG and Redis up first.
|
|
#
|
|
# Retiring the Helm release: Argo adopts the existing objects on first sync.
|
|
# Delete the release secrets afterwards so helm stops claiming ownership:
|
|
# kubectl -n cicd delete secret -l owner=helm,name=forgejo
|
|
#
|
|
# automated sync is deliberately absent. This chart owns the Forgejo PVC and
|
|
# the git forge itself; the first sync is manual so its diff can be read before
|
|
# anything is applied. Turn on automated+selfHeal once that diff is clean.
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: forgejo
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
spec:
|
|
project: homelab
|
|
sources:
|
|
- repoURL: https://dl.gitea.com/charts/
|
|
chart: gitea
|
|
targetRevision: 12.7.0
|
|
helm:
|
|
valueFiles:
|
|
- $values/k8s/bootstrap/phase3-forgejo/forgejo-values.yaml
|
|
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
ref: values
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: cicd
|
|
# Reloader injects a STAKATER_* env var carrying a hash of the config Secret,
|
|
# so the pod rolls when that Secret changes. The chart does not render it, so
|
|
# Argo would strip it on every sync — and with selfHeal on, Argo and Reloader
|
|
# would fight over the field and Recreate the forge each round.
|
|
ignoreDifferences:
|
|
- group: apps
|
|
kind: Deployment
|
|
name: forgejo-gitea
|
|
jqPathExpressions:
|
|
- '.spec.template.spec.containers[].env[] | select(.name | startswith("STAKATER_"))'
|
|
syncPolicy:
|
|
syncOptions:
|
|
# Adopt the objects the bootstrap Helm release already created rather
|
|
# than failing on "already exists".
|
|
- ServerSideApply=true
|
|
---
|
|
# Forgejo runners (local chart, one instance per language), replacing the
|
|
# single generic "docker"-labeled runner. Each instance is a full standalone
|
|
# Deployment with its own dind sidecar, own PVCs (registration + layer
|
|
# cache) and own registered label -- there is no shared generic runner
|
|
# anymore, so each instance also builds and pushes images for the repos it
|
|
# serves (the chart's ConfigMap/NetworkPolicy fixes for that -- valid_volumes,
|
|
# network: host, egress to ingress-nginx -- apply identically to all three).
|
|
#
|
|
# `values.yaml` is the chart's default and doubles as the golang instance's
|
|
# config; node and rust layer a small values-<lang>.yaml override on top for
|
|
# just runner.name/runner.labels. All three share one runner-token Secret
|
|
# (Forgejo registration tokens are reusable across multiple runners, unlike
|
|
# GitHub's one-time tokens) -- if that assumption is ever wrong, registration
|
|
# will fail loudly in the register initContainer's logs, not silently.
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: forgejo-runner-golang
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
# Image promotion: Forgejo package webhook → api-gw.
|
|
# Replaced ArgoCD Image Updater (removed 2026-09-10).
|
|
spec:
|
|
project: homelab
|
|
source:
|
|
repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
path: k8s/infra/forgejo-runner
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: cicd
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
---
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: forgejo-runner-node
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
# Image promotion: Forgejo package webhook → api-gw.
|
|
# Replaced ArgoCD Image Updater (removed 2026-09-10).
|
|
spec:
|
|
project: homelab
|
|
source:
|
|
repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
path: k8s/infra/forgejo-runner
|
|
helm:
|
|
valueFiles:
|
|
- values-node.yaml
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: cicd
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
---
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: forgejo-runner-rust
|
|
namespace: argocd
|
|
annotations:
|
|
argocd.argoproj.io/sync-wave: "3"
|
|
# Image promotion: Forgejo package webhook → api-gw.
|
|
# Replaced ArgoCD Image Updater (removed 2026-09-10).
|
|
spec:
|
|
project: homelab
|
|
source:
|
|
repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
|
|
targetRevision: main
|
|
path: k8s/infra/forgejo-runner
|
|
helm:
|
|
valueFiles:
|
|
- values-rust.yaml
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: cicd
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|