mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
fix(bedrock): authorize runtime/agent actions under the bedrock: IAM namespace (#820)
The gateway derived each request's IAM action prefix from the wire-service name, so bedrock-runtime, bedrock-agent and bedrock-agent-runtime calls were checked as bedrock-runtime:ConverseStream, bedrock-agent-runtime:Retrieve, etc. AWS namespaces every Bedrock action under bedrock:, so an AWS-shaped scoped policy never matched and only a wildcard admitted the call. Collapse the Bedrock family to the shared bedrock: namespace in IAMAction, the single choke point for policy decisions; recordResolvedAction keeps the wire name for telemetry.
This commit is contained in:
@@ -1,6 +1,27 @@
|
||||
package policy
|
||||
|
||||
// IAMAction formats a service and action as the IAM policy string "service:ActionName".
|
||||
func IAMAction(service, action string) string {
|
||||
return service + ":" + action
|
||||
// bedrockIAMFamily lists the Bedrock wire/signing service names that all
|
||||
// authorize under the single "bedrock:" IAM namespace in AWS (runtime, agent,
|
||||
// and agent-runtime actions are namespaced as bedrock: on AWS).
|
||||
var bedrockIAMFamily = map[string]bool{
|
||||
"bedrock-runtime": true,
|
||||
"bedrock-agent": true,
|
||||
"bedrock-agent-runtime": true,
|
||||
}
|
||||
|
||||
// iamNamespace maps a wire service name to its IAM policy namespace, collapsing
|
||||
// the Bedrock family to the shared "bedrock:" namespace. Every other service
|
||||
// keeps its own name.
|
||||
func iamNamespace(service string) string {
|
||||
if bedrockIAMFamily[service] {
|
||||
return "bedrock"
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
// IAMAction formats a service and action as the IAM policy string
|
||||
// "namespace:ActionName", collapsing the Bedrock family to the shared bedrock:
|
||||
// namespace so AWS-shaped policies authorize as they do on AWS.
|
||||
func IAMAction(service, action string) string {
|
||||
return iamNamespace(service) + ":" + action
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package policy
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestIAMAction_BedrockNamespace asserts the Bedrock wire-service family
|
||||
// collapses to the shared "bedrock:" IAM namespace, while other services keep
|
||||
// their own prefix, so AWS-shaped policies authorize as they do on AWS.
|
||||
func TestIAMAction_BedrockNamespace(t *testing.T) {
|
||||
cases := []struct {
|
||||
service, action, want string
|
||||
}{
|
||||
{"bedrock", "Converse", "bedrock:Converse"},
|
||||
{"bedrock-runtime", "ConverseStream", "bedrock:ConverseStream"},
|
||||
{"bedrock-runtime", "InvokeModel", "bedrock:InvokeModel"},
|
||||
{"bedrock-agent", "CreateKnowledgeBase", "bedrock:CreateKnowledgeBase"},
|
||||
{"bedrock-agent-runtime", "Retrieve", "bedrock:Retrieve"},
|
||||
{"bedrock-agent-runtime", "RetrieveAndGenerate", "bedrock:RetrieveAndGenerate"},
|
||||
{"ecr", "GetAuthorizationToken", "ecr:GetAuthorizationToken"},
|
||||
{"ecs", "RunTask", "ecs:RunTask"},
|
||||
{"s3", "GetObject", "s3:GetObject"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := IAMAction(c.service, c.action); got != c.want {
|
||||
t.Errorf("IAMAction(%q, %q) = %q, want %q", c.service, c.action, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user