Adds terraform/zitadel: the provisioning half the ArgoCD wiring left open. It declares 1 project, 19 project roles, 12 OIDC applications, 5 machine users plus keys, one API application for the gateway, project grants, per-agent claim metadata, and a disabled groups-claim action. Facts established while writing it: - Client IDs cannot be preserved. ZITADEL v4.19.2 CreateOIDCApplicationRequest has no client_id field, and provider 3.8.7 rejects a settable application id (terraform validate reports "Invalid or unknown key"). Plan §3.2 assumed a client_id-preserving re-point; every consumer now also changes client ID. - Role keys equal the existing group names, so the groups claim can be byte-identical and no RBAC file changes. v4.19.2 allows role keys of 1-200 characters with no character-set restriction. - Machine users get JWT profile keys, not passwords. Per-agent claims move to user metadata and reach tokens only through the groups-claim action. - The action stays gated: enable_groups_claim_action defaults to false because the action runtime API is unverified. Two validations stop a null script from reaching file(). Checks: terraform fmt -check -recursive clean, terraform validate 0 errors, plan reaches only the expected missing-credentials error, structural gate 0 error / 0 warning, and one reviewer round: BLOCK on a plan-time fileexists(null) and on the missing api-gw machine path, both fixed, re-reviewed to SIGN-OFF. State is local and git-ignored; it carries generated client secrets and machine keys. Move it to MinIO before a second operator applies. Not applied: no Zitadel instance is running yet.
59 lines
2.5 KiB
Terraform
59 lines
2.5 KiB
Terraform
# The groups claim — the single load-bearing decision of the migration.
|
|
#
|
|
# ZITADEL does not issue a `groups` claim. Authentik did, and these consumers
|
|
# read it: kube-apiserver RBAC (`--oidc-groups-claim=groups` plus 11 RoleBindings
|
|
# on oidc:<group>), MinIO (`MINIO_IDENTITY_OPENID_CLAIM_NAME=groups`), Grafana
|
|
# role mapping, and every service that filters on a group name.
|
|
#
|
|
# Plan §1.3 Option A keeps those consumers unchanged by synthesizing the claim.
|
|
# Option B refactors all of them. This module takes responsibility only for the
|
|
# ZITADEL side of Option A: the action resource and its trigger.
|
|
#
|
|
# The script body is NOT shipped by default. The go/no-go gate (§1.3, §1.5 task
|
|
# 1.3) is: prove on the live instance that the action runtime can read project
|
|
# roles plus user metadata and write both `groups` and the per-agent claims,
|
|
# for a human token AND a machine-user token. Until that proof exists, enabling
|
|
# this resource would move every consumer onto an unverified claim source:
|
|
#
|
|
# terraform apply -var enable_groups_claim_action=true \
|
|
# -var groups_claim_script=./groups-claim.js
|
|
#
|
|
# After it applies, verify with a real token exchange before moving a consumer:
|
|
#
|
|
# curl -s -X POST https://zitadel.riotpiao.com/oauth/v2/token \
|
|
# -d grant_type=refresh_token -d refresh_token=<t> \
|
|
# -d client_id=kubernetes | jq -R 'split(".")[1] | @base64d | fromjson'
|
|
#
|
|
# The decoded access token must contain `"groups":["homelab-admins", ...]`.
|
|
|
|
resource "zitadel_action" "groups_claim" {
|
|
count = var.enable_groups_claim_action ? 1 : 0
|
|
|
|
org_id = data.zitadel_org.default.id
|
|
name = "homelab-groups-claim"
|
|
script = file(var.groups_claim_script)
|
|
timeout = "5s"
|
|
allowed_to_fail = false
|
|
}
|
|
|
|
# Both triggers are needed. The access-token trigger fills the JWT that
|
|
# Kubernetes and MinIO read. The userinfo trigger fills the response that
|
|
# Grafana, paperless and Forgejo read.
|
|
resource "zitadel_trigger_actions" "groups_claim_access_token" {
|
|
count = var.enable_groups_claim_action ? 1 : 0
|
|
|
|
org_id = data.zitadel_org.default.id
|
|
flow_type = "FLOW_TYPE_CUSTOMISE_TOKEN"
|
|
trigger_type = "TRIGGER_TYPE_PRE_ACCESS_TOKEN_CREATION"
|
|
action_ids = [zitadel_action.groups_claim[0].id]
|
|
}
|
|
|
|
resource "zitadel_trigger_actions" "groups_claim_userinfo" {
|
|
count = var.enable_groups_claim_action ? 1 : 0
|
|
|
|
org_id = data.zitadel_org.default.id
|
|
flow_type = "FLOW_TYPE_CUSTOMISE_TOKEN"
|
|
trigger_type = "TRIGGER_TYPE_PRE_USERINFO_CREATION"
|
|
action_ids = [zitadel_action.groups_claim[0].id]
|
|
}
|