Register rapp-qonto KeyCape client
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

This commit is contained in:
tegwick 2026-07-27 20:17:56 +02:00
parent 9026d7f904
commit 11a14648c4
3 changed files with 44 additions and 18 deletions

View file

@ -131,6 +131,15 @@ clients:
allowedScopes: ["openid", "profile", "email", "groups"] allowedScopes: ["openid", "profile", "email", "groups"]
grantTypes: ["authorization_code"] grantTypes: ["authorization_code"]
clientType: "public" clientType: "public"
- clientId: "rapp-qonto-client"
displayName: "rapp-qonto workload"
allowedScopes: ["qonto:read"]
grantTypes: ["client_credentials"]
clientType: "confidential"
secretRef: "env:KEYCAPE_RAPP_QONTO_CLIENT_SECRET"
serviceSubject: "rapp-qonto"
tenant: "tenant:friendly:binky"
roles: ["qonto-reader"]
EOF EOF
) )

View file

@ -54,7 +54,7 @@ spec:
# 2026-05-24: direct-imported into railiance01 k3s for the # 2026-05-24: direct-imported into railiance01 k3s for the
# bootstrap-console OIDC/MFA rollout. Use IfNotPresent while the # bootstrap-console OIDC/MFA rollout. Use IfNotPresent while the
# HTTP registry push/pull path is being cleaned up. # HTTP registry push/pull path is being cleaned up.
image: 92.205.130.254:32166/coulomb/key-cape:main-nonce-0601 image: 92.205.130.254:32166/coulomb/key-cape:main-e877d27-2
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
@ -65,6 +65,11 @@ spec:
env: env:
- name: KEYCAPE_CONFIG - name: KEYCAPE_CONFIG
value: /etc/keycape/config.yaml value: /etc/keycape/config.yaml
- name: KEYCAPE_RAPP_QONTO_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: keycape-rapp-qonto-client
key: client-secret
volumeMounts: volumeMounts:
# keycape-config Secret provides config.yaml and key.pem # keycape-config Secret provides config.yaml and key.pem

View file

@ -34,6 +34,18 @@ OPENBAO_CLIENT = {
"clientType": "public", "clientType": "public",
} }
RAPP_QONTO_CLIENT = {
"clientId": "rapp-qonto-client",
"displayName": "rapp-qonto workload",
"allowedScopes": ["qonto:read"],
"grantTypes": ["client_credentials"],
"clientType": "confidential",
"secretRef": "env:KEYCAPE_RAPP_QONTO_CLIENT_SECRET",
"serviceSubject": "rapp-qonto",
"tenant": "tenant:friendly:binky",
"roles": ["qonto-reader"],
}
LLDAP_REQUIRED = { LLDAP_REQUIRED = {
"userOU": "ou=people", "userOU": "ou=people",
"groupOU": "ou=groups", "groupOU": "ou=groups",
@ -55,38 +67,38 @@ def load_config() -> dict[str, Any]:
return config return config
def client_errors(config: dict[str, Any]) -> list[str]: def client_errors(config: dict[str, Any], required: dict[str, Any]) -> list[str]:
clients = config.get("clients") clients = config.get("clients")
if not isinstance(clients, list): if not isinstance(clients, list):
return ["clients must be a list"] return ["clients must be a list"]
target = next( target = next(
(client for client in clients if isinstance(client, dict) and client.get("clientId") == OPENBAO_CLIENT["clientId"]), (client for client in clients if isinstance(client, dict) and client.get("clientId") == required["clientId"]),
None, None,
) )
if target is None: if target is None:
return ["missing openbao-admin client"] return [f"missing {required['clientId']} client"]
errors: list[str] = [] errors: list[str] = []
for key in ("displayName", "clientType"): for key, expected in required.items():
if target.get(key) != OPENBAO_CLIENT[key]: if key in ("redirectUris", "allowedScopes", "grantTypes", "roles"):
errors.append(f"{key} should be {OPENBAO_CLIENT[key]!r}") missing = sorted(set(expected) - set(target.get(key) or []))
for key in ("redirectUris", "allowedScopes", "grantTypes"): if missing:
missing = sorted(set(OPENBAO_CLIENT[key]) - set(target.get(key) or [])) errors.append(f"{required['clientId']}.{key} missing: {', '.join(missing)}")
if missing: elif target.get(key) != expected:
errors.append(f"{key} missing: {', '.join(missing)}") errors.append(f"{required['clientId']}.{key} should be {expected!r}")
return errors return errors
def upsert_client(config: dict[str, Any]) -> dict[str, Any]: def upsert_client(config: dict[str, Any], required: dict[str, Any]) -> dict[str, Any]:
clients = config.get("clients") clients = config.get("clients")
if not isinstance(clients, list): if not isinstance(clients, list):
clients = [] clients = []
config["clients"] = clients config["clients"] = clients
for index, client in enumerate(clients): for index, client in enumerate(clients):
if isinstance(client, dict) and client.get("clientId") == OPENBAO_CLIENT["clientId"]: if isinstance(client, dict) and client.get("clientId") == required["clientId"]:
clients[index] = dict(OPENBAO_CLIENT) clients[index] = dict(required)
return config return config
clients.append(dict(OPENBAO_CLIENT)) clients.append(dict(required))
return config return config
@ -111,7 +123,7 @@ def enforce_lldap_defaults(config: dict[str, Any]) -> dict[str, Any]:
def render_patch(config: dict[str, Any]) -> None: def render_patch(config: dict[str, Any]) -> None:
updated = enforce_lldap_defaults(upsert_client(config)) updated = enforce_lldap_defaults(upsert_client(upsert_client(config, OPENBAO_CLIENT), RAPP_QONTO_CLIENT))
config_text = yaml.safe_dump(updated, sort_keys=False) config_text = yaml.safe_dump(updated, sort_keys=False)
encoded = base64.b64encode(config_text.encode("utf-8")).decode("ascii") encoded = base64.b64encode(config_text.encode("utf-8")).decode("ascii")
json.dump({"data": {"config.yaml": encoded}}, sys.stdout, separators=(",", ":")) json.dump({"data": {"config.yaml": encoded}}, sys.stdout, separators=(",", ":"))
@ -119,12 +131,12 @@ def render_patch(config: dict[str, Any]) -> None:
def verify(config: dict[str, Any]) -> None: def verify(config: dict[str, Any]) -> None:
errors = client_errors(config) + lldap_errors(config) errors = client_errors(config, OPENBAO_CLIENT) + client_errors(config, RAPP_QONTO_CLIENT) + lldap_errors(config)
if errors: if errors:
for error in errors: for error in errors:
print(f"[FAIL] {error}") print(f"[FAIL] {error}")
raise SystemExit(1) raise SystemExit(1)
print("[PASS] openbao-admin client and LLDAP OU lookup settings are present") print("[PASS] openbao-admin and rapp-qonto clients and LLDAP OU lookup settings are present")
def main() -> None: def main() -> None: