
Compliance
AI Governance Frameworks: What to Build, Not Which to Pick
AI governance frameworks overlap on evidence, not paperwork: mapping ISO 42001, the NIST AI RMF and the EU AI Act onto three artefacts a GPU cluster emits.
Search the phrase and you get comparison matrices: columns for ISO/IEC 42001, the NIST AI RMF, the EU AI Act; rows for scope, certifiability, cost, coverage. For a reader who governs an organisation's use of somebody else's models, that is the right artefact — the decision genuinely is a selection.
It is close to useless for whoever owns the GPU nodes. That reader holds a narrower question: which files must this cluster emit, which does it emit today, which one is missing. No matrix answers it: the frameworks specify outcomes rather than files, and leave the artefacts to whoever runs the hardware.
Three Regimes, One Question: What Do I Have to Build?
Start with legal status, because the three things being compared are not the same kind of object and adjacent columns hide that.
- EU AI Act — Regulation (EU) 2024/1689. Binding law with dated application. Nothing is adopted; obligations attach or they do not.
- ISO/IEC 42001 — a certifiable management-system standard. A third party audits your organisation and issues a certificate.
- NIST AI RMF — NIST AI 100-1, voluntary by design: "The Framework is intended to be voluntary, rights-preserving, non-sector-specific, and use-case agnostic".
The RMF's content sits in its Core, which "is composed of four functions: GOVERN, MAP, MEASURE, and MANAGE. Each of these high-level functions is broken down into categories and subcategories." Those subcategories are phrased as outcomes, and the phrasing matters. MEASURE 2.1 reads: "Test sets, metrics, and details about the tools used during TEVV are documented." MAP 4.1 does the same for component risk mapping, third-party data and software included.
Neither names a file, a format or a signature. Both describe a state of affairs in which something is documented — a gift to a platform team, which gets to choose the artefact, and a trap for a governance programme, because choosing nothing satisfies the sentence until somebody asks to see it. The AI Act is more specific and still stops short of format. Selection decides what the paperwork is called and who audits it, and barely touches what the cluster produces — the same split that runs through NIST CSF 2.0's Govern function.
Where the Frameworks Converge — and Exactly Where They Stop
Line up what each regime wants documented and the overlap is in the evidence, not the vocabulary. Annex IV wants "the version of the system reflecting its relation to previous versions", and separately the development methods and steps, including recourse to pre-trained systems provided by third parties and how those were used, integrated or modified. Article 12(1) adds a capability requirement rather than a policy one: "High-risk AI systems shall technically allow for the automatic recording of events (logs) over the lifetime of the system."
Read those as engineering requirements and three files fall out. A manifest pinning which weights, from where, modified how, evaluated against what. A log of what the system did, per request. A change record naming who swapped the model and to what. That decomposition is this article's, not the regimes' — no source says "these are the three artefacts".
Now the stopping point, which most comparison pages assert without citing: an ISO/IEC 42001 certificate buys nothing under the AI Act's presumption of conformity.
For example, although ISO/IEC 42001:2023 helps to set up an AI management system, its goals and definitions are not aligned with the quality management system that is required under the AI Act. This is why the Commission has requested the development of a new standard for a quality management system that focuses on regulatory compliance with the AI Act.
Article 40(1) is the mechanism: the presumption reaches only standards "the references of which have been published in the Official Journal of the European Union". Publication and citation are two separate events, and only the second does anything legally. As that FAQ put it in March 2026, "the first harmonised standards are expected to be published by CEN and CENELEC in 2026. After that, the Commission will start the review to assess whether the references to these standards can be published in the Official Journal of the European Union." CEN-CENELEC has since published EN 18286:2026 for AI Act regulatory purposes. Check the Official Journal for the citation before anyone claims a presumption from it.
That does not make 42001 worthless; it makes it a wrapper, useful where a customer wants a certificate — though certificate quality varies enormously, its own subject in Stage 1, Stage 2 and the recognition gap. The platform point is narrower: no wrapper produces the three files.
Artefact One: A Signed Model Manifest With Evaluation Evidence
One file per served model version, and the only place anyone should have to look to answer what this is, where it came from and what cleared it. Write it as data beside the Deployment: a wiki page has no digest and cannot be signed.
# model-manifest.yaml -- one per served model version, committed beside the
# Deployment. No standard defines this schema; it is local.
apiVersion: platform.example.internal/v1
kind: ModelManifest
metadata:
name: ticket-classifier
version: "4.2.0" # carries Annex IV(1)(a): version of the system,
supersedes: "4.1.3" # reflecting its relation to previous versions
spec:
intendedPurpose: >-
Routes support tickets into 14 categories. Not used for creditworthiness,
employment, education or eligibility decisions.
provenance: # carries Annex IV(2)(a): recourse to pre-trained
upstream: # third-party systems or tools, and how
source: huggingface.co/example-org/ticket-classifier-base
revision: 1d4f6c2a8b7e0359d1ca46fb82e7905c3ab1de64
modifications: # those were used, integrated or modified
- type: lora-adapter
trainingSet: s3://evidence/datasets/tickets-2026-07.tar.zst
weights:
# Derived from the signed in-toto subjects, not recomputed from disk.
setDigest: sha256:c4a91f0b7d28e6531a0fc94bd27e850361af7c9e02d4b8153e6a0cf91b4d728e
signature: 4.2.0.sig
evaluation: # carries the MEASURE 2.1 outcome: test sets,
suite: git.example.internal/eval/tickets@v9 # metrics and TEVV tooling
testSetDigest: sha256:9e0b3f7c1a54d8260fb9e4c30a7d15826be4f09c3d71a85204ef6b1c9d03a472
metrics: { macroF1: 0.913, worstGroupF1: 0.864 }
tooling: { harness: lm-evaluation-harness 0.4.9, accelerator: 1x L40S }
clearedOn: "2026-09-02"Two fields do work that is easy to miss. supersedes turns a version string into the relation to previous versions Annex IV(1)(a) asks to be recorded; a bare semantic version expresses no lineage. worstGroupF1 sits beside macroF1 because an aggregate documents that you measured, not what you found.
Signing makes the digest mean something, and the mechanics are covered already: ISO 42001 clause to artefact for provenance, SBOM, Sigstore and admission control for the signing infrastructure. What matters here is extracting the identifier the other two artefacts join on.
#!/usr/bin/env bash
# Sign a model directory, verify it, derive the identifier the other two
# artefacts join on. pip install model-signing
set -euo pipefail
MODEL_DIR=/srv/models/ticket-classifier/4.2.0
SIG=$MODEL_DIR.sig
IDENTITY=release-bot@example.com
OIDC_PROVIDER=https://accounts.example.com
model_signing sign "$MODEL_DIR" --signature "$SIG" # defaults to sigstore
# Verification needs the identity and its issuer; there is no bare
# one-argument verify.
model_signing verify "$MODEL_DIR" --signature "$SIG" --identity "$IDENTITY" --identity_provider "$OIDC_PROVIDER"
# The bundle wraps an in-toto statement whose subjects are (file path,
# digest) pairs. Read what was signed, not the directory.
jq -r .dsseEnvelope.payload "$SIG" | base64 -d > /tmp/st.json
jq -r '.subject[]
| "\(.name) \(.digest | to_entries[0] | "\(.key):\(.value)")"' /tmp/st.json | LC_ALL=C sort > /tmp/weights.set
# One identifier over the signed set. The algorithm key inside .digest is
# read, not assumed -- it follows the hashing config.
echo "sha256:$(sha256sum /tmp/weights.set | cut -d' ' -f1)"Artefact Two: An Inference Log Keyed to a Request ID
Article 12(1) is a capability obligation on the system, not a retention policy on the organisation. On vLLM that capability is off by default — off in two independent places whose flag names invite conflation.
So be deliberate about the record source. --enable-log-requests produces request-ID lines at INFO; an OpenTelemetry export produces structured spans; both is the usual answer.
The OpenTelemetry side needs its caveat in writing. The GenAI semantic conventions are marked Status: Development and have left the main semantic-conventions repository — the old page now says they "have moved to the OpenTelemetry GenAI semantic conventions repository. This page has moved and is no longer maintained in this repository." Attribute names can churn, so pin the revision and record which one produced each record.
There is a trap inside the attribute set too. gen_ai.response.id is "The unique identifier for the completion", example chatcmpl-123. That is not the HTTP request identifier; vLLM's X-Request-Id is. Collapsing them destroys the referential integrity this article argues for, so the record carries both.
{
"ts": "2026-09-11T07:41:58.302Z",
"http": {
"request_id": "req_01K4Z8Q3M7N2VBXH5TF0YJ9C6D",
"route": "/v1/chat/completions",
"status": 200
},
"otel": {
"gen_ai.operation.name": "chat",
"gen_ai.provider.name": "vllm",
"gen_ai.request.model": "ticket-classifier",
"gen_ai.response.id": "chatcmpl-8f3a1c0d4b5e47a9",
"gen_ai.response.finish_reasons": ["stop"],
"gen_ai.usage.input_tokens": 412,
"gen_ai.usage.output_tokens": 17,
"semconv_revision": "genai-development-2026-08"
},
"served_model": {
"manifest": "ticket-classifier/4.2.0/model-manifest.yaml",
"set_digest": "sha256:c4a91f0b7d28e6531a0fc94bd27e850361af7c9e02d4b8153e6a0cf91b4d728e",
"signature_verified_at": "2026-09-11T06:02:11Z"
},
"change_record": { "audit_id": "f0b7a41c-3e52-4d18-9a6c-27bd5e0138af" },
"content": {
"prompt": "excluded-by-policy",
"completion": "excluded-by-policy",
"basis": "record of the event, not a copy of the input"
}
}Retention is where the role question bites. Article 19(1) binds providers: logs under their control "shall be kept for a period appropriate to the intended purpose of the high-risk AI system, of at least six months". Article 26(6) puts the same floor on deployers. A self-hosting team can be either or both, depending on whether it placed the system on the market under its own name — worked through in what actually binds a deployer.
Artefact Three: A Change-Control Record for Every Model Swap
This is the artefact teams assume they have: the cluster writes audit events and somebody built a pipeline years ago. The question that decides whether those events are evidence is narrower — does the record name the model that was swapped in?
First they have to exist. The policy is passed "to kube-apiserver using the --audit-policy-file flag. If the flag is omitted, no events are logged." Then the level decides content: Metadata logs "events with metadata (requesting user, timestamp, resource, verb, etc.) but not request or response body"; Request adds the request body; RequestResponse adds both.
Read that against what a model swap is: a patch on a Deployment whose new image reference, or model-path argument, exists only inside the request body. A Metadata rule names the user, the Deployment and the time, and not what they changed it to. That documents the existence of a change without recording the change — worse than nothing, because it reads as coverage.
# /etc/kubernetes/audit/inference-policy.yaml
# Passed as --audit-policy-file. Omit the flag and nothing is logged.
apiVersion: audit.k8s.io/v1
kind: Policy
metadata:
name: inference-audit-policy
omitStages:
- RequestReceived
rules:
# Reads dominate volume and teach nothing about change.
- level: None
verbs: ["get", "list", "watch"]
# Mutations with the request body -- the level at which the new image
# reference or model path is recorded. Metadata names the Deployment,
# not what it became.
- level: RequestResponse
namespaces: ["inference"]
verbs: ["create", "update", "patch", "delete"]
resources:
- group: "apps"
resources: ["deployments", "statefulsets"]
- group: ""
resources: ["configmaps", "pods"]
# Serving CRDs sit outside apps/ and are swapped the same way.
- group: "serving.kserve.io"
resources: ["inferenceservices"]
# Everything else stays cheap.
- level: Metadata
namespaces: ["inference"]That is a policy, not a pipeline; shipping the events somewhere they survive, in a jurisdiction you chose, is the separate build in audit logs into a SIEM you operate. One warning: RequestResponse on configmaps records their contents, so keep secrets out of ConfigMaps or narrow the rule.
The Join Key: Making Three Artefacts Answer One Question
Three artefacts are three artefacts. They become evidence only when somebody can start at one request ID and reach the exact weights that served it and the change record that put them there. That traversal is the part nobody builds, because each file looks complete alone.
One structural detail makes or breaks the last hop. The audit record carries a container image reference; the inference log carries the weights set digest. If weights are mounted from a volume rather than baked into the image, nothing in the audit event mentions them. The fix is cheap but deliberate: put the set digest in the pod template, as an annotation or environment variable, so swapping the model must mutate a field that lands in the request body. Without it, manifest and change record share no key.
#!/usr/bin/env bash
# One request ID -> the weights that served it -> their signature -> the
# change that deployed them.
set -euo pipefail
REQ_ID=${1:?usage: trace-request.sh <x-request-id>}
LOGS=/srv/evidence/inference # NDJSON, one record per request
AUDIT=/srv/evidence/kube-audit # kube-apiserver audit log
MODELS=/srv/models/ticket-classifier
IDENTITY=release-bot@example.com
OIDC_PROVIDER=https://accounts.example.com
# 1. Join on the HTTP request ID. gen_ai.response.id identifies the
# completion and will not match the gateway value.
rec=$(jq -c --arg id "$REQ_ID" 'select(.http.request_id == $id)' "$LOGS"/*.ndjson | head -n 1)
[ -n "$rec" ] || { echo "no record for $REQ_ID" >&2; exit 2; }
digest=$(jq -r .served_model.set_digest <<< "$rec")
ver=$(jq -r '.served_model.manifest | split("/")[1]' <<< "$rec")
# 2a. The resident bytes still match a signature that is still ours.
model_signing verify "$MODELS/$ver" --signature "$MODELS/$ver.sig" --identity "$IDENTITY" --identity_provider "$OIDC_PROVIDER"
# 2b. Referential integrity: re-derive the set digest from the signed
# subjects and refuse a log that named a different set.
signed=sha256:$(jq -r .dsseEnvelope.payload "$MODELS/$ver.sig" | base64 -d | jq -r '.subject[]
| "\(.name) \(.digest | to_entries[0] | "\(.key):\(.value)")"' | LC_ALL=C sort | sha256sum | cut -d' ' -f1)
[ "$signed" = "$digest" ] || {
echo "log claims $digest, signature covers $signed" >&2; exit 3; }
# 3. Only Request or RequestResponse level captures requestObject,
# where the deployed digest appears.
jq -c --arg d "$digest" '
select(.objectRef.namespace == "inference")
| select((.requestObject // empty | tostring) | contains($d))
| { auditID, at: .requestReceivedTimestamp, who: .user.username, verb }' "$AUDIT"/*.ndjsonStep 2b earns the script. Verifying the signature proves the bytes on disk match what was signed; it says nothing about whether the log named that set. Comparing the two digests is what makes three files one chain — and a stack that looks fully instrumented can still fail it.
Failure Modes That Turn Evidence Back Into Noise
All three degrade quietly. None raises an error; each leaves a file that still looks like evidence.
- The unverified warm cache. Weights verified on first pull, then served from a node-local cache or a restart that skips the check. The manifest says the digest was signed; nothing says the resident bytes are those bytes. Verification belongs on the load path, not the download path.
- Request IDs minted per hop. Gateway mints one, mesh another, model server a third, each log internally consistent. The join then gets reconstructed by timestamp — an inference, not evidence. Mint once at ingress and propagate.
- Retention below the floor, by default. Rotation at 30 days, a lifecycle rule at 90, a SIEM tier ageing out at 14. Articles 19(1) and 26(6) both set at least six months, sectoral law often longer. Component defaults fall short of the statutory minimum.
- Evaluation evidence pinned to a version no longer served. The 4.2.0 manifest has its metrics; production moved to 4.3.1 on a hotfix that skipped the suite. MEASURE 2.1's outcome is documented metrics for what you run, not its ancestor. Make the evaluation block a deployment gate.
Choosing the Paperwork Wrapper, and Keeping the Exit Open
With the artefacts built, the selection question becomes answerable: it reduces to what the paperwork has to do.
- A certificate a customer recognises — ISO/IEC 42001, the only one of the three a third party certifies. Budget for a multi-year programme and read the accreditation scope first.
- A vocabulary that lands with US federal buyers — the NIST AI RMF. Voluntary, free, and its function-and-subcategory structure maps onto profile work a security team has likely done for CSF 2.0.
- In scope of the EU AI Act — not a choice. The wrapper chosen for the other reasons changes nothing about what Articles 12, 19 and 26 and Annex IV ask for.
Keeping that choice reversible is a format decision made early. All three artefacts are plain text — YAML, NDJSON, a sigstore bundle — in storage you control, joined by a digest rather than a vendor's row ID. A platform that ingests them can be swapped; one that *holds* them cannot, the same exit problem as any other data-gravity lock-in. Keep the clause-to-artefact mapping in your repository, not inside a tool, and a fourth regime costs an afternoon.
The Long Game: Artefacts Outlive the Frameworks
The regimes move. On 8 July 2026 the EU adopted Regulation (EU) 2026/1744, the Digital Omnibus on AI, amending the AI Act. Read on 11 September 2026, it sets "the date of application of Sections 1, 2 and 3 of Chapter III ... to 2 December 2027 for AI systems classified as high-risk pursuant to Article 6(2) and Annex III, and to 2 August 2028 for AI systems classified as high-risk pursuant to Article 6(1) and Annex I". Programmes organised around a deadline were replanned; a cluster emitting a signed manifest, a joined log and a change record with bodies did not change at all.
That asymmetry is the argument. Frameworks are the disposable layer — superseded, deferred, amended, replaced. The artefacts are durable precisely because no framework specified them: they describe what your system did, which stays true however the question is phrased. Build the evidence your infrastructure can produce, keep it in formats you can move, and treat the framework as the cover sheet.
§FAQ/Common questions
Frequently asked
What are the main AI governance frameworks?
Three dominate the conversation, and they are different kinds of object. The EU AI Act (Regulation (EU) 2024/1689) is binding law with dated application. ISO/IEC 42001 is a certifiable management-system standard, which means a third party audits your organisation and issues a certificate. The NIST AI Risk Management Framework (NIST AI 100-1) is voluntary by design — NIST describes it as "intended to be voluntary, rights-preserving, non-sector-specific, and use-case agnostic" — and structures its content as four Core functions, GOVERN, MAP, MEASURE and MANAGE, broken into categories and subcategories. Comparing them in adjacent columns hides the fact that only one of them can apply to you whether you adopt it or not.
Does ISO 42001 certification mean I comply with the EU AI Act?
No, and two primary texts say so. The European Commission's standardisation FAQ states that although ISO/IEC 42001:2023 helps set up an AI management system, "its goals and definitions are not aligned with the quality management system that is required under the AI Act", and that the Commission has therefore requested a new standard for that purpose. Separately, AI Act Article 40(1) attaches a presumption of conformity only to harmonised standards "the references of which have been published in the Official Journal of the European Union". Publication of a standard by CEN and CENELEC and citation of its reference in the Official Journal are two separate steps; only the second confers the presumption. Check the Official Journal directly before relying on one.
Which artefacts does an AI governance framework require on a Kubernetes cluster?
None of them names a file, and that is the point worth internalising. The AI Act's Annex IV asks for documentation of the system version and its relation to previous versions, and of recourse to pre-trained third-party systems and how they were used or modified; Article 12(1) requires the system to technically allow automatic recording of events; the NIST AI RMF asks for documented test sets, metrics and TEVV tooling (MEASURE 2.1) and documented mapping of third-party component risk (MAP 4.1). Mapping those onto a signed model manifest, a request-ID-keyed inference log and a change-control record is this article's engineering analysis, not something the regimes jointly prescribe — but the same three files carry all of those documentation outcomes at once.
Is enabling vLLM's request ID header enough for EU AI Act logging?
No. Those are two separate flags in vLLM and both default to off. The --enable-request-id-headers flag means the API server adds an X-Request-Id header to responses — it writes no records anywhere. Record emission is governed by --enable-log-requests, which logs the request ID, parameters and LoRA request at INFO level and prompt inputs at DEBUG, or by an OpenTelemetry GenAI export that produces structured spans. A deployment with headers on, request logging off and no OTel export has no log records at all while appearing instrumented to every caller.
How long do AI system logs have to be retained under the EU AI Act?
At least six months, with your role deciding which article binds you. Article 19(1) requires providers to keep logs automatically generated by their high-risk systems, to the extent those logs are under their control, for a period appropriate to the intended purpose and of at least six months unless other Union or national law provides otherwise. Article 26(6) imposes the same floor on deployers for logs under their control. Six months is a minimum rather than a target — sectoral and data-protection law frequently require longer, and in some jurisdictions another regime sets the binding number.
Further reading
- ISO 42001 for Self-Hosted Inference: Clause to Artefact
- ISO/IEC 42001: Stage 1, Stage 2 and the Recognition Gap
- EU AI Act Summary: What Actually Binds a Deployer
- EU AI Act High-Risk Systems: An On-Prem Compliance Path
- Kubernetes Audit Logs Into a SIEM You Operate: Wazuh
- NIST CSF 2.0 Govern: A Profile for Infrastructure You Own
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.