πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Security advanced ⏱ 15 minutes K8s 1.28+

Kyverno ISO 27001 Compliance Policies

Implement ISO 27001 and BSI IT-Grundschutz security controls in Kubernetes using Kyverno policies: access control, cryptography, operations security, and audit

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: Map ISO 27001 Annex A controls and BSI IT-Grundschutz requirements to Kyverno policies that enforce encryption, access control, network segmentation, logging, and vulnerability management at the Kubernetes admission level.

The Problem

Organizations need to demonstrate compliance with:

  • ISO 27001:2022 Annex A controls (93 controls across 4 themes)
  • BSI IT-Grundschutz (German federal security standard)
  • Evidence of technical enforcement (not just documentation)
  • Continuous compliance (not point-in-time audits)

The Solution

ISO 27001 Control Mapping

ISO 27001 Control              Kyverno Policy
──────────────────────────────────────────────────────────────
A.5.15 Access Control          β†’ Restrict ServiceAccount tokens
A.5.23 Cloud Service Security  β†’ Enforce resource limits
A.8.9  Configuration Mgmt      β†’ Require labels/annotations
A.8.10 Information Deletion    β†’ Enforce PV reclaim policies
A.8.20 Network Security        β†’ Require NetworkPolicies
A.8.24 Cryptography            β†’ Enforce TLS on Ingress
A.8.25 Development Security    β†’ Image signing verification
A.8.28 Secure Coding           β†’ Block privileged containers
A.8.31 Separation of Envs      β†’ Namespace isolation
A.8.34 Audit Logging           β†’ Require sidecar logging

A.8.24 β€” Cryptography (Enforce TLS)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: iso27001-a824-enforce-tls
  annotations:
    policies.kyverno.io/title: "ISO 27001 A.8.24 - Enforce TLS"
    policies.kyverno.io/description: "All Ingress must use TLS"
spec:
  validationFailureAction: Enforce
  rules:
    - name: ingress-must-have-tls
      match:
        any:
          - resources:
              kinds:
                - Ingress
      validate:
        cel:
          expressions:
            - expression: "has(object.spec.tls) && object.spec.tls.size() > 0"
              message: "[ISO27001-A.8.24] Ingress must configure TLS"
            - expression: |
                object.spec.tls.all(t, has(t.secretName) && t.secretName.size() > 0)
              message: "[ISO27001-A.8.24] TLS must reference a certificate secret"

    - name: service-require-https
      match:
        any:
          - resources:
              kinds:
                - Service
              namespaceSelector:
                matchExpressions:
                  - key: compliance/iso27001
                    operator: Exists
      validate:
        message: "[ISO27001-A.8.24] Services in compliance namespaces must use HTTPS"
        pattern:
          metadata:
            annotations:
              service.beta.kubernetes.io/port_443_no_tls: "!*"

A.8.20 β€” Network Security (Require NetworkPolicy)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: iso27001-a820-network-segmentation
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-network-policy
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaceSelector:
                matchLabels:
                  compliance/iso27001: "true"
      preconditions:
        all:
          - key: "{{ request.object.metadata.labels.app || '' }}"
            operator: NotEquals
            value: ""
      validate:
        message: "[ISO27001-A.8.20] Namespace must have a NetworkPolicy before deploying Pods"
        deny:
          conditions:
            all:
              - key: "{{ request.namespace }}"
                operator: AnyNotIn
                value: "{{ request.object.metadata.namespace | networkpolicies(@) }}"

A.5.15 β€” Access Control (ServiceAccount Restrictions)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: iso27001-a515-access-control
spec:
  validationFailureAction: Enforce
  rules:
    - name: restrict-automount-token
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        cel:
          expressions:
            - expression: |
                has(object.spec.automountServiceAccountToken) &&
                object.spec.automountServiceAccountToken == false
              message: "[ISO27001-A.5.15] automountServiceAccountToken must be false"

    - name: no-default-service-account
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        cel:
          expressions:
            - expression: |
                !has(object.spec.serviceAccountName) ||
                object.spec.serviceAccountName != 'default'
              message: "[ISO27001-A.5.15] Must use a dedicated ServiceAccount, not 'default'"

A.8.28 β€” Secure Coding (Pod Security)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: iso27001-a828-pod-security
spec:
  validationFailureAction: Enforce
  rules:
    - name: restrict-containers
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        cel:
          expressions:
            - expression: |
                object.spec.containers.all(c,
                  has(c.securityContext) &&
                  has(c.securityContext.runAsNonRoot) &&
                  c.securityContext.runAsNonRoot == true
                )
              message: "[ISO27001-A.8.28] Containers must run as non-root"

            - expression: |
                object.spec.containers.all(c,
                  has(c.securityContext) &&
                  has(c.securityContext.readOnlyRootFilesystem) &&
                  c.securityContext.readOnlyRootFilesystem == true
                )
              message: "[ISO27001-A.8.28] Root filesystem must be read-only"

            - expression: |
                !has(object.spec.hostPID) || object.spec.hostPID == false
              message: "[ISO27001-A.8.28] hostPID is not allowed"

BSI IT-Grundschutz Module: Container (SYS.1.6)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: bsi-sys16-container-hardening
  annotations:
    policies.kyverno.io/title: "BSI SYS.1.6 Container Hardening"
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-resource-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        cel:
          expressions:
            - expression: |
                object.spec.containers.all(c,
                  has(c.resources) &&
                  has(c.resources.limits) &&
                  has(c.resources.limits.memory) &&
                  has(c.resources.limits.cpu)
                )
              message: "[BSI-SYS.1.6] All containers must have CPU and memory limits"

    - name: require-liveness-probe
      match:
        any:
          - resources:
              kinds:
                - Pod
      exclude:
        any:
          - resources:
              selector:
                matchLabels:
                  batch.kubernetes.io/job-name: "?*"
      validate:
        cel:
          expressions:
            - expression: |
                object.spec.containers.all(c,
                  has(c.livenessProbe)
                )
              message: "[BSI-SYS.1.6] Long-running containers must have liveness probes"

Compliance Reporting

# View policy violations
kubectl get policyreport -A -o wide

# Export compliance report
kubectl get policyreport -A -o json | jq '
  .items[] |
  {
    namespace: .metadata.namespace,
    pass: .summary.pass,
    fail: .summary.fail,
    warn: .summary.warn
  }
'

# Generate ISO 27001 evidence report
kubectl get cpol -o json | jq '.items[] |
  select(.metadata.annotations["policies.kyverno.io/title"] | startswith("ISO")) |
  {
    control: .metadata.annotations["policies.kyverno.io/title"],
    action: .spec.validationFailureAction,
    rules: [.spec.rules[].name]
  }
'

Common Issues

Policies block system workloads

  • Cause: Kyverno enforces on all Pods including kube-system
  • Fix: Add exclude for system namespaces or use namespaceSelector

Compliance drift after policy update

  • Cause: Existing non-compliant resources not re-evaluated
  • Fix: Enable background scanning; use kubectl get policyreport to find violations

Too many policy violations overwhelm team

  • Cause: Enforcing everything at once
  • Fix: Start with Audit; fix violations namespace by namespace; then Enforce

Best Practices

  1. Map controls to policies β€” document which ISO control each policy implements
  2. Use annotations for audit trail (policies.kyverno.io/title)
  3. Namespace-scoped rollout β€” label namespaces compliance/iso27001: true
  4. Background scanning β€” catch pre-existing violations
  5. Policy Reports as evidence β€” export for auditors
  6. Exception process β€” PolicyException CRD for approved deviations

Key Takeaways

  • Kyverno can enforce 20+ ISO 27001 Annex A controls at admission time
  • CEL expressions provide type-safe compliance validation
  • BSI IT-Grundschutz SYS.1.6 maps directly to Pod security policies
  • PolicyReports provide continuous compliance evidence for auditors
  • Namespace labels (compliance/iso27001: true) enable gradual rollout
  • Exception CRD allows documented, approved deviations
  • Audit β†’ Fix β†’ Enforce pattern prevents production disruption
#kyverno #compliance #iso27001 #security #policy
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens