AWS IAM policies for the Bedrock embedding benchmark
Two policies, deliberately separate, because they have different lifetimes.
| File | Purpose | Lifetime |
|---|---|---|
bedrock-embedding-invoke.json |
List, describe and invoke only amazon.titan-embed-text-v2:0 and cohere.embed-v4:0 in us-east-1 |
Attached for as long as the benchmark and the embedding job need to run |
bedrock-model-access-bootstrap.json |
Turn on model access, including the AWS Marketplace subscription a third-party model needs before its first call | One-time. Attach, enable access, detach |
Splitting them matters: aws-marketplace:Subscribe is the right to commit the
account to a paid offer. That is not a permission an embedding batch job
should carry around after the one moment it was needed.
Measured starting state (2026-08-03)
aws sts get-caller-identity -> arn:aws:iam::<account>:user/ai-lab-user
aws iam list-attached-user-policies -> []
aws iam list-user-policies -> []
aws iam list-groups-for-user -> AI-Lab-Group
aws iam list-attached-group-policies -> AmazonEC2FullAccess, IAMFullAccess,
ElasticLoadBalancingFullAccess,
AmazonVPCFullAccess
aws iam list-group-policies -> []
ai-lab-user holds no bedrock:* permission from any source, which is the
whole of the failure. Both of these were observed, not inferred:
aws bedrock list-foundation-models --region us-east-1
AccessDeniedException ... not authorized to perform: bedrock:ListFoundationModels
aws bedrock-runtime invoke-model --model-id amazon.titan-embed-text-v2:0 ...
AccessDeniedException ... not authorized to perform: bedrock:InvokeModel
Applying them
aws iam create-policy \
--policy-name BedrockEmbeddingInvoke \
--policy-document file://infra/aws/iam/bedrock-embedding-invoke.json
aws iam attach-group-policy \
--group-name AI-Lab-Group \
--policy-arn arn:aws:iam::<account-id>:policy/BedrockEmbeddingInvoke
Same two commands for the bootstrap policy, then aws iam detach-group-policy once model access shows as granted.
What is documented vs. what is confirmed
Confirmed by running the commands above: the current permission state, and
that both ListFoundationModels and InvokeModel are denied.
Taken from AWS documentation and not yet confirmed against this account:
- that the action list in each policy is sufficient — no live call has succeeded yet, so "sufficient" is unproven either way;
- that
cohere.embed-v4:0needs a Marketplace subscription in this account. It is a third-party model, so the bootstrap policy provides for it; - the foundation-model ARN form
arn:aws:bedrock:us-east-1::foundation-model/<id>(no account number) — this is the form AWS's own denial message returned, so it is corroborated; - whether the account has an SCP or permissions boundary that would still deny Bedrock after these policies are attached. Nothing here can rule that out from inside the account.
Region is pinned to us-east-1 to match the configured region. Widening to
arn:aws:bedrock:*::foundation-model/... is a one-line change if the
benchmark moves region, but it should be a deliberate one.