Skip to content

fix(graphql-generation-transformer): grant InvokeModel on inference profile and underlying models - #3495

Closed
sarayev wants to merge 1 commit into
mainfrom
fix/generation-bedrock-inference-profile-iam
Closed

fix(graphql-generation-transformer): grant InvokeModel on inference profile and underlying models#3495
sarayev wants to merge 1 commit into
mainfrom
fix/generation-bedrock-inference-profile-iam

Conversation

@sarayev

@sarayev sarayev commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description of changes

The @generation transformer creates an AppSync→Bedrock IAM role that grants bedrock:InvokeModel. Previously the role scoped the action to a single regional foundation-model ARN:

arn:<partition>:bedrock:<region>::foundation-model/<modelId>

For a cross-region inference profile model id (prefixed us., eu., or apac. — e.g. us.anthropic.claude-haiku-4-5-20251001-v1:0) that ARN is incorrect. Invoking an inference profile requires bedrock:InvokeModel on the inference-profile ARN and on the underlying regional foundation-model ARNs the profile routes to. Because the transformer only granted the (malformed) foundation-model ARN, customers using a cross-region profile id with @generation hit runtime AccessDenied.

(The @conversation path is unaffected — it invokes Bedrock through @aws-amplify/ai-constructs.)

Fix

When the model id matches /^(us|eu|apac)\./, the role now grants bedrock:InvokeModel on both:

  • the inference-profile ARN: arn:<partition>:bedrock:<region>:<account>:inference-profile/<modelId>
  • the underlying foundation-model ARN with a wildcard region: arn:<partition>:bedrock:*::foundation-model/<foundationModelId>, where <foundationModelId> is the profile id with the region prefix stripped. A wildcard region is used because a cross-region profile may dispatch to any of several regions.

Plain foundation-model ids keep the existing single-ARN behavior. All ARNs are built from CDK partition/region/account tokens — nothing is hardcoded.

Tests

Added unit/snapshot tests in the generation transformer package proving:

  • a plain FM id grants only the foundation-model ARN (unchanged behavior), and
  • an inference-profile id grants both the profile ARN and the wildcard-region foundation-model ARN.

These tests are offline (no AWS). Full suite: 16 passed, 16 total (jest).

CDK / CloudFormation Parameters Changed

None. Only the resource list of an existing inline IAM policy statement changes.

Issue #, if available

N/A

Description of how you validated changes

  • jest (offline) — 16 passed, 16 total, including 2 new tests + 2 new snapshots.
  • tsc --noEmit — passes (exit 0).

Checklist

  • PR description included
  • yarn test passes (generation transformer package: 16/16)
  • E2E test run linked
  • Tests are changed or added
  • Relevant documentation is changed or added (no docs file exists for this package)
  • New AWS SDK calls or CloudFormation actions have been added to relevant test and service IAM policies
  • Any CDK or CloudFormation parameter changes are called out explicitly

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

sarayev added a commit that referenced this pull request Jun 26, 2026
## Description

Splits the e2e CI infrastructure out of the mixed draft #3493 into a
clean, self-contained change off `main`. This PR contains **only** the
CI/e2e-infra file-set; the generation/conversation test fixes ship
separately, and the generation IAM change is #3495.

### Two self-contained waved CodeBuild batches

The single e2e batch is split into two independent batches — `api+gql`
(~78 shards) and `cdk` (~108 shards) — each with its own
prep/build/verify chain and cleanup. Every shard is chained into an
index-offset wave window (`SPLIT_E2E_WAVE_SIZE`) so in-flight builds
stay under the orchestrator's concurrent-build ceiling. A
`cloudE2ESplit` trigger and a `wait-for-all-codebuild-split` aggregator
drive and join the two batches. The legacy single-batch path is
retained.

### Reconciliation self-check

The generator now asserts that the split total equals the combined total
with no missing/extra/duplicate/overlapping shards. Current run: **PASS
(186 == 186)**.

### Region pool

`sa-east-1` is removed from the round-robin region assignment — its
limited Amplify service coverage (RDS/OpenSearch) was producing e2e
failures.

### CDK OOM: shard-split via RUN_SOLO

The five heavy CDK construct-deploy suites (utils, log-config,
gsi-projection-type, ddb-iam-access, data-construct) were bin-packed
into one shard and exhausted the worker heap (SIGKILL/OOM). They are
added to the existing `RUN_SOLO` list so each deploys in its own shard.
This grows the cdk batch to 108 and the combined workflow to 186; no
test is dropped.

### Gen1 placeholder app: self-healing + cleanup-protect

An idempotent, self-healing `ensureGen1PlaceholderApp(region)` is added
to `amplify-e2e-core` and wired into a jest `globalSetup` hook in the
two e2e packages that run `amplify init`, so the Gen1 deprecation-bypass
placeholder app (and its `test` backend env) is recreated per shard
before any test runs. `cleanup-e2e-resources` is updated to skip
deleting `DoNotDeleteAppToBypassGen1Deprecation` so it persists across
runs.

## How did you test this change?

- Regenerated specs with `yarn ts-node ./scripts/split-e2e-tests.ts
prod`; output is deterministic (no diff on re-run).
- Reconciliation self-check: **PASS**, split total 186 == combined 186,
no missing/extra/duplicate/overlap; max in-flight per batch within cap;
no sa-east-1 assignments.

## Notes

Draft. Supersedes the CI portion of #3493. Companion PRs:
generation/conversation e2e test fixes (separate) and #3495 (generation
IAM).
…rofile and underlying models

The @generation transformer builds an AppSync->Bedrock IAM role that
scoped bedrock:InvokeModel to a single regional foundation-model ARN
(arn:<partition>:bedrock:<region>::foundation-model/<modelId>). For a
cross-region inference profile id (us./eu./apac. prefix) that ARN is
wrong: invoking a profile requires InvokeModel on the inference-profile
ARN AND on the underlying regional foundation-model ARNs the profile
routes to. As a result, customers using a cross-region profile model id
with @generation hit runtime AccessDenied.

When the model id matches /^(us|eu|apac)\./ the role now grants
InvokeModel on both the inference-profile ARN
(arn:<partition>:bedrock:<region>:<account>:inference-profile/<modelId>)
and the underlying foundation-model ARN with a wildcard region
(arn:<partition>:bedrock:*::foundation-model/<foundationModelId>), where
the underlying model id is the profile id with the region prefix
stripped. Plain foundation-model ids keep the existing single-ARN
behavior. All ARNs use CDK account/region/partition tokens.

Added unit/snapshot tests proving a plain FM id grants only the
foundation-model ARN (unchanged) and an inference-profile id grants both
the profile ARN and the wildcard-region foundation-model ARN. The
generation transformer unit tests run offline and all 16 pass.

---
Prompt: Draft the OPTION A product fix as its own branch/PR. The
@generation transformer scopes bedrock:InvokeModel to a single
foundation-model ARN; for a cross-region inference profile id that ARN
is wrong, so @generation + cross-region profile hits AccessDenied.
Implement granting InvokeModel on both the inference-profile ARN and the
underlying regional foundation-model ARNs (wildcard region), add tests,
build, commit, push, and open a draft PR off main.
@sarayev
sarayev force-pushed the fix/generation-bedrock-inference-profile-iam branch from c526e9b to d546bf1 Compare June 26, 2026 09:21
@sarayev

sarayev commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Closing as superseded. This PR added IAM for cross-region Bedrock inference profiles to support the @generation e2e using a Claude inference-profile model. The e2e fix landed differently: #3500 switched @generation to amazon.nova-lite-v1:0, a plain ON_DEMAND foundation model that needs no inference-profile IAM. The generation shard now passes (validated in batch d7085183). The @conversation path uses ai-constructs, which already handles the inference-profile IAM (no AccessDenied observed). So this inference-profile IAM change is no longer needed. Closing.

@sarayev sarayev closed this Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant