diff --git a/.claude/agents/cpg-operator.md b/.claude/agents/cpg-operator.md new file mode 100644 index 0000000..3962440 --- /dev/null +++ b/.claude/agents/cpg-operator.md @@ -0,0 +1,34 @@ +--- +name: cpg-operator +description: Drives a live cpg MCP session (`start_session`/`get_status`/`stop_session` + plus the query tools and `get_bootstrap_policy`) on behalf of `cpg-triage` and + `cpg-audit-onboard`. Never invoked directly by the operator — spawned by those + two skills whenever a live session needs to be driven end-to-end. +tools: Bash, Read +--- + +# cpg-operator + +## Operating contract + +- You are spawned by `cpg-triage` or `cpg-audit-onboard`, never invoked standalone. + If you are somehow asked to run outside that context, say so and stop — you have + no independent workflow of your own. +- Before calling ANY tool, call `tools/list` and read the live schema. Never assume + an argument name, a result field, or a tool's exact behavior from this document + or from the calling skill's prose — those are workflow routers, not a copy of the + tool contract. The MCP server (`cpg mcp`) is the single source of truth. +- Drive the session lifecycle the calling skill asks for (typically some ordering + of `start_session`, `get_status`, `stop_session`, and the read-only query tools: + `list_dropped_flows`, `list_policies`, `get_policy`, `get_evidence`, + `get_cluster_health`, `get_bootstrap_policy`). Report findings back to the + calling skill in plain terms — you are the driver, not the presenter. +- `Bash` is for spawning `cpg mcp` and driving JSON-RPC over stdio (or a thin MCP + client wrapping that subprocess). `Read` is for inspecting policy YAML and + evidence files a session writes to its own tmpdir. You have no `Write`/`Edit` — + you drive and report, you never author files in this repository. +- Stop the session cleanly (`stop_session`) once the calling skill's workflow is + done or once a hard error stops progress — never leave a session dangling. +- If a tool response looks like an error, check whether it is actually a documented + non-error state (e.g. a mid-capture "not ready yet" marker) before surfacing it as + a failure to the calling skill. diff --git a/.claude/skills/cpg-audit-onboard/SKILL.md b/.claude/skills/cpg-audit-onboard/SKILL.md new file mode 100644 index 0000000..742f8a3 --- /dev/null +++ b/.claude/skills/cpg-audit-onboard/SKILL.md @@ -0,0 +1,129 @@ +--- +name: cpg-audit-onboard +description: > + Guide an operator through onboarding a brand-new namespace into enforced + default-deny network policy: bootstrap, per-endpoint audit mode, capture, + and the human-applied enforce checklist. Use when a namespace has no + default-deny CiliumNetworkPolicy yet and needs to be brought onto one + safely. Do NOT use for triaging an already-running capture on a namespace + that is already onboarded (see cpg-triage) or for offline review of + existing policies (see cpg-policy-review). +--- + +# cpg-audit-onboard + +Router for the full onboarding workflow documented in +[docs/bootstrap-runbook.md](../../../docs/bootstrap-runbook.md). This skill +GUIDES the human through the CLI steps that are human-run, DRIVES the capture +step via the `cpg-operator` agent, and ENDS with the human applying policy — +it never runs `cpg bootstrap`/`cpg audit-window` itself and never invokes an +apply tool, because none exists and none should be invented. + +## Step 0: Check prerequisites + +Point the operator at the runbook's +[Prerequisites](../../../docs/bootstrap-runbook.md#prerequisites) section: +`cpg` on `PATH`, a working `kubeconfig` with `create`/`apply` RBAC for the +target namespace, and Cilium >= 1.16 on the cluster. Confirm these before +proceeding — a stale Cilium version silently degrades `cpg bootstrap`'s +output rather than failing loudly. + +## Step 0.5: Pick the order (live traffic vs fresh namespace) + +Ask the operator one question before anything else: **does the namespace +carry live traffic?** + +- **Live traffic → audit window FIRST, bootstrap second** (swap Steps 1 + and 2 below). Flipping `PolicyAuditMode` is a no-op until a policy + matches, so opening the window first is harmless — and the bootstrap + apply then produces `AUDIT` verdicts instead of real drops. Zero real + drops, end to end. +- **Fresh or scaled-down namespace → bootstrap first** (the order as + written). Nothing is running to drop, and the namespace is enforced from + the very first pod. + +See the runbook's +[Choose Your Order](../../../docs/bootstrap-runbook.md#choose-your-order-live-traffic-vs-fresh-namespace) +section. Either way, remind the operator the namespace is NOT enforced +while the window is open — keep the `--ttl` as short as the capture needs. + +## Step 1: Guide bootstrap (human-run) + +Instruct the operator to run, in their own terminal: + +```bash +cpg bootstrap -n | kubectl apply -f - +``` + +This is a human-run CLI step — this skill does not execute it. If the +operator wants to review before applying, tell them they can redirect to a +file first and `kubectl apply -f` it themselves; see the runbook's +[Bootstrap the Namespace](../../../docs/bootstrap-runbook.md#bootstrap-the-namespace) +section for both paths, plus the note on +[Deploy / Scale Considerations](../../../docs/bootstrap-runbook.md#deploy--scale-considerations) +if the namespace carries live traffic (in which case Step 2's window should +already be open per Step 0.5). + +## Step 2: Guide per-endpoint audit mode (human-run) + +Instruct the operator to run `cpg audit-window` in its own supervised +terminal for the duration of the onboarding capture: + +```bash +cpg audit-window -n --ttl +``` + +This skill does not run this command either — it is foreground and +supervised by design, and it self-reverts on every exit path (Ctrl+C, +SIGTERM, or `--ttl` expiry). Point the operator at the runbook's +[Enable Per-Endpoint Audit Mode](../../../docs/bootstrap-runbook.md#enable-per-endpoint-audit-mode) +section for the RBAC it needs and the documented new-endpoint race window. +Use the per-endpoint form only — never suggest the daemon-wide audit-mode +setting; that ConfigMap knob disables enforcement cluster-wide and the +runbook's own leading warning confines it to a single paragraph for exactly +that reason. + +## Step 3: Drive the capture + +Once the operator confirms audit mode is active, delegate to the +`cpg-operator` agent to call `start_session` with audit-inclusion enabled — +discover the exact argument name for that via `tools/list` at call time; do +not assume it from this document (Router Principle). Let the capture run +long enough to observe the traffic the operator cares about, then have +`cpg-operator` call `stop_session`. + +For a wider verdict view alongside the MCP-driven capture, the operator may +also want the runbook's +[Observe Policy Verdicts](../../../docs/bootstrap-runbook.md#observe-policy-verdicts) +Hubble command — that stays a human/CLI step, not something this skill runs. + +## Step 4: Enforce checklist (ends with the human applying) + +1. Review the generated policy YAML the capture produced. +2. Cross-check against the runbook's + [Create and Apply Generated Policies](../../../docs/bootstrap-runbook.md#create-and-apply-generated-policies) + section. +3. The HUMAN applies the reviewed policy: + + ```bash + kubectl apply -f ./policies// + ``` + +There is no apply tool in this workflow and none should be invoked or +suggested — this step is intentionally the operator's own action, taken +outside this skill, after they have reviewed the YAML. + +## Step 5: Verify and clean up (human-run) + +Point the operator at the runbook's +[Verify Enforcement](../../../docs/bootstrap-runbook.md#verify-enforcement) and +[Clean-up](../../../docs/bootstrap-runbook.md#clean-up) sections to confirm the +endpoint left audit mode and, if this was a one-off exercise, to tear down +what was applied. Per-endpoint audit mode has no separate disable step — +stopping `cpg audit-window` in Step 2 already reverted it. + +## After onboarding + +Once a namespace is onboarded and enforcing, route follow-up live-capture +work to `cpg-triage` and offline policy audits to `cpg-policy-review` — this +skill's job ends at a verified, enforcing namespace. diff --git a/.claude/skills/cpg-health-report/SKILL.md b/.claude/skills/cpg-health-report/SKILL.md new file mode 100644 index 0000000..5330b97 --- /dev/null +++ b/.claude/skills/cpg-health-report/SKILL.md @@ -0,0 +1,60 @@ +--- +name: cpg-health-report +description: > + Turn a captured cluster-health.json into a shareable, self-contained HTML + report of infra/transient drops broken down by node and workload, with + Cilium remediation links. Use when an operator wants a readable report of + the infra side of a session (drops that were not turned into policy). Do + NOT use for generating or reviewing CiliumNetworkPolicies (see cpg-triage + or cpg-policy-review). +--- + +# cpg-health-report + +Router for turning `cluster-health.json` into a shareable HTML report. This +skill routes to where the data lives and what to render — it does not +restate the JSON schema field-by-field beyond naming the fields needed to +route the rendering. + +## Step 1: Obtain cluster-health.json + +Two sources exist — pick the one that matches the invocation context and +STATE which one was used in the report itself: + +- **A saved/archived session directory:** read the file directly from disk + at `/cluster-health.json` (available post-`stop_session`). + This copy is uncapped. +- **An already-running or already-driven session:** call the + `get_cluster_health` MCP tool (via `cpg-operator` if a session is already + being driven for another purpose). This path is server-capped at 100 + node/workload entries per drop. + +## Step 2: Render a self-contained HTML file + +Build one static HTML file, inline `