modules.zitadel: declare projects, OIDC apps, grants and IdPs
lass.zitadel describes Zitadel's login policy, its external IdPs and one
project per service with OIDC apps and an access mode:
- public: no "check authorization on authentication", every registered
user may log in.
- declarative: the check is on and the project's user grants are exactly
the listed users (login name or verified email address). Removing a
user from the list revokes the grant; grants given in the console are
removed as well.
- managed: the check is on, the grants are left to the console.
zitadel-reconcile, a oneshot after zitadel, applies it at boot and on
every deploy that changes it. It authenticates with the PAT of a service
user (IAM_OWNER) that zitadel's setup creates with the first instance
(FirstInstance.Org.Machine, PatPath). Setup writes that file world
readable, so /var/lib/zitadel becomes a 0700 state directory. An empty Pat
section creates no token, hence the explicit expiration date (Zitadel's
own default).
A small Python script against the admin/management v1 REST APIs rather
than OpenTofu with the zitadel provider:
- "declarative" has to own all grants of a project, including ones made
in the console; terraform only removes what is in its state.
- Users are listed before they register. A failed user lookup would fail
the whole plan; the script skips such users until the next run.
- No state file that has to match Zitadel: objects are found by name, so
e.g. an app deleted in the console is created again.
- The provider talks gRPC to the external domain, through nginx and TLS;
the script talks plain HTTP to 127.0.0.1 with the Host header.
- Projects and apps removed from the config stay in Zitadel instead of
being destroyed together with their grants.
Zitadel shows a client secret only when it creates one. The script keeps a
root-only copy per app in /var/lib/zitadel-apps and renders the app's env
file from it (path, owner and variable names configurable); without a copy
for the current client id it generates a new secret. Services on other
hosts find their secret there too, for now.
The login policy moves from DefaultInstance, which only applies when the
instance is created, to lass.zitadel.loginPolicy. GitHub and Google logins
come from persisted prompt vars; an empty prompt leaves the IdP out, so
the first deploy works before the OAuth apps exist. Their callback is
/ui/login/login/externalidp/callback (login UI v1, the default in 2.71).
Users may create accounts with them and link them to existing ones.
The script waits for /admin/v1/healthz rather than /debug/ready: the HTTP
gateway's connection to the gRPC API comes up later.
modules.zitadel: declare projects, OIDC apps, grants and IdPs
lass.zitadel describes Zitadel's login policy, its external IdPs and one
project per service with OIDC apps and an access mode:
- public: no "check authorization on authentication", every registered
user may log in.
- declarative: the check is on and the project's user grants are exactly
the listed users (login name or verified email address). Removing a
user from the list revokes the grant; grants given in the console are
removed as well.
- managed: the check is on, the grants are left to the console.
zitadel-reconcile, a oneshot after zitadel, applies it at boot and on
every deploy that changes it. It authenticates with the PAT of a service
user (IAM_OWNER) that zitadel's setup creates with the first instance
(FirstInstance.Org.Machine, PatPath). Setup writes that file world
readable, so /var/lib/zitadel becomes a 0700 state directory. An empty Pat
section creates no token, hence the explicit expiration date (Zitadel's
own default).
A small Python script against the admin/management v1 REST APIs rather
than OpenTofu with the zitadel provider:
- "declarative" has to own all grants of a project, including ones made
in the console; terraform only removes what is in its state.
- Users are listed before they register. A failed user lookup would fail
the whole plan; the script skips such users until the next run.
- No state file that has to match Zitadel: objects are found by name, so
e.g. an app deleted in the console is created again.
- The provider talks gRPC to the external domain, through nginx and TLS;
the script talks plain HTTP to 127.0.0.1 with the Host header.
- Projects and apps removed from the config stay in Zitadel instead of
being destroyed together with their grants.
Zitadel shows a client secret only when it creates one. The script keeps a
root-only copy per app in /var/lib/zitadel-apps and renders the app's env
file from it (path, owner and variable names configurable); without a copy
for the current client id it generates a new secret. Services on other
hosts find their secret there too, for now.
The login policy moves from DefaultInstance, which only applies when the
instance is created, to lass.zitadel.loginPolicy. GitHub and Google logins
come from persisted prompt vars; an empty prompt leaves the IdP out, so
the first deploy works before the OAuth apps exist. Their callback is
/ui/login/login/externalidp/callback (login UI v1, the default in 2.71).
Users may create accounts with them and link them to existing ones.
The script waits for /admin/v1/healthz rather than /debug/ready: the HTTP
gateway's connection to the gRPC API comes up later.