Skip to content
Stribog

Compliance

All writing

ISO 27001 Without Inherited Controls: Annex A You Operate

ISO 27001 compliance on infrastructure you run: how to scope the ISMS, write a Statement of Applicability, and evidence Annex A 8.9, 8.16, 8.13 and 5.23.

Stribog13 min read

There is a persistent assumption in platform teams that self-hosting makes certification harder. It is worth stating the opposite plainly: it makes certification explicit. Nothing about running your own infrastructure adds an Annex A control. It relocates a set of them from outside your management system to inside it, where you implement them and — the part that actually decides the outcome — where you can produce the record.

Search the primary term and the results are Statement of Applicability templates, 93-control checklists and readiness landing pages, nearly all published by compliance-automation vendors and nearly all assuming a hyperscaler underneath. None of them answer the only question an infrastructure engineer has: which mechanism in my cluster produces the evidence for a given control?

The Controls You Can No Longer Inherit

First, a correction to the framing most content still carries. The 2022 revision is not upcoming and the transition is not open. ISO/IEC 27002:2022 replaced the 2013 Annex A control set — 114 controls across A.5 to A.18 became 93, reorganised into four themes: organisational, people, physical and technological. IAF MD 26 set the schedule for that changeover, requiring certification bodies to conduct initial certification and recertification against the 2022 edition only from 30 April 2024, and to complete transitions of certified clients by 31 October 2025. Certifications based on the 2013 edition expire or are withdrawn at the end of that period. There is one Annex A to certify against now.

The current edition is ISO/IEC 27001:2022 as amended by Amendment 1:2024, 'Climate action changes', published in February 2024, which integrates climate considerations into the clauses on organisational context and interested parties rather than into Annex A. It does not change a single control.

Which controls move when the infrastructure becomes yours is not a long list, but it is a consequential one. Physical and environmental controls, control-plane hardening, node operating system configuration, storage encryption, backup and the whole logging and monitoring family stop being answered by reference to a provider's certificate and start being answered by reference to something running in your estate. That is the entire substantive difference, and it lands almost exclusively in the technological theme.

Self-hosting does not add controls. It moves them across the boundary — and everything crossing that boundary passes through the same two documents.

Clause 4.3: The Scope Boundary Is the Budget

Clause 4.3 requires you to determine the boundaries and applicability of the information security management system and state them. It is one short document and it is the single most expensive decision in the programme, because everything inside it gets audited and everything outside it has to be justified as outside.

Teams get this wrong in both directions. Scope too wide — 'the whole company' — and Stage 2 fieldwork walks through corporate laptops, an office badge system and a marketing SaaS estate that has nothing to do with the product you are certifying. Scope too narrow, and a customer reads the certificate, sees that the service they buy is not inside the boundary, and treats the certificate as worthless. The certificate names the scope. Procurement reads it.

For a self-hosted platform, the boundary that survives contact with an auditor is usually drawn around the product and the infrastructure that runs it: the clusters, the control planes, the CI/CD path into them, the identity system that governs access, and the people who operate all of that. The colocation facility sits outside, but not silently — the operator becomes a supplier assessed under the supplier-relationship controls, and an interested party under clause 4.2. Deliberately excluded is not the same as unexamined.

One practical note from our engagements: write the scope statement in terms of services and locations, not in terms of technology. A boundary defined as 'Kubernetes' ages badly and invites a debate about whether a new runtime is in or out. A boundary defined as the platform that delivers a named service, at named sites, does not.

The Statement of Applicability That Survives Review

The Statement of Applicability is mandated by clause 6.1.3, inside the clause on actions to address risks and opportunities. It lists all 93 Annex A controls, records whether each is implemented, justifies its inclusion or exclusion, and briefly describes how each applicable control is implemented. It is read alongside the clause 4.3 scope, and both are on the table at Stage 1 — before anyone tests a control.

The failure mode is the implementation column. Written as prose, it becomes 93 paragraphs of intent that nobody maintains and that contradict the cluster within two quarters. Written as a pointer, it becomes a map: control identifier, decision, justification, the mechanism that implements it, and the path where its evidence accumulates. Keeping the SoA as structured data in the same repository as the platform means it reviews like code and drifts like code — which is to say, visibly.

yaml
# Excerpt — two of the 93 Annex A rows. The full file carries every control.
- control: "8.9"
  name: Configuration management
  decision: included
  justification: >-
    Cluster and node configuration is inside the ISMS scope and drifts
    without enforcement. Risk register entry R-014.
  mechanism:
    - CIS-aligned hardening baseline, benchmark version recorded per run
    - Kyverno ClusterPolicy evaluated on admission and in background scans
    - GitOps reconciliation; every change arrives as a reviewed commit
  evidence:
    - evidence/8.9/kube-bench/       # one dated directory per scheduled run
    - evidence/8.9/policy-reports/   # PolicyReport snapshots, same cadence
  owner: platform-engineering

# ... rows 8.10 through 7.3 omitted ...

- control: "7.4"
  name: Physical security monitoring
  decision: excluded
  justification: >-
    The organisation operates no premises hosting in-scope systems. Compute
    is colocated; the facility operator is assessed as a supplier under
    5.19-5.22 and its own certification is held on file.
  evidence:
    - evidence/5.19/supplier-assessments/colocation-2026.pdf
soa.yaml — an excerpt: two rows of ninety-three. The implementation column points at a mechanism and a path, not at a paragraph.

Exclusions are where inexperienced SoAs lose credibility. An exclusion needs a reason rooted in the organisation, not in effort: no premises, no software development activity, no cryptographic key issuance. 'Not applicable to us' with nothing behind it is the sentence that turns a Stage 1 into a longer Stage 1.

Annex A 8.9: Configuration Management You Already Do

Guidance on 8.9 sets two expectations that map cleanly onto a platform team's existing habits. The first is standardised hardening templates drawn from vendor and open-source instructions. The second is the one people miss: configurations must be recorded together with a history of changes. That second expectation is a records requirement, and it is why a hardened cluster with no history still fails the control.

kube-bench checks whether a cluster is deployed in line with the CIS Kubernetes Benchmark — one common way to evidence 8.9, not the only one. Run it the way upstream does: the host's PID namespace plus the config, state and binary directories mounted in, with the master and node targets landing on matching node roles. A pod without those mounts reports missing files, not a baseline. Record the benchmark version with every run, because CIS Benchmark releases do not map one-to-one onto Kubernetes releases.

The change history comes from two places. Git carries the intent — reviewed commits, with the review itself acting as the authorisation record. Admission policy carries the outcome. Kyverno emits PolicyReport and ClusterPolicyReport custom resources in the wgpolicyk8s.io/v1alpha2 API group, with per-result values of pass, fail, warn, error and skip. Start in audit rather than enforce so the first reports describe reality instead of blocking it.

yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: annex-a-8-9-baseline
  annotations:
    policies.kyverno.io/category: ISO 27001 Annex A 8.9
spec:
  background: true
  rules:
    - name: containers-run-as-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        failureAction: Audit
        message: >-
          Containers must set runAsNonRoot (Annex A 8.9 configuration baseline).
        pattern:
          spec:
            securityContext:
              runAsNonRoot: true
A baseline rule that reports rather than blocks. failureAction lives on the rule; the policy-level spec.validationFailureAction field is deprecated. The pattern reads pod-level securityContext only — illustrative, not a CIS-equivalent baseline.
bash
#!/usr/bin/env bash
# capture-8-9.sh — Annex A 8.9 configuration evidence, one dated snapshot.
set -euo pipefail

DAY="$(date -u +%Y-%m-%d)"
OUT="evidence/8.9/${DAY}"
KB="v0.15.6"
mkdir -p "${OUT}"

# Configuration baseline. The upstream Jobs carry hostPID, the hostPath mounts
# the CIS checks read and the node affinity. Pin the image; they ship :latest.
for TARGET in master node; do
  curl -fsSL "https://raw.githubusercontent.com/aquasecurity/kube-bench/${KB}/job-${TARGET}.yaml" \
    | sed "s|kube-bench:latest|kube-bench:${KB}|; s|\"--targets\", \"${TARGET}\"|&, \"--json\"|" \
    | kubectl apply -f -
  kubectl wait --for=condition=complete --timeout=300s "job/kube-bench-${TARGET}"
  kubectl logs "job/kube-bench-${TARGET}" > "${OUT}/kube-bench-${TARGET}.json"
  kubectl delete job "kube-bench-${TARGET}"
done

# The benchmark version, read back from the reports themselves.
jq -rs '[.. | .version? // empty] | unique | join(" ")' \
  "${OUT}"/kube-bench-*.json > "${OUT}/benchmark-version.txt"

# Configuration outcome, cluster-wide, at this instant.
kubectl get clusterpolicyreports.wgpolicyk8s.io -o json > "${OUT}/cluster-policy-reports.json"
kubectl get policyreports.wgpolicyk8s.io -A -o json > "${OUT}/policy-reports.json"

# Make the snapshot self-describing, then seal it.
git -C . rev-parse HEAD > "${OUT}/platform-revision.txt"
sha256sum "${OUT}"/*.json "${OUT}"/*.txt > "${OUT}/SHA256SUMS"
Evidence capture named for the control it serves. Run it on a schedule, not on request.

Annex A 8.15 and 8.16: Logging You Can Sample, Monitoring That Operates

8.16 Monitoring Activities is new in the 2022 revision — it had no counterpart in the 2013 Annex A. The distinction between it and 8.15 logging matters more than it looks. 8.15 is about records existing. 8.16 is about somebody watching, with a defined baseline of normal, alerting that fires, and a disposition recorded when it does. Retained logs alone satisfy one of the two.

On Kubernetes, the record starts at the API server, and it starts switched off. Auditing is enabled by --audit-policy-file; without that flag no events are logged at all. The policy object is audit.k8s.io/v1, a policy with zero rules is illegal, and the first matching rule sets an event's level, so ordering is the design. The four levels — None, Metadata, Request and RequestResponse — are what let you tier by sensitivity instead of choosing between silence and terabytes.

yaml
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
  - RequestReceived
rules:
  # Never log the read-heavy control-plane chatter — it buries the signal.
  - level: None
    users: ["system:kube-scheduler", "system:kube-controller-manager"]
    verbs: ["get", "list", "watch"]

  # Secrets: metadata only. Bodies would put secret material in the log.
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets", "configmaps"]

  # Authorisation changes: the full picture, request and response.
  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]

  # Every other write, with the submitted object.
  - level: Request
    verbs: ["create", "update", "patch", "delete"]

  # Catch-all, so nothing falls through unrecorded.
  - level: Metadata
A tiered audit policy. First match wins, so the noise-suppression rules come before the catch-all.

Two operational points decide whether this is evidence or a liability. Ship the events off the control-plane node, because an audit trail an attacker with node access can edit is not an audit trail — the same argument made in our self-hosted observability work. And set retention past the certification cycle, not past your debugging horizon: an auditor sampling a surveillance period wants events from a date you had already rotated away.

For 8.16 specifically, the artefact is not the log. It is the alert record: what fired, when, who looked, what they concluded. In our engagements that record is the thing most often missing, because the alerting exists and nobody kept the dispositions.

Annex A 8.13 and 8.24: Backup and Cryptography on Storage You Own

8.13 information backup is where self-hosting is straightforwardly easier, because the mechanism and the evidence are the same object. Velero (v1.16 documentation) backs up and restores cluster resources and persistent volumes; a Schedule with an explicit ttl produces Backup objects that carry their own retention, which is a control artefact rather than an assertion that backups happen.

yaml
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: annex-a-8-13-nightly
  namespace: velero
spec:
  schedule: "0 2 * * *"
  useOwnerReferencesInBackup: false   # deleting the Schedule must not delete evidence
  template:
    ttl: 2160h0m0s          # 90 days — stated, auditable, not implied
    includedNamespaces:
      - "*"
    excludedNamespaces:
      - kube-system
    snapshotVolumes: true
    storageLocation: default
Retention is declared, so expiry is evidence rather than a cleanup script nobody reads. Leave useOwnerReferencesInBackup false: set true, deleting the Schedule deletes the Backups it created, and the period evidence goes with it.

A backup nobody has restored is an untested control, and auditors have learned to ask. Rehearse the restore on a cadence you set, into a scratch namespace, and write a dated result carrying a measured recovery time and an integrity verdict — the discipline covered at length in our Kubernetes disaster recovery article.

8.24 use of cryptography brings the trap. At-rest encryption of Kubernetes API data is enabled with --encryption-provider-config on kube-apiserver, and the first provider in the list is the one used for encryption — all providers are tried in order for decryption. The identity provider performs no encryption. A configuration file that lists identity first is a fully valid file, on a cluster whose flag is set, storing everything in plain text.

Provider choice deserves the same scepticism. The Kubernetes documentation marks aescbc as not recommended, given CBC's exposure to padding-oracle attacks, and aesgcm as not recommended except where an automated key rotation scheme is implemented — its key must be rotated every 200,000 writes. For a sovereign stack the coherent answer is KMS v2 envelope encryption against a key service you also run, which keeps the key encryption key off the control-plane host; see our secrets management article for the surrounding architecture.

yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
      - configmaps
    providers:
      # Envelope encryption: the KEK lives in a key service you operate,
      # not on the control-plane filesystem next to the ciphertext.
      - kms:
          apiVersion: v2
          name: sovereign-kms
          endpoint: unix:///var/run/kmsplugin/socket.sock
          timeout: 3s
      # Retained ONLY to read data written before encryption was enabled.
      # Delete once every resource has been rewritten; while it is present,
      # anything still stored in the clear remains readable.
      - identity: {}
identity comes last, and only while legacy plaintext remains. Once every resource is rewritten, remove that line.

Evidence the outcome, not the intent. Read the provider list back from the running API server, and read a key directly out of etcd to confirm the value is ciphertext. A screenshot of the flag proves the flag.

The control walk in one view. Each row ends in the same place: an SoA column that points at a running system.

Annex A 5.23: The Control That Contemplates an Exit

5.23, information security for use of cloud services, is read almost universally as a due-diligence control about buying cloud. That reading is half the control. Its scope covers the processes required for acquisition, use, management of and exit from cloud services — and exit is not an afterthought in the guidance. It expects a defined strategy for ceasing or amending cloud services, either supplier by supplier or through cloud-to-on-premise migration, and it expects the agreement to secure provider support during transition or decommissioning at the end of the relationship.

Be precise about the status of that reading. The certifiable control text is paywalled; the exit-strategy expectation as described here comes from the accompanying guidance as rendered by practitioner and certification-body sources. It is not accurate to say ISO 27001 mandates an exit plan. It is accurate to say the control's scope includes exit, and that an auditor asking how you discharge 5.23 is entitled to ask what your exit looks like.

For a self-hosting practice that is a useful alignment rather than a burden. The exit-ramp engineering we argue for on optionality grounds — a documented dependency register, a named migration target, a data path that has actually been walked — is the same artefact set 5.23 wants. Organisations that have already made the build, buy or self-host decision deliberately tend to find this control the cheapest one in the technological and organisational themes, because the work predates the audit.

The distinction to hold onto is that a rehearsed exit is evidence and a written exit is a document. In our engagements the difference shows up immediately: the team that has restored into a second environment answers the question in an afternoon, and the team with a plan spends the afternoon explaining the plan.

Certification Is Not Attestation, and the Cycle Is the Point

Procurement conversations routinely treat ISO 27001 and SOC 2 as interchangeable. They answer different questions. SOC 2 is an examination performed by CPAs against trust services categories, producing a practitioner's report over a system you describe — an attestation, with no management system, no scope clause and no Statement of Applicability. ISO 27001 is certification by an accredited body against a management-system standard, and the certificate says the ISMS conforms, not that a set of controls was tested effective over a window. Our SOC 2 article covers the other model in the same detail; a buyer asking for both is asking two reasonable and non-overlapping questions.

The accreditation layer beneath all of this changed recently, which matters for reading a certificate correctly. Global Accreditation Cooperation Incorporated commenced full operations on 1 January 2026, bringing together the work of the International Accreditation Forum and the International Laboratory Accreditation Cooperation. Accreditations issued under the existing arrangements continue to be recognised as they transition to the new mutual recognition arrangement. IAF MD 26 remains the transition requirement that closed the 2013 edition; IAF is no longer the operating body.

The long-game framing is the certification cycle itself: initial certification, then surveillance audits, then recertification. It is a rhythm, not a project, and it punishes exactly the pattern that a self-hosted platform is well placed to avoid — controls that exist for the audit and lapse afterwards. When the control is a Velero schedule, an admission policy and an audit configuration, it does not lapse, because the platform stops working before the control does. That is the strongest argument for owning this layer, and it is the same argument that runs through the wider EU regulatory picture: certification is voluntary, the consequence of failure is a withdrawn certificate rather than a fine, but the engineering that satisfies it is the engineering you wanted anyway.

§FAQ/Common questions

Frequently asked

Is ISO 27001 compliance harder on self-hosted infrastructure than on a managed cloud platform?

It is more explicit rather than harder. On a managed platform a slice of Annex A — physical and environmental controls, control-plane hardening, node operating system configuration — is answered by pointing at the provider's own certificate and its Statement of Applicability. Operating the stack yourself moves those controls inside your clause 4.3 scope boundary, so you implement them and evidence them. The evidence side is where self-hosting is often the easier position: the artefacts are first-party and machine-generated, such as scheduled configuration-baseline reports, admission-policy reports, API server audit events and completed backup objects with a dated restore result. You are not requesting a report under NDA and reconciling its period against yours.

Is the ISO 27001:2022 transition still open?

No. IAF MD 26 required certification bodies to conduct initial certification and recertification against ISO/IEC 27001:2022 only from 30 April 2024, and to complete the transition of all certified clients by 31 October 2025, which is 36 months from the end of the standard's publication month. Certifications based on ISO/IEC 27001:2013 expire or are withdrawn at the end of that transition period. Any current certificate is against the 93-control Annex A. The only subsequent change to the standard is Amendment 1:2024, 'Climate action changes', published in February 2024, which touches the clauses on organisational context and interested parties and leaves Annex A untouched.

What is the difference between the ISMS scope statement and the Statement of Applicability?

The clause 4.3 scope statement determines the boundaries and applicability of the management system — which services, sites, systems and people are inside it. The clause 6.1.3 Statement of Applicability is the control-level document: it lists all 93 Annex A controls, records whether each is implemented, gives a justification for including or excluding each one, and briefly describes how each applicable control is implemented. They are read together, and both are reviewed at Stage 1 before any control is tested. In practice the scope statement sets the cost of the audit and the SoA sets the shape of it, which is why both deserve more drafting effort than the control work that follows.

Does Annex A 5.23 require an exit plan for cloud services?

It is more accurate to say the control's scope includes exit than that it mandates an exit plan. The control covers the processes required for acquisition, use, management of and exit from cloud services. The accompanying guidance, as rendered by practitioner and certification-body sources, expects a defined strategy for ceasing or amending cloud services — either supplier by supplier or through cloud-to-on-premise migration — and expects agreements to secure provider support during transition or decommissioning at the end of the relationship. The certifiable control text itself is paywalled, so treat the exit expectation as guidance rather than as quoted requirement. Either way, an auditor asking how you discharge 5.23 is entitled to ask what your exit actually looks like, and a rehearsed migration answers that far better than a document.

Which Annex A evidence can a self-hosted Kubernetes cluster produce by itself?

Most of what gets sampled in the technological theme. For 8.9 configuration management: a CIS-aligned baseline report with the benchmark version recorded, admission-policy reports captured on a schedule, and Git commit history carrying the authorisation record. For 8.15 and 8.16 logging and monitoring: kube-apiserver audit events, which require --audit-policy-file to exist at all, shipped off the control-plane node and retained past the certification cycle, plus alert records showing dispositions. For 8.13 information backup: scheduled backups with a declared retention, and a dated restore-drill result with a measured recovery time. For 8.24 cryptography: the live encryption provider list read back from the running API server, and an etcd read confirming ciphertext. What a cluster cannot produce is the physical theme, which is either your own facility records or a colocation supplier you assess.

iso 27001 complianceiso 27001 annex a controls kubernetesisms scope statement self-hosted infrastructurestatement of applicability self-managed stackiso 27001 2022 annex a 5.23 cloud services exitiso 27001 certification on-premises evidence

Executive Briefing

Thirty minutes to clarify your infrastructure risk

Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.