CDK Codepipeline CloudFormationCreateUpdateStackAction getting "S3: Access Denied" only with Nested Stacks - amazon-web-services

I am trying to set up a CDK Codepipeline for updating the cdk project itself, with the project being under one stack, and having multiple nested stacks in the constructor. The pipeline is in a second stack with the service stack passed in to access the name. I am using CloudFormationCreateUpdateStackAction to update the stack after I have run cdk synth and put the output in an artifact using codebuild.
pipeline.addStage({
stageName: 'ServiceUpdate',
actions: [
new CloudFormationCreateUpdateStackAction({
actionName: 'Service_Update',
stackName: props.serviceStack.stackName,
templatePath: cdkPipelineBuildOutput.atPath(
`${props.serviceStack.stackName}.template.json`
),
adminPermissions: true,
}),
],
});
This is able to update the stack if it is empty, or has some resources directly in it, however if there is a nested stack inside the service stack I get
S3: AccessDenied
for each of the nested stacks inside of the stack.
If I run "cdk deploy ExampleServiceStackName" from my terminal with admin credentials the nested stacks are created/updated correctly, leading me to believe that there is something wrong with the IAM roles of codebuild or codepipeline here. But I don't know where to start as I have set adminPermissions to true in the CloudFormationCreateUpdateStackAction.
I also manually set admin permissions by calling addToDeploymentRolePolicy on the CloudFormationCreateUpdateStackAction, and CodePipeline, passing
const policy = new PolicyStatement({
resources: ['*'],
actions: ['*'],
effect: Effect.ALLOW,
});
with no change in the access denied error.
I also make sure to specify "cdk synth --all" in my ci script in an attempt to ensure the nested stacks templates will be synthesized.
Other stack overflow questions I have read:
S3 error: Access Denied when deploying CFN template with Nested Stacks
This Q was related to a typo in the manually written cloud formation template. I have looked in the generated templates, and the nested stack name is correctly generated and referenced by cdk. cdk deploy from local terminal also works, further leading me to believe there is no typo problem. I also pass the service stack as a prop and call the stackName property to avoid a typo in accessing the template.
If you spot a way there could be a problem accessing due to a typo, please let me know as that would still be the best-case scenario.
Codepipeline S3 Bucket access denied in Codebuild
This Q says it was solved by giving permissions to the CMK on the S3 bucket. I have used a code pipeline Artifact for source of the "cdk synth -> cloudformation templates". I'm not aware of any KMS CMK being used in this setup. If there is a way I can specify decryption abilities on the artifact maybe that would help.
If there is a way to get more verbose error messages about the s3: Access Denied status that would also be appreciated. It doesn't even share what s3 bucket is being denied, I'm just having to assume.
Thanks for any suggestions.

Related

AWS cloudformation resource already exists : deploy without deleting old resource

I created and deployed a S3 resource (bucket) using cloudformation.
After that i deployed a version without that resource.
Then i deployed a version with the resource.
Since the bucket exists, it gives me an error that it cannot deploy.
This has happened to me before, in past times I deleted the resource and deployed again.
I'm looking for a way to use the resource for future deployments. It is the exact same resource, this is the yaml :
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "myBucketName"
Is there anything I can add to the resource, a policy, a unique ID, anything so that i could use the existing resource?
Thanks!
To "use the existing resource" in a CFN, you have to import it. Also its a bad practice to keep modify resources created by CFN outside of CFN. This leads to drift and number of issues, one of which you are experiencing.

AWS CDK update/add lifecycle to existing S3 bucket using custom source

I created an S3 bucket but now I would like to update/add lifecycle policies to it using CDK.
Currently I can import this bucket to a new stack file.
const testBucket = s3.Bucket.fromBucketAttributes(this, 'TestBucket', {
bucketArn: 'arn:aws:s3:::xxxxxx'});
How can I use AwsCustomResource to update/add lifecycle policies? For example, for prefix = long, I want those objects to expire in 7 days, and for prefix = short, I want them to expire in 3 days.
Or is there a general way of updating an existing S3 bucket in a new stack with CDK?
The best option for this is probably to add it to the stack using resource importing. Don't confuse a custom resource with a CDK construct. A custom resource involves deploying a lambda function and calling that function when the CloudFormation custom resource is present in your stack. A CDK construct is used to generate a CloudFormation template. It allows you to combine different resources into a single bit of code, and allows some logical decisions based on the input values.
Steps to import:
Make sure your current CDK is what is deployed. You cannot import resources when there are other changes.
Add the S3 bucket to your CDK code as if you were creating it for the first time. Make sure that all the settings are the same as what is currently deployed. This is important because the import process doesn't validate that what you have configured matches what you are importing.
Run cdk synth to generate the CloudFormation template that includes the S3 bucket.
In the CloudFormation console locate the stack that represents the CDK stack you are working with.
Select Import resources into stack from the Stack actions menu.
Follow the prompts. When asked for the template select Upload a template file and select the template created by the cdk synth command (hint: it will be in cdk-out). You will be prompted to add the bucket name. This should be the bucket that you are wanting to add to this stack.
Once that is done you can modify the bucket as if it were created by your stack.
One thing to note. CDK includes some meta-data in the CloudFormation template. This value must be the same as what is currently deploy or it will be seen as a change and you won't be able to perform the import. You can copy the values from what is currently deployed and manually edit the template created by cdk synth to match that.
Need to access the CfnBucket reference of the testBucket and add lifecycle rules to it.
const testBucket = s3.Bucket.fromBucketAttributes(this, 'TestBucket', {
bucketArn: 'arn:aws:s3:::xxxxxx')
testBucket.node.root.addLifecycleRule({prefix: 'short', expiration:3, enabled:true})
testBucket.node.root.addLifecycleRule({prefix: 'long', expiration:7, enabled:true})

aws cdk ignores assume role statement

I've try to recreate cloudfront stack with lambda.
got an error:
The function execution role must be assumable with edgelambda.amazonaws.com as well as lambda.amazonaws.com principals. Update the IAM role and try again
However the principal is assumed:
Does generated cloudformation output of two set of "assumedRole" actions
is correct?
The code seems working for me, the change that was made is that I deleted local cdk.out.
Cured by deploying the same stack with the another name.

AWS SAM deploy failure

I was testing the AWS SAM functionality and encountered an issue.
If by manually delete a resource that was originally created by the SAM template, then subsequent SAM deployment will fail. I do understand that deleting resource manually that was created by SAM is not a good practice. But this was just a test only
Error
Is there any way to fix this?
AWS SAM uses Cloudformation underneath to create various resources.
How do I update an AWS CloudFormation stack that's failing because of a resource that I manually deleted?
If you delete a resource from an AWS CloudFormation stack, then you must remove the resource from your AWS CloudFormation template. Otherwise, your stack fails to update, and you get an error message.
similar post : Function not found after manually deleting a function in a SAM CloudFormation stack

Function not found after manually deleting a function in a SAM CloudFormation stack

I am using sam deploy to deploy lambda function and API gateway. It works fine but it doesn't work after I manually deleted the lambda function via AWS console. I got below error:
"ResourceStatusReason": "Function not found:
arn:aws:lambda:ap-southeast-2:286334053171:function:polaroid (Service:
AWSLambdaInternal; Status Code: 404; Error Code: ResourceNotFoundException;
Request ID: b431cbfc-7772-11e9-8022-1b92fa2cfa9e)
What is the proper way to delete the lambda and do a refresh deployment? If this happens, how can I force SAM to create the missing lambda function?
My lambda in template yaml looks like:
...
Resources:
PolaroidFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: test
CodeUri: ./lambdas
Handler: lib/index.fun
Runtime: nodejs8.10
Events:
polaroid:
Type: Api
Properties:
Path: /test
Method: post
...
I guess you already learnt the hard way that you should never manually delete resources managed by SAM or CloudFormation.
In general, if you just want to change the function, you can just call sam build and sam deploy, and the new version of it will be deployed. There is no need to delete anything. If you need a more advanced workflow, you will need to read blog posts. There is no one right way to do this.
To fix your immediate problem however, here is what you can do.1
Firstly, you need to get the generated AWS CloudFormation template:
▶ aws cloudformation get-template --stack-name HelloWorld \
--template-stage Processed --query TemplateBody | cfn-flip -y > processed.yml
Next, you need to comment out the function in the processed.yml file you just created, and also comment out the Lambda Permissions that refer to it. Save a backup of the original processed.yml file too.
Also, update any other template references to it if possible with the actual values CloudFormation computed when you built the stack, by getting them from your AWS console. For example, if you had references to ${HelloWorldFunction.Arn} you might have to update those references in the template with a string like arn:aws:lambda:ap-southeast-2:123456789012:function:HelloWorld-HelloWorldFunction-1NJGQI7GEAUM1.
Next, validate the template using AWS CloudFormation commands:
▶ aws cloudformation validate-template --template-body file://processed.yml
{
"CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]",
"Description": "sam-app\nSample SAM Template for sam-app\n",
"Parameters": [],
"Capabilities": [
"CAPABILITY_IAM"
]
}
Next, you will update the stack using this modified template. By updating the stack this way, you get your template and real state to be back in sync from CloudFormation's point of view:
▶ aws cloudformation update-stack --template-body file://processed.yml --stack-name HelloWorld --capabilities CAPABILITY_IAM
{
"StackId": "arn:aws:cloudformation:ap-southeast-2:885164491973:stack/HelloWorld/af2c6810-7884-11e9-9bb3-068b1a8e1450"
}
If all goes well, your stack goes into UPDATE_COMPLETE state. Great!
Finally, uncomment all the resources you commented out, and restore all the original values. Then update stack a second time, and your stack should be restored to its original state.
See also:
AWS Knowledge Base, 2016, 2019, How do I update an AWS CloudFormation stack that's failing because of a resource that I manually deleted?.
More on the cfn-flip utility, if you don't have it.
1 Note that I tested this method using the default HelloWorld Python 2.7 example that ships with SAM.
I had a similar issue. In my case I had deleted the Lambda as an experiment while trying to reset the TRIM_HORIZON to get it to reprocess old events in a DynamoDB Stream.
I found a simpler solution:
Go into the CloudFormation Console and delete the deployed Stack.
sam deploy works fine again after that.
So as suggested in other answers I deleted the function manually from the console.
I was deploying the stack from CDK
The solution
comment the lambda function code (in cdk) of the function I deleted manually.
Deploy stack
Un-comment the code and deploy again
If you want to avoid deleting the stack and deploying it back again, or avoid aligning the CloudFormation template file, perhaps you can just align the resources in AWS to the template file.
That means, if you deleted a certain Lambda (for example) that was created initially from the template file, just create the same Lambda MANUALLY in AWS (either GUI or aws cli).
Now run 'sam deploy' again - you should be aligned.
Now remove the Lambda definition from the template file and deploy again - the Lambda should be removed and the CloudFormation will be aligned.