cdklabs / cdk-stacksets

Apache License 2.0
78 stars 12 forks source link

s3 sync returns non-zero exit status 1 #456

Open kaidobit opened 1 month ago

kaidobit commented 1 month ago

I would like to leverage cdk-stacksets in order to deploy multiregional and into multiple accounts including File Assets.

Environment:

Node: v18.14.2
TypeScript: ~5.4.5
CDK: 2.138.0
cdk-stacksets: ^0.0.150

I have created a list of buckets accordingly to this scheme <BUCKET_PREFIX>-<REGION> outside the scope of my CDK app, each with these bucket-permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:Get*",
                "s3:List*",
                "s3:Put*",
                "s3:Delete*",
            ],
            "Resource": [
                "arn:aws:s3:::<BUCKET_PREFIX>-<REGION>",
                "arn:aws:s3:::<BUCKET_PREFIX>-<REGION>/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalOrgID": "<ORGANIZATION_ID>"
                }
            }
        }
    ]
}

Then I imported the bucket, assigned the assetBucket and assetBucketPrefix in order to create the stack:

// import only eu-central-1 bucket
const sharedAssetBucket = aws_s3.Bucket.fromBucketName(this, "SharedAssetsBucket", "<BUCKET_PREFIX>-<REGION>")
const myStackSetStack = new MyStackSetStack(this, 'MyStackSetStack', {
    assetBuckets: [sharedAssetBucket],
    assetBucketPrefix: "<BUCKET_PREFIX>"
})
const myStackSet = new StackSet(this, 'MyStackSet', {
        stackSetName: "MyStackSet",
        template: StackSetTemplate.fromStackSetStack(myStackSetStack),
        target: ...
    }
);

This is my SteckSetTemplate:

export class MyStackSetStack extends StackSetStack {
  constructor(scope: Construct, id: string, props: StackSetStackProps) {
    super(scope, id);

     new cr.AwsCustomResource(this, 'GetParameterCustomResource', {
      onUpdate: {
        service: 'SSM',
        action: 'getParameter',
        parameters: {
          Name: 'my-parameter',
        },
        physicalResourceId: cr.PhysicalResourceId.of('test-resource'),
      },
      policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
        resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
      }),
    });
    // or any other resource leveraging file assets
  }
}

When I run deploy I get the error message:

Command '['/opt/awscli/aws', 's3', 'sync', '/tmp/tmp04w0o9tq/contents', 's3://<BUCKET_PREFIX>-<REGION>/']' returned non-zero exit status 1.

Accordingly to #428 permissions for the AwsApiCall are not being created, however he fixed it, without mentioning the fix.

  1. Is it correct to provide only one single bucket in the assetBuckets-array, if so why is it an array?
  2. Should assetBuckets be an array of every regional asset bucket, then whats the point of assetBucketPrefix?
  3. Is there any workaround to fixing this issue?

Please clarify.

josh-demuth commented 1 month ago

@kaidobit -

if deploying to one single region yes you would have just one bucket. but you still need to name the bucket with the {prefix}-{region} naming convention and for consistency it is still a list. the reason it was done this way is due to how the resulting cloudformation template can be parameterized. for stacksets, we get one template that is used across all accounts/regions the stackset is deployed to so this limits flexibility. we can have a hardcoded prefix that is shared across all asset buckets then use cfn pseudo parameters to make it region specific and allow different buckets for different regions as required by the lambda service.

this is a big difference compared to how single stacks are deployed with cdk deploy since the bucket name for each region would be hardcoded and each region would get its own cfn template.

for your error, i would recommend looking at cloudtrail in the account throwing the error.