quorate/vendor/platform/zitadel/bootstrap.md

3.4 KiB

Zitadel Bootstrap

1. Terraform — Vault KV + database engine

vault kv put secret/cloudflare/api-token api-token="<cloudflare-api-token>"
vault kv put secret/postgres/admin username="********" password="<postgres-admin-password>"
cd terraform/internal/vault
../../scripts/tofu-versitygw-state apply \
  -var="internal_domain=quorate.internal" \
  -var='users=["<admin-user>"]' \
  -var="admin_user=<admin-user>"

2. PostgreSQL — roles and database

cd terraform/internal/postgres
../../scripts/tofu-versitygw-state apply

3. Network policies

kubectl --context default apply -f vendor/platform/postgres/network-policies.yaml
kubectl --context default apply -f vendor/platform/vault/network-policies.yaml
vault read database/config/postgres

4. cert-manager — Cloudflare token + Let's Encrypt issuer

kubectl --context default apply -f vendor/platform/cert-manager/config/vso.yaml
kubectl --context default apply -f vendor/platform/cert-manager/config/issuers.yaml
kubectl --context default get secret cloudflare-api-token -n cert-manager

5. Gateway R

flux reconcile kustomization platform-cilium-config --context default -n flux-system --with-source

The gateway-relay-tls Certificate triggers a DNS-01 ACME challenge. Monitor:

kubectl --context default describe certificate gateway-relay-tls -n kube-system

Cloudflare declares auth.quorate.dev from the OCI relay state in terraform/external/cloudflare.

6. Zitadel namespace + network policies + VSO

kubectl --context default create namespace zitadel
# Pre-create the service account so VSO can authenticate before Helm runs
kubectl --context default create serviceaccount zitadel -n zitadel
kubectl --context default apply -f vendor/platform/zitadel/network-policies.yaml
kubectl --context default apply -f vendor/platform/zitadel/vso.yaml

Wait for both secrets:

kubectl --context default get secret zitadel-masterkey -n zitadel
kubectl --context default get secret zitadel-db -n zitadel

7. Helm install

helm repo add zitadel https://charts.zitadel.com
helm upgrade --install zitadel zitadel/zitadel \
  --namespace zitadel \
  -f vendor/platform/zitadel/values.yaml

8. HTTPRoute

kubectl --context default apply -f vendor/platform/zitadel/route.yaml

9. Post-deploy — organization and OIDC clients

Once Zitadel is up and the IAM admin machine key secret exists, mirror it to Vault for Terraform:

kubectl --context default get secret iam-admin -n zitadel -o jsonpath='{.data.iam-admin\.json}' | base64 -d > iam-admin.json
vault kv put secret/zitadel/iam-admin iam-admin.json=@iam-admin.json
cd terraform/internal/zitadel
../../scripts/tofu-versitygw-state apply -var="zitadel_domain=auth.quorate.dev"

This creates the primary service organization, the shared service project, and the Forgejo OIDC application.

The Forgejo OIDC client material is mirrored into Vault for later VSO sync. Use the non-secret outputs when configuring or verifying Forgejo's OAuth2 authentication source:

tofu output forgejo_oidc_authentication_name
tofu output forgejo_oidc_discovery_url
tofu output forgejo_oidc_redirect_uri
tofu output forgejo_oidc_vault_secret_path

The Forgejo authentication source name must stay aligned with the redirect URI: https://forge.quorate.internal/user/oauth2/Zitadel/callback.