Skip to content

Policy Management

Rendering, versioning, and discovering policies from multiple sources.

Policy Rendering Pipeline

How Policies Are Rendered

graph LR
    BASE[Base values.yaml] --> MERGE[yq merge]
    ENV[Environment values] --> MERGE
    MERGE --> COMBINED[Combined values]
    COMBINED --> HELM[helm template]
    TEMPLATE[Policy templates] --> HELM
    HELM --> RENDERED[Rendered policies]

    %% Ghostty Hardcore Theme
    style RENDERED fill:#65d9ef,color:#1b1d1e

Example command:

# Merge base + environment values
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' \
  /repos/security-policy/charts/security-policy/values.yaml \
  /repos/security-policy/cd/prd/values.yaml \
> merged-values.yaml

# Render policies
helm template security-policy \
  /repos/security-policy/charts/security-policy \
  -f merged-values.yaml \
> security-policies.yaml

Two-Stage Rendering

Always merge values first with yq, then render with helm template. This ensures environment-specific values override base values correctly.


Environment-Specific Enforcement

Base Values

charts/security-policy/values.yaml (defaults):

policies:
  resourceLimits:
    enabled: true
    validationFailureAction: Audit

  imageTag:
    enabled: true
    allowLatest: true
    validationFailureAction: Audit

  privileged:
    enabled: true
    validationFailureAction: Enforce

Development Override

cd/dev/values.yaml:

policies:
  resourceLimits:
    validationFailureAction: Audit  # Warn only

  imageTag:
    allowLatest: true
    validationFailureAction: Audit

Production Override

cd/prd/values.yaml:

policies:
  resourceLimits:
    validationFailureAction: Enforce  # Block violations

  imageTag:
    allowLatest: false
    validationFailureAction: Enforce

Production Must Be Stricter

Same policy templates. Different enforcement per environment. Production policies must never be more permissive than dev.


Policy Versioning Strategy

Semantic Versioning

Each policy repo uses semantic versioning:

# Chart.yaml
apiVersion: v2
name: security-policy
version: 2.1.2
appVersion: 2.1.2

Version meaning:

  • Major (2.x.x): Breaking changes, new required fields
  • Minor (x.1.x): New policies, non-breaking changes
  • Patch (x.x.2): Bug fixes, policy refinements

Pinning Policy Versions

Pin specific policy versions in CI:

# Use specific version
docker pull policy-platform:v1.0.2

# Or pin policy repo versions
helm template security-policy /repos/security-policy/charts/security-policy \
  --version 2.1.2

Policy Discovery

Listing Available Policies

# List all policies in container
docker run --rm policy-platform:latest \
  find /repos -name "*.yaml" -path "*/templates/*"

Output:

/repos/security-policy/charts/security-policy/templates/require-resource-limits.yaml
/repos/security-policy/charts/security-policy/templates/disallow-latest-tag.yaml
/repos/devops-policy/charts/devops-policy/templates/require-labels.yaml
/repos/devops-policy/charts/devops-policy/templates/naming-conventions.yaml

Policy Metadata

Extract policy information:

# Get policy names and descriptions
docker run --rm policy-platform:latest \
  yq eval '.metadata.name, .metadata.annotations["policies.kyverno.io/title"]' \
  /repos/security-policy/charts/security-policy/templates/*.yaml

Conflict Resolution

Handling Overlapping Policies

When multiple repos define similar policies:

Strategy 1: Namespace policies

metadata:
  name: security-require-resource-limits  # Prefix with source

metadata:
  name: devops-require-resource-limits

Strategy 2: Policy precedence

Security policies override DevOps policies:

# Apply in order: DevOps first, Security last
kyverno apply devops-policy.yaml --resource app.yaml
kyverno apply security-policy.yaml --resource app.yaml

Strategy 3: Merge policies

Combine rules into single policy during Helm rendering.

Namespace by Source

Prefix policy names with their source repository (security-, devops-, app-). This prevents conflicts and makes policy ownership clear.


Next Steps

Comments