A brief introduction to AWS Cloudformation
Tags: aws, cloudformation, iac, devops
Published: 2019-10-30 03:47:31

<!-- wp:image {"id":178} -->
<figure class="wp-block-image"><img src="https://milapneupane.com.np/wp-content/uploads/2019/10/CloudFormation.jpg" alt="AWS CloudFormation" class="wp-image-178"/><figcaption>AWS CloudFormation</figcaption></figure>
<!-- /wp:image -->

Originally published on https://milapneupane.com.np/2019/10/07/a-brief-introduction-to-aws-cloudformation

<!-- wp:paragraph -->
<p>AWS CloudFormation is a tool to write the Infrastructure as a Code(IaC).  Any kind of AWS resources such as VPCs, EC2, S3, RDS or any other kind of resources can be created using AWS CloudFormation. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This has a lot of advantages such as:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Automation of AWS resource creation</li><li>Disaster recovery</li><li>Copying a resource from one location to another</li><li>Code review of the infrastructure and many more.</li></ol>
<!-- /wp:list -->

<!-- wp:heading -->
<h2>AWS CloudFormation Template</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Cloudformation uses stacks to create resources. A stack might contain one or more resources. Let us look into a simple DynamoDB creation with AWS CloudFormation template:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// dynamodb-cloudformation.yaml

AWSTemplateFormatVersion: "2010-09-09"
Resources:
&nbsp;&nbsp;userDynamoDBTable:
&nbsp; &nbsp;&nbsp;Type: AWS::DynamoDB::Table
&nbsp; &nbsp; Properties:&nbsp;
&nbsp; &nbsp;  AttributeDefinitions:&nbsp;
&nbsp; &nbsp;  -&nbsp;
&nbsp; &nbsp;  AttributeName: "Id"
&nbsp; &nbsp;  AttributeType: "S"
&nbsp; &nbsp;  KeySchema:
&nbsp; &nbsp;  -&nbsp;
&nbsp; &nbsp;  AttributeName: "Id"
&nbsp; &nbsp;  KeyType: "HASH"
&nbsp; &nbsp;  ProvisionedThroughput:
&nbsp; &nbsp;  ReadCapacityUnits: "5"
&nbsp; &nbsp;  WriteCapacityUnits: "5"
&nbsp; &nbsp;  TableName: "users"</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>The above template is used to create a DynamoDB table. It contains a key AWSTemplateFormatVersion which is used to describe the version of the CloudFormation template. This is just to identify the version of the CloudFormation template. Do not write a random date there. It is a predefined version of CloudFormation. AWS CloudFormation is written in a&nbsp;<a rel="noreferrer noopener" target="_blank" href="https://yaml.org/">YAML</a>&nbsp;format. It has three important top-level keys beside the AWSTemplateFormatVersion:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Resource</li><li>Parameter</li><li>Output</li></ol>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>Resource</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the above example, the DynamoDB resource is defined inside the&nbsp;Resource&nbsp;key. A resource always has two keys:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Type:</strong>  The type of resource. In our case it is the Dynamodb so we keep the value as AWS::DynamoDB::Table.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Properties:</strong> Properties define the configuration and options for the resource. Such as the read capacity, primary key, table name, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, let us create an AWS CloudFormation stack with the above template using the following command:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&nbsp;&gt; aws cloudformation create-stack \
   --template-body file://dynamodb-cloudformation.yaml \
   --stack-name dynamodb-table</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This will start the process of stack creation. This will take some time before completion. You can check the progress of the stack creation using the following command:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation describe-stack-events \
  --stack-name dynamodb-table</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This will return an array of events, during the stack creation. The stack can have various states. Bellow are the possible state while creation</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>CREATE_IN_PROGRESS</li><li>CREATE_COMPLETE</li><li>CREATE_FAILED</li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>You can keep polling using describe-stack-events to see if the stack creation is complete or you can use the wait command, which will wait until the stack create complete or fails:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation wait stack-create-complete \
  --stack-name dynamodb-table</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>If you do not like using CLI commands you can simply go to AWS console on your browser, go to CloudFormation service and check the status of the CloudFormation stack from there.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Parameters</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Parameters in a template make the stack configurable. With parameters, you can provide input and use the same template to provide different configurations for the stack creation. Let us use the above template and make it configurable and create two different DynamoDB tables using the same template:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// <em>dynamodb-cloudformation.yaml</em>
AWSTemplateFormatVersion: "2010-09-09"
<strong>Parameters:</strong>
<strong>&nbsp; &nbsp; &nbsp;TableName:</strong>
<strong>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Description: Name of the table</strong>
<strong>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Type: String</strong>
Resources:
&nbsp; &nbsp; &nbsp;userDynamoDBTable:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Type: AWS::DynamoDB::Table
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Properties:&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AttributeDefinitions:&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AttributeName: "Id"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AttributeType: "S"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;KeySchema:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AttributeName: "Id"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;KeyType: "HASH"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProvisionedThroughput:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ReadCapacityUnits: "5"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WriteCapacityUnits: "5"
<strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TableName: !Ref TableName</strong></pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>In the above example, the TableName can be provided by passing it as a parameter with the following command:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation create-stack \
  --template-body file://dynamodb-cloudformation.yaml \
  --stack-name dynamodb-table \
  --parameters ParameterKey=TableName,ParameterValue=users</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>You can use the&nbsp;<strong>!Ref</strong>&nbsp;&nbsp;keyword to reference the parameter passed for the table name or any other parameters.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let us add some more parameters here:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// <em>dynamodb-cloudformation.yaml</em>
AWSTemplateFormatVersion: "2010-09-09"
<strong>Parameters:</strong>
<strong>&nbsp; ReadCapacityUnits:</strong>
<strong>&nbsp; &nbsp; Description: Name of the table</strong>
<strong>&nbsp; &nbsp; Type: String</strong>
<strong>&nbsp; &nbsp; Default: '5'</strong>
<strong>&nbsp; &nbsp; MinValue: '1'</strong>
<strong>&nbsp; &nbsp; MaxValue: '20'</strong>
<strong>&nbsp; &nbsp; ConstraintDescription: must be between MinValue and MaxValue</strong>
<strong>&nbsp;&nbsp;WriteCapacityUnits:</strong>
<strong>&nbsp; &nbsp;&nbsp;Description: Name of the table</strong>
<strong>&nbsp; &nbsp;&nbsp;Type: String</strong>
<strong>&nbsp; &nbsp; Default: '5'</strong>
<strong>&nbsp; &nbsp; MinValue: '1'</strong>
<strong>&nbsp; &nbsp; MaxValue: '20'</strong>
<strong>&nbsp; &nbsp; ConstraintDescription: must be between MinValue and MaxValue</strong>
<strong>&nbsp;</strong>&nbsp;TableName:
&nbsp; &nbsp; &nbsp;Description: Name of the table
&nbsp; &nbsp; &nbsp;Type: String
Resources:
.....
</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>The parameters in the template support constraints and default values. The constraint in the limits the min value and max value for the capacity to be 1 - 20. If no parameter provided it uses 5 by default.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We can create the stack with few more parameters:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation create-stack \
  --template-body file://dynamodb-cloudformation.yaml \
  --stack-name dynamodb-table \
  --parameters ParameterKey=TableName,ParameterValue=users \
               ParameterKey=WriteCapacityUnits,ParameterValue=20 \
               ParameterKey=ReadCapacityUnits,ParameterValue=10 \</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>With more and more parameter the command to create the stack gets bigger. We can move the parameters to a file as well.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a parameter file:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// <em>paramters.json</em>
[
&nbsp;&nbsp;{
&nbsp; &nbsp;&nbsp;"ParameterKey": "TableName",
&nbsp; &nbsp;&nbsp;"ParameterValue": "users"
&nbsp;&nbsp;},&nbsp;
&nbsp;&nbsp;{
&nbsp; &nbsp;&nbsp;"ParameterKey": "WriteCapacityUnits",
&nbsp; &nbsp;&nbsp;"ParameterValue": "20"
&nbsp;&nbsp;},
  {
&nbsp; &nbsp;&nbsp;"ParameterKey": "ReadCapacityUnits",
&nbsp; &nbsp;&nbsp;"ParameterValue": "10"
&nbsp;&nbsp;}
]</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Now use the file to create the stack:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation create-stack \
  --template-body file://dynamodb-cloudformation.yaml \
  --stack-name dynamodb-table \
  --parameters file:///parameters.json</pre>
<!-- /wp:preformatted -->

<!-- wp:heading {"level":3} -->
<h3>Outputs</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The third part of the AWS Cloudformation is the output section. This section contains the value that you can export and can be used by another Cloudformation template by importing it.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You can export the Arn of the DynamoDB form this template and use it in another template. Let us export the DynamoDB Arn and import it in another template:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// dynamodb-cloudformation.yaml

AWSTemplateFormatVersion: "2010-09-09"
Resources:
&nbsp;&nbsp;userDynamoDBTable:
&nbsp; &nbsp;&nbsp;Type: AWS::DynamoDB::Table
&nbsp; &nbsp; Properties:&nbsp;
&nbsp; &nbsp;   AttributeDefinitions:&nbsp;
   &nbsp; &nbsp;-&nbsp;
&nbsp; &nbsp;   AttributeName: "Id"
   &nbsp; &nbsp;AttributeType: "S"
&nbsp; &nbsp;   KeySchema:
   &nbsp; &nbsp;-&nbsp;
&nbsp; &nbsp;   AttributeName: "Id"
  &nbsp; &nbsp; KeyType: "HASH"
&nbsp;   &nbsp; ProvisionedThroughput:
  &nbsp; &nbsp; ReadCapacityUnits: "5"
&nbsp;   &nbsp; WriteCapacityUnits: "5"
  &nbsp; &nbsp; TableName: "users"
<strong>  Outputs:
    DynamoDbArn:
      Value: !GetAtt userDynamoDBTable.Arn
      Description: Arn of the user dynamodb
      Export:
        Name: DynamoDBArn</strong></pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>We can now import the Output in another CloudFormation template using the export value with the intrinsic function <strong>Fn::ImportValue</strong></p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><strong>Fn::ImportValue: DynamoDBArn</strong></pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2><strong>Intrinsic Functions</strong></h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The CloudFormation template supports different types of&nbsp;<a rel="noreferrer noopener" target="_blank" href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html">intrinsic functions</a>. In the above examples, we used&nbsp;<strong>!Ref&nbsp;</strong>to refer to the parameter.&nbsp;<strong>!Ref&nbsp;</strong>is one of the intrinsic functions. There are several kinds of intrinsic functions. Let us look into a couple of them:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Fn::Join</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>It joins a set of values separated by the specified delimiter:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><strong>TableName:  Fn::Join: [ :, [ !Ref TableName, "table"] ]</strong></pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>The table name will now be user:table.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Fn::GetAtt</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This function can be used to fetch certain attributes of the resource. If you want the Arn of the newly created dynamoDB you can use this function:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><strong>Fn::GetAtt: [ userDynamoDBTable,&nbsp;<em>Arn</em>&nbsp;]</strong></pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2><strong>Updating/Deleting a stack</strong></h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You can Delete the resources created by a Cloudformation stack using the following command:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation delete-stack \
  --stack-name dynamodb-table</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This will remove the resources present in the AWS CloudFormation stack</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you want to update the resources simply change the template and call the update stack command:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">&gt; aws cloudformation update-stack \
  --template-body file://dynamodb-cloudformation.yaml \
  --stack-name dynamodb-table --parameters file:///parameters.json</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2><strong>Custom CloudFormation</strong></h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>AWS CloudFormation supports most of the AWS resource creation. In some cases when a new service is introduced or when we have some custom CloudFormation might not have the support for it. For these kinds of cases, we can create custom AWS CloudFormation. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>A custom Cloudformation can be created using AWS Lambda. The lambda needs to handle resource creation, deletion, and update. We will see more about the Custom Cloudformation in my next blog:</p>
<!-- /wp:paragraph -->

<!-- wp:core-embed/wordpress {"url":"https://milapneupane.com.np/2019/10/08/a-guide-to-aws-custom-cloudformation-resource/","type":"wp-embed","providerNameSlug":"milap-neupane-blog","className":""} -->
<figure class="wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-milap-neupane-blog"><div class="wp-block-embed__wrapper">
https://milapneupane.com.np/2019/10/08/a-guide-to-aws-custom-cloudformation-resource/
</div></figure>
<!-- /wp:core-embed/wordpress -->

<!-- wp:paragraph -->
<p>AWS Cloudformation is a power tool to provision AWS resources with infrastructure as a Code. Using AWS CloudFormation helps to build large scale applications with good disaster recovery in place.</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p>Interested in learning about AWS ECS deployment using Cloudformation? Learn more about it in detail here: </p>
<!-- /wp:paragraph -->

<!-- wp:core-embed/wordpress {"url":"https://milapneupane.com.np/2019/07/28/how-to-deploy-a-docker-container-with-aws-ecs-using-cloudformation/","type":"wp-embed","providerNameSlug":"milap-neupane-blog","align":"center","className":""} -->
<figure class="wp-block-embed-wordpress aligncenter wp-block-embed is-type-wp-embed is-provider-milap-neupane-blog"><div class="wp-block-embed__wrapper">
https://milapneupane.com.np/2019/07/28/how-to-deploy-a-docker-container-with-aws-ecs-using-cloudformation/
</div><figcaption>AWS ECS Cloudformation</figcaption></figure>
<!-- /wp:core-embed/wordpress -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->