Skip to content

Deployment module: create the per-end-user cost attribution role instead of requiring a hand-written one #203

Description

@JGoutin

aws_bedrock_user_role_arn turns on per-end-user cost attribution, but the module only consumes an ARN: the role itself, its trust policy and its permission policy are the operator's to write. That is the one piece of the feature nothing in the module or the docs hands over, and it is the piece that is easy to get wrong — the trust policy needs both sts:AssumeRole and sts:TagSession for the task role, and the permission policy needs every ARN shape a cross-region inference profile or a Marketplace model endpoint resolves to. Get either wrong and every model request fails AccessDenied, or the feature silently attributes nothing.

The sandbox already carries a hand-written version of exactly this role, which is evidence that the module should own it.

Proposal

Add aws_bedrock_user_role_create (bool, default false), following the aws_bedrock_batch_role_create / aws_bedrock_batch_role_arn pair already in the module:

  • when true, the module creates a fully managed role — trust policy, permission policy, tags — and wires its ARN into AWS_BEDROCK_USER_ROLE_ARN;
  • aws_bedrock_user_role_arn keeps taking precedence, so an operator with their own role is unaffected;
  • the ARN is published as a bedrock_user_role_arn output, so a caller can reference it (cost allocation tags, an SCP, a permissions boundary);
  • aws_bedrock_user_role_require_identity is accepted with either source of the role, not only with an explicit ARN.

Permission scope

The session signs exactly four bedrock-runtime operations (Converse, ConverseStream, InvokeModel, InvokeModelWithResponseStreamUSER_ROLE_OPERATIONS in stdapi/aws.py), so the created role grants bedrock:InvokeModel / bedrock:InvokeModelWithResponseStream and only what those invocations evaluate under the session's own identity:

  • guardrails applied inline by the invocation;
  • the built-in web search tool, with ExternalWebAccess only when aws_bedrock_external_web_access is on;
  • sagemaker:InvokeEndpoint* conditioned on aws:CalledViaLast = bedrock.amazonaws.com, only when aws_bedrock_marketplace_endpoints_enabled is on.

Bedrock Mantle, SageMaker AI endpoints, batch inference and every supporting service stay out: they are not bedrock-runtime calls, so they never carry the end user session.

Acceptance criteria

  • aws_bedrock_user_role_create = true alone produces a working deployment: the server assumes the role at startup with no warning, and a model request is attributed to its end user.
  • aws_bedrock_user_role_arn set together with create = true uses the supplied ARN and creates nothing.
  • Neither set leaves the feature off, exactly as today.
  • bedrock_user_role_arn output returns the created ARN, the supplied ARN, or null.
  • terraform validate and terraform fmt -check pass; the generated README.md is regenerated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity related

    Type

    No type

    Projects

    • Status
      In review

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions