generated from coulomb/repo-seed
feat(keycape): add netkingdom OIDC mount and bao.coulomb.social callbacks
Configure OpenBao auth for both netkingdom and keycape mounts with browser redirect URIs; update verify scripts and runtime architecture notes.
This commit is contained in:
@@ -24,8 +24,8 @@ Recursive trust rule: Normal tenant admin (even Coulomb) must never suffice to a
|
||||
- MFA/Token: privacyIDEA (self-service enrollment for TOTP; pi-admin for setup/repair; used for assurance on privileged actions).
|
||||
- OIDC Provider: KeyCape (issuer https://kc.coulomb.social; conforms to NetKingdom IAM Profile v0.2).
|
||||
- KeyCape issues tokens with required claims: tenant, principal_type, groups, roles, scope/scp, assurance.
|
||||
- Registered clients include: netkingdom-bootstrap-console (for console OIDC login), openbao-admin (for OpenBao OIDC auth).
|
||||
- Redirects: http://localhost:8250/oidc/callback, http://127.0.0.1:8250/oidc/callback.
|
||||
- Registered clients include: netkingdom-bootstrap-console (for console OIDC login), openbao-admin (for OpenBao OIDC auth).
|
||||
- Redirects: http://localhost:8250/oidc/callback, http://127.0.0.1:8250/oidc/callback, https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback, https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback.
|
||||
- Groups/roles for bootstrap: net-kingdom-admins (for platform-admin OpenBao policy), net-kingdom-users (for scoped non-root).
|
||||
- platform-root / king credential: dedicated LLDAP user (separate from personal accounts like tegwick). Password in operator password safe; TOTP via privacyIDEA; roles include platform-root-custodian, openbao-admin, identity-admin.
|
||||
|
||||
@@ -56,6 +56,10 @@ Authelia acts as the SSO proxy/authenticator in lightweight mode, fronting LLDAP
|
||||
- Delivery: direct clients, External Secrets Operator -> K8s Secrets, CSI mounts.
|
||||
- Auth: OIDC/JWT against KeyCape (maps claims/groups to policies, e.g. platform-admin for net-kingdom-admins group).
|
||||
- platform-root can obtain platform-admin policy via KeyCape/MFA (proven in 0015/0017).
|
||||
- Browser operator access uses `https://bao.coulomb.social` for the OpenBao UI
|
||||
and redirects to KeyCape at `kc.coulomb.social`; use auth path `netkingdom`
|
||||
and role `platform-admin`, not root-token browser login. The `keycape` auth
|
||||
path is retained only as a compatibility alias.
|
||||
- Root token: revoked/dispositioned after init; used only for bootstrap/break-glass. Unseal keys in custody (age/SOPS protected, offline packets, king credential).
|
||||
|
||||
**Bootstrap to runtime transition:**
|
||||
@@ -202,4 +206,4 @@ See NET-WP-0019 and sso-mfa/k8s/lldap/dry-run-nonroot-user.sh:
|
||||
- NET-WP-0017, 0019 workplans + their evidence
|
||||
- DECISIONS.md, ADRs (e.g. 0007, 0010), canon/standards/iam-profile_v0.2.md
|
||||
|
||||
This document will be updated as T03 retrospective, T05 guide, T06/T08 work, and T09 risk assessment proceed. It is the single source for "what the running system actually is" for rebuild guidance.
|
||||
This document will be updated as T03 retrospective, T05 guide, T06/T08 work, and T09 risk assessment proceed. It is the single source for "what the running system actually is" for rebuild guidance.
|
||||
|
||||
@@ -117,7 +117,7 @@ keeps KeyCape from using the admin token-list API as the MFA-required check.
|
||||
|
||||
Downstream applications are registered in the `clients:` block in
|
||||
`keycape/create-secrets.sh`. The NetKingdom bootstrap console and Railiance
|
||||
OpenBao admin CLI clients are code-defined there; operators should not create
|
||||
OpenBao admin clients are code-defined there; operators should not create
|
||||
those clients manually in a separate UI. After changing the block:
|
||||
|
||||
```bash
|
||||
@@ -126,16 +126,20 @@ kubectl rollout restart deployment/keycape -n sso
|
||||
```
|
||||
|
||||
The `openbao-admin` client is intentionally a public PKCE client for the
|
||||
current local operator CLI flow. It registers the OpenBao CLI callback URIs:
|
||||
current operator flow. It registers both the OpenBao CLI callback URIs and the
|
||||
browser UI callbacks for `bao.coulomb.social`:
|
||||
|
||||
```text
|
||||
http://localhost:8250/oidc/callback
|
||||
http://127.0.0.1:8250/oidc/callback
|
||||
https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
|
||||
https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback
|
||||
```
|
||||
|
||||
OpenBao browser UI callbacks are not registered yet because Railiance OpenBao
|
||||
currently has public ingress disabled. Add exact UI callback URIs only after
|
||||
the OpenBao UI exposure model is explicitly designed.
|
||||
The browser UI callback is paired with the Railiance Platform OpenBao ingress
|
||||
at `https://bao.coulomb.social`. The preferred browser auth mount is
|
||||
`netkingdom`; `keycape` remains a compatibility alias. Keep the localhost
|
||||
callbacks unless there is a separate decision to retire CLI login.
|
||||
|
||||
To add or refresh only the OpenBao client in a live cluster, do not decrypt the
|
||||
bootstrap secret bundle and do not re-run the full secret generator. Patch the
|
||||
@@ -161,6 +165,13 @@ KeyCape:
|
||||
bash ./configure-openbao-oidc.sh
|
||||
```
|
||||
|
||||
That script registers the browser UI callbacks on the OpenBao
|
||||
`auth/netkingdom/role/platform-admin` role and the compatibility
|
||||
`auth/keycape/role/platform-admin` role. Browser operators should use the
|
||||
OpenBao UI at `https://bao.coulomb.social`, leave namespace blank, choose
|
||||
OIDC, set mount path `netkingdom`, and use role `platform-admin`; root-token
|
||||
browser use is outside the approved operator path.
|
||||
|
||||
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
|
||||
|
||||
@@ -22,25 +22,12 @@ OPENBAO_POD="${OPENBAO_POD:-openbao-0}"
|
||||
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"
|
||||
OPENBAO_OIDC_MOUNTS="netkingdom keycape"
|
||||
|
||||
# Keep array-valued groups in groups_claim/bound_claims only. OpenBao
|
||||
# claim_mappings copy scalar claim values into metadata and will fail if the
|
||||
@@ -53,7 +40,9 @@ OPENBAO_POD="${OPENBAO_POD:-openbao-0}"
|
||||
"oidc_scopes": ["openid", "profile", "email", "groups"],
|
||||
"allowed_redirect_uris": [
|
||||
"http://localhost:8250/oidc/callback",
|
||||
"http://127.0.0.1:8250/oidc/callback"
|
||||
"http://127.0.0.1:8250/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback"
|
||||
],
|
||||
"bound_claims": {
|
||||
"groups": ["net-kingdom-admins"]
|
||||
@@ -67,7 +56,26 @@ OPENBAO_POD="${OPENBAO_POD:-openbao-0}"
|
||||
}
|
||||
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
|
||||
for mount in $OPENBAO_OIDC_MOUNTS; do
|
||||
bao auth enable -path="$mount" oidc >/tmp/openbao-${mount}-auth-enable.out 2>/tmp/openbao-${mount}-auth-enable.err || {
|
||||
if grep -q "path is already in use" /tmp/openbao-${mount}-auth-enable.err; then
|
||||
printf "auth/%s already exists\n" "$mount" >&2
|
||||
else
|
||||
cat /tmp/openbao-${mount}-auth-enable.err >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
bao write "auth/${mount}/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"
|
||||
|
||||
bao write "auth/${mount}/role/platform-admin" @/tmp/openbao-platform-admin-role.json
|
||||
printf "configured auth/%s/role/platform-admin\n" "$mount" >&2
|
||||
done
|
||||
|
||||
rm -f /tmp/openbao-platform-admin-role.json /tmp/openbao-*-auth-enable.out /tmp/openbao-*-auth-enable.err
|
||||
unset BAO_TOKEN
|
||||
'
|
||||
|
||||
@@ -122,10 +122,12 @@ clients:
|
||||
grantTypes: ["authorization_code"]
|
||||
clientType: "public"
|
||||
- clientId: "openbao-admin"
|
||||
displayName: "Railiance OpenBao Admin CLI"
|
||||
displayName: "Railiance OpenBao Admin"
|
||||
redirectUris:
|
||||
- "http://localhost:8250/oidc/callback"
|
||||
- "http://127.0.0.1:8250/oidc/callback"
|
||||
- "https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback"
|
||||
- "https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback"
|
||||
allowedScopes: ["openid", "profile", "email", "groups"]
|
||||
grantTypes: ["authorization_code"]
|
||||
clientType: "public"
|
||||
|
||||
@@ -22,10 +22,12 @@ except ImportError as exc: # pragma: no cover - operator environment guard
|
||||
|
||||
OPENBAO_CLIENT = {
|
||||
"clientId": "openbao-admin",
|
||||
"displayName": "Railiance OpenBao Admin CLI",
|
||||
"displayName": "Railiance OpenBao Admin",
|
||||
"redirectUris": [
|
||||
"http://localhost:8250/oidc/callback",
|
||||
"http://127.0.0.1:8250/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback",
|
||||
],
|
||||
"allowedScopes": ["openid", "profile", "email", "groups"],
|
||||
"grantTypes": ["authorization_code"],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Patch the live KeyCape config Secret with non-secret code-defined settings:
|
||||
# the OpenBao CLI client and LLDAP OU lookup paths.
|
||||
# the OpenBao admin client, browser auth mount callbacks, and LLDAP OU lookup
|
||||
# paths.
|
||||
# This does not require decrypted bootstrap secrets and does not print existing
|
||||
# Secret values.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Verify the live KeyCape config carries the OpenBao CLI client and KeyCape is
|
||||
# serving OIDC discovery after rollout.
|
||||
# Verify the live KeyCape config carries the OpenBao admin client and KeyCape
|
||||
# is serving OIDC discovery after rollout.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -15,30 +15,41 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
PUBLIC_URL="${KEYCAPE_PUBLIC_URL:-https://kc.coulomb.social}"
|
||||
PUBLIC_AUTHORIZE_URL="${PUBLIC_URL%/}/authorize"
|
||||
PUBLIC_PROBE_OUTPUT=$(
|
||||
curl -sS -i -G "$PUBLIC_AUTHORIZE_URL" \
|
||||
--data-urlencode "client_id=openbao-admin" \
|
||||
--data-urlencode "redirect_uri=http://localhost:8250/oidc/callback" \
|
||||
--data-urlencode "response_type=code" \
|
||||
--data-urlencode "scope=openid profile email groups" \
|
||||
--data-urlencode "state=netkingdom-openbao-client-probe" \
|
||||
--data-urlencode "code_challenge=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ" \
|
||||
--data-urlencode "code_challenge_method=S256" \
|
||||
2>&1 || true
|
||||
)
|
||||
|
||||
if grep -q '"unknown client_id"' <<<"$PUBLIC_PROBE_OUTPUT"; then
|
||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL rejects openbao-admin with unknown client_id" >&2
|
||||
echo " Check DNS for kc.coulomb.social and ensure it reaches the KeyCape ingress that was patched." >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qE '^HTTP/[0-9.]+ 302 ' <<<"$PUBLIC_PROBE_OUTPUT"; then
|
||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL did not return the expected OIDC redirect for openbao-admin" >&2
|
||||
echo " First response:" >&2
|
||||
sed -n '1,12p' <<<"$PUBLIC_PROBE_OUTPUT" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] public KeyCape authorize endpoint recognizes openbao-admin"
|
||||
probe_redirect() {
|
||||
local label="$1"
|
||||
local redirect_uri="$2"
|
||||
local output
|
||||
output=$(
|
||||
curl -sS -i -G "$PUBLIC_AUTHORIZE_URL" \
|
||||
--data-urlencode "client_id=openbao-admin" \
|
||||
--data-urlencode "redirect_uri=$redirect_uri" \
|
||||
--data-urlencode "response_type=code" \
|
||||
--data-urlencode "scope=openid profile email groups" \
|
||||
--data-urlencode "state=netkingdom-openbao-client-probe" \
|
||||
--data-urlencode "code_challenge=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ" \
|
||||
--data-urlencode "code_challenge_method=S256" \
|
||||
2>&1 || true
|
||||
)
|
||||
|
||||
if grep -q '"unknown client_id"' <<<"$output"; then
|
||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL rejects openbao-admin with unknown client_id" >&2
|
||||
echo " Check DNS for kc.coulomb.social and ensure it reaches the KeyCape ingress that was patched." >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qE '^HTTP/[0-9.]+ 302 ' <<<"$output"; then
|
||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL did not accept the $label redirect URI for openbao-admin" >&2
|
||||
echo " Redirect URI: $redirect_uri" >&2
|
||||
echo " First response:" >&2
|
||||
sed -n '1,12p' <<<"$output" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] public KeyCape authorize endpoint accepts $label redirect"
|
||||
}
|
||||
|
||||
probe_redirect "CLI" "http://localhost:8250/oidc/callback"
|
||||
probe_redirect "browser UI netkingdom mount" "https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback"
|
||||
probe_redirect "browser UI keycape compatibility mount" "https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback"
|
||||
|
||||
KC_POD=$("$KUBECTL" get pod -n "$NAMESPACE" \
|
||||
-l app.kubernetes.io/name=keycape \
|
||||
|
||||
@@ -187,6 +187,8 @@ if not target:
|
||||
required_redirects = {
|
||||
"http://localhost:8250/oidc/callback",
|
||||
"http://127.0.0.1:8250/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
|
||||
"https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback",
|
||||
}
|
||||
required_scopes = {"openid", "profile", "email", "groups"}
|
||||
missing_redirects = sorted(required_redirects - set(target.get("redirectUris") or []))
|
||||
@@ -200,7 +202,7 @@ if missing_redirects:
|
||||
if missing_scopes:
|
||||
print("openbao-admin missing scope(s): " + ", ".join(missing_scopes))
|
||||
raise SystemExit(5)
|
||||
print("openbao-admin client has local CLI redirects and required scopes")
|
||||
print("openbao-admin client has CLI/browser redirects and required scopes")
|
||||
' 2>/dev/null || echo "missing or invalid openbao-admin client")
|
||||
if [[ "$OPENBAO_CLIENT_CHECK" == openbao-admin* ]]; then
|
||||
pass "$OPENBAO_CLIENT_CHECK"
|
||||
|
||||
Reference in New Issue
Block a user