Skip to content

Conversation

@pahud
Copy link
Contributor

@pahud pahud commented Jan 22, 2026

Issue # (if applicable)

Closes #36774.

Reason for this change

The grantProfileUsage() method in CrossRegionInferenceProfile only grants IAM permissions for the current region (Aws.REGION), but cross-region inference profiles dynamically route requests across multiple regions within a geoRegion. This causes Lambda functions to fail with "Your account is not authorized to invoke this API operation with a prompt resource" when the profile routes requests to regions other than the source region.

Description of changes

┌─────────────────────────────────────────────────────────────────────────────┐
│                     CROSS-REGION INFERENCE PROFILE                          │
│                                                                             │
│   User configures: geoRegion = "US"                                         │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    AWS Bedrock Service                              │   │
│   │                                                                     │   │
│   │   Cross-Region Inference Profile dynamically routes requests to:   │   │
│   │                                                                     │   │
│   │      ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐        │   │
│   │      │us-east-1 │  │us-east-2 │  │us-west-1 │  │us-west-2 │        │   │
│   │      │ (N.VA)   │  │ (Ohio)   │  │(N.Calif) │  │ (Oregon) │        │   │
│   │      └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘        │   │
│   │           │             │             │             │              │   │
│   │           └─────────────┴──────┬──────┴─────────────┘              │   │
│   │                                │                                   │   │
│   │                    Routes based on availability                    │   │
│   │                         and demand                                 │   │
│   └────────────────────────────────┼───────────────────────────────────┘   │
│                                    │                                        │
│                                    ▼                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                         Lambda Function                             │   │
│   │                                                                     │   │
│   │   Invokes inference profile → Request may go to ANY US region      │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                           THE PROBLEM (Before)                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   grantProfileUsage() generated IAM policy with SINGLE region:              │
│                                                                             │
│   {                                                                         │
│     "Effect": "Allow",                                                      │
│     "Action": ["bedrock:GetInferenceProfile", "bedrock:InvokeModel*"],      │
│     "Resource": "arn:aws:bedrock:us-east-1:123456789:inference-profile/..." │
│   }                            ─────────                                    │
│                                    │                                        │
│                                    └── Only current region!                 │
│                                                                             │
│   ❌ Request routed to us-west-2 → ACCESS DENIED                            │
│   ❌ Request routed to us-east-2 → ACCESS DENIED                            │
│   ✅ Request routed to us-east-1 → Works (by luck)                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                           THE FIX (After)                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   grantProfileUsage() now generates IAM policy with ALL regions in geo:     │
│                                                                             │
│   {                                                                         │
│     "Effect": "Allow",                                                      │
│     "Action": ["bedrock:GetInferenceProfile", "bedrock:InvokeModel*"],      │
│     "Resource": [                                                           │
│       "arn:aws:bedrock:us-east-1:123456789:inference-profile/...",          │
│       "arn:aws:bedrock:us-east-2:123456789:inference-profile/...",          │
│       "arn:aws:bedrock:us-west-1:123456789:inference-profile/...",          │
│       "arn:aws:bedrock:us-west-2:123456789:inference-profile/..."           │
│     ]                ─────────────────────────────────────────              │
│   }                              │                                          │
│                                  └── All US regions from RegionInfo!        │
│                                                                             │
│   ✅ Request routed to us-west-2 → Works                                    │
│   ✅ Request routed to us-east-2 → Works                                    │
│   ✅ Request routed to us-east-1 → Works                                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                        IMPLEMENTATION APPROACH                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   Uses RegionInfo from aws-cdk-lib/region-info to dynamically determine     │
│   regions for each geoRegion:                                               │
│                                                                             │
│   ┌─────────────┬───────────────────────────────────────────────────────┐   │
│   │  geoRegion  │  Regions Granted                                      │   │
│   ├─────────────┼───────────────────────────────────────────────────────┤   │
│   │  US         │  All regions starting with "us-" (aws partition)      │   │
│   │  EU         │  All regions starting with "eu-" (aws partition)      │   │
│   │  APAC       │  All regions starting with "ap-" or "me-"             │   │
│   │  GLOBAL     │  Wildcard "*" (all commercial regions)                │   │
│   │  US_GOV     │  All regions in aws-us-gov partition                  │   │
│   │  JP         │  ap-northeast-1, ap-northeast-3 (Tokyo, Osaka)        │   │
│   │  AU         │  ap-southeast-2, ap-southeast-4 (Sydney, Melbourne)   │   │
│   └─────────────┴───────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Implemented the RegionInfo approach to grant IAM permissions for all regions within a geoRegion:

  • Added RegionInfo import from aws-cdk-lib/region-info
  • Added private geoRegion property to store the configured geographic area
  • Added getRegionsForGeoArea() helper method that returns the list of AWS regions for each geoRegion
  • Modified grantProfileUsage() to generate multiple ARNs (one per region in the geoRegion)

Describe any new or updated permissions being added

  • IAM permissions: No new IAM actions added. The same bedrock:GetInferenceProfile and bedrock:InvokeModel* actions are granted.
  • Resource access: The IAM policy now grants access to the inference profile ARN in all regions within the configured geoRegion, rather than just the current region. This is an additive change that expands permissions to match the actual runtime behavior of cross-region inference profiles.

Description of how you validated changes

  • Unit tests: Added 6 comprehensive tests for multi-region ARN generation (US, EU, APAC, GLOBAL, JP, AU geoRegions)
  • Unit test: Added test to verify all enum values are supported (prevents future regressions)
  • Integration test: Added IAM role with grantProfileUsage() call to verify multi-region ARN generation in CloudFormation template
  • All tests pass: 21/21 tests passing in cross-region-inference-profile.test.ts
  • TypeScript compilation: Passes without errors
  • Linting: Passes without errors

Security considerations

  • Least-privilege enforcement: Unknown geoRegions now throw an error instead of falling back to wildcard * permissions. This prevents silent over-permissioning if new geoRegions are added in the future without updating the region mappings.

  • Region mapping approach: According to AWS documentation, the exact destination regions for a cross-region inference profile depend on both the specific model and the source region. For example, us.anthropic.claude-3-haiku from us-east-2 routes to us-east-1, us-east-2, us-west-2, but from us-west-2 only routes to us-east-1, us-west-2.

    Our implementation grants permissions to all regions in the geographic area (e.g., all us-* regions for US geoRegion) rather than trying to predict exact routing. This is intentionally more permissive because:

    1. It covers all possible destination regions regardless of model or source region
    2. It won't break if AWS adds new destination regions for a model
    3. The AWS docs state: "if an inference profile is tied to a geography (such as US, EU, or APAC), its destination Region list will never change" - so granting all regions in the geography is a safe superset

Checklist


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

…erence profiles

- Add RegionInfo import to dynamically determine regions for geographic areas
- Store geoRegion as private property in CrossRegionInferenceProfile class
- Implement getRegionsForGeoArea() method to map geoRegion to AWS region lists
- Update grantProfileUsage() to generate ARNs for all regions in the geoRegion
- Add comprehensive documentation explaining multi-region permission scope
- Include warnings about data residency for APAC geoRegion (includes me-central-1)
- Add detailed JSDoc comments explaining regional permission grants
- Add test coverage for multi-region ARN generation across all geoRegion types
- Support region filtering by partition (aws, aws-us-gov) and prefix matching
- Ensure cross-region inference profiles grant permissions across all regions in configured geoRegion to support dynamic request routing
@aws-cdk-automation aws-cdk-automation requested a review from a team January 22, 2026 18:57
@github-actions github-actions bot added bug This issue is a bug. effort/medium Medium work item – several days of effort p2 labels Jan 22, 2026
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Jan 22, 2026
…ssions

- Update grantProfileUsage documentation to reflect bedrock:InvokeModel* permissions instead of bedrock:ListInferenceProfiles
- Add detailed explanation of cross-region permission scope across all regions within configured geoRegion
- Include examples for US, EU, APAC, and GLOBAL geoRegions showing affected regions
- Add compliance warning for users with strict regional requirements
- Link to AWS documentation on geographic cross-region inference IAM setup
- Clarify that permissions are granted dynamically based on geoRegion availability, not just deployment region
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This review is outdated)

pahud added 3 commits January 22, 2026 14:11
…shots

- Update BedrockInferenceProfilesTestDefaultTestDeployAssert4CC2EFAB.assets.json with new asset hashes
- Update BedrockInferenceProfilesTestDefaultTestDeployAssert4CC2EFAB.template.json to remove CDK metadata
- Update aws-cdk-bedrock-inference-profiles-integ.assets.json with refreshed asset references
- Update aws-cdk-bedrock-inference-profiles-integ.template.json with latest CloudFormation template
- Refresh cdk.out, integ.json, manifest.json, and tree.json snapshots
- Regenerate snapshots to reflect current test state and CDK version alignment
…shots

- Update integration test snapshot version from 45.0.0 to 48.0.0
- Regenerate template asset hashes to reflect current CloudFormation state
- Add TestRole and TestRoleDefaultPolicy resources for cross-region inference profile permissions testing
- Update inference profile resource ARNs to include multi-region support (us-east-1, us-east-2, us-west-1, us-west-2)
- Regenerate manifest and tree.json snapshots to match updated test infrastructure
@aws-cdk-automation aws-cdk-automation dismissed their stale review January 22, 2026 19:17

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results24 ran24 passed
TestResult
No test annotations available

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results with resolved templates24 ran24 passed
TestResult
No test annotations available

@aws-cdk-automation aws-cdk-automation added the pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. label Jan 22, 2026
pahud added 3 commits January 22, 2026 14:55
…card fallback

- Remove wildcard fallback to enforce least-privilege principle
- Add test to verify all enum values are supported by grantProfileUsage
@pahud pahud marked this pull request as ready for review January 22, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug This issue is a bug. contribution/core This is a PR that came from AWS. effort/medium Medium work item – several days of effort p2 pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bedrock-alpha: grant methods limit to only one region

2 participants