# terraform/zitadel — identity configuration for the ZITADEL instance # # Scope: this root module declares the objects INSIDE ZITADEL (org, project, # roles, OIDC applications, machine users, grants). It does NOT deploy ZITADEL # itself — that is ArgoCD's job (`k8s/argocd/apps/30-security.yaml`, values in # `k8s/infra/iam/zitadel-values.yaml`). # # Migration plan: ~/workplace/homelab-doc/ZITADEL_MIGRATION.html (outside git). # This file implements §1.3 (roles), §1.4 (machine users), §2.4 (grants) and # §6.2 (Terraform provider route). The claim-injection action of §1.3 lives in # `actions.tf` and stays disabled until the live go/no-go gate proves it. # # Authentication to ZITADEL uses the `iam-admin` machine key that the chart's # setup job writes to the `iam-admin` Secret in namespace iam: # # kubectl -n iam get secret iam-admin -o jsonpath='{.data.iam-admin\.json}' \ # | base64 -d > ~/.config/zitadel/iam-admin.json # chmod 600 ~/.config/zitadel/iam-admin.json # # export ZITADEL_JWT_PROFILE_FILE=$HOME/.config/zitadel/iam-admin.json # terraform -chdir=terraform/zitadel init # terraform -chdir=terraform/zitadel plan # # State is LOCAL and git-ignored (`terraform/*.tfstate` in .gitignore). That is # a deliberate first step, not the final answer: §8 risk 8 of the plan names # state drift as a blast-radius item. Move the state to MinIO before a second # operator ever runs `apply`. No secret is written to state except the generated # client secrets and machine keys, which are marked sensitive — they still land # in the state file, so treat that file as a secret. terraform { required_version = ">= 1.6.0" required_providers { zitadel = { source = "zitadel/zitadel" version = "3.8.7" } } } provider "zitadel" { domain = var.zitadel_domain port = var.zitadel_port # JWT profile of the iam-admin machine user. Preferred over a PAT: it is # short-lived per call and never sits in the environment as a bearer token. # Set the path through ZITADEL_JWT_PROFILE_FILE. jwt_profile_file = var.jwt_profile_file # The instance serves plain HTTP behind ingress-nginx, which terminates TLS. # Turn this on only if the provider must call the pod directly. insecure = var.zitadel_insecure }