generated from coulomb/repo-seed
Use helper for OpenBao OIDC auth setup
This commit is contained in:
@@ -139,6 +139,21 @@ decoded `config.yaml` or signing key. The verifier checks the live Secret and
|
|||||||
then opens a short local `kubectl port-forward` to KeyCape; it does not require
|
then opens a short local `kubectl port-forward` to KeyCape; it does not require
|
||||||
`curl` or `wget` inside the KeyCape container image.
|
`curl` or `wget` inside the KeyCape container image.
|
||||||
|
|
||||||
|
After the live KeyCape client is present, configure Railiance OpenBao to trust
|
||||||
|
KeyCape:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ./configure-openbao-oidc.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script prompts for a root/sudo-capable OpenBao token inside the pod TTY.
|
||||||
|
OpenBao currently requires `oidc_client_secret` for OIDC auth config, while
|
||||||
|
KeyCape's `openbao-admin` client is public PKCE and does not validate a
|
||||||
|
downstream client secret. The script therefore writes the explicit
|
||||||
|
non-secret compatibility value `keycape-public-pkce-compatibility-value`.
|
||||||
|
Replace that with a real managed client secret when KeyCape supports
|
||||||
|
confidential downstream clients.
|
||||||
|
|
||||||
Example entry (public client, PKCE, for a SPA):
|
Example entry (public client, PKCE, for a SPA):
|
||||||
```yaml
|
```yaml
|
||||||
clients:
|
clients:
|
||||||
|
|||||||
71
sso-mfa/k8s/keycape/configure-openbao-oidc.sh
Normal file
71
sso-mfa/k8s/keycape/configure-openbao-oidc.sh
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Configure Railiance OpenBao to trust KeyCape for platform-admin OIDC login.
|
||||||
|
# The OpenBao token is prompted inside the pod TTY and is never placed on the
|
||||||
|
# local command line or stored by this script.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
KUBECTL="${KUBECTL:-kubectl}"
|
||||||
|
OPENBAO_NAMESPACE="${OPENBAO_NAMESPACE:-openbao}"
|
||||||
|
OPENBAO_POD="${OPENBAO_POD:-openbao-0}"
|
||||||
|
|
||||||
|
"$KUBECTL" exec -it -n "$OPENBAO_NAMESPACE" "$OPENBAO_POD" -- sh -lc '
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
restore_tty() { stty echo 2>/dev/null || true; }
|
||||||
|
trap restore_tty EXIT INT TERM
|
||||||
|
|
||||||
|
printf "OpenBao root/sudo token: " >&2
|
||||||
|
stty -echo
|
||||||
|
read -r BAO_TOKEN
|
||||||
|
stty echo
|
||||||
|
printf "\n" >&2
|
||||||
|
export BAO_TOKEN
|
||||||
|
|
||||||
|
bao auth enable -path=keycape oidc >/tmp/keycape-auth-enable.out 2>/tmp/keycape-auth-enable.err || {
|
||||||
|
if grep -q "path is already in use" /tmp/keycape-auth-enable.err; then
|
||||||
|
printf "auth/keycape already exists\n" >&2
|
||||||
|
else
|
||||||
|
cat /tmp/keycape-auth-enable.err >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# OpenBao requires oidc_client_secret for OIDC auth config. The current
|
||||||
|
# KeyCape openbao-admin profile is public PKCE and does not validate this
|
||||||
|
# downstream client-secret field, so this compatibility value is not a
|
||||||
|
# protected secret. Replace this with a real managed client secret when
|
||||||
|
# KeyCape supports confidential downstream clients.
|
||||||
|
bao write auth/keycape/config \
|
||||||
|
oidc_discovery_url="https://kc.coulomb.social" \
|
||||||
|
oidc_client_id="openbao-admin" \
|
||||||
|
oidc_client_secret="keycape-public-pkce-compatibility-value" \
|
||||||
|
default_role="platform-admin"
|
||||||
|
|
||||||
|
cat >/tmp/openbao-platform-admin-role.json <<'"'"'ROLE_JSON'"'"'
|
||||||
|
{
|
||||||
|
"role_type": "oidc",
|
||||||
|
"user_claim": "sub",
|
||||||
|
"groups_claim": "groups",
|
||||||
|
"oidc_scopes": ["openid", "profile", "email", "groups"],
|
||||||
|
"allowed_redirect_uris": [
|
||||||
|
"http://localhost:8250/oidc/callback",
|
||||||
|
"http://127.0.0.1:8250/oidc/callback"
|
||||||
|
],
|
||||||
|
"bound_claims": {
|
||||||
|
"groups": ["net-kingdom-admins"]
|
||||||
|
},
|
||||||
|
"claim_mappings": {
|
||||||
|
"email": "email",
|
||||||
|
"preferred_username": "username",
|
||||||
|
"groups": "groups"
|
||||||
|
},
|
||||||
|
"policies": ["platform-admin"],
|
||||||
|
"ttl": "1h"
|
||||||
|
}
|
||||||
|
ROLE_JSON
|
||||||
|
|
||||||
|
bao write auth/keycape/role/platform-admin @/tmp/openbao-platform-admin-role.json
|
||||||
|
rm -f /tmp/openbao-platform-admin-role.json /tmp/keycape-auth-enable.out /tmp/keycape-auth-enable.err
|
||||||
|
unset BAO_TOKEN
|
||||||
|
'
|
||||||
@@ -1349,7 +1349,7 @@ def admin_identity_command_payloads(data: dict[str, Any]) -> list[dict[str, str]
|
|||||||
auth_state = "done" if auth_configured else "todo" if client_deployed else "blocked"
|
auth_state = "done" if auth_configured else "todo" if client_deployed else "blocked"
|
||||||
auth_reason = "OpenBao OIDC/JWT auth is recorded as configured."
|
auth_reason = "OpenBao OIDC/JWT auth is recorded as configured."
|
||||||
if auth_state == "todo":
|
if auth_state == "todo":
|
||||||
auth_reason = "Operator action: requires a root/sudo-capable OpenBao token at the hidden prompt; the token value is not recorded."
|
auth_reason = "Operator action: run the helper script and enter a root/sudo-capable OpenBao token at the pod TTY prompt. The token value is not recorded."
|
||||||
if auth_state == "blocked":
|
if auth_state == "blocked":
|
||||||
auth_reason = "Apply and confirm the live KeyCape openbao-admin client before configuring OpenBao auth."
|
auth_reason = "Apply and confirm the live KeyCape openbao-admin client before configuring OpenBao auth."
|
||||||
|
|
||||||
@@ -1371,57 +1371,7 @@ def admin_identity_command_payloads(data: dict[str, Any]) -> list[dict[str, str]
|
|||||||
"bash ./verify-openbao-client.sh\n"
|
"bash ./verify-openbao-client.sh\n"
|
||||||
"NETKINGDOM_KEYCAPE_APPLY\n"
|
"NETKINGDOM_KEYCAPE_APPLY\n"
|
||||||
)
|
)
|
||||||
oidc_config_inner = """bao auth enable -path=keycape oidc >/tmp/keycape-auth-enable.out 2>/tmp/keycape-auth-enable.err || {
|
configure_command = f"bash {shlex.quote(str(KEYCAPE_OPENBAO_CLIENT_CONFIG.parent / 'configure-openbao-oidc.sh'))}"
|
||||||
if grep -q "path is already in use" /tmp/keycape-auth-enable.err; then
|
|
||||||
printf "auth/keycape already exists\\n" >&2
|
|
||||||
else
|
|
||||||
cat /tmp/keycape-auth-enable.err >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
bao write auth/keycape/config \\
|
|
||||||
oidc_discovery_url="https://kc.coulomb.social" \\
|
|
||||||
oidc_client_id="openbao-admin" \\
|
|
||||||
oidc_client_secret="" \\
|
|
||||||
default_role="platform-admin"
|
|
||||||
cat >/tmp/openbao-platform-admin-role.json <<ROLE_JSON
|
|
||||||
{
|
|
||||||
"role_type": "oidc",
|
|
||||||
"user_claim": "sub",
|
|
||||||
"groups_claim": "groups",
|
|
||||||
"oidc_scopes": ["openid", "profile", "email", "groups"],
|
|
||||||
"allowed_redirect_uris": [
|
|
||||||
"http://localhost:8250/oidc/callback",
|
|
||||||
"http://127.0.0.1:8250/oidc/callback"
|
|
||||||
],
|
|
||||||
"bound_claims": {
|
|
||||||
"groups": ["net-kingdom-admins"]
|
|
||||||
},
|
|
||||||
"claim_mappings": {
|
|
||||||
"email": "email",
|
|
||||||
"preferred_username": "username",
|
|
||||||
"groups": "groups"
|
|
||||||
},
|
|
||||||
"policies": ["platform-admin"],
|
|
||||||
"ttl": "1h"
|
|
||||||
}
|
|
||||||
ROLE_JSON
|
|
||||||
bao write auth/keycape/role/platform-admin @/tmp/openbao-platform-admin-role.json
|
|
||||||
rm -f /tmp/openbao-platform-admin-role.json /tmp/keycape-auth-enable.out /tmp/keycape-auth-enable.err"""
|
|
||||||
configure_command = (
|
|
||||||
"kubectl exec -it -n openbao openbao-0 -- sh -lc '\n"
|
|
||||||
" restore_tty() { stty echo 2>/dev/null || true; }\n"
|
|
||||||
" trap restore_tty EXIT INT TERM\n"
|
|
||||||
" printf \"OpenBao root/sudo token: \" >&2\n"
|
|
||||||
" stty -echo\n"
|
|
||||||
" read -r BAO_TOKEN\n"
|
|
||||||
" stty echo\n"
|
|
||||||
" printf \"\\n\" >&2\n"
|
|
||||||
" export BAO_TOKEN\n"
|
|
||||||
f"{oidc_config_inner}\n"
|
|
||||||
" unset BAO_TOKEN\n"
|
|
||||||
"'"
|
|
||||||
)
|
|
||||||
login_command = (
|
login_command = (
|
||||||
"# Terminal 1: keep a local OpenBao API port open while testing.\n"
|
"# Terminal 1: keep a local OpenBao API port open while testing.\n"
|
||||||
"kubectl -n openbao port-forward svc/openbao-active 8200:8200\n\n"
|
"kubectl -n openbao port-forward svc/openbao-active 8200:8200\n\n"
|
||||||
@@ -1442,7 +1392,7 @@ rm -f /tmp/openbao-platform-admin-role.json /tmp/keycape-auth-enable.out /tmp/ke
|
|||||||
),
|
),
|
||||||
action(
|
action(
|
||||||
"Configure OpenBao OIDC auth",
|
"Configure OpenBao OIDC auth",
|
||||||
"Create or update the auth/keycape mount and platform-admin role so KeyCape group claims map to OpenBao platform-admin policy.",
|
"Create or update the auth/keycape mount and platform-admin role so KeyCape group claims map to OpenBao platform-admin policy. The helper uses a non-secret compatibility client-secret value because OpenBao requires the field while the current KeyCape client is public PKCE.",
|
||||||
auth_state,
|
auth_state,
|
||||||
auth_reason,
|
auth_reason,
|
||||||
configure_command,
|
configure_command,
|
||||||
|
|||||||
@@ -339,6 +339,12 @@ uses a short local `kubectl port-forward` plus Python HTTP request for OIDC
|
|||||||
discovery, avoiding assumptions about tools installed inside the KeyCape
|
discovery, avoiding assumptions about tools installed inside the KeyCape
|
||||||
container.
|
container.
|
||||||
|
|
||||||
|
**2026-05-26:** Fixed the OpenBao OIDC auth setup after OpenBao rejected an
|
||||||
|
empty `oidc_client_secret` even though the current KeyCape `openbao-admin`
|
||||||
|
client is public PKCE. The UI now points to a short helper script instead of a
|
||||||
|
long nested shell/JSON command, and the helper writes an explicit non-secret
|
||||||
|
compatibility value until KeyCape supports confidential downstream clients.
|
||||||
|
|
||||||
**2026-05-24:** Stepped back from ad hoc secret rollout and added the
|
**2026-05-24:** Stepped back from ad hoc secret rollout and added the
|
||||||
custodian age-key bootstrap model to the control surface. The UI now records
|
custodian age-key bootstrap model to the control surface. The UI now records
|
||||||
the custodian public age recipient, a derived fingerprint, and a non-secret
|
the custodian public age recipient, a derived fingerprint, and a non-secret
|
||||||
|
|||||||
Reference in New Issue
Block a user