feat(openbao): add SSH engine automation for ops-warden signing

Declarative roles, warden-sign policy, apply/verify scripts, and Makefile
targets openbao-configure-ssh and openbao-verify-ssh. Document operator flow
in docs/openbao.md for NET-WP-0020 T5 / WP-0008 T2.
This commit is contained in:
2026-06-18 01:06:43 +02:00
parent 108944cd3e
commit c24956fb5a
6 changed files with 521 additions and 7 deletions

View File

@@ -18,15 +18,26 @@ S5 workloads / operators
-> openbao-0
-> integrated Raft storage on local-path PVC
-> audit storage PVC mounted at /openbao/audit
Platform operators with approved admin identity
-> https://bao.coulomb.social
-> Traefik Ingress + TLS
-> openbao-ui service
-> OpenBao UI/API
-> KeyCape OIDC at https://kc.coulomb.social for login
```
- OpenBao is the canonical Railiance S3 secrets service.
- SOPS/age remains the Git-at-rest bootstrap mechanism.
- The first Railiance01 deployment is single-replica Raft, not true HA.
- Public ingress is disabled. Operators use `kubectl exec` or port-forwarding.
- Browser UI/API exposure is declared for `https://bao.coulomb.social`.
Operators authenticate through KeyCape/OIDC with MFA and the
`platform-admin` role. Do not use the root token through the browser UI.
- `kubectl exec` and port-forwarding remain valid break-glass/operator paths
for maintenance and non-browser verification.
- TLS is disabled inside the pod listener for this internal-only bootstrap. Add
cert-manager-backed internal TLS before exposing OpenBao beyond cluster-local
traffic.
cert-manager-backed internal TLS before relying on cluster-internal traffic
from untrusted namespaces.
## Deployment
@@ -41,6 +52,10 @@ make openbao-deploy
make openbao-status
```
`make openbao-deploy` also applies `helm/openbao-middleware.yaml`, which
defines the Traefik rate-limit and HSTS middlewares referenced by the OpenBao
Ingress.
On Railiance01 directly:
```bash
@@ -51,10 +66,13 @@ sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml make openbao-status
```
If the repo is not present on Railiance01 yet, copy only the non-secret values
file and run Helm directly:
and middleware files, then run Helm directly:
```bash
scp helm/openbao-values.yaml tegwick@92.205.62.239:/tmp/openbao-values.yaml
scp helm/openbao-middleware.yaml tegwick@92.205.62.239:/tmp/openbao-middleware.yaml
ssh tegwick@92.205.62.239 \
'sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -f /tmp/openbao-middleware.yaml'
ssh tegwick@92.205.62.239 \
'sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml helm upgrade --install openbao openbao/openbao \
--version 0.28.2 \
@@ -78,6 +96,8 @@ Expected immediately after install:
- `openbao-0` is Running.
- `openbao`, `openbao-active`, `openbao-internal`, and `openbao-ui` services
exist as cluster-internal services.
- After DNS points at the cluster ingress, `https://bao.coulomb.social` serves
the OpenBao UI over valid TLS.
- data and audit PVCs are Bound.
- `bao status` reports `Initialized: false` and `Sealed: true`.
@@ -213,6 +233,50 @@ Store that token through the approved operator secret path, then revoke or
tightly escrow the initial root token. The root token should not become the
normal operator credential.
## SSH Secrets Engine (ops-warden)
After `openbao-configure-initial`, enable the SSH user CA used by `ops-warden`
(`warden sign` via `backend: vault`). This is **NET-WP-0020 T5** / **WP-0008 T2**
prerequisite.
Declarative artifacts:
- `openbao/ssh/roles-spec.yaml` — `adm-role`, `agt-role`, `atm-role` TTLs
- `openbao/policies/warden-sign.hcl` — least-privilege signing policy
- `scripts/openbao-apply-ssh-engine.sh` — idempotent apply via `kubectl exec`
- `scripts/openbao-verify-ssh-engine.sh` — non-mutating verification
Apply (requires `platform-admin` or equivalent token with `ssh/*` admin):
```bash
mkdir -p ~/.local/openbao
# Store platform-admin token locally (mode 600, never commit):
# echo '<token>' > ~/.local/openbao/platform-admin.token && chmod 600 ~/.local/openbao/platform-admin.token
OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token OPENBAO_SSH_CA_PUBKEY_OUT=/tmp/openbao-ssh-ca.pub make openbao-configure-ssh
OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token make openbao-verify-ssh
```
The apply script exports the CA public key to `OPENBAO_SSH_CA_PUBKEY_OUT` and
updates K8s secret `openbao/openbao-ssh-ca-pub` (non-secret pubkey only).
Create a dedicated warden signing token (do not use platform-admin daily):
```bash
kubectl exec -n openbao openbao-0 -- bao token create -policy=warden-sign -period=8h -orphan
```
Host trust and principals are **railiance-infra** scope:
```bash
cd ~/railiance-infra
make bootstrap-ssh-ca SSH_CA_PUBKEY=/tmp/openbao-ssh-ca.pub
```
Then on the workstation: `bao login` (or export `VAULT_TOKEN` from the
`warden-sign` token) and run `warden sign` per `ops-warden/wiki/OpenBaoSshEngineChecklist.md`.
## Auth And Workload Integration
Initial auth model:
@@ -228,6 +292,56 @@ Initial auth model:
| Human identity | NetKingdom IAM Profile/OIDC | target model; OpenBao is not the identity provider |
| Automation | Kubernetes auth or short-lived operator token | no root tokens in automation |
### Browser UI Login
The browser operator surface is:
```text
https://bao.coulomb.social
```
Use the KeyCape-backed auth method:
```text
method: OIDC
namespace: leave blank
mount path: netkingdom
role: platform-admin
```
The OpenBao UI redirects the browser to KeyCape at `kc.coulomb.social`, then
returns to:
```text
https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback
```
The legacy `keycape` mount remains a compatibility alias for existing
operator notes and CLI experiments. The preferred browser mount is
`netkingdom`.
The browser callback URI must be present in both:
- KeyCape `openbao-admin` client redirect URIs; and
- OpenBao `auth/netkingdom/role/platform-admin` `allowed_redirect_uris`.
If the compatibility alias is kept enabled, also keep
`https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback` in the
KeyCape client and `auth/keycape/role/platform-admin`.
Use the browser UI for metadata inspection and attended operator workflows.
Do not use the OpenBao root token through the browser UI. Do not copy secret
values, Inter-Hub keys, unseal shares, root tokens, OIDC client secrets, or
screenshots of secret values into Git, State Hub, chat, or workplans.
For `HF-WP-0001`, prefer metadata-only inspection of candidate paths such as:
```text
platform/
platform/operators/
platform/operators/inter-hub/
```
Workload delivery choice:
- Prefer External Secrets Operator for values that should become Kubernetes
@@ -299,8 +413,8 @@ make openbao-verify-authenticated
The target prompts for the token without echoing it, never puts the token on
the command line, and only runs non-mutating checks. It verifies that
`bao audit list` shows `file/`, `bao secrets list` shows `platform/`,
`bao auth list` shows both `kubernetes/` and `keycape/`, and that the file
audit log is non-empty.
`bao auth list` shows `kubernetes/`, `netkingdom/`, and `keycape/`, and that
the file audit log is non-empty.
If a previous attended OIDC login stored a still-valid token in the pod token
helper, use: