Some checks failed
Run Check Script / check (pull_request) Failing after 12s
Add wait_for_ready field (default: true) to PostgreSQLConfig. When enabled, K8sPostgreSQLInterpret waits for the cluster's -rw service to exist after applying the Cluster CR, ensuring callers like get_endpoint() succeed immediately. This eliminates the retry loop in the harmony_sso example's deploy_zitadel() -- ZitadelScore now deploys in a single pass because the PG service is guaranteed to exist before Zitadel's Helm chart init job tries to connect. The deploy_zitadel function shrinks from a 5-attempt retry loop to a simple score.interpret() call.
Harmony SSO Example
Deploys Zitadel (identity provider) and OpenBao (secrets management) on a local k3d cluster, then demonstrates using them as harmony_config backends for shared config and secret management.
Prerequisites
- Docker running
- Ports 8080 and 8200 free
/etc/hostsentries (or use a local DNS resolver):127.0.0.1 sso.harmony.local 127.0.0.1 bao.harmony.local
Usage
Full deployment
# Deploy everything (OpenBao + Zitadel)
cargo run -p example-harmony-sso
# OpenBao only (faster, skip Zitadel)
cargo run -p example-harmony-sso -- --skip-zitadel
Config storage demo (token auth)
After deployment, run the config demo to verify harmony_config works with OpenBao:
cargo run -p example-harmony-sso -- --demo
This writes and reads a SsoExampleConfig through the ConfigManager chain (EnvSource -> StoreSource<OpenbaoSecretStore>), demonstrating environment variable overrides and persistent storage in OpenBao KV v2.
SSO device flow demo
Requires a Zitadel application configured for device code grant:
HARMONY_SSO_CLIENT_ID=<zitadel-app-client-id> \
cargo run -p example-harmony-sso -- --sso-demo
Cleanup
cargo run -p example-harmony-sso -- --cleanup
What gets deployed
| Component | Namespace | Access |
|---|---|---|
| OpenBao (standalone, file storage) | openbao |
http://bao.harmony.local:8200 |
| Zitadel (with CNPG PostgreSQL) | zitadel |
http://sso.harmony.local:8080 |
OpenBao configuration
- Auth methods: userpass, JWT
- Secrets engine: KV v2 at
secret/ - Policy:
harmony-devgrants CRUD onsecret/data/harmony/* - Userpass credentials:
harmony/harmony-dev-password - JWT auth: configured with Zitadel as OIDC provider, role
harmony-developer - Unseal keys: saved to
~/.local/share/harmony/openbao/unseal-keys.json
Architecture
Developer CLI
|
|-- harmony_config::ConfigManager
| |-- EnvSource (HARMONY_CONFIG_* env vars)
| |-- StoreSource<OpenbaoSecretStore>
| |-- Token auth (OPENBAO_TOKEN)
| |-- Cached token validation
| |-- Zitadel OIDC device flow (RFC 8628)
| |-- Userpass fallback
|
v
k3d cluster (harmony-example)
|-- OpenBao (KV v2 secrets engine)
| |-- JWT auth -> validates Zitadel id_tokens
| |-- userpass auth -> dev credentials
|
|-- Zitadel (OpenID Connect IdP)
|-- Device authorization grant
|-- Federated login (Google, GitHub, Entra ID)