How to Convert the existing stack to nested stack - amazon-web-services

I have a single stack with two instances RDS,EC2.I have to follow the structure that has root stack and two nested stack RDS,EC2.
Following should be the structure
1.Root stack
2.Webserver stack: All services related to EC2
3.DB stack: All services related to RDS

The general procedure would be as follows:
Extract rds and ec2 resources to its own template files (e.g. ec2.yaml, rds.yaml)
Parameterize ec2.yaml and rds.yaml, as well as add Outputs section to them. The Outputs are needed if you want to reference their return values in the Root stack.
Upload the ec2.yaml and rds.yaml into S3.
In the root stack create two resources of type AWS::CloudFormation::Stack, i.e. one for rds and one for ec2. Use TemplateUrl to provide paths to locations in S3 (step 3). Use Parameters to define input parameters created in step 2.
Use GetAtt to reference outputs of the nested stack in the root stack.

Related

Add new environment variables to Lambda using Cloud Formation Template

I have a nested Cloud Formation Template (multiple templates within a root template )to create a complete web application.
Lambda is created in the first template and few environment variables are added to it.
The later part of the templates also produces some values that has to be added as environment variables.
Is there a way to attach these environment variables to the existing lambda function?
I don't think so, but there are a few options. If you could change the stack dependency order, you could build the stack creating the values depended upon first. If you cannot, you can store your environment variables in SSM Parameter Store as mentioned in this knowledge center article.
So you set the environment variable to a path where the value can be expected, then when creating the stack that knows the value, you store it at that path. When the lambda runs, you just do get parameter.

AWS-CDK: Passing cross-stack references props between multi region (cross-region) stacks in AWS- CDK

I have to deploy one stack, let's call it the parent stack in one region
Them a second stack(child) needs to be deployed, in another region.
The region of the second stack(child stack) can not include the region where the parent was deployed. The second stack can be deployed in multiple regions.
However, the second stack needs props from the first stack. Specifically, it needs an ARN value. The default region is us-east-1. That is where the parent stack will get deployed.
To solve this I attempted the following
1- First Attempt : Using cfnOutput
Created a cfnOutput in the parent and in the child I capture the value with cdk.Fn.ImportValue()
RESULT: Got an error as cfnOutput can not be used between stacks on different regions as explained in CloudFormation User Guide
2- Second Attempt: Using StackProps
Created an interface in the parent stack that inherit from StackProps, set a public property and put the ARN value there
from the lib/mystack file
export interface myStackProps extends cdk.StackProps {
principalKeyArn: string
}
Passed the value to the second stack as props along with the env key containing the region as under:
from the bin/myapp file
const app = new cdk.App();
const regions = ["us-east-2"]
const primaryMRKey = new KmsMultiregionPrincipalKey(app, 'KmsMultiregionKeyStack')
for (let region of regions){
const envToDeploy = {region: region, account: "123456789123"}
new KmsReplicaKey(app, 'KmsReplicaKey-' + region, {env: envToDeploy, principalKeyArn: primaryMRKey.principalKeyArn } )
}
RESULT: Cross stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack
Question:
How to resolve the issue of passing cross-stack references between stacks that are using different regions in CDK?
[Edited]
one solution to this problem is using SSM as explained below.
Thanks in advance
Use a Parameter Store value with a CustomResource.
This answer has a full Typescript CDK example of cross-region refs.
(I originally posted this as a comment because I thought the question was perhaps a duplicate. But on reflection, I see that the linked question and tags only mention CloudFormation, not the CDK. Seems the community gets the most benefit from keeping this question alive).

Set global parameters in aws cloudformation

I'm building a complex application in AWS using Cloudformation.
My setup is the following: I'm going to use yaml files to define the stacks and corresponding json files which contain the stack parameters. Anyway there are parameters which are the same in multiple json files and I'd like to define them globally in one file/stack instead of having to update them in multiple files everytime they change.
What is the recommended way to set such global parameters using cloudformation?
Help would be highly appreciated.
You could possibly create one stack with command parameters, end export their values from this stack. Then, in other stack, the parameter values would be accessed using Fn::ImportValue.
An alternative could be to store common parameters in SSM Parameter Store, and then use dynamic references in your template to access them.

Add Resources to existing CloudFormation stack

I have a CloudFormation master stack. I want to write a tool that allows me to add Lambda functions to the master stack using Boto3.
In order to add the function to the stack I need to be able to
Get Outputs from the master stack to use in the function's template.
Add the Function to the master stack.
I have only been able to get this to work with:
Build, zip, and upload the function to S3
Add the function's template to the master stack's templates. (requires editing the master stack's files)
Deploy the master stack.
I would like to be able to create the function without editing the master stack's files.
(i.e. boto3.get_stack_id -> boto3.add_resource_to_stack_by_stack_id)
Is this possible? If so, how do I do it?
No that is not possible. When updating a stack, you always have to provide a URL for the new stack template, or provide the full template body as a string, or use the previous template.
Source: https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_UpdateStack.html
There is no API call that allows you to directly add a resource to a stack.

How do I force a CloudFormation stack to update when the parameter is updated?

I am running a AWS CloudFormation stack that takes in some parameters and launches EC2 instances along with other AWS resources. The parameters are fed into the user data of the EC2 instance and based on that changes are made dynamically to the web application residing on the EC2 instance.
UserData:
Fn::Base64:
Fn::Join:
- ""
-
- "#!/bin/bash \n"
- "sh website-conf/website_mysql_config.sh "
- " -c \""
-
Ref: "CompanyName"
As shown in the example above, CompanyName is one of the many parameters passed to the userdata script. The problem is, when any one or multiple of parameters are updated, CloudFormation does not detect that and instead throws this error.
So, in order to update the stack, I have to edit the stack and make changes to the ASG so that CloudFormation 'sees' the changes and executes the stack update.
Is there a way to force CFN to update the stack when the parameters are updated?
CloudFormation will not update the stack unless there is a change in properties of the resources already created in the stack.
For example:
Consider I have a simple template to create a database where I need to pass 2 parameters:
db-name
region
Assume that I am using db-name passing it as value to DBInstanceIdentifier.
Also assume that I am not using the input parameter region for any purpose in creation of resources (or its properties) of the stack in any way.It is more of a dummy parameter I keep for readability purpose.
I passed (TEST-DB1, us-east-1) as input parameters to the CloudFormation template and successfully created the resources.
Scenario-1:
Now if I update the stack(still using the existing template) and just change the input parameters to (TEST-DB2, us-east-1). ie: changing just the db-name and not the region. Then CloudFormation will detect that, this parameter update, results in change in properties of running resource(s) of the stack and will compute and display the modifications as a change set.
Scenario-2:
Suppose I make another update(still using the existing template) property and just change the input parameters to (TEST-DB1, us-east-2). ie: changing just the region and not the db-name. Then CloudFormation will detect that, this parameter update, result in NO change in properties of running resource(s) of the stack will show the Error creating change set.
Bottomline:
Your change in input parameter must result in an update/replacement of any resources(or its attributes like security-groups,port etc..) of the stack. Then AWS CloudFormation will display them as Change Sets for your review. Also, the method (update or replacement) AWS CloudFormation uses depends on which property you update for a given resource type.
Your parameter "CompanyName" is not making any changes to the running
resources of the stack. Hence it is reporting as Error creating
change set. You need to use it to create any resource/resource properties of the stack. Then CloudFormation will detect the change-sets when you modify it. The same applies for any other input-parameters which you use.
Use the AWS CLI Update-Stack command. If you use the AWS CLI you can inject parameters into your stack so any change to any of the parameters result in a new stack. I do this myself to inject the Git/version commit ID into UserData so simply committing changes to the stack's JSON/Yaml to Git will allow stack updates. Any change to the parameters file will allow stack updates, even just a comment. I reference my Git commit ID in UserData the same way you are referencing Ref:CompanyName so when I change the Git commit ID the userData section is updated on stack updates.
Update Stack Command
aws cloudformation update-stack --stack-name MyStack --template-body file:///Users/Documents/Git/project/cloudformation/stack.json --parameters file:///Users/Documents/Git/project/cloudformation/parameters/stack-parameters.dev.json --capabilities CAPABILITY_IAM
Process
With this approach you make your parameters changes to the parameters json or yaml file then check it into version control. Now if you use a build server you can update your stack by checking out master and just running that one line above. Using AWS CodeBuild makes this easy so you don't need jenkins.
The answer of your problem is already answered with this state, CloudFormation will not update the stack unless there is a change in properties of the resources already created in the stack.
And for the answer for your question, please check the explanation below.
There is a way to force Cloudformation to update the stack using the AWS::CloudFormation::Init.
By using cfn-init, each instance can update itself when it detect the change that made by AWS::CloudFormation::Init in metadata.
There is a concept that we must understand first, that is the difference between UserData and metadata, at least under the AWS::CloudFormation::Init case.
Userdata: Will be only called once when the instance is being launch for the first time (this including update that need the instance to be replaced). So, if you update the stack (not creating a new one), even if you change the parameter value, it won't change anything if you call the parameter under UserData.
Metadata: Can be updated anytime. To make it works, you have to make sure that the daemon that detect the metadata changed is running (the daemon is called the cfn-hup)
If you already use the Metadata and AWS::CloudFormation::Init, the data is not immediately being updated. As far I know, here is the condition the data to be change after change the Metadata value.
Reboot the instance
Run cfn-init command again with it's parameter
Waiting about 15 minutes, because the daemon to check the change in Metadata is checking the change once in 15 minutes.