ISO 42001 Annex A on AWS: the Working Mapping
Theme by theme, the AWS primitive that carries each Annex A grouping — and the management-system work no service can sell you.
Our AIMS certifies an estate that runs almost entirely on AWS, so twice a year we re-earn the same lesson: ISO/IEC 42001 Annex A maps onto AWS services beautifully — about halfway. Every one of the nine control groupings has an AWS primitive that does real heavy lifting, and every one has a residue no primitive touches, because the standard is buying management-system muscle and AWS sells enforcement and evidence. This note is the narrative version of the mapping we keep next to our control register; the raw table lives in the control map.
How we actually use it: each Annex A control in our register gets four fields — the AWS primitive (if any), its configuration reference (an IaC path, not a console screenshot), the human process that completes the control, and the evidence an auditor can pull without us improvising. The walk below goes theme by theme in Annex A order, and for each we name the thing AWS carries and the thing it cannot.
A.2 — Policies: the document and its deniable subset
Our AI policy is a markdown file in the governance repo (policy/ai-policy.md), versioned, reviewed on a calendar trigger and after incidents — that part is A.2.2 and A.2.4, and no AWS service is involved. The AWS work is extracting the policy’s deniable subset: every sentence that can be rewritten as a denial becomes a service control policy. 'Models run only in EU regions' becomes an SCP denying bedrock:Invoke* outside the approved region list. 'Only models on the approved list' becomes a model-ID condition. 'No unguarded inference' becomes the bedrock:GuardrailIdentifier IAM condition — an explicit deny on InvokeModel, InvokeModelWithResponseStream, Converse, and ConverseStream for any request not carrying the approved guardrail and version, which turns the policy sentence into an access-denied error.
What no SCP can express is most of the policy: purpose limits, risk appetite, escalation paths, the A.2.3 reconciliation with the privacy and security policy estate, and the review commitment itself. Our rule of thumb: if the auditor asks where a policy statement is enforced, the answer is an SCP ARN; if they ask where it is decided, the answer is a commit history. (A.3, internal organization, gets a sentence rather than a section: IAM roles are not A.3 roles. The standard wants named accountable humans and a concern-reporting channel — an org chart and a form, not a trust policy.)
A.4 — Resources: three allow-lists deep, then paperwork
Resources for AI systems is where AWS coverage is thickest. We run the model estate as three nested allow-lists: Bedrock model access at the account level (no model is usable until access is granted on the Model access page, which makes granting it a gateable event in our intake workflow), SCP model-ID conditions at the organization level (so a rogue account admin cannot widen the list), and per-role IAM scoping of bedrock:InvokeModel to specific model ARNs (so the claims chatbot cannot borrow the code assistant’s model). A.4.3 data resources and A.4.5 compute largely fall out of ordinary tagging and Config inventory.
The residue is A.4.2 and A.4.6. AWS can inventory every resource it hosts; it cannot write the resource documentation the control actually asks for — which datasets, which tooling, which people and competences each lifecycle stage needs. Our A.4.6 evidence is a skills matrix in a spreadsheet, reviewed with HR. There is no API for it, and pretending the IAM console covers it is how you earn a finding.
A.5 — Impact assessment: a process wearing a gate
A.5 is a process control end to end: the method (ours follows ISO/IEC 42005’s shape), the affected-party analysis, the sign-off authority. AWS contributes exactly two things — a place to file the record, and a way to make the process blocking. The second matters more. Because model access is grant-based (see A.4), we wired the intake workflow so the grant is only requested after the impact assessment is approved: no assessment, no model, no exceptions without an expiry date. A gate someone can walk around is a suggestion.
A.6 — Lifecycle: config-as-code or it did not happen
The lifecycle grouping is where AWS earns its keep, because three of its controls describe things machines do well. Bedrock Guardrails as IaC: every guardrail is a CloudFormation-managed, versioned resource — content filters, denied topics, sensitive-information filters, contextual grounding thresholds all live in a reviewed template, and the draft→version workflow mirrors code review. Evaluation jobs in CI: Bedrock model evaluation jobs (automatic metrics and LLM-as-a-judge, reports landing in S3) run our adversarial prompt sets and quality baselines inside the deployment pipeline, so A.6.2.4 verification and validation produces artifacts instead of meeting minutes. Operation and monitoring: Guardrails emit per-policy InvocationsIntervened metrics to CloudWatch, we alarm on deviations, and A.6.2.8 event logs are model invocation logging to S3 plus CloudTrail for the control plane.
What AWS cannot supply is everything in A.6 that involves judgment: the A.6.1.2 objectives for responsible development, the A.6.2.3 record of design choices and the roads not taken, and — the one that bites — the acceptance criteria for those evaluation jobs. A pipeline that runs an evaluation and deploys regardless is theater. Someone accountable has to set the thresholds, and the sign-off that the scores clear them is a human artifact the pipeline merely references.
How a guardrail change becomes audit evidence
- Pull request to guardrail template
The proposed change to filters, topics, or thresholds — diffable, attributable, linked to the risk decision that motivated it.
- Named-owner review
The control owner approves. This is the human half of the control; the register names who.
- Evaluation jobs pass?
CI runs the adversarial and quality evaluation sets against the candidate configuration, scored against written acceptance criteria.
- Change rejected, findings filed
- New guardrail version published
CloudFormation applies the change; Bedrock assigns an immutable version number.
- IAM condition pinned to new version
The GuardrailIdentifier condition now denies inference under any other version — rollout is enforcement, not announcement.
- Evidence accrues
CloudTrail records who changed what; CloudWatch intervention metrics show the new version operating. The audit answer writes itself.
A.7 — Data: the catalog knows what, never whether you should
For data controls we lean on three primitives. The Glue Data Catalog is the dataset inventory — every training and retrieval source registered, classified, tagged with an owner (lineage capture, note, actually runs through DataZone / SageMaker Catalog over Glue tables via OpenLineage events, a naming tangle worth checking against current docs before you cite it in a control description). Knowledge Base ingestion hygiene is A.7.6 preparation made runnable: we run ApplyGuardrail over chunks at ingestion time and reject any source without provenance metadata, so nothing enters the RAG corpus anonymously. And the sensitive-information filters on our guardrails mask PII on the input path — a DLP-style minimisation control that means the model never receives the raw identifier.
The residue is the whole top half of A.7: the data management process (A.7.2), the lawfulness of acquisition (A.7.3 — the catalog will happily register a beautifully documented scrape you had no right to collect), and the representativeness judgment inside quality (A.7.4). Statistics can flag skew; deciding whether the skew matters for the people the system affects is analysis no service performs.
A.8 through A.10 — the relationship themes
The last three groupings govern what you tell people, how the system may be used, and who you depend on. AWS coverage here is real but thin — these are the themes where the register cells most often say 'process control' in the primitive column.
A.8 Information for users
The AWS lift: SageMaker Model Cards give model documentation a standard, versioned shape, and Bedrock’s provider documentation supplies the upstream facts to cite. Our artifact: instructions-for-use is a versioned markdown document in the product repo — capabilities, limits, known failure modes, the human-oversight expectations — released in lockstep with the system, so version 3.2 of the product ships version 3.2 of the instructions. Moffatt v. Air Canada is the case we cite when someone calls this paperwork. What AWS cannot do: decide what users need to know, run the A.8.3 external reporting channel, or send the A.8.4 incident communication. The most it offers is hosting for the page.
A.9 Responsible use
The AWS lift: scope enforcement. Denied topics (up to 30, defined in natural language) fence the chatbot out of financial advice on both the question and the answer; Bedrock Agents action groups scope tools with deliberately narrow OpenAPI schemas, confirmation-before-execution on high-impact actions, and IAM caps on what each action Lambda may touch. What AWS cannot do: decide what responsible means for your context. The denied-topic list is a transcription of a decision made in a room — which uses are ours, which users are ours, what the system must refuse on principle rather than on risk score. Ship the primitive without the decision and you have configured someone else’s ethics.
A.10 Third-party
The AWS lift: version discipline. We invoke version-pinned model IDs — never floating aliases — and a model upgrade is a change request that flows through the same evaluation pipeline as a guardrail change, because a new model version is a new supplier deliverable. Our artifact: a vendor file per model — provider documentation, evaluation reports, the AWS service terms, acceptable-use terms — reviewed when the pin changes. What AWS cannot do: be accountable on your behalf. A.10 runs both directions, and the customer-facing half (what your deployers need from you) is entirely yours; no console page ever mentions it.
| Annex A theme | AWS primitive doing the lifting | What AWS cannot do for you | Evidence we point auditors at |
|---|---|---|---|
A.2 Policies | SCP region/model denials; the GuardrailIdentifier IAM condition enforcing guarded inference | Write the policy, reconcile it with the rest of the policy estate (A.2.3), review it (A.2.4) | Policy repo commit history; SCP ARNs; a denied unguarded invocation from the test account |
A.4 Resources | Bedrock model access grants; SCP model-ID conditions; per-role IAM scoping to model ARNs | Document data, tooling, and human resources per system (A.4.2, A.4.6) | Model-access grant records; the resource sheet per system; the skills matrix |
A.5 Impact assessment | A filing place (versioned S3 + Object Lock) and a blocking gate (no assessment → no model-access grant) | The assessment itself: method, affected-party analysis, sign-off authority | The assessment folder per system; the intake ticket showing approval preceded access |
A.6 Lifecycle | Guardrails as versioned IaC; Bedrock evaluation jobs in CI; CloudWatch intervention metrics; invocation logging + CloudTrail (A.6.2.8) | Set objectives (A.6.1.2), record design choices (A.6.2.3), own the acceptance criteria the pipeline enforces | Guardrail template history; evaluation reports in S3 against written thresholds; log retention config |
A.7 Data | Glue Data Catalog inventory (lineage via DataZone/SageMaker Catalog); ApplyGuardrail at KB ingestion; PII masking filters | The data management process; acquisition lawfulness; the representativeness judgment | Catalog entries with owners; ingestion-rejection logs; the data-quality review record |
A.8 Information for users | SageMaker Model Cards; provider model documentation to cite | Decide what users must know; run external reporting (A.8.3) and incident comms (A.8.4) | The versioned instructions-for-use artifact, release-locked to the system version |
A.9 Responsible use | Denied topics on input and output; Agents action groups with narrow schemas, confirmations, IAM-capped Lambdas | Decide what responsible use is for your users and context | The denied-topic list traced to the use-policy decision; action-group schema diffs |
A.10 Third-party | Version-pinned model IDs; upgrades gated through the evaluation pipeline | Assess suppliers; carry your own obligations to your customers | The vendor file per model; the change request behind every pin change |
Every finding we have ever taken against this mapping — our own audits and the ones we get called in after — reduces to the same shape: the service was bought, the control was assumed. Five recurring specimens, anonymised and merged from more engagements than we would like.
“We enabled Guardrails” — but nothing made anyone use them
The guardrail existed, beautifully configured. The auditor asked the only question that matters: what stops a developer invoking the model without it? Answer: nothing — attachment was a code convention. Finding against A.6 and A.2. The fix took an afternoon: an explicit-deny IAM statement on the inference APIs conditioned on bedrock:GuardrailIdentifier, pinned to the approved guardrail and version. Enforcement is the difference between a control and a custom.
“Our logs record everything” — and nobody had decided anything about them
Model invocation logging was on (in one region of three, it turned out), but there was no documented decision about what gets logged, why, or for how long — and when asked to produce the record of a specific interaction from four months earlier, the team could not. A.6.2.8 asks for a determined logging posture, not an enabled checkbox. The rebuild: logging in every inference region, a written retention rule, and a quarterly retrieval drill so producing a record is routine, not archaeology.
“We have Model Cards” — written once, at launch, in a hurry
The SageMaker Model Card described the model as evaluated at launch. Two pinned-version upgrades later, nobody had touched it: the card cited evaluation results for a model no longer deployed. Stale documentation is worse than absent documentation — it is evidence that your review process does not run. The fix was procedural, not technical: the model-version change request now includes a card update as a completion criterion.
“The impact assessment was done” — by someone, presumably, at some point
A filled-in template existed. What did not exist: any record of who approved it, whether the approver had the authority the process names, or proof that deployment waited for it — the access grant predated the assessment by three weeks. A.5 controls are about the process being real, and timestamps are how auditors test reality. This is why we wired the gate into model access: the sequence is now mechanically impossible to fake.
“We monitor drift with Model Monitor” — a service closed to new customers
The control description named SageMaker Model Monitor. AWS documentation states Model Monitor is no longer open to new customers — and this team was a new customer. The control had never run; nobody noticed because nobody had ever tested it. Two lessons. First, write control descriptions around outcomes ('drift measured monthly against these thresholds'), never product names — the obligation survives the product’s retirement. Second, a control that has never been exercised should be presumed broken.