You are currently viewing How to solve the “api:s3:putbucketpolicy access denied” Error

How to solve the “api:s3:putbucketpolicy access denied” Error

Encountering the “api:s3:putbucketpolicy access denied” error while using the Serverless Framework with Typescript can be frustrating. In this comprehensive guide, we will explore the root cause of this error, explain the recent changes in AWS S3, and provide step-by-step solutions to resolve the issue. Follow along to regain control over your S3 bucket policies and overcome the access denied error.

Table of Contents

Understanding the “api:s3:putbucketpolicy access denied” Error

In this section, we will delve into the details of the error message, explaining its implications and the potential causes. Understanding the error will lay the foundation for resolving it effectively.
There are several factors that can cause this error. Let’s explore some of the common reasons:

  • Insufficient IAM permissions: Your AWS Identity and Access Management (IAM) user or role may lack the required permissions to modify the bucket policy.
  • Incorrect bucket policy: Your existing bucket policy may be denying access to the PutBucketPolicy action.
  • Account-level restrictions: AWS Organizations service control policies (SCPs) may be limiting your access to the required actions.

Exploring the api:s3:putbucketpolicy access denied Error in the serverless template

In this section, we will introduce the serverless template that led to the encounter with the api:s3:putbucketpolicy access denied error. The serverless template defines the creation of an S3 bucket with specific configurations. However, during the deployment process, the error occurred due to recent changes in AWS S3. We will explore the details of the serverless template and delve into the error in the following section.
Let’s take a look at our serverless template

resources: {
    Resources: {
      UploaderS3Bucket: {
        Type: 'AWS::S3::Bucket',
        Properties: {
          BucketName: '${self:provider.environment.UPLOADER_S3_BUCKET}',
          CorsConfiguration : {
            CorsRules : [
              {
                AllowedOrigins: ['*'],
                AllowedHeaders: ['*'],
                AllowedMethods: [
                  'GET',
                  'PUT',
                  'POST',
                  'DELETE',
                  'HEAD'
                ],
                MaxAge: 3000
              }
            ]
          }
        }
      },
      BuckePoliciy: {
        Type: 'AWS::S3::BucketPolicy',
        Properties: {
          Bucket: { Ref: "UploaderS3Bucket" },
          PolicyDocument: {
            Id: 'MyBucketPolicy',
            Version: "2012-10-17",
            Statement: [
              {
                Sid: "PublicReadForGetBucketObjects",
                Effect: "Allow",
                Principal: '*',
                Action: ['s3:GetObject'],
                Resource: ['arn:aws:s3:::${self:provider.environment.UPLOADER_S3_BUCKET}/*']
              }
            ]
          }
        }
      }
    }
  }

This template defines a CloudFormation resource that creates an S3 bucket with the specified CORS configuration and public access block configuration. The bucket policy allows public read access for objects in the bucket and allows putting new objects. 

Recent changes in AWS S3 and its impact

AWS S3 recently introduced changes that affect access control and public access settings. In this section, we will discuss these changes, particularly the automatic disabling of ACLs and the enforcement of block public access. We will explore how these changes contribute to the “api:s3:putbucketpolicy access denied” error.

In April 2023, Amazon S3 made a change to automatically enable a feature called “Block Public Access” for newly created buckets. This feature helps prevent unintended public access to S3 buckets by blocking certain permission settings. As a result, the use of Access Control Lists (ACLs) to manage public access to buckets has been disabled by default.

If you are trying to update the bucket policy using a serverless template or any other method that relies on setting ACLs, you may encounter an “access denied” error because the new bucket settings do not allow ACL-based permissions.

Step-by-Step Solutions for Resolving the “api:s3:putbucketpolicy access denied” Error

To resolve the “api:s3:putbucketpolicy access denied” error, you have a few options:

  • Update your serverless template: Instead of using a bucket policy based on ACLs, you can modify your template to use the newer access control mechanisms provided by Amazon S3, such as IAM policies. IAM policies allow you to define fine-grained access permissions for your S3 resources.
  • Manually update the bucket policy: If you prefer to manage the bucket policy outside of your serverless template, you can modify it directly in the AWS Management Console or through AWS CLI/API. Ensure that the policy aligns with the new Block Public Access settings and uses IAM policies instead of ACLs.
  • Disable Block Public Access (not recommended): If you have a specific use case that requires ACL-based permissions, you can disable the Block Public Access feature for your bucket. However, this is generally not recommended as it may introduce security risks and unintended public access to your bucket.

Let’s take a look at our updated template : 

functions: { 
    mediaProcessor : {
      ...mediaProcessor,
      role: 'S3BucketAccessRole'
    },
    getSignedUrl : {
      ...getSignedUrl,
      role: 'S3BucketAccessRole'
    },
    getPresignedUrl : {
      ...getPresignedUrl,
      role: 'S3BucketAccessRole'
    }
},
...
resources: {
    Resources: {
      UploaderS3Bucket: {
        Type: 'AWS::S3::Bucket',
        Properties: {
          BucketName: '${self:provider.environment.UPLOADER_S3_BUCKET}',
          CorsConfiguration : {
            CorsRules : [
              {
                AllowedOrigins: ['*'],
                AllowedHeaders: ['*'],
                AllowedMethods: [
                  'GET',
                  'PUT',
                  'POST',
                  'DELETE',
                  'HEAD'
                ],
                MaxAge: 3000
              }
            ]
          },
          PublicAccessBlockConfiguration: {
            BlockPublicAcls: true,
            IgnorePublicAcls: true,
            BlockPublicPolicy: true,
            RestrictPublicBuckets: true
          }
        }
      },
      S3BucketAccessRole: {
        Type: 'AWS::IAM::Role',
        Properties: {
          RoleName: 'S3BucketAccessRole',
          AssumeRolePolicyDocument: {
            Version: '2012-10-17',
            Statement: [
              {
                Effect: 'Allow',
                Principal: {
                  Service: 'lambda.amazonaws.com',
                },
                Action: 'sts:AssumeRole'
              }
            ]
          },
          Policies: [
            {
              PolicyName: 'MediaProcessorPolicy',
              PolicyDocument: {
                Version: '2012-10-17',
                Statement: [
                  {
                    Effect: 'Allow',
                    Action: ['s3:GetObject', 's3:PutObject'],
                    Resource: [
                      'arn:aws:s3:::${self:provider.environment.UPLOADER_S3_BUCKET}/*',
                    ],
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }

Let’s explain the changes we made :

S3 Bucket Changes:

Public Access Block: To align with the new S3 behavior, we added the PublicAccessBlockConfiguration property to the UploaderS3Bucket resource. This configuration helps enforce restrictions on public access to your bucket.
BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, and RestrictPublicBuckets are all set to true, ensuring that public access through ACLs and policies is blocked, and public access to public buckets is restricted.

IAM Role for S3 Access:
Role Creation: We added an S3BucketAccessRole resource of type AWS::IAM::Role. This role is used to grant permissions for your Lambda functions to access the S3 bucket.
Assume Role Policy: The AssumeRolePolicyDocument property defines who can assume (use) this role. In this case, the Lambda service is specified as the principal that can assume the S3BucketAccessRole.
Access Policies: The Policies property specifies the permissions granted to the role. In the MediaProcessorPolicy, you allow the role to perform s3:GetObject and s3:PutObject actions on objects within the bucket. The bucket’s ARN (Amazon Resource Name) is dynamically derived from the UPLOADER_S3_BUCKET environment variable.

Functions and Environment:
Function Role Assignment: We updated the mediaProcessor, getSignedUrl, and getPresignedUrl functions to include the role property with the value set to S3BucketAccessRole. This assigns the S3BucketAccessRole to the Lambda functions, granting them the necessary permissions to access the S3 bucket.

Conclusion

Encountering the “api:s3:putbucketpolicy access denied” error in AWS S3 can be frustrating, but armed with knowledge and solutions, you can overcome this challenge. By understanding the error’s causes, the impact of recent changes in AWS S3, and following the step-by-step solutions provided, you can regain control over your S3 bucket policies.

Ensure that your serverless templates align with the updated AWS S3 settings, utilizing IAM policies instead of ACLs. Alternatively, you can manually update the bucket policy or make use of AWS Management Console or AWS CLI/API to modify it directly. However, it is generally recommended to avoid disabling the Block Public Access feature, as it may compromise security and introduce unintended public access risks.

By taking proactive measures and staying up-to-date with AWS S3 changes, you can successfully navigate the complexities of bucket policy management and overcome the “api:s3:putbucketpolicy access denied” error, ensuring a seamless experience while leveraging the power of AWS S3.

Leave a Reply