FLEX-WP-0006: implement ops-warden signing gate policy
Some checks failed
CI / Build and Test (push) Has been cancelled
CI / Lint (push) Has been cancelled

This commit is contained in:
2026-06-23 21:17:42 +02:00
parent 53e0d055c9
commit 0fde95a87c
25 changed files with 1796 additions and 10 deletions

View File

@@ -0,0 +1,230 @@
---
id: FLEX-WP-0006
type: workplan
title: "Ops-Warden SSH Signing Policy Gate"
domain: infotech
repo: flex-auth
status: finished
owner: codex
topic_slug: flex-auth
planning_priority: P0
planning_order: 60
depends_on_workplans:
- FLEX-WP-0002
- FLEX-WP-0005
related_workplans:
- WARDEN-WP-0009
created: "2026-06-23"
updated: "2026-06-23"
state_hub_workstream_id: "bbea4049-8acc-4d7c-8cf5-3106c6b93f7f"
---
# FLEX-WP-0006: Ops-Warden SSH Signing Policy Gate
## Purpose
Publish the flex-auth policy package, registry fixtures, and service contract
evidence needed for ops-warden's opt-in pre-sign gate.
Ops-warden already shipped the caller side in `WARDEN-WP-0007`:
`policy.enabled: true` makes `warden sign` and local-backend `warden issue`
call `POST /v1/check` before signing. Production OpenBao-backed signing was
verified in `WARDEN-WP-0008`. The remaining blocked work is flex-auth-owned:
policies for `resource.type: ssh-certificate` and `action: sign`.
This workplan unblocks `ops-warden/workplans/WARDEN-WP-0009-flex-auth-policy-gate-production.md`.
## Gate Contract
The shipped ops-warden gate sends this flex-auth decision request:
| Field | Meaning |
| --- | --- |
| `subject.id` | `WARDEN_POLICY_SUBJECT` when set, otherwise actor name |
| `subject.type` | Actor type: `adm`, `agt`, or `atm` |
| `tenant` | `policy.tenant`, default `tenant:platform` |
| `resource.id` | `ssh-cert:actor/<actor-name>` |
| `resource.type` | `ssh-certificate` |
| `resource.system` | `ops-warden` |
| `action` | `sign` |
| `context.principals` | Requested SSH certificate principals from inventory |
| `context.actor_type` | Actor type: `adm`, `agt`, or `atm` |
| `context.pubkey_fingerprint` | SHA256 fingerprint of the submitted public key text |
| `context.ttl_hours` | Requested certificate TTL |
Allow responses must return `effect: allow` plus a decision `id` or
`request_id`; ops-warden records that value as `policy_decision_id` in
`signatures.log`. Deny responses must include a human-readable `reason` that
the ops-warden CLI can surface.
## Policy Boundary
flex-auth decides whether this specific signing request is allowed now.
ops-warden remains responsible for SSH CA operation, OpenBao integration, actor
inventory, host documentation, and local scorecard checks.
The flex-auth policy must not request or store SSH private keys, OpenBao
tokens, database credentials, or other secrets. Acceptance evidence should use
fixtures, non-secret request bodies, decision ids, and sanitized logs only.
## T1 - Pin the ops-warden protected-system contract
```task
id: FLEX-WP-0006-T01
status: done
priority: high
state_hub_task_id: "8831b904-dbef-4d55-8eb5-053c939c86b3"
```
Add an ops-warden protected-system manifest and registry fixture slice that
declares:
- protected system `ops-warden`
- resource type `ssh-certificate`
- action `sign`
- tenant `tenant:platform`
- supported actor subject types `adm`, `agt`, and `atm`
- required context fields: `principals`, `actor_type`,
`pubkey_fingerprint`, and `ttl_hours`
Output should live under `examples/ops-warden/` unless implementation reveals a
more idiomatic local path. The manifest and fixture must validate with the
existing `flex-auth validate` and `flex-auth load-registry` commands.
## T2 - Author the ssh-certificate sign policy package
```task
id: FLEX-WP-0006-T02
status: done
priority: high
state_hub_task_id: "9ea206fa-f93d-46b6-8b8e-e8669dd502d4"
```
Create the Rego-in-Markdown policy package for ops-warden signing decisions.
Minimum allow criteria:
- request action is `sign`
- resource system is `ops-warden`
- resource type is `ssh-certificate`
- tenant is `tenant:platform` unless the fixture explicitly tests another
configured tenant
- subject and `context.actor_type` are aligned with the actor resource
- requested TTL is positive and within the policy's configured maximum for the
actor type
- requested principals are non-empty and allowed for the actor fixture
- `context.pubkey_fingerprint` is present
Minimum deny criteria:
- unknown subject or actor resource
- mismatched `subject.type`, `context.actor_type`, or
`resource.id: ssh-cert:actor/<actor>`
- TTL outside policy bounds
- missing fingerprint
- disallowed or empty principals
- wrong action, system, resource type, or tenant
The package should produce clear deny reasons and preserve the standard
decision envelope so ops-warden can surface `reason` without special casing.
## T3 - Add allow and deny fixtures
```task
id: FLEX-WP-0006-T03
status: done
priority: high
state_hub_task_id: "6bf5cb9b-d46c-49cf-aec0-12f6e864a1f8"
```
Add fixture requests and expected decisions for the gate.
Required fixtures:
- allow: valid `adm` sign request
- allow: valid `agt` sign request, if an agent actor fixture exists
- deny: unknown subject
- deny: actor type mismatch
- deny: TTL above policy max
- deny: missing or disallowed principal
- deny: missing `pubkey_fingerprint`
Wire the fixtures into Go tests or the existing policy fixture runner so
`make test` proves the package behavior. Fixture data must remain non-secret.
## T4 - Verify the `/v1/check` service contract
```task
id: FLEX-WP-0006-T04
status: done
priority: high
state_hub_task_id: "077d29db-30e0-4447-90fd-620c0884306c"
```
Run `flex-auth serve` with the ops-warden registry and policy package, then
exercise `POST /v1/check` with ops-warden-shaped JSON.
Acceptance evidence:
- allow response includes `effect: allow` and a stable decision `id`
- deny response includes `effect: deny` and a useful `reason`
- decision log records the allow and deny decisions without secrets
- method mismatch and malformed JSON fail predictably
- the documented behavior is compatible with ops-warden `fail_closed: true`
If the current service shape needs a small compatibility adjustment, keep it
inside the stable v1 API instead of adding an ops-warden-specific route.
## T5 - Hand off production-readiness evidence to ops-warden
```task
id: FLEX-WP-0006-T05
status: done
priority: medium
state_hub_task_id: "06cac0b1-51c0-4ae0-b605-c940f7821ac7"
```
Publish the handoff notes ops-warden needs to close `WARDEN-WP-0009 T01` and
start its production enablement smoke.
Include:
- policy package path and version
- registry fixture path
- local service command
- allow and deny fixture names
- non-secret decision ids from local smoke
- expected `policy.enabled` production sequence
- reminder that OpenBao SSH signing and SSH CA custody remain ops-warden-owned
Record progress in State Hub and ask the custodian operator to run
`make fix-consistency REPO=flex-auth` from `~/state-hub` after this workplan is
merged or otherwise accepted.
## Implementation Summary
Implemented on 2026-06-23.
- Added examples/ops-warden/ with the protected-system manifest, subject and
resource manifests, combined registry snapshot, policy package, check
requests, and allow/deny fixtures.
- Added top-level tenant support to CheckRequest and BatchCheckRequest so the
shipped ops-warden policy gate request shape is accepted by /v1/check.
- Added CLI and HTTP service tests for the ops-warden allow path, deny path,
malformed JSON, method mismatch, and decision-log recording.
- Added docs/ops-warden-policy-gate-handoff.md with non-secret smoke evidence
and the ops-warden production enablement sequence.
## Exit Criteria
- flex-auth contains a validated ops-warden protected-system manifest and
registry fixture.
- flex-auth contains an `ssh-certificate` / `sign` policy package with allow
and deny fixtures for `adm`, `agt`, and `atm`-style actors where applicable.
- `make test` passes.
- `POST /v1/check` accepts the shipped ops-warden request shape and returns
decision envelopes compatible with `policy.enabled: true`.
- A sanitized handoff note exists for ops-warden `WARDEN-WP-0009`.
- State Hub progress is logged and the operator is told to run
`make fix-consistency REPO=flex-auth`.