Record founder approval of the MAS backup reader.
CCR-2026-0062 is approved with the live delivery account confirmed. The OpenBao policy is not installed and no provider key was created. Assistant: grok Assistant-Session: 01a198fa-fd27-7e41-a0a2-57355c3e4efd
This commit is contained in:
parent
a274938232
commit
0fb2305def
4 changed files with 184 additions and 34 deletions
128
scripts/install-mas-backup-primary-reader.sh
Executable file
128
scripts/install-mas-backup-primary-reader.sh
Executable file
|
|
@ -0,0 +1,128 @@
|
|||
#!/bin/sh
|
||||
# Install the MAS backup-primary reader policy and Kubernetes auth role.
|
||||
# Silent: warden access rejects any child output. Receipts stay on absolute paths.
|
||||
# This does not create a provider key, write a KV value, or create a node file.
|
||||
set -eu
|
||||
export BAO_ADDR="${BAO_ADDR:-http://127.0.0.1:18200}"
|
||||
export VAULT_ADDR="${VAULT_ADDR:-http://127.0.0.1:18200}"
|
||||
receipt_dir=/home/worsch/.local/state/railiance/receipts
|
||||
umask 077
|
||||
mkdir -p "$receipt_dir"
|
||||
stage="$receipt_dir/mas-backup-primary-reader.stage"
|
||||
: >"$stage"
|
||||
python3 - "$stage" <<'PY'
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
stage = Path(sys.argv[1])
|
||||
root = Path("/home/worsch/railiance-platform")
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"credential_change", root / "scripts/credential-change.py"
|
||||
)
|
||||
cc = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(cc)
|
||||
|
||||
name = "CCR-2026-0062-mas-backup-primary.yaml"
|
||||
safe_role_keys = (
|
||||
"audience",
|
||||
"bound_service_account_names",
|
||||
"bound_service_account_namespaces",
|
||||
"policies",
|
||||
"token_explicit_max_ttl",
|
||||
"token_max_ttl",
|
||||
"token_no_default_policy",
|
||||
"token_num_uses",
|
||||
"token_policies",
|
||||
"token_type",
|
||||
"ttl",
|
||||
)
|
||||
|
||||
def run(argv):
|
||||
result = subprocess.run(argv, cwd=root, capture_output=True)
|
||||
if result.returncode != 0:
|
||||
stage.write_text(f"exit {result.returncode} step {argv[1]}\n", encoding="utf-8")
|
||||
raise SystemExit(result.returncode or 1)
|
||||
return result.stdout.decode()
|
||||
|
||||
ccr = json.loads((root / "credential-change-requests" / name).read_text(encoding="utf-8"))
|
||||
if ccr.get("status") != "approved" or ccr["openbao"]["auth"].get("bound_claims_confirmed") is not True:
|
||||
stage.write_text(f"{ccr.get('id')} not approved for apply\n", encoding="utf-8")
|
||||
raise SystemExit(44)
|
||||
blockers = cc.applier_readiness_blockers(ccr)
|
||||
if blockers:
|
||||
stage.write_text(ccr["id"] + " blocked\n", encoding="utf-8")
|
||||
raise SystemExit(45)
|
||||
openbao = ccr["openbao"]
|
||||
auth = openbao["auth"]
|
||||
policy_path = root / openbao["policy_file"]
|
||||
run(["bao", "policy", "write", openbao["policy_name"], str(policy_path)])
|
||||
installed = run(["bao", "policy", "read", openbao["policy_name"]])
|
||||
if cc.normalized_policy_body(installed) != cc.normalized_policy_body(policy_path.read_text(encoding="utf-8")):
|
||||
stage.write_text(openbao["policy_name"] + " readback differs\n", encoding="utf-8")
|
||||
raise SystemExit(46)
|
||||
payload = cc.auth_payload(ccr)
|
||||
role_file = Path(f"/home/worsch/.local/state/railiance/receipts/{auth['role']}.payload.json")
|
||||
role_file.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
role_file.chmod(0o600)
|
||||
run(["bao", "write", f"auth/{auth['mount']}/role/{auth['role']}", f"@{role_file}"])
|
||||
raw = run(["bao", "read", "-format=json", f"auth/{auth['mount']}/role/{auth['role']}"])
|
||||
data = json.loads(raw).get("data", {})
|
||||
names = data.get("bound_service_account_names")
|
||||
namespaces = data.get("bound_service_account_namespaces")
|
||||
policies = data.get("token_policies") or data.get("policies")
|
||||
audience = data.get("audience") or data.get("audiences")
|
||||
problems = []
|
||||
if names != payload["bound_service_account_names"]:
|
||||
problems.append("names")
|
||||
if namespaces != payload["bound_service_account_namespaces"]:
|
||||
problems.append("namespaces")
|
||||
if policies != payload["policies"].split(","):
|
||||
problems.append("policies")
|
||||
if audience not in (payload.get("audience"), [payload.get("audience")]):
|
||||
problems.append("audience")
|
||||
if data.get("token_no_default_policy") is not True:
|
||||
problems.append("no_default")
|
||||
if data.get("token_num_uses") != 4:
|
||||
problems.append("uses")
|
||||
if data.get("token_type") != "service":
|
||||
problems.append("type")
|
||||
if data.get("ttl") not in (300, "5m", "300s"):
|
||||
problems.append("ttl")
|
||||
if data.get("token_max_ttl") not in (300, "5m", "300s"):
|
||||
problems.append("max_ttl")
|
||||
if data.get("token_explicit_max_ttl") not in (300, "5m", "300s"):
|
||||
problems.append("explicit_max_ttl")
|
||||
if problems:
|
||||
observed = {key: data.get(key) for key in safe_role_keys if key in data}
|
||||
stage.write_text(
|
||||
json.dumps({"role": auth["role"], "problems": problems, "observed": observed}, indent=2)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
raise SystemExit(47)
|
||||
receipt = {
|
||||
"status": "installed",
|
||||
"id": ccr["id"],
|
||||
"policy": openbao["policy_name"],
|
||||
"role": auth["role"],
|
||||
"policies": policies,
|
||||
"bound_service_account_names": names,
|
||||
"bound_service_account_namespaces": namespaces,
|
||||
"ttl": data.get("ttl"),
|
||||
"token_max_ttl": data.get("token_max_ttl"),
|
||||
"token_explicit_max_ttl": data.get("token_explicit_max_ttl"),
|
||||
"token_num_uses": data.get("token_num_uses"),
|
||||
"token_no_default_policy": data.get("token_no_default_policy"),
|
||||
"token_type": data.get("token_type"),
|
||||
}
|
||||
out = Path("/home/worsch/.local/state/railiance/receipts/mas-backup-primary-reader.json")
|
||||
out.write_text(json.dumps(receipt, indent=2) + "\n", encoding="utf-8")
|
||||
out.chmod(0o600)
|
||||
PY
|
||||
if [ -s "$stage" ]; then
|
||||
exit 48
|
||||
fi
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue