scripts/iam/zitadel-provision.py replaces the manual sequence that provision-rbac.py did for Authentik. Phases: keys, apply, secrets, users, verify. `all` runs keys -> apply -> secrets -> verify; users stays manual because the password hash must come from a human, one user at a time. - keys: extract the chart's iam-admin machine key and PAT to ~/.config/zitadel at 0600, outside the repo. - apply: terraform apply terraform/zitadel with the machine key. - secrets: write generated client secrets into the SOPS files, write client ids into the plain manifests that carry them, write machine keys per agent. Requires an exactly-one-match regex before it edits a manifest, prints the diff without --apply-config, and is a no-op when the value already matches. - users: import a human user with the Django pbkdf2_sha256 hash converted to the passwap MCF form ZITADEL accepts. - verify: discovery endpoint, client count, and it refuses to clear cutover while the groups-claim action is disabled. Design points that came out of review: - Multi-document SOPS files (minio) are rewritten whole, because `sops set` cannot address one document. sops reads the creation rule from the filename, so the temp file is passed with --filename-override; without it sops finds no matching rule and refuses. Ciphertext is staged in the destination directory and installed with os.replace, so the mode is preserved and EXDEV is impossible. SIGTERM/SIGINT trigger cleanup of the decrypted temp file. - homarr is listed as manual: the live workload mounts Secret homarr-oidc, which no SOPS file in git defines, and the tracked homarr-auth-oidc.enc.yaml has no consumer. Writing the new secret into the orphan file would report success while the dashboard kept the old one. - Secrets never enter argv: curl reads its config from stdin, so the PAT and the password hash do not appear in ps. .gitignore: allow this one script through the scripts/iam/*.py ignore rule (it embeds no credential), and ignore authentik-m2m-tokens.env, which holds live M2M tokens and was one `git add -A` away from being committed. Checks: py_compile clean, --help lists every phase, convert_hash verified on a synthetic hash, the 3-document SOPS rewrite tested on a real copy (3 documents survive, value set, second run unchanged, mode 644 kept, no temp left), all three client-id regexes match exactly once, dry-run leaves the manifests untouched. Reviewer round: BLOCK on the sops creation rule, the orphan homarr Secret, the missing client-id writes and argv exposure; all fixed and re-reviewed to SIGN-OFF. Not run against a live ZITADEL: no instance exists yet.
84 lines
2.4 KiB
Plaintext
84 lines
2.4 KiB
Plaintext
# Environment files — real values must never be committed
|
|
.env
|
|
.env.terraform.sh
|
|
|
|
# Private CA key and generated TLS certs — ca.key must never enter the cluster or git.
|
|
# Only ca.crt is safe to share, but we exclude the whole dir to avoid accidents.
|
|
forge/pki/
|
|
|
|
# Talos machine configs — contain WireGuard private keys, bootstrap tokens, PKI
|
|
cluster-config/controlplane.yaml
|
|
cluster-config/worker*.yaml
|
|
cluster-config/talos-worker*.yaml
|
|
cluster-config/cp-*.yaml
|
|
cluster-config/talos-cp-*.yaml
|
|
cluster-config/secrets.yaml
|
|
cluster-config/talosconfig
|
|
talos-forge-trust.yaml
|
|
# Kubeconfig — contains admin client certificate + private key
|
|
cluster-config/kubeconfig
|
|
|
|
*.html
|
|
LOG.md
|
|
project_context.md
|
|
.claude/*
|
|
|
|
ca.crt
|
|
ca.key
|
|
ca.srl
|
|
|
|
forgejo.crt
|
|
forgejo.key
|
|
forgejo.csr
|
|
|
|
# Compiled test binary — Go produces a native binary named after the directory.
|
|
# Source is k8s/storage/test/main.go; the binary has no place in version control.
|
|
k8s/storage/test/test
|
|
|
|
*.key
|
|
*.conf
|
|
|
|
# CLAUDE.md is now version-controlled (was previously excluded as a
|
|
# private-notes file; contains no secrets - just architecture, IPs
|
|
# [private RFC1918 space], and operational lessons, same bar as README.md).
|
|
|
|
# Terraform state and cache (local files, remote state in MinIO)
|
|
.terraform/
|
|
terraform/.terraform/
|
|
terraform/*.tfstate
|
|
terraform/*.tfstate.*
|
|
# The Zitadel root module keeps its own state (see terraform/zitadel/providers.tf).
|
|
# That state carries generated client secrets and machine keys.
|
|
terraform/zitadel/*.tfstate
|
|
terraform/zitadel/*.tfstate.*
|
|
terraform/zitadel/*.tfvars
|
|
terraform.tfvars.local
|
|
skills-lock.json
|
|
secrets-plaintext.yaml
|
|
|
|
# Saved plan files — binary, environment-specific, may embed resource attributes
|
|
terraform/tfplan
|
|
terraform/tfplan-*
|
|
|
|
.DS_Store
|
|
CLAUDE.md
|
|
docs/
|
|
|
|
bootstrap-argocd.log
|
|
|
|
# Any plaintext (non-SOPS) secret manifest. Encrypted ones are *.enc.yaml and
|
|
# ARE committed — see .sops.yaml. A missing newline once merged two patterns on
|
|
# one line here, which is how a plaintext deploy key reached a public remote.
|
|
k8s/**/*-secret.yaml
|
|
!k8s/**/*.enc.yaml
|
|
|
|
# IAM provisioning scripts contain credential references — never commit
|
|
scripts/iam/*.py
|
|
# Exception: this one reads every credential from the cluster at run time and
|
|
# embeds none. Keep it reviewable in git.
|
|
!scripts/iam/zitadel-provision.py
|
|
|
|
# Runtime credential export from the old Authentik provisioning run. Holds live
|
|
# M2M tokens; never commit it.
|
|
/authentik-m2m-tokens.env
|