Request groups scope for whynot OIDC role

This commit is contained in:
2026-06-28 13:23:14 +02:00
parent adf865611c
commit 3527bc1cae
7 changed files with 74 additions and 5 deletions

View File

@@ -58,6 +58,12 @@ openbao:
allowed_redirect_uris:
- https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
- http://localhost:8250/oidc/callback
- http://127.0.0.1:8250/oidc/callback
oidc_scopes:
- openid
- profile
- email
- groups
user_claim: sub
groups_claim: groups
bound_claims:
@@ -104,6 +110,14 @@ verification:
- OIDC role read showed the whynot-design bound claim, read policy, and callback URIs.
- Metadata read showed catalog-id whynot-design-npm-publish.
- Secret field presence check found NPM_AUTH_TOKEN without printing or recording the value.
- at: '2026-06-28T11:20:06+00:00'
actor: codex
kind: non_secret_oidc_role_correction
result: applied
details:
- Positive login reported missing groups claim because the role did not request the groups scope.
- Updated auth/netkingdom/role/whynot-design-workload-kv-read with oidc_scopes openid/profile/email/groups.
- Added the 127.0.0.1 local CLI callback URI alongside localhost and browser callbacks.
lifecycle:
deactivate: Disable ops-warden catalog entry and remove or detach auth role policy.
rotate: Replace NPM_AUTH_TOKEN value directly in OpenBao and record non-secret rotation

View File

@@ -98,7 +98,14 @@ Role payload:
"role_type": "oidc",
"allowed_redirect_uris": [
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
"http://localhost:8250/oidc/callback"
"http://localhost:8250/oidc/callback",
"http://127.0.0.1:8250/oidc/callback"
],
"oidc_scopes": [
"openid",
"profile",
"email",
"groups"
],
"user_claim": "sub",
"groups_claim": "groups",
@@ -119,7 +126,14 @@ cat >"$role_payload_file" <<'JSON'
{
"allowed_redirect_uris": [
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
"http://localhost:8250/oidc/callback"
"http://localhost:8250/oidc/callback",
"http://127.0.0.1:8250/oidc/callback"
],
"oidc_scopes": [
"openid",
"profile",
"email",
"groups"
],
"bound_claims": {
"groups": [
@@ -192,7 +206,7 @@ Only after these are true:
- secret metadata confirmed;
- policy exists and is scoped to the corrected `coulomb/whynot-design` path;
- OIDC role exists and binds only `groups=["whynot-design"]` with approved
browser and local CLI callback URIs;
browser/local CLI callback URIs and `groups` OIDC scope;
- positive verification passed;
- negative verification passed;

View File

@@ -35,7 +35,7 @@ Ops-warden batch follow-up:
| Policy file | `openbao/policies/workload-kv-read-whynot-design-npm-publish.hcl` |
| OIDC auth mount | `netkingdom` |
| OIDC role | `whynot-design-workload-kv-read` |
| OIDC callback URIs | `https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback`, `http://localhost:8250/oidc/callback` |
| OIDC callback URIs | `https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback`, `http://localhost:8250/oidc/callback`, `http://127.0.0.1:8250/oidc/callback` |
| Kubernetes auth role | `whynot-design-workload-kv-read` if an in-cluster service account consumes this lane |
| flex-auth ref | `secret.read:whynot-design` if tenant policy requires pre-approval |
@@ -116,6 +116,17 @@ OpenBao:
```text
https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
http://localhost:8250/oidc/callback
http://127.0.0.1:8250/oidc/callback
```
The role must request these OIDC scopes so KeyCape emits the group claim OpenBao
checks:
```text
openid
profile
email
groups
```
The whynot-design pilot claim is confirmed as `groups=whynot-design`. Before
@@ -180,7 +191,9 @@ warden access "npm token" \
```
Use `--no-policy` only while the local ops-warden config reports
`policy.enabled=false`; remove it once the flex-auth gate is enforced.
`policy.enabled=false`; remove it once the flex-auth gate is enforced. If login
fails with `groups claim not found`, the OpenBao role is missing the `groups`
OIDC scope and must be corrected before retrying.
Negative verification:

View File

@@ -86,6 +86,7 @@ workload_kv_read:
required:
- allowed_redirect_uris
allowed_redirect_uris: non-empty list of OpenBao callback URIs accepted by the role
groups_claim: requires openbao.auth.oidc_scopes to include groups
access_frontdoor_readiness:
allowed:

View File

@@ -183,6 +183,19 @@ def validate_workload_kv_read(ccr: dict[str, Any], errors: list[str], warnings:
errors.append(
f"openbao.auth.allowed_redirect_uris[{index}] must be a non-empty string"
)
if auth.get("groups_claim"):
oidc_scopes = require_list(
auth.get("oidc_scopes"), "openbao.auth.oidc_scopes", errors
)
if "groups" not in oidc_scopes:
errors.append(
"openbao.auth.oidc_scopes must include 'groups' when groups_claim is set"
)
for index, scope in enumerate(oidc_scopes):
if not isinstance(scope, str) or not scope.strip():
errors.append(
f"openbao.auth.oidc_scopes[{index}] must be a non-empty string"
)
policies = [str(policy) for policy in require_list(auth.get("policies"), "openbao.auth.policies", errors)]
if policies != [policy_name]:
errors.append("openbao.auth.policies must contain exactly openbao.policy_name")
@@ -362,6 +375,8 @@ def auth_payload(ccr: dict[str, Any]) -> dict[str, Any]:
payload["groups_claim"] = auth["groups_claim"]
if auth.get("allowed_redirect_uris"):
payload["allowed_redirect_uris"] = auth["allowed_redirect_uris"]
if auth.get("oidc_scopes"):
payload["oidc_scopes"] = auth["oidc_scopes"]
return payload

View File

@@ -142,8 +142,13 @@ class CredentialChangeTests(unittest.TestCase):
[
"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback",
"http://localhost:8250/oidc/callback",
"http://127.0.0.1:8250/oidc/callback",
],
)
self.assertEqual(
payload["oidc_scopes"],
["openid", "profile", "email", "groups"],
)
def test_apply_plan_refuses_unapproved_ccr(self) -> None:
with self.assertRaises(SystemExit):
@@ -170,6 +175,8 @@ class CredentialChangeTests(unittest.TestCase):
self.assertIn('role_payload_file="$(mktemp)"', rendered)
self.assertIn('"bound_claims": {', rendered)
self.assertIn('"allowed_redirect_uris": [', rendered)
self.assertIn('"oidc_scopes": [', rendered)
self.assertIn('"groups"', rendered)
self.assertIn(
'"https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback"',
rendered,

View File

@@ -191,6 +191,11 @@ subject; do not create an unbounded OIDC role.
`workload-kv-read-whynot-design-npm-publish` policy, `ttl=15m`, and the approved
browser/local CLI callback URIs.
**2026-06-28:** Positive verification found the OIDC role was missing
`oidc_scopes`, causing OpenBao login to fail with `groups claim not found`.
Updated the live role and source CCR to request `openid`, `profile`, `email`,
and `groups`, matching the platform-admin OIDC scope shape.
## T04 - Provision the KV path without exposing the token
```task