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).
|
- 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).
|
- 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.
|
- 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).
|
- 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.
|
- 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).
|
- 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.
|
- 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.
|
- 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).
|
- 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).
|
- 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).
|
- 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:**
|
**Bootstrap to runtime transition:**
|
||||||
|
|||||||
@@ -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
|
Downstream applications are registered in the `clients:` block in
|
||||||
`keycape/create-secrets.sh`. The NetKingdom bootstrap console and Railiance
|
`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:
|
those clients manually in a separate UI. After changing the block:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -126,16 +126,20 @@ kubectl rollout restart deployment/keycape -n sso
|
|||||||
```
|
```
|
||||||
|
|
||||||
The `openbao-admin` client is intentionally a public PKCE client for the
|
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
|
```text
|
||||||
http://localhost:8250/oidc/callback
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
OpenBao browser UI callbacks are not registered yet because Railiance OpenBao
|
The browser UI callback is paired with the Railiance Platform OpenBao ingress
|
||||||
currently has public ingress disabled. Add exact UI callback URIs only after
|
at `https://bao.coulomb.social`. The preferred browser auth mount is
|
||||||
the OpenBao UI exposure model is explicitly designed.
|
`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
|
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
|
bootstrap secret bundle and do not re-run the full secret generator. Patch the
|
||||||
@@ -161,6 +165,13 @@ KeyCape:
|
|||||||
bash ./configure-openbao-oidc.sh
|
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.
|
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
|
OpenBao currently requires `oidc_client_secret` for OIDC auth config, while
|
||||||
KeyCape's `openbao-admin` client is public PKCE and does not validate a
|
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
|
printf "\n" >&2
|
||||||
export BAO_TOKEN
|
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
|
# OpenBao requires oidc_client_secret for OIDC auth config. The current
|
||||||
# KeyCape openbao-admin profile is public PKCE and does not validate this
|
# KeyCape openbao-admin profile is public PKCE and does not validate this
|
||||||
# downstream client-secret field, so this compatibility value is not a
|
# downstream client-secret field, so this compatibility value is not a
|
||||||
# protected secret. Replace this with a real managed client secret when
|
# protected secret. Replace this with a real managed client secret when
|
||||||
# KeyCape supports confidential downstream clients.
|
# KeyCape supports confidential downstream clients.
|
||||||
bao write auth/keycape/config \
|
OPENBAO_OIDC_MOUNTS="netkingdom keycape"
|
||||||
oidc_discovery_url="https://kc.coulomb.social" \
|
|
||||||
oidc_client_id="openbao-admin" \
|
|
||||||
oidc_client_secret="keycape-public-pkce-compatibility-value" \
|
|
||||||
default_role="platform-admin"
|
|
||||||
|
|
||||||
# Keep array-valued groups in groups_claim/bound_claims only. OpenBao
|
# Keep array-valued groups in groups_claim/bound_claims only. OpenBao
|
||||||
# claim_mappings copy scalar claim values into metadata and will fail if the
|
# 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"],
|
"oidc_scopes": ["openid", "profile", "email", "groups"],
|
||||||
"allowed_redirect_uris": [
|
"allowed_redirect_uris": [
|
||||||
"http://localhost:8250/oidc/callback",
|
"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": {
|
"bound_claims": {
|
||||||
"groups": ["net-kingdom-admins"]
|
"groups": ["net-kingdom-admins"]
|
||||||
@@ -67,7 +56,26 @@ OPENBAO_POD="${OPENBAO_POD:-openbao-0}"
|
|||||||
}
|
}
|
||||||
ROLE_JSON
|
ROLE_JSON
|
||||||
|
|
||||||
bao write auth/keycape/role/platform-admin @/tmp/openbao-platform-admin-role.json
|
for mount in $OPENBAO_OIDC_MOUNTS; do
|
||||||
rm -f /tmp/openbao-platform-admin-role.json /tmp/keycape-auth-enable.out /tmp/keycape-auth-enable.err
|
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
|
unset BAO_TOKEN
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -122,10 +122,12 @@ clients:
|
|||||||
grantTypes: ["authorization_code"]
|
grantTypes: ["authorization_code"]
|
||||||
clientType: "public"
|
clientType: "public"
|
||||||
- clientId: "openbao-admin"
|
- clientId: "openbao-admin"
|
||||||
displayName: "Railiance OpenBao Admin CLI"
|
displayName: "Railiance OpenBao Admin"
|
||||||
redirectUris:
|
redirectUris:
|
||||||
- "http://localhost:8250/oidc/callback"
|
- "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"
|
||||||
allowedScopes: ["openid", "profile", "email", "groups"]
|
allowedScopes: ["openid", "profile", "email", "groups"]
|
||||||
grantTypes: ["authorization_code"]
|
grantTypes: ["authorization_code"]
|
||||||
clientType: "public"
|
clientType: "public"
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ except ImportError as exc: # pragma: no cover - operator environment guard
|
|||||||
|
|
||||||
OPENBAO_CLIENT = {
|
OPENBAO_CLIENT = {
|
||||||
"clientId": "openbao-admin",
|
"clientId": "openbao-admin",
|
||||||
"displayName": "Railiance OpenBao Admin CLI",
|
"displayName": "Railiance OpenBao Admin",
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:8250/oidc/callback",
|
"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",
|
||||||
],
|
],
|
||||||
"allowedScopes": ["openid", "profile", "email", "groups"],
|
"allowedScopes": ["openid", "profile", "email", "groups"],
|
||||||
"grantTypes": ["authorization_code"],
|
"grantTypes": ["authorization_code"],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Patch the live KeyCape config Secret with non-secret code-defined settings:
|
# 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
|
# This does not require decrypted bootstrap secrets and does not print existing
|
||||||
# Secret values.
|
# Secret values.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Verify the live KeyCape config carries the OpenBao CLI client and KeyCape is
|
# Verify the live KeyCape config carries the OpenBao admin client and KeyCape
|
||||||
# serving OIDC discovery after rollout.
|
# is serving OIDC discovery after rollout.
|
||||||
|
|
||||||
set -euo pipefail
|
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_URL="${KEYCAPE_PUBLIC_URL:-https://kc.coulomb.social}"
|
||||||
PUBLIC_AUTHORIZE_URL="${PUBLIC_URL%/}/authorize"
|
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
|
probe_redirect() {
|
||||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL rejects openbao-admin with unknown client_id" >&2
|
local label="$1"
|
||||||
echo " Check DNS for kc.coulomb.social and ensure it reaches the KeyCape ingress that was patched." >&2
|
local redirect_uri="$2"
|
||||||
exit 1
|
local output
|
||||||
fi
|
output=$(
|
||||||
if ! grep -qE '^HTTP/[0-9.]+ 302 ' <<<"$PUBLIC_PROBE_OUTPUT"; then
|
curl -sS -i -G "$PUBLIC_AUTHORIZE_URL" \
|
||||||
echo "[FAIL] $PUBLIC_AUTHORIZE_URL did not return the expected OIDC redirect for openbao-admin" >&2
|
--data-urlencode "client_id=openbao-admin" \
|
||||||
echo " First response:" >&2
|
--data-urlencode "redirect_uri=$redirect_uri" \
|
||||||
sed -n '1,12p' <<<"$PUBLIC_PROBE_OUTPUT" >&2
|
--data-urlencode "response_type=code" \
|
||||||
exit 1
|
--data-urlencode "scope=openid profile email groups" \
|
||||||
fi
|
--data-urlencode "state=netkingdom-openbao-client-probe" \
|
||||||
echo "[PASS] public KeyCape authorize endpoint recognizes openbao-admin"
|
--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" \
|
KC_POD=$("$KUBECTL" get pod -n "$NAMESPACE" \
|
||||||
-l app.kubernetes.io/name=keycape \
|
-l app.kubernetes.io/name=keycape \
|
||||||
|
|||||||
@@ -187,6 +187,8 @@ if not target:
|
|||||||
required_redirects = {
|
required_redirects = {
|
||||||
"http://localhost:8250/oidc/callback",
|
"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",
|
||||||
}
|
}
|
||||||
required_scopes = {"openid", "profile", "email", "groups"}
|
required_scopes = {"openid", "profile", "email", "groups"}
|
||||||
missing_redirects = sorted(required_redirects - set(target.get("redirectUris") or []))
|
missing_redirects = sorted(required_redirects - set(target.get("redirectUris") or []))
|
||||||
@@ -200,7 +202,7 @@ if missing_redirects:
|
|||||||
if missing_scopes:
|
if missing_scopes:
|
||||||
print("openbao-admin missing scope(s): " + ", ".join(missing_scopes))
|
print("openbao-admin missing scope(s): " + ", ".join(missing_scopes))
|
||||||
raise SystemExit(5)
|
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")
|
' 2>/dev/null || echo "missing or invalid openbao-admin client")
|
||||||
if [[ "$OPENBAO_CLIENT_CHECK" == openbao-admin* ]]; then
|
if [[ "$OPENBAO_CLIENT_CHECK" == openbao-admin* ]]; then
|
||||||
pass "$OPENBAO_CLIENT_CHECK"
|
pass "$OPENBAO_CLIENT_CHECK"
|
||||||
|
|||||||
Reference in New Issue
Block a user