Fix OpenBao role payload handoff

This commit is contained in:
2026-06-28 02:33:42 +02:00
parent e3147b7fd5
commit f630d5135e
3 changed files with 31 additions and 26 deletions

View File

@@ -104,18 +104,31 @@ Role payload:
}
```
Equivalent CLI command from an approved OpenBao operator context:
Equivalent CLI command from an approved OpenBao operator shell:
```bash
bao write auth/netkingdom/role/whynot-design-workload-kv-read \
'bound_claims={"groups":["whynot-design"]}' \
groups_claim=groups \
policies=workload-kv-read-whynot-design-npm-publish \
role_type=oidc \
ttl=15m \
user_claim=sub
role_payload_file="$(mktemp)"
trap 'rm -f "$role_payload_file"' EXIT
cat >"$role_payload_file" <<'JSON'
{
"bound_claims": {
"groups": [
"whynot-design"
]
},
"groups_claim": "groups",
"policies": "workload-kv-read-whynot-design-npm-publish",
"role_type": "oidc",
"ttl": "15m",
"user_claim": "sub"
}
JSON
bao write auth/netkingdom/role/whynot-design-workload-kv-read @"$role_payload_file"
```
The OpenBao Web UI console may treat `bound_claims={...}` as a string. Use a
raw JSON/API role editor when staying in the UI, or use the shell form above.
## Non-Secret Reads
These commands should succeed from an operator-capable identity and do not print

View File

@@ -375,26 +375,12 @@ def render_plan(ccr: dict[str, Any]) -> str:
return "\n".join(lines)
def shell_kv_arg(key: str, value: Any) -> str:
if isinstance(value, (dict, list)):
encoded = json.dumps(value, sort_keys=True, separators=(",", ":"))
elif isinstance(value, bool):
encoded = "true" if value else "false"
elif value is None:
encoded = ""
else:
encoded = str(value)
return shlex.quote(f"{key}={encoded}")
def render_operator_commands(ccr: dict[str, Any]) -> str:
openbao = ccr["openbao"]
auth = openbao["auth"]
auth_path = f"auth/{auth['mount']}/role/{auth['role']}"
payload = auth_payload(ccr)
role_args = " ".join(
shell_kv_arg(key, payload[key]) for key in sorted(payload)
)
role_payload = json.dumps(payload, indent=2, sort_keys=True)
secret_args = " ".join(
shlex.quote(f"{field}=<enter-through-approved-custody>")
for field in openbao["fields"]
@@ -404,7 +390,12 @@ def render_operator_commands(ccr: dict[str, Any]) -> str:
"# Run from the railiance-platform repo with an approved OpenBao operator token.",
"set -euo pipefail",
f"bao policy write {shlex.quote(openbao['policy_name'])} {shlex.quote(openbao['policy_file'])}",
f"bao write {shlex.quote(auth_path)} {role_args}",
'role_payload_file="$(mktemp)"',
'trap \'rm -f "$role_payload_file"\' EXIT',
'cat >"$role_payload_file" <<\'JSON\'',
role_payload,
"JSON",
f"bao write {shlex.quote(auth_path)} @\"$role_payload_file\"",
"",
"# Secret provisioning remains under approved OpenBao/operator custody.",
"# Do not paste secret values into Git, State Hub, workplans, logs, or chat.",
@@ -414,7 +405,6 @@ def render_operator_commands(ccr: dict[str, Any]) -> str:
]
return "\n".join(lines)
def validate_or_exit(path: Path) -> tuple[dict[str, Any], list[str]]:
ccr, errors, warnings = validate_ccr(path)
for warning in warnings:

View File

@@ -144,8 +144,10 @@ class CredentialChangeTests(unittest.TestCase):
"bao write auth/netkingdom/role/whynot-design-workload-kv-read",
rendered,
)
self.assertIn('role_payload_file="$(mktemp)"', rendered)
self.assertIn('"bound_claims": {', rendered)
self.assertIn(
'bound_claims={"groups":["whynot-design"]}',
'bao write auth/netkingdom/role/whynot-design-workload-kv-read @"$role_payload_file"',
rendered,
)
self.assertIn(