generated from coulomb/repo-seed
FLEX-WP-0006: implement ops-warden signing gate policy
This commit is contained in:
230
workplans/FLEX-WP-0006-ops-warden-ssh-signing-policy-gate.md
Normal file
230
workplans/FLEX-WP-0006-ops-warden-ssh-signing-policy-gate.md
Normal 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`.
|
||||
Reference in New Issue
Block a user