You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Both compute payload buckets grant the compute role bucket-wide read via CDK's grantRead, which renders s3:GetObject*, s3:GetBucket* and s3:List* across the whole bucket:
cdk/src/constructs/lambda-microvm-compute.ts — payloadBucket.grantRead(executionRole) (ADR-021 P1, same shape by design/precedent)
Raised in review of PR #689 (ADR-021 P1). Pre-existing on the ECS side, so not a MicroVM regression — but the 4 KB runHookPayload cap makes the MicroVM payload bucket a hot path (virtually every task delivers its payload through it), which raises the value of tightening it.
Why it matters
The compute role runs untrusted repository code. Payload objects are keyed <task_id>/payload.json, and a hydrated payload contains the prompt, issue thread and repo context. Bucket-wide read means task A's container can read task B's hydrated payload, and s3:List* lets it enumerate every recent task id — a cross-tenant read plus an inventory primitive, on the least-trusted role in the platform. Write and delete are correctly withheld; read is the remaining gap.
Proposal
Drop s3:List*. Nothing in either agent lists the bucket — both are handed an exact URI. No-behavior-change tightening; removes the enumeration primitive on its own.
Scope s3:GetObject to the task's own prefix. Preference order:
(b) if the payload read happens before SessionRole assumption (it does today: read once at boot on the task/execution role), either move the read after assumption or hand the container a presigned URL minted by the orchestrator (which already has write access).
Apply to BOTH backends in one change and extend the existing "read-only, nothing mutating" assertions in both construct test suites to also assert the absence of s3:List* and the presence of the task-scoping condition.
Notes / open questions
Option (b) changes the boot sequence and is the larger change; (a) needs confirmation the payload read can move behind SessionRole assumption without breaking the "read payload first" boot ordering both paths rely on.
The existing cdk-nag AwsSolutions-IAM5 suppressions on both constructs cite "CDK grantRead on the dedicated payload bucket" — those reasons must be narrowed as part of this work.
Not a P1 blocker for ADR-021: exposure equals the shipped ECS backend, and the payload TTL is 1 day.
Context
Both compute payload buckets grant the compute role bucket-wide read via CDK's
grantRead, which renderss3:GetObject*,s3:GetBucket*ands3:List*across the whole bucket:cdk/src/constructs/ecs-agent-cluster.ts) —grantRead(taskRole)(introduced with the S3-pointer payload path, ECS compute strategy: RunTask rejected — payload inlined into 8 KB containerOverrides limit #502)cdk/src/constructs/lambda-microvm-compute.ts—payloadBucket.grantRead(executionRole)(ADR-021 P1, same shape by design/precedent)Raised in review of PR #689 (ADR-021 P1). Pre-existing on the ECS side, so not a MicroVM regression — but the 4 KB
runHookPayloadcap makes the MicroVM payload bucket a hot path (virtually every task delivers its payload through it), which raises the value of tightening it.Why it matters
The compute role runs untrusted repository code. Payload objects are keyed
<task_id>/payload.json, and a hydrated payload contains the prompt, issue thread and repo context. Bucket-wide read means task A's container can read task B's hydrated payload, ands3:List*lets it enumerate every recent task id — a cross-tenant read plus an inventory primitive, on the least-trusted role in the platform. Write and delete are correctly withheld; read is the remaining gap.Proposal
s3:List*. Nothing in either agent lists the bucket — both are handed an exact URI. No-behavior-change tightening; removes the enumeration primitive on its own.s3:GetObjectto the task's own prefix. Preference order:aws:PrincipalTag/task_idcondition on the object ARN, reusing the per-task SessionRole taggingAgentSessionRole.admitComputeRolealready establishes (feat(security): per-session IAM scoping — session-tagged AssumeRole, DynamoDB leading-key conditions, Bedrock ARN allowlist #209) — the artifacts bucket already uses this exact pattern (artifacts/${aws:PrincipalTag/task_id}/*);s3:List*and the presence of the task-scoping condition.Notes / open questions
AwsSolutions-IAM5suppressions on both constructs cite "CDK grantRead on the dedicated payload bucket" — those reasons must be narrowed as part of this work.Refs #645, #502, PR #689 (review suggestion 3)