# Policy as Code — Derived Rules > Derives from `domains/compliance/first-principles.md`. Covers P4 > (Policy is Code) and P5 (Policy is Evaluated as a Gate). Referenced > by `audit-logs.md` (policy decisions are audited) and `evidence.md` > (policy decisions are evidence). Framework-agnostic per D-024. ## Policy is Code (P4 Policy is Code) - Compliance policy is expressed in versioned, reviewable, testable code — not in spreadsheets, prose documents, or tribal knowledge. Policy in a spreadsheet is untestable, unreviewable, and undeployable; it is a wishlist, not a control. - Policy-as-code inherits the disciplines of `domains/infrastructure-as-code/P1 Declarative Intent`: declarative intent, version control, review before merge, plan before apply. A compliance rule that is not executable is a rule that cannot be enforced, which is a rule that does not exist. - Policy code is tested like any other code: unit tests for the rule logic (given an input, the rule allows or denies as expected), integration tests for the gate (the rule fires at the right point in the pipeline), and versioning for the policy itself (a policy change is a reviewed, merged, deployed change). ## Policy is Evaluated as a Gate (P5 Policy is Evaluated as a Gate) - Policy violations block **before** the action, not after the audit. Enforcement happens at: - **Admission time** — a kubernetes admission webhook denies a non-compliant resource before it is created (`domains/kubernetes/rbac.md`). - **Pipeline time** — a CI/CD gate denies a non-compliant change before it merges (`domains/devops/ci-cd.md`). - **Provisioning time** — an IaC plan gate denies a non-compliant resource before `apply` (`domains/infrastructure-as-code/`). - A policy that logs violations but does not block the action is a postcard, not a gate. Detection is not enforcement. A logged violation that the actor could ignore is a P5 violation — the policy exists, but the system is not compliant by construction. - The gate is the contract. The policy author writes the rule; the gate operator wires the rule into the enforcement point; the auditor verifies the gate fired. All three are auditable (`audit-logs.md`). ## Engine Comparison (IDEATE-23) | Engine | Policy Language | Evaluation Gate | Ecosystem | Notes | |--------|-----------------|-----------------|-----------|-------| | **OPA / Rego** | Rego (declarative, set-based, Datalog-inspired) | CI/CD, k8s admission (Gatekeeper), HTTP API, IaC plan (Terraform Sentinel-style), service mesh | Broadest ecosystem; CNCF graduated; library of reusable bundles | General-purpose; the default choice when the gate location varies | | **AWS Cedar** | Cedar (declarative, authorization-focused, schema-typed) | k8s admission (via Cedar-agent), application authorization, AVP (Verified Permissions) | AWS-native; tight schema typing; separates policy from entities | Authorization-focused; strong where the policy is "who can do what on which resource" | | **HashiCorp Sentinel** | Sentinel (declarative, restricted, policy-focused) | Terraform / TFE plan gate, Nomad, Vault | HashiCorp ecosystem; embedded in Terraform Enterprise / HCP | IaC-plan-gate native; the enforcement point is the `plan` output | | **Kyverno** | Kyverno (YAML-declarative, k8s-native, no new DSL) | k8s admission (native), cluster-wide policy reports | Kubernetes-native; no separate language — policy is a CRD | k8s-cluster-gate native; the choice when the gate is admission and the team prefers YAML over a DSL | - None is advocated over the others. The choice is (a) where the gate fires, (b) the team's tolerance for a new policy language, and (c) ecosystem fit. All four satisfy P4/P5 when wired correctly. - A gate is a gate regardless of engine: the rule is declarative, the evaluation is pre-action, and the decision is allow-or-deny. The engine difference is language and enforcement-point fit, not correctness. ## Policy Testing - Policy code is unit-tested like any other code. A test asserts that a given input produces the expected decision (allow / deny / warn). The test is versioned with the policy; a policy change with no test change is a red flag. ``` // illustrative Rego policy + test // policy: deny containers running as root package k8s.admission deny[msg] { input.kind == "Pod" c := input.spec.containers[_] not c.securityContext.runAsNonRoot msg := sprintf("container %s must set runAsNonRoot", [c.name]) } // test (Rego unit test) package k8s.admission test_deny_root_container { some msg in deny with input as { "kind": "Pod", "spec": { "containers": [ { "name": "app", "securityContext": {} } ] } } msg == "container app must set runAsNonRoot" } ``` - Integration tests assert the gate fires: a non-compliant resource submitted to the admission endpoint is denied; a compliant one is allowed. The integration test runs against the real gate, not a mock, because the gate wiring is half the contract. ## Policy Versioning - Policy is versioned in git. A policy change is a reviewed, merged, deployed change — the same discipline as application code. A policy that is edited in production without review is a P4 violation: the policy is code, but it is being treated as config. - A policy change can break existing workloads (a new deny rule blocks a previously-allowed resource). The rollout is staged: warn-only mode first (log violations, do not block), then enforce mode after the violation count is zero. This is the policy analogue of `domains/devops/P5 Progressive Delivery`. ## What Violates Policy-as-Code Discipline | Violation | Principle | |-----------|-----------| | A compliance rule in a spreadsheet | P4 Policy is Code | | A policy that logs violations but does not block the action | P5 Policy is Evaluated as a Gate | | A policy edited in production without review | P4 Policy is Code | | A policy with no unit tests for the rule logic | P4 Policy is Code | | A gate wired with a mock instead of the real engine | P5 Policy is Evaluated as a Gate | | A new deny rule enforced without a warn-only rollout | P5 Policy is Evaluated as a Gate | | A policy in prose ("the team should not use root containers") | P4 Policy is Code | | A policy decision with no audit record | P5 Policy is Evaluated as a Gate | ## Relationship to Other Domains - `domains/infrastructure-as-code/first-principles.md` — policy-as- code inherits declarative intent, versioning, and plan-before- apply from IaC. - `domains/kubernetes/rbac.md` — k8s admission is a primary enforcement gate; Kyverno and OPA Gatekeeper wire into it. - `domains/devops/ci-cd.md` — CI/CD is a pipeline-time enforcement gate; a policy step blocks a non-compliant change before merge. - `domains/compliance/audit-logs.md` — every policy decision (allow / deny) is an audited significant action. - `domains/compliance/evidence.md` — policy decisions and the policy code itself are evidence of enforcement posture. - `domains/security/authorization.md` — Cedar's authorization- focused policy overlaps with authz; the split is that authz is the runtime decision, policy-as-code is the reviewed rule that drives it.