Skip to content

s3.Bucket: AccessDenied when disabling autoDeleteObjects property #37257

@wandora58

Description

@wandora58

Describe the bug

When an S3 bucket is created with autoDeleteObjects: true and later updated to disable it (autoDeleteObjects: false), the Custom Resource deletion triggers an AccessDenied error. This is because the Lambda function's execution role does not include the s3:GetBucketTagging permission, which is required by the isBucketTaggedForDeletion() function in the auto-delete-objects handler.

The relevant handler code is here:
https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/custom-resource-handlers/lib/aws-s3/auto-delete-objects-handler/index.ts#L92-L124

async function onDelete(bucketName?: string) { if (!bucketName) { throw new Error('No BucketName was provided.'); } try { if (!await isBucketTaggedForDeletion(bucketName)) { console.log(`Bucket does not have '${AUTO_DELETE_OBJECTS_TAG}' tag, skipping cleaning.`); return; } await denyWrites(bucketName); await emptyBucket(bucketName); } catch (error: any) { // Bucket doesn't exist, all is well if (error.name === 'NoSuchBucket') { console.log(`Bucket '${bucketName}' does not exist.`); return; } throw error; } } /**  * The bucket will only be tagged for deletion if it is being deleted in the same  * deployment as this Custom Resource.  *  * If the Custom Resource is ever deleted before the bucket, it must be because  * `autoDeleteObjects` has been switched to false, in which case the tag would have  * been removed before we get to this Delete event.  */ async function isBucketTaggedForDeletion(bucketName: string) { const response = await s3.getBucketTagging({ Bucket: bucketName }); return response.TagSet?.some(tag => tag.Key === AUTO_DELETE_OBJECTS_TAG && tag.Value === 'true'); }

During a stack update that disables autoDeleteObjects, CloudFormation removes the bucket policy (which grants s3:GetBucket*) before the Custom Resource's Delete event fires. At that point, the Lambda role only has AWSLambdaBasicExecutionRole permissions , so the getBucketTagging call fails with AccessDenied.

Image

The stack update itself eventually succeeds because the Lambda function and IAM role are deleted afterward, but the AccessDenied error is logged and may cause confusion or delays.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Library Version

No response

Expected Behavior

The Custom Resource Lambda execution role should include s3:GetBucketTagging permission directly on the IAM role (not only via the bucket policy), so that the isBucketTaggedForDeletion() check succeeds even after the bucket policy has been removed during a stack update.

Current Behavior

When disabling autoDeleteObjects, CloudFormation removes the bucket policy before deleting the Custom Resource. The Lambda then fails with AccessDenied on getBucketTagging because the s3:GetBucket* permission was only granted via the bucket policy.

Reproduction Steps

 const bucket = new s3.Bucket(this, 'Bucket', { bucketName: 'egmfjgjfjf', blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, enforceSSL: true, removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true, }); 
  1. deploy the stack with autoDeleteObjects: true and RemovalPolicy.DESTROY
  2. comment out removalPolicy and autoDeleteObjects (default: false)
  3. run cdk deploy

Possible Solution

Add s3:GetBucketTagging policy with the Lambda function's execution role, rather than relying solely on the bucket policy statement which uses s3:GetBucket*.

Additional Information/Context

No response

AWS CDK Library version (aws-cdk-lib)

2.243.0

AWS CDK CLI version

2.1111.0

Node.js Version

22.9.0

OS

Mac

Language

TypeScript

Language Version

No response

Other information

Related issue: #14649

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-s3Related to Amazon S3bugThis issue is a bug.effort/mediumMedium work item – several days of effortp1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions