policy-as-code
Skill1 starsChanged 3 months agoMITView on GitHub
Enforcing platform rules mechanically — admission control, CI policy tests, and runtime detection, so a security rule is a check rather than a convention. Carries: Kyverno vs Gatekeeper/OPA and when each fits, validate/mutate/generate policy patterns, audit-then-enforce rollout so you don't break the cluster, conftest/Rego for the same rules in CI before the manifest merges, image signature verification at admission, Falco for runtime detection, and the three-layer model (edit-time hook, CI, admission) with the honest statement of which one is actually a boundary. Load when enforcing a platform rule across many workloads, wiring admission control, writing CI policy tests, or turning a repeated review comment into a check. Triggers: policy as code, OPA, Rego, Kyverno, Gatekeeper, admission controller, validating webhook, mutating webhook, conftest, Falco, runtime security, enforce pod security, cluster policy, block privileged containers, CIS compliance check, kube-bench. The rules themselves are `policy/platform-security.md`.
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 43
Only admission is enforced by the cluster.
- Distinctive: line 145
Never exclude by wildcard.
- Distinctive: line 198
Blocking without a message that says what to do: Every policy message names the canon rule and the fix, or people work around it.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
policy-as-code — turning a rule people remember into a check that runs
Pinned: kyverno, opa/gatekeeper, conftest, falco, kube-bench — unpinned · authored 2026-07 · run
/skill-update policy-as-code once the tools are installed; CIS control numbering follows
policy/frameworks/cis-kubernetes.md (v2.0.1).
On-demand: load this when a rule needs enforcing across many workloads rather than remembering. The rules are canon at
.claude/memory/policy/platform-security.md; this skill is the enforcement machinery. Writing a single hardened manifest iskubernetes; pipeline wiring issecure-cicd.
When this applies
A review comment you've made three times. A rule in canon with no mechanism. Wiring admission control. Adding a CI policy gate. Detecting at runtime what you couldn't prevent.
The three layers, and which one is real
platform-security.md states this and it's worth repeating because it determines where effort goes:
| Layer | Mechanism | Catches | Boundary? |
| Edit | guard-k8s-manifests.py (exit 2) | The misconfiguration as it's written | No — a guardrail |
| CI | conftest / Kyverno CLI on the PR | Anything authored outside a Claude session, or generated | No — bypassable by anyone with cluster access |
| Admission | Kyverno / Gatekeeper / PSS | Everything that reaches the API server | Yes |
| Runtime | Falco | What was already running when the policy changed, and what admission can't see | Detective, not preventive |
Only admission is enforced by the cluster. The earlier layers exist because finding out at admission means finding out during a rollout, at which point the bad manifest is already merged and reviewed. Write the policy once, run it at all three.
Kyverno vs Gatekeeper
| Kyverno | Gatekeeper (OPA) | |
| Policy language | YAML — Kubernetes-native, no new language | Rego — powerful, genuinely hard to learn |
| Mutate / generate | Yes — can fix and create resources | Validation-focused |
| Scope | Kubernetes only | Anything (Rego runs on any JSON) |
| Best for | Kubernetes policy, most teams | Complex logic; policy reused beyond k8s |
Default to Kyverno for cluster policy — the YAML is reviewable by people who won't learn Rego,
which is what makes policy stick. Reach for OPA/Rego when the logic is genuinely complex, or when
you want the same policy over Terraform plans and manifests (conftest).
Kyverno patterns
Start from the shipped baseline.
.claude/templates/policies/kyverno-baseline.yamlcarries the cluster policies this scaffold's canon requires (policy/platform-security.md) already written — copy it into the project'spolicies/and adjust, rather than authoring from scratch. Theconftestequivalent for CI istemplates/policies/conftest/platform.rego.
Validate — the workhorse. Note validationFailureAction: Audit first; see rollout below.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: { name: require-digest-pinned-images }
spec:
validationFailureAction: Audit # -> Enforce after the audit period (P4)
background: true
rules:
- name: image-must-be-digest-pinned
match:
any: [{ resources: { kinds: [Pod] } }]
validate:
message: >-
Images must be digest-pinned from an approved registry
(platform-security.md P4, CIS 5.x). Use registry.example.com/name@sha256:...
pattern:
spec:
containers:
- image: "registry.example.com/*@sha256:*"Mutate — apply a safe default rather than rejecting. Good for things authors forget and that have an obviously correct value:
- name: default-deny-service-account-token
match: { any: [{ resources: { kinds: [Pod] } }] }
mutate:
patchStrategicMerge:
spec:
+(automountServiceAccountToken): false # P6Generate — create the resources every namespace must have, so they can't be forgotten:
- name: every-namespace-gets-default-deny
match: { any: [{ resources: { kinds: [Namespace] } }] }
generate:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: default-deny-all
namespace: "{{request.object.metadata.name}}"
synchronize: true
data: { spec: { podSelector: {}, policyTypes: [Ingress, Egress] } }That last one is the highest-leverage policy in the set: it makes P5 (default-deny networking) the
automatic state of every new namespace rather than a thing someone remembers.
Verify images — this is where supply-chain.md C3 becomes real, because signing without
verification is theatre:
- name: verify-signature
match: { any: [{ resources: { kinds: [Pod] } }] }
verifyImages:
- imageReferences: ["registry.example.com/*"]
attestors:
- entries:
- keyless:
subject: "https://github.com/ORG/REPO/.github/workflows/*"
issuer: "https://token.actions.githubusercontent.com"Rolling out without breaking the cluster
The way this goes wrong is shipping Enforce on day one and blocking a deploy at 2am.
Auditfirst. Policy runs, violations are recorded, nothing is blocked.- Read the report.
kubectl get policyreport -A— expect existing violations; that's the point. - Fix or exclude, explicitly. Namespace exclusions for
kube-systemand vendor operators are normal; each is a decision-log entry (platform-security.md), not a quietexclude:block. - Flip to
Enforcefor new resources, with the exclusions recorded. - Keep the report. It feeds
memory/process/control-coverage.md.
Never exclude by wildcard. An exclusion nobody can enumerate is a policy nobody has.
The same rules in CI
conftest runs Rego against rendered manifests before merge — the failure is a PR comment instead of
a failed rollout:
kubectl kustomize deploy/overlays/prod | conftest test -p policies/ -
kyverno apply policies/ --resource <(kubectl kustomize deploy/overlays/prod) # same policies, CIpackage main
deny[msg] {
input.kind == "Deployment"
c := input.spec.template.spec.containers[_]
not c.resources.limits.memory
msg := sprintf("%s: container %s has no memory limit (platform-security.md P3)",
[input.metadata.name, c.name])
}Test your policies. A policy with no test asserting it rejects a bad input is a policy that might be silently passing everything — the most common failure in a policy repo. Every rule gets a fixture that must fail and one that must pass.
Runtime detection — Falco
Admission checks what could run; Falco watches what is running (syscalls via eBPF). It's detective, not preventive, and it covers what admission can't see: shell spawned in a container, unexpected outbound connection, write to a binary directory, sensitive file read.
Tune before enabling alerts or the noise trains people to ignore it. Route to the same place as
telemetry (observability).
Benchmarking the cluster
kube-bench asserts CIS Kubernetes Benchmark controls against the running cluster. Run it in CI
where the cluster is self-managed; on managed clusters, sections 1–4 are largely the provider's and
belong in control-coverage.md as their attestation rather than your finding. Pair the benchmark
version to the cluster version — v2.0.1 targets k8s 1.34/1.35, and a mismatch produces both false
passes and false failures.
Gotchas
- Audit mode forever. A policy in
Auditfor six months is a report nobody reads. Set a date to flip it when you write it. - Policies that only run at admission. Existing workloads were admitted under the old rules;
background: truescans them, and the backlog is real. - Webhook failure policy.
failurePolicy: Failmeans a broken policy controller blocks all deploys;Ignoremeans it silently stops enforcing. Both are wrong sometimes — choose per policy, deliberately, and monitor the webhook's own health. - Blocking without a message that says what to do. Every policy message names the canon rule and the fix, or people work around it.
- Assuming policy replaces the hook. They catch different things at different times; the hook is what stops the manifest being written, and the policy is what stops it running.
In this repository59 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agent-evaluationSkill
- agent-securitySkill
- annotationSkill
- authn-authzSkill
- caching-and-queuesSkill
- config-hydraSkill
- config-omegaconfSkill
- containersSkill
- data-acquisitionSkill
- data-dvcSkill
- datasetsSkill
- edaSkill
- env-uvSkill
- evaluationSkill
- example-skillSkill
- finetune-unslothSkill
- gitopsSkill
- governanceSkill
- graph-storesSkill
- guardrailsSkill
- hpo-optunaSkill
- iac-terraformSkill
- infra-awsSkill
- infra-azureSkill
- infra-gcpSkill
- kubernetesSkill
- llm-evalSkill
- llm-red-teamingSkill
- local-stackSkill
- mcp-securitySkill
- memorySkill
- monitoringSkill
- notebooksSkill
- object-and-lakehouseSkill
- observabilitySkill
- pipelinesSkill
- processSkill
- relational-storesSkill
- reliability-sreSkill
- reportingSkill
- secrets-managementSkill
- secure-cicdSkill
- servingSkill
- sqlSkill
- statisticsSkill
- supply-chain-securitySkill
- tabularSkill
- testingSkill
- threat-modelingSkill
- timeseriesSkill
- tracking-mlflowSkill
- tracking-wandbSkill
- trainingSkill
- vector-storesSkill
- visualizationSkill
- wave-planningSkill
- workflow-orchestrationSkill
- wranglingSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

