A look at Infrastructure as Code in the AWS Cloud

What’s with all the hype around Infrastructure as Code? Well Amazon wrote half of the tools being compared here, so let's take a look at what they have to say:

Infrastructure was traditionally provisioned using a combination of scripts and manual processes. Sometimes these scripts were stored in version control systems or documented step by step in text files or run-books. Often the person writing the run books is not the same person executing these scripts or following through the run-books. This results in the creation of new environments not always being repeatable, reliable, or consistent.

https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/infrastructure-as-code.html

Being practical with your implementation of Infrastructure as Code means applying the same rigor of application development to the resource provisioning done in the cloud. Typically, this is done through creating multi-stage CI/CD pipelines to introduce automatic review with manual approval. Formatting and security linters, like tflint and tfsec for Terraform, are amazing tools to ensure high level quality bars for the code you write just like you would do with Java or Golang. All of this enables one to take a modularized approach to infrastructure patterns so you can rubber-stamp what is deployed in your development, quality assurance, and production environments.

Here are the tools being compared:

CloudFormation

An “AWS Native” Solution. Resources are written in text files using JavaScript Object Notation (JSON) or Yet Another Markup Language (YAML). A CloudFormation template is deployed into the AWS environment as a "stack" of different resources.

Cloud Development Kit

An open-source software development framework to model and provision your cloud application resources. Enables you to model application infrastructure using TypeScript, Python, Java, and .NET. Utilizes AWS CloudFormation in the background.

Serverless Framework

Serverless Framework is the one of the simplest way to develop infinitely scalable, pay-per-execution serverless applications. Manages your code as well as your infrastructure & supports multiple languages: (Node.js, Python, Java, and more)

Terraform

HashiCorp Configuration Language (HCL) allows for the concise descriptions of resources using blocks, arguments, and expressions. Extensible providers allow Terraform to manage a wide range of resources, including IaaS, PaaS, SaaS, & hardware services.

CloudFormation: An “AWS Native” Solution

You can use a single CloudFormation template to create and update an entire environment or separate templates to manage multiple layers within an environment. There are several options when it comes to managing stacks, either through the AWS Management Console, AWS Command Line Interface, or AWS CloudFormation APIs. When actualizing changes to infrastructure through CloudFormation, stacks typically go through changes in parallel and steps have to be backed out manually if there are significant enough errors. When’s the right time to use CloudFormation? When you want an 100% AWS Native Solution for maintaining the resources you deploy in your accounts and are only trying to apply Infrastructure as Code principles to what you do inside AWS accounts. CloudFormation isn't recommended when your applications don’t need programmatic access to granular deployment tools to define their own processes. Here's an example of some CloudFormation code:


# Source: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-ec2.html
{
    "Resources" : {
        "EC2Instance" : {
            "Type" : "AWS::EC2::Instance",
            "Properties" : {
                "InstanceType" : { "Ref" : "InstanceType" },
                "SecurityGroups" : [ { "Ref" : "InstanceSecurityGroup" } ],
                "KeyName" : { "Ref" : "KeyName" },
                "ImageId" : { 
                    "Fn::FindInMap" : [ 
                        "AWSRegionArch2AMI", 
                        { "Ref" : "AWS::Region" },
                        { "Fn::FindInMap" : [ 
                            "AWSInstanceType2Arch", 
                            { "Ref" : "InstanceType" }, 
                            "Arch" 
                            ] 
                        }
                    ] 
                }
            }
        },
        "InstanceSecurityGroup" : {
            "Type" : "AWS::EC2::SecurityGroup",
            "Properties" : {
                "GroupDescription" : "Enable SSH access via port 22",
                "SecurityGroupIngress" : [ {
                    "IpProtocol" : "tcp",
                    "FromPort" : "22",
                    "ToPort" : "22",
                    "CidrIp" : { "Ref" : "SSHLocation"}
                } ]
            }
        }
    }
}      

Cloud Development Kit: Open-source SDK Framework

Amazon provides the Cloud Development Kit as a way to more directly write custom application code in the pre-existing language you're most comfortable with. By combining the basic building blocks of CDK code together, you can quickly and easily create complex architectures for deployment. Where as automating multiple phase deployments with JSON/YAML using CloudFormation can take some pretty custom logic, CDK empowers developers to do more with less lines of code. When’s the right time to use Amazon's Cloud Development Kit? If there is a custom application that you would like to programmatically integrate with infrastructure deployments. Deployments should have granular phases that can allow for concepts like automation and parallelization, otherwise this option becomes a little bit overkill. AWS also offers pre-existing libraries of common infrastructure patterns in the AWS Construct Library.

Serverless Framework: A Lambda First IaC Approach

The Serverless Framework is one of the simplest ways to develop infinitely scalable, pay-per-execution serverless applications. This option easily manages your code as well as your infrastructure & supports multiple languages: Node.js, Python, Java, and more. S.F. translates all of its syntax in serverless.yml and packages your code into an AWS CloudFormation template so that it can automatically deploy them together for you. It comes with a CLI that offers structure, automation and best practices out-of-the-box. When’s the right time to use the Serverless Framework? When there's a new application to write or a want to completely modernize old ones and you want a single tool to handle the software as well as the infrastructure to support them.


# Source: https://github.com/serverless/examples/blob/v3/aws-node-express-api/serverless.yml
service: aws-node-express-api
frameworkVersion: '3'

provider:
    name: aws
    runtime: nodejs14.x

functions:
    api:
    handler: handler.handler
    events:
        - httpApi: '*'

Terraform: A Multi-Cloud IaC Framework

Terraform offers a consistent and reliable environment for infrastructure management and includes easy but secure access to shared state and secret data as well as access controls for approving changes. Even if the resources being managed are only in the AWS Cloud, Terraform can help to manage resources CloudFormation can’t; e.g.: Postgres Schema inside AuroraDB on RDS. The real power comes from having a single access point to managing resources in other Cloud providers like Azure, GCP, and Okta. Once an application and all its environments are Terraformed with proper CI/CD pipelines that see active use it becomes practically impossible to miss critical infrastructure changes or newly introduced security risks. So when’s the right time to use Terraform? Realistically, it's when your software has intricate use of several Cloud services, including AWS, and you desire a single tool for multi-cloud deployments that easily replicate complex environments across several accounts.


# Source: https://registry.terraform.io/providers/hashicorp/aws/latest/docs
terraform {
    required_providers {
        aws = {
        source  = "hashicorp/aws"
        version = "~> 3.0"
        }
    }
}
    
# Configure the AWS Provider
provider "aws" {
    region = "us-east-1"
}

# Create a VPC
resource "aws_vpc" "example" {
    cidr_block = "10.0.0.0/16"
}

Closing Remarks

All of these tools are amazing entry points to managing your cloud infrastructure as code rather than a series of manual process and possibly version-controlled scripts. I have used all of them in some sort of professional setting with extensive experience using both Terraform and the Serverless Framework. Each of them have their place and can bring positive additions to the processes they oversee. As usual though, a tool is only as good as the person using it so it's up to the individual users to define what their standards are and how they want to enforce them to actualize the changes they want to see. Hopefully you've found this article as an interesting insight into the different ways to implement IaC in your AWS, and possibly other, cloud environments.