generated from coulomb/repo-seed
feat: opt-in flex-auth policy gate and OpenBao verify (WP-0007)
Add policy.py client that calls flex-auth /v1/check before sign/issue when policy.enabled is true. Record policy_decision_id in signatures.log. Default off preserves existing inventory-only behavior. Document production OpenBao health probe and update config/wiki references.
This commit is contained in:
@@ -1,26 +1,15 @@
|
||||
# Policy-Gated SSH Signing (design)
|
||||
# Policy-Gated SSH Signing
|
||||
|
||||
Date: 2026-06-17
|
||||
Status: **design only** — not implemented in WARDEN-WP-0006
|
||||
Status: **implemented (opt-in)** — WARDEN-WP-0007
|
||||
|
||||
Today `warden sign` authorizes via **inventory allow-list** and TTL policy only.
|
||||
This document proposes flex-auth integration so SSH issuance matches the
|
||||
NetKingdom authorization path before OpenBao/SSH engine signing.
|
||||
By default `warden sign` authorizes via **inventory allow-list** and TTL policy
|
||||
only. When `policy.enabled: true` in `warden.yaml`, ops-warden calls flex-auth
|
||||
before signing and records the decision id in `signatures.log`.
|
||||
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
Inventory-only gating is sufficient for early ops but weak for:
|
||||
|
||||
- many agents and automations across tenants
|
||||
- temporary elevation without inventory edits
|
||||
- unified audit with flex-auth decision envelopes
|
||||
- aligning SSH issuance with IAM Profile claims
|
||||
|
||||
---
|
||||
|
||||
## Target flow (v2)
|
||||
## Flow
|
||||
|
||||
```text
|
||||
warden sign <actor> --pubkey <path>
|
||||
@@ -29,71 +18,82 @@ warden sign <actor> --pubkey <path>
|
||||
Load actor from inventory (type, principals, ttl)
|
||||
|
|
||||
v
|
||||
Obtain identity claims (optional v2.1)
|
||||
OIDC token / env-injected JWT from key-cape session
|
||||
policy.enabled?
|
||||
no -> skip
|
||||
yes -> flex-auth POST /v1/check
|
||||
|
|
||||
v
|
||||
flex-auth Evaluate
|
||||
resource: ssh-certificate / actor:<name>
|
||||
action: sign
|
||||
context: tenant, principal list, pubkey fingerprint, requestor
|
||||
|
|
||||
+-- DENY -> CAError with flex-auth explanation
|
||||
+-- DENY / unreachable (fail_closed) -> CAError
|
||||
|
|
||||
v ALLOW
|
||||
CABackend.sign() (local or OpenBao SSH engine)
|
||||
|
|
||||
v
|
||||
Append signatures.log (+ optional flex-auth audit correlation id)
|
||||
Append signatures.log (+ policy_decision_id when set)
|
||||
```
|
||||
|
||||
The same gate runs for `warden issue` (local backend only).
|
||||
|
||||
---
|
||||
|
||||
## flex-auth request shape (proposed)
|
||||
## flex-auth request shape
|
||||
|
||||
| Field | Source |
|
||||
| --- | --- |
|
||||
| `subject` | IAM Profile `sub` or service identity |
|
||||
| `tenant` | `tenant:platform` or `tenant:coulomb` |
|
||||
| `resource` | `ssh-cert:actor/<actor-name>` |
|
||||
| `subject.id` | `WARDEN_POLICY_SUBJECT` env var, or actor name |
|
||||
| `subject.type` | Actor type (`adm` / `agt` / `atm`) |
|
||||
| `tenant` | `policy.tenant` (default `tenant:platform`) |
|
||||
| `resource.id` | `ssh-cert:actor/<actor-name>` |
|
||||
| `resource.type` | `ssh-certificate` |
|
||||
| `action` | `sign` |
|
||||
| `context.principals` | From inventory |
|
||||
| `context.actor_type` | adm \| agt \| atm |
|
||||
| `context.pubkey_fingerprint` | SHA256 of pubkey |
|
||||
| `context.pubkey_fingerprint` | SHA256 of pubkey text |
|
||||
| `context.ttl_hours` | Requested TTL |
|
||||
|
||||
Decision envelope should return `allow` \| `deny` and `audit_correlation_id`
|
||||
stored in `signatures.log`.
|
||||
flex-auth must return `effect: allow` and an `id` (or `request_id`) on allow.
|
||||
Deny responses include a `reason` surfaced in the CLI error.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
```yaml
|
||||
# warden.yaml — policy gate (opt-in, default off)
|
||||
policy:
|
||||
enabled: false
|
||||
flex_auth_url: http://127.0.0.1:8080
|
||||
fail_closed: true
|
||||
tenant: tenant:platform
|
||||
subject_env: WARDEN_POLICY_SUBJECT
|
||||
system: ops-warden
|
||||
```
|
||||
|
||||
| Key | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `enabled` | `false` | When `true`, call flex-auth before every sign/issue |
|
||||
| `flex_auth_url` | `http://127.0.0.1:8080` | flex-auth base URL |
|
||||
| `fail_closed` | `true` | Deny sign when flex-auth is unreachable or returns HTTP error |
|
||||
| `tenant` | `tenant:platform` | Tenant sent in subject and resource |
|
||||
| `subject_env` | `WARDEN_POLICY_SUBJECT` | Env var for IAM subject id override |
|
||||
| `system` | `ops-warden` | Resource system identifier |
|
||||
|
||||
Set `WARDEN_POLICY_SUBJECT` to the caller's IAM profile `sub` when available.
|
||||
If unset, the actor name is used as subject id.
|
||||
|
||||
---
|
||||
|
||||
## Versioning
|
||||
|
||||
| Version | Gate | Notes |
|
||||
| Version | Gate | Status |
|
||||
| --- | --- | --- |
|
||||
| **v1 (today)** | Inventory + TTL max | Shipped |
|
||||
| **v2** | flex-auth required for `backend: vault` production | Config flag |
|
||||
| **v2.1** | Identity claims required for `adm` signs | OIDC from key-cape |
|
||||
| **v3** | Tenant-scoped policies per `tenant:*` | NK recursive rule |
|
||||
| **v1** | Inventory + TTL max | Shipped |
|
||||
| **v2** | flex-auth opt-in via `policy.enabled` | Shipped (WP-0007) |
|
||||
| **v2.1** | Identity claims required for `adm` signs | Planned |
|
||||
| **v3** | Tenant-scoped policies per `tenant:*` | Planned |
|
||||
|
||||
---
|
||||
|
||||
## Configuration sketch (future)
|
||||
|
||||
```yaml
|
||||
# warden.yaml — not implemented
|
||||
policy:
|
||||
enabled: true
|
||||
flex_auth_url: http://flex-auth.flex-auth.svc.cluster.local:8080
|
||||
require_identity_for_adm: true
|
||||
fail_closed: true
|
||||
```
|
||||
|
||||
`fail_closed: true` — if flex-auth unreachable, deny sign (no silent bypass).
|
||||
|
||||
---
|
||||
|
||||
## What stays in inventory (v2)
|
||||
## What stays in inventory
|
||||
|
||||
- Actor registration (name, type, default principals, default TTL)
|
||||
- Host reference documentation
|
||||
@@ -104,26 +104,18 @@ defines **what the actor is allowed to request**.
|
||||
|
||||
---
|
||||
|
||||
## Non-goals (this design)
|
||||
## Production rollout
|
||||
|
||||
- flex-auth implementation changes in WP-0006
|
||||
- Replacing OpenBao SSH engine with flex-auth
|
||||
- Storing flex-auth policies in ops-warden repo
|
||||
|
||||
---
|
||||
|
||||
## Implementation follow-up
|
||||
|
||||
Promote to **WARDEN-WP-0007** (proposed) after:
|
||||
|
||||
1. flex-auth resource type for `ssh-certificate` agreed
|
||||
2. NK platform policy for platform vs tenant sign paths
|
||||
3. Operator approval for `fail_closed` production behavior
|
||||
1. Deploy flex-auth policies for resource type `ssh-certificate`.
|
||||
2. Enable `policy.enabled: true` in production `warden.yaml`.
|
||||
3. Keep `fail_closed: true` unless an explicit break-glass procedure exists.
|
||||
4. Verify `signatures.log` entries include `policy_decision_id`.
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- `flex-auth/INTENT.md`
|
||||
- `wiki/OpsWardenConfig.md` — full config reference
|
||||
- `wiki/CredentialRouting.md`
|
||||
- `flex-auth/INTENT.md`
|
||||
- `net-kingdom/docs/platform-identity-security-architecture.md`
|
||||
Reference in New Issue
Block a user