aws-amplify / amplify-cli

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development.
Apache License 2.0
2.82k stars 820 forks source link

v12.12.5 - policy already exists on bucket #13878

Closed electronicalias closed 3 months ago

electronicalias commented 3 months ago

How did you install the Amplify CLI?

npm install -g @aws-amplify/cli

If applicable, what version of Node.js are you using?

the latest

Amplify CLI Version

v12.12.5

What operating system are you using?

Ubuntu

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

Deployment of the Amplify project started failing after 12.12.5 was released. No manual changes, but we do apply a post-push.js script to set the buckets to SSL only (because this wasn't a native feature).

Last successful run appears to be prior to the release (10 hours ago), whereas the release was 8 hours ago. The standard output of our jobs doesn't check the version of the Amplify CLI, so I can't tell you whether it was successful the first time.

Can see in CloudFormation that a Bucket Policy does not exist ont the main stack, so we assume it does NOT work if there is a pre-defined policy on the bucket.

Describe the bug

Updated version tries to create a bucket policy. If one already exists (as in our case) we get: CREATE_FAILED DeploymentBucketBlockHTTP AWS::S3::BucketPolicy Fri Aug 02 2024 08:21:18 GMT+0000 (Coordinated Universal Time) The bucket policy already exists on bucket amplify--deployment.

Expected behavior

Technically, I would expect it to check before deployment, but I doubt this is possible and we'll need to refactor our post-push.js scripts for about 30 applications. Manually remove the policy, then update to this version and redeploy.

Reproduction steps

  1. Bulid an Amplify App using cli version 12.12.4
  2. Use the following (or similar for your environment) in a post-push.js script to implement a bucket policy for the deployment.

jsonData: team-provider-info.json region: the region we're running in parameters: pulled from jsonData['ourenvname'].cloudformation awsConfig: SDK credentials configuration object

NOTE: You can keep it simple, ultimately we find the deployment bucket name in this way and then apply the policy to it.

const { fromIni } = require("@aws-sdk/credential-providers");
const { S3Client, PutBucketPolicyCommand } = require("@aws-sdk/client-s3");

class DeploymentBucketUpdater {
    constructor(region, parameters, jsonData, awsConfig) {
        // Region from main functin
        this.region = region;
        this.jsonData = jsonData;
        this.awsConfig = awsConfig
        this.parameters = parameters

        // Configure S3
        this.s3Client = new S3Client(this.awsConfig);

        console.log('Deployment Bucket Handler Initialised.')
    }
    updateDeploymentBucketPolicy = async () => {
        // Function to recursively search for keys in an object
        function findDeploymentBucketNames(obj, result = new Set()) {
            if (typeof obj !== 'object' || obj === null) return result;

            for (const key in obj) {
                if (key === 'DeploymentBucketName') {
                    result.add(obj[key]);
                } else if (typeof obj[key] === 'object') {
                    findDeploymentBucketNames(obj[key], result);
                }
            }
            return result;
        }

        // Extract the deployment bucket names
        const deploymentBucketNames = findDeploymentBucketNames(this.jsonData[this.parameters.data.amplify.environment.envName]);
        const uniqueBucketNames = [...deploymentBucketNames];

        for (const bucketName of uniqueBucketNames) {
            const sslPolicy = {
                Version: "2012-10-17",
                Statement: [
                    {
                        Sid: "EnforceSSL",
                        Effect: "Deny",
                        Principal: "*",
                        Action: "s3:*",
                        Resource: [
                            `arn:aws:s3:::${bucketName}`,
                            `arn:aws:s3:::${bucketName}/*`
                        ],
                        Condition: {
                            Bool: {
                                "aws:SecureTransport": "false"
                            }
                        }
                    }
                ]
            };

            const params = {
                Bucket: bucketName,
                Policy: JSON.stringify(sslPolicy)
            };

            try {
                this.s3Client.send(new PutBucketPolicyCommand(params));
                console.log(`SSL policy applied to bucket ${bucketName}`);
            } catch (error) {
                console.error(`Error applying SSL policy to bucket ${bucketName}:`, error);
            }
        }
    }
}

module.exports = DeploymentBucketUpdater;
  1. Deploy using 12.12.4
  2. Upgrade to 12.12.5
  3. Deploy using 12.12.5

Project Identifier

No response

Log output

``` # Put your logs below this line ```

Additional information

Meanwhile we've reverted to 12.12.4 and the pipeline is working again.

Before submitting, please confirm:

awsluja commented 3 months ago

Hi @electronicalias , thank you for submitting this. We are making changes that are aligned with security best practices which will help all customers. Unfortunately, custom logic in post-push scripts will need to be updated or removed like you have outlined. In the meantime, 12.12.4 will continue to work for you

ykethan commented 3 months ago

Closing the issue, do reach out if you require any further assistance on this.

github-actions[bot] commented 3 months ago

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.