feat: generate STS external ID for Bedrock role assumption (#26869)

Implements:
https://linear.app/codercom/issue/AIGOV-495/add-externalid-to-prevent-confused-deputy-problem

When a Bedrock provider assumes an IAM role via STS, the gateway now
generates a unique external ID for it and sends that value on every
`AssumeRole` call. The external ID guards against the [confused deputy
problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
on cross-account role assumption. Per [AWS's
recommendation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html),
the gateway generates and owns the value rather than accepting one from
the operator; that ownership is what makes it effective, since a party
who knows another's external ID can't induce the gateway to send it.

The external ID is server-owned and read-only over the API. It is
generated once, when a provider first has a `role_arn`, and is stable
thereafter. Clients cannot set it: create rejects any supplied
`external_id`, and update rejects a value that differs from the stored
one. An update may echo the stored value back unchanged, so the normal
read-modify-write flow (GET the provider, change a field, PATCH the full
settings object) keeps working. The value is not a secret and is
returned on GET so operators can copy it into the target role's trust
policy as an `sts:ExternalId` condition.

It is persisted in the existing JSON settings blob, so there is no
migration or audit-table change.
This commit is contained in:
Yevhenii Shcherbina
2026-07-01 20:44:15 +00:00
committed by GitHub
parent 1101a0f974
commit db7f4438b4
13 changed files with 527 additions and 66 deletions
+2
View File
@@ -211,6 +211,7 @@ func protoToProviderSpec(pp *proto.AIProvider) aiProviderSpec {
b.GetSmallFastModel(),
)
bedrock.RoleARN = b.GetRoleArn()
bedrock.ExternalID = b.GetExternalId()
spec.Bedrock = ptr.Ref(bedrock)
}
return spec
@@ -352,6 +353,7 @@ func bedrockConfig(baseURL string, bedrock *codersdk.AIProviderBedrockSettings)
Model: bedrockSettings.Model,
SmallFastModel: bedrockSettings.SmallFastModel,
RoleARN: bedrockSettings.RoleARN,
ExternalID: bedrockSettings.ExternalID,
}
}