From 41214e0f2ce10667509e0631cb8570717f4fb6ec Mon Sep 17 00:00:00 2001 From: Javier Castiarena Date: Thu, 23 Apr 2026 15:33:27 -0300 Subject: [PATCH] fix(aws-s3-bucket): replace enumerated action list with s3:* in bucket mgmt policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agent IAM policy `nullplatform_s3_policy` enumerated ~22 specific s3 actions. The AWS Terraform provider refreshes `aws_s3_bucket` by reading a wide surface of bucket attributes (ACL, CORS, Logging, Lifecycle, Replication, OwnershipControls, Website, Notification, AccelerateConfiguration, RequestPayment, ObjectLock, ...). Each time the provider gains a new refreshed attribute, the enumerated list breaks with AccessDenied on the missing Get* action. Observed failure on provider v6.x: Error: reading S3 Bucket (...) ACL: operation error S3: GetBucketAcl, https response error StatusCode: 403, ... User: arn:aws:sts:::assumed-role// is not authorized to perform: s3:GetBucketAcl on resource: "..." `s3:GetBucketAcl` is not in the current enumerated list, and neither are several other attributes the provider reads during refresh. Fix: replace the enumerated list with `s3:*`. Resource stays `"*"` to preserve current behavior — tenants wanting a tighter blast radius can attach this policy via a wrapper that overrides the Resource list to a known prefix (the service's default naming is `np--` for user buckets and `np-service-` for tfstate buckets — both under `np-*`), which is the approach documented in the `nullplatform-implementations/implementation-aws` tenant comment on the equivalent inline policy. `nullplatform_s3_iam_policy` and `nullplatform_s3_tfstate_policy` are unaffected: IAM users operate through Object-level API only, and tfstate buckets are created via the `aws s3api create-bucket` CLI plus the OpenTofu s3 backend's Object-level I/O — neither triggers an `aws_s3_bucket` resource refresh. Co-Authored-By: Claude Opus 4.7 (1M context) --- aws-s3-bucket/requirements/main.tf | 41 +++++++++++++----------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/aws-s3-bucket/requirements/main.tf b/aws-s3-bucket/requirements/main.tf index c22da2a..0757aa4 100644 --- a/aws-s3-bucket/requirements/main.tf +++ b/aws-s3-bucket/requirements/main.tf @@ -25,6 +25,22 @@ resource "aws_iam_role_policy_attachment" "s3_tfstate" { ################################################################################ # Permissions to create/configure/delete user buckets managed by this service. +# +# Uses `s3:*` rather than an enumerated Get/Put list because the AWS +# Terraform provider refreshes `aws_s3_bucket` by reading a wide surface of +# bucket attributes (ACL, CORS, Logging, Lifecycle, Replication, +# OwnershipControls, Website, Notification, AccelerateConfiguration, +# RequestPayment, ObjectLock, ...). Each time the provider gains a new +# refreshed attribute, an enumerated list breaks with AccessDenied on the +# missing Get* action. Observed on provider v6.x: `s3:GetBucketAcl` was not +# in the previous enumerated list and aborted the first create workflow on +# a tenant with an up-to-date provider. +# +# Resource stays `"*"` to preserve current behavior. Tenants wanting a +# tighter blast radius can attach this policy via a wrapper that overrides +# the Resource list to a known bucket prefix (this service's default naming +# is `np--` for user buckets and +# `np-service-` for tfstate buckets — both `np-*`). resource "aws_iam_policy" "nullplatform_s3_policy" { name = "nullplatform_${var.name}_s3_policy" description = "Policy for managing S3 buckets provisioned by the aws-s3-bucket service" @@ -34,30 +50,7 @@ resource "aws_iam_policy" "nullplatform_s3_policy" { "Statement" : [ { "Effect" : "Allow", - "Action" : [ - "s3:CreateBucket", - "s3:DeleteBucket", - "s3:GetBucketLocation", - "s3:GetBucketVersioning", - "s3:GetBucketEncryption", - "s3:GetBucketPublicAccessBlock", - "s3:GetBucketPolicy", - "s3:GetBucketTagging", - "s3:PutBucketVersioning", - "s3:PutBucketEncryption", - "s3:PutBucketPublicAccessBlock", - "s3:PutBucketPolicy", - "s3:PutBucketTagging", - "s3:DeleteBucketPolicy", - "s3:HeadBucket", - "s3:ListBucket", - "s3:ListBucketVersions", - "s3:GetObject", - "s3:PutObject", - "s3:DeleteObject", - "s3:DeleteObjectVersion", - "s3:ListAllMyBuckets" - ], + "Action" : "s3:*", "Resource" : "*" } ]