From 9ba7dd2786f3b231797060bd5096f3348c229628 Mon Sep 17 00:00:00 2001 From: Alexander Amiri Date: Thu, 12 Mar 2026 16:01:33 +0100 Subject: [PATCH 1/2] Fix Bedrock IAM: add foundation model ARNs for EU destination regions Cross-region inference profiles (eu.anthropic.*) route to foundation models in eu-central-1, eu-north-1, eu-west-1, eu-west-3. IAM requires explicit access to the destination model ARNs, not just the inference profile. Condition scopes foundation model access to only work via our inference profiles. Fixes plan role, slack-alert role, and cost-report role. --- terraform/platform/iam/main.tf | 24 ++++++++++++- terraform/platform/lambdas/main.tf | 54 ++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/terraform/platform/iam/main.tf b/terraform/platform/iam/main.tf index 1d7f6b2..a3c10a7 100644 --- a/terraform/platform/iam/main.tf +++ b/terraform/platform/iam/main.tf @@ -94,7 +94,7 @@ resource "aws_iam_role_policy" "ci_infra_plan_extras" { Resource = "arn:aws:s3:::${var.project}-ci-plan-artifacts-${var.aws_account_id}/*" }, { - Sid = "BedrockForReview" + Sid = "BedrockInferenceProfile" Effect = "Allow" Action = [ "bedrock:InvokeModel", @@ -102,6 +102,28 @@ resource "aws_iam_role_policy" "ci_infra_plan_extras" { ] Resource = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" }, + { + # Cross-region inference profiles route to foundation models in EU + # destination regions. IAM requires access to destination model ARNs. + # Condition scopes this to only work via our inference profiles. + Sid = "BedrockFoundationModels" + Effect = "Allow" + Action = [ + "bedrock:InvokeModel", + "bedrock:Converse", + ] + Resource = [ + "arn:aws:bedrock:eu-central-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-north-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-west-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-west-3::foundation-model/anthropic.*", + ] + Condition = { + StringLike = { + "bedrock:InferenceProfileArn" = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" + } + } + }, { Sid = "SSMReadSlackWebhook" Effect = "Allow" diff --git a/terraform/platform/lambdas/main.tf b/terraform/platform/lambdas/main.tf index 354c395..b53b7a7 100644 --- a/terraform/platform/lambdas/main.tf +++ b/terraform/platform/lambdas/main.tf @@ -6,6 +6,16 @@ locals { lambda_src_path = "${path.module}/../../lambda-src" github_org_url = "https://github.com/javaBin" + + # EU cross-region inference profile destination regions. + # IAM requires foundation model access in all regions the profile can route to. + bedrock_eu_foundation_model_arns = [ + "arn:aws:bedrock:eu-central-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-north-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-west-1::foundation-model/anthropic.*", + "arn:aws:bedrock:eu-west-3::foundation-model/anthropic.*", + ] + bedrock_inference_profile_arn = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" } ################################################################################ @@ -159,13 +169,21 @@ resource "aws_iam_role_policy" "slack_alert" { ] }, { - Sid = "Bedrock" - Effect = "Allow" - Action = [ - "bedrock:InvokeModel", - "bedrock:Converse", - ] - Resource = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" + Sid = "BedrockInferenceProfile" + Effect = "Allow" + Action = ["bedrock:InvokeModel", "bedrock:Converse"] + Resource = local.bedrock_inference_profile_arn + }, + { + Sid = "BedrockFoundationModels" + Effect = "Allow" + Action = ["bedrock:InvokeModel", "bedrock:Converse"] + Resource = local.bedrock_eu_foundation_model_arns + Condition = { + StringLike = { + "bedrock:InferenceProfileArn" = local.bedrock_inference_profile_arn + } + } }, { Sid = "PricingRead" @@ -236,13 +254,21 @@ resource "aws_iam_role_policy" "cost_report" { Resource = "*" }, { - Sid = "Bedrock" - Effect = "Allow" - Action = [ - "bedrock:InvokeModel", - "bedrock:Converse", - ] - Resource = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" + Sid = "BedrockInferenceProfile" + Effect = "Allow" + Action = ["bedrock:InvokeModel", "bedrock:Converse"] + Resource = local.bedrock_inference_profile_arn + }, + { + Sid = "BedrockFoundationModels" + Effect = "Allow" + Action = ["bedrock:InvokeModel", "bedrock:Converse"] + Resource = local.bedrock_eu_foundation_model_arns + Condition = { + StringLike = { + "bedrock:InferenceProfileArn" = local.bedrock_inference_profile_arn + } + } }, ] }) From 516fde7d885020c1ecbb9796c5a14ae9af026516 Mon Sep 17 00:00:00 2001 From: Alexander Amiri Date: Thu, 12 Mar 2026 16:12:37 +0100 Subject: [PATCH 2/2] Fix Bedrock IAM: wildcard eu-* for foundation models, fail on review error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use eu-* wildcard for foundation model ARNs instead of listing specific regions — Bedrock routes to any EU region dynamically. - Fail the pipeline when LLM review returns FAILED instead of silently passing through to the apply job. --- scripts/extract-review-risk.sh | 5 +++++ terraform/platform/iam/main.tf | 7 +------ terraform/platform/lambdas/main.tf | 13 ++++--------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/scripts/extract-review-risk.sh b/scripts/extract-review-risk.sh index 36b3eb1..286c74e 100644 --- a/scripts/extract-review-risk.sh +++ b/scripts/extract-review-risk.sh @@ -21,3 +21,8 @@ fi echo "risk_level=${RISK}" >> "$GITHUB_OUTPUT" echo "LLM review risk: ${RISK}" + +if [ "$RISK" = "FAILED" ]; then + echo "LLM review failed — blocking pipeline." + exit 1 +fi diff --git a/terraform/platform/iam/main.tf b/terraform/platform/iam/main.tf index a3c10a7..99cd8c8 100644 --- a/terraform/platform/iam/main.tf +++ b/terraform/platform/iam/main.tf @@ -112,12 +112,7 @@ resource "aws_iam_role_policy" "ci_infra_plan_extras" { "bedrock:InvokeModel", "bedrock:Converse", ] - Resource = [ - "arn:aws:bedrock:eu-central-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-north-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-west-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-west-3::foundation-model/anthropic.*", - ] + Resource = "arn:aws:bedrock:eu-*::foundation-model/anthropic.*" Condition = { StringLike = { "bedrock:InferenceProfileArn" = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" diff --git a/terraform/platform/lambdas/main.tf b/terraform/platform/lambdas/main.tf index b53b7a7..716c61c 100644 --- a/terraform/platform/lambdas/main.tf +++ b/terraform/platform/lambdas/main.tf @@ -7,15 +7,10 @@ locals { lambda_src_path = "${path.module}/../../lambda-src" github_org_url = "https://github.com/javaBin" - # EU cross-region inference profile destination regions. - # IAM requires foundation model access in all regions the profile can route to. - bedrock_eu_foundation_model_arns = [ - "arn:aws:bedrock:eu-central-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-north-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-west-1::foundation-model/anthropic.*", - "arn:aws:bedrock:eu-west-3::foundation-model/anthropic.*", - ] - bedrock_inference_profile_arn = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" + # EU cross-region inference profiles route to any eu-* region. + # IAM requires foundation model access in destination regions. + bedrock_eu_foundation_model_arns = "arn:aws:bedrock:eu-*::foundation-model/anthropic.*" + bedrock_inference_profile_arn = "arn:aws:bedrock:${var.region}:${var.aws_account_id}:inference-profile/eu.anthropic.*" } ################################################################################