Route railiance01 admin kubeconfig through an attended lane
Assistant: grok Assistant-Session: 01a1625d-4770-76a0-8dee-7f5c514a47eb
This commit is contained in:
parent
97c2e3533d
commit
537d551ef2
7 changed files with 94 additions and 4 deletions
|
|
@ -214,6 +214,42 @@ entries:
|
|||
exec_capable: true
|
||||
lane: login
|
||||
|
||||
- id: kubernetes-railiance01-admin
|
||||
title: Attended railiance01 cluster-admin kubeconfig
|
||||
# Identity pointer for the admin kubeconfig file. The agent default path is
|
||||
# the scoped ops-mason-builder identity (MASON-IN-0006 choice (b), decision
|
||||
# 30d29060-8d14-4a8e-9cde-34aa826eb8d1). This lane does not read the file.
|
||||
risk: high
|
||||
workload_ref:
|
||||
applicability: not-applicable
|
||||
reason: "Attended operator identity for the railiance01 admin kubeconfig file. The agent default path is the scoped ops-mason-builder user."
|
||||
need_keywords: [kubernetes, kubeconfig, railiance01, cluster-admin, k3s, admin-kubeconfig, ops-mason-builder]
|
||||
owner_repo: railiance-platform
|
||||
subsystem: attended kubeconfig file outside the agent default path
|
||||
warden_executes: false
|
||||
wiki_ref: wiki/playbooks/kubernetes-railiance01-admin.md#worker-checklist
|
||||
canon_ref: railiance-platform/argocd/platform-addons/ops-mason-builder
|
||||
reviewed: "2026-10-22"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: railiance-platform
|
||||
reviewed: "2026-10-22"
|
||||
verified: source-read
|
||||
auth_method: "attended operator; set KUBECONFIG to /home/worsch/.kube/config-railiance01 for one command. That file is not the agent default path."
|
||||
path_template: "/home/worsch/.kube/config-railiance01"
|
||||
fetch_command: "test -f /home/worsch/.kube/config-railiance01"
|
||||
exec_capable: true
|
||||
lane: secret
|
||||
# vends_secret is structural (active secret lane with a path). Renewal is
|
||||
# re-establishing the file in place, never reading or copying it.
|
||||
rotation:
|
||||
method: re-establish
|
||||
owner: railiance-platform
|
||||
automatable: false
|
||||
steps:
|
||||
- "Re-establish the attended admin kubeconfig at /home/worsch/.kube/config-railiance01, outside the agent default path. Do not copy the admin client key into the builder kubeconfig and do not print the file."
|
||||
|
||||
- id: secrets-engine-approval-client-login
|
||||
title: Attended secrets-engine approval client reader login
|
||||
risk: high
|
||||
|
|
|
|||
|
|
@ -79,8 +79,15 @@ def denied_data_paths(policy_text: str) -> set[str]:
|
|||
|
||||
|
||||
def to_data_path(path_template: str) -> str | None:
|
||||
"""Catalog path -> KV v2 data path. `<mount>/rest` -> `<mount>/data/rest`."""
|
||||
if PLACEHOLDER.search(path_template) or " " in path_template:
|
||||
"""Catalog path -> KV v2 data path. `<mount>/rest` -> `<mount>/data/rest`.
|
||||
|
||||
An absolute filesystem path is not a KV mount.
|
||||
"""
|
||||
if (
|
||||
PLACEHOLDER.search(path_template)
|
||||
or " " in path_template
|
||||
or path_template.startswith("/")
|
||||
):
|
||||
return None
|
||||
mount, _, rest = path_template.partition("/")
|
||||
return f"{mount}/data/{rest}" if rest else None
|
||||
|
|
|
|||
|
|
@ -118,7 +118,14 @@ def build() -> tuple[str, int]:
|
|||
|
||||
def _to_data_path(template: str) -> str | None:
|
||||
import re
|
||||
if re.search(r"[<>{}*]", template) or " " in template or template.startswith("k8s:"):
|
||||
# A leading slash is a filesystem path, not an OpenBao mount. partition()
|
||||
# would otherwise invent an empty mount and a fake `/data/...` address.
|
||||
if (
|
||||
re.search(r"[<>{}*]", template)
|
||||
or " " in template
|
||||
or template.startswith("k8s:")
|
||||
or template.startswith("/")
|
||||
):
|
||||
return None
|
||||
mount, _, rest = template.partition("/")
|
||||
return f"{mount}/data/{rest}" if rest else None
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ class TestToDataPath:
|
|||
"""`ops-warden-warden-sign-token` is a broker grant, not a KV path."""
|
||||
assert mod.to_data_path("credential-grants/catalog.yaml grant ops-warden/warden-sign") is None
|
||||
|
||||
def test_absolute_filesystem_path_has_no_kv_address(self):
|
||||
"""A kubeconfig path must not become an empty-mount `/data/...` address."""
|
||||
assert mod.to_data_path("/home/worsch/.kube/config-railiance01") is None
|
||||
|
||||
|
||||
class TestAgainstTheRealCatalog:
|
||||
def test_every_high_risk_lane_resolves_or_is_explicitly_pattern(self):
|
||||
|
|
|
|||
|
|
@ -266,6 +266,25 @@ def test_platform_admin_login_lane_is_exact_and_non_value_bearing():
|
|||
assert entry.workload_ref.resolution == "not-applicable"
|
||||
|
||||
|
||||
def test_kubernetes_railiance01_admin_lane_is_attended_file_pointer():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
entry = catalog.get("kubernetes-railiance01-admin")
|
||||
assert entry is not None
|
||||
assert entry.status == "active"
|
||||
assert entry.risk == "high"
|
||||
assert entry.lane == "secret"
|
||||
assert entry.lane != "login"
|
||||
assert entry.exec_capable is True
|
||||
assert entry.resolvable is True
|
||||
assert entry.fetch_command == "test -f /home/worsch/.kube/config-railiance01"
|
||||
assert entry.path_template == "/home/worsch/.kube/config-railiance01"
|
||||
assert "cat" not in entry.fetch_command
|
||||
assert "config view" not in entry.fetch_command
|
||||
assert "<" not in entry.fetch_command and ">" not in entry.fetch_command
|
||||
matches = catalog.find("kubernetes railiance01 admin kubeconfig", limit=1)
|
||||
assert matches[0].id == "kubernetes-railiance01-admin"
|
||||
|
||||
|
||||
def test_netkingdom_sso_bind_lanes_are_routed_but_not_resolvable():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
for lane_id in (
|
||||
|
|
@ -405,7 +424,7 @@ def test_exec_capable_without_fetch_command_rejected(tmp_path):
|
|||
@pytest.mark.parametrize(
|
||||
"leaked",
|
||||
[
|
||||
"bao write x token=ghp_abcdef0123456789abcdef0123", # github token prefix
|
||||
"bao write x ghp_abcdef0123456789abcdef0123", # github pat prefix
|
||||
"x=AKIAIOSFODNN7EXAMPLE", # aws key id
|
||||
"header=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", # jwt prefix
|
||||
"val=ZmFrZXNlY3JldDEyMzQ1Njc4OWFiY2RlZmdoaWprbA", # high-entropy run
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ lists the interim set — WARDEN-WP-0030).
|
|||
| `ops-warden-warden-sign-token` | "railiance-platform broker owns the `warden-sign` lease — use `credential exec`" | `railiance-platform/scripts/credential.py exec --grant ops-warden/warden-sign` (see playbook) |
|
||||
| `openbao-api-key` | "OpenBao owns this — here is the path/command shape" | Call OpenBao directly, or use `warden access --fetch/--exec` as yourself when the lane is `exec_capable` |
|
||||
| `openbao-platform-admin-login` | "This is an attended OpenBao administration identity act, not workload secret retrieval" | Use KeyCape-backed OIDC/MFA at `auth/netkingdom`, role `platform-admin`; never substitute a workload role or root token |
|
||||
| `kubernetes-railiance01-admin` | "Attended railiance01 admin kubeconfig; the agent default path is ops-mason-builder" | Prefix kubectl with KUBECONFIG=/home/worsch/.kube/config-railiance01. Do not fetch the file. |
|
||||
| `openbao-shamir-recovery-ceremony` | "This is an attended trust-root ceremony, not secret provisioning" | Obtain one explicit approval and follow the railiance-platform recovery checklist with the existing out-of-band custodians; never send shares through Warden |
|
||||
| `flex-auth-policy-check` | "flex-auth decides — here is the policy doc" | Query flex-auth / embed the PEP |
|
||||
| `key-cape-oidc-login` | "key-cape / Keycloak owns identity" | Authenticate via IAM Profile, or use the `warden access` login lane as yourself |
|
||||
|
|
|
|||
16
wiki/playbooks/kubernetes-railiance01-admin.md
Normal file
16
wiki/playbooks/kubernetes-railiance01-admin.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Attended railiance01 cluster-admin kubeconfig
|
||||
|
||||
## Worker checklist
|
||||
|
||||
This lane is the attended path required by MASON-IN-0006 choice (b). It names
|
||||
the admin kubeconfig file. It does not read that file.
|
||||
|
||||
- The admin file is `/home/worsch/.kube/config-railiance01` and stays that path.
|
||||
- After the scoped identity is installed, `~/.kube/config` is the ops-mason-builder context named `default`, and is not cluster-admin.
|
||||
- Reach admin by prefixing the command: `KUBECONFIG=/home/worsch/.kube/config-railiance01 kubectl ...`
|
||||
- Do not cat the kubeconfig, do not run `kubectl config view`, and do not use `warden access --fetch` to obtain the file. The fetch_command only tests that the file exists.
|
||||
- Do not copy the admin client key into the builder kubeconfig.
|
||||
|
||||
The catalog fetch command is `test -f /home/worsch/.kube/config-railiance01`.
|
||||
A passing test means the file is present. It does not mean the file was read,
|
||||
copied, or made the agent default.
|
||||
Loading…
Add table
Add a link
Reference in a new issue