Getting started with Python based IaC using AWS CDK
Tags: aws, cdk, tutorial, beginners
Published: 2022-06-14 11:56:01

## AWS CDK Getting Started

## Table of Contents
- [Introduction](#introduction)
- [What is AWS CDK](#what-is-aws-cdk)
- [Concepts and Key Components](#concepts-and-key-components)
- [Steps to getting into AWS CDK](#steps-to-getting-into-aws-cdk)
  - [Step 1 Setting up Pre Requisites](#step-1-setting-up-pre-requisites)
      - [Install node package manager](#install-node-package-manager)
      - [Install Python and Pip](#install-python-and-pip)
      - [Configure AWS Cloud Credentials](#configure-aws-cloud-credentials)
  - [Step 2 Install AWS CDK](#step-2-install-aws-cdk)
  - [Step 3 Create CDK project](#step-3-create-cdk-project)
      - [cdk init](#cdk-init)
  - [Step 4 Setup Python Virtual Environment](#step-4-setup-python-virtual-environment)
  - [Step 5 Install Dependencies](#step-5-install-dependencies)
  - [Step 6 Verifying the project](#step-6-verifying-the-project)
      - [cdk ls](#cdk-ls)
  - [Step 7 Defining AWS Infrastructure using Python](#step-7-defining-aws-infrastructure-using-python)
  - [Step 8 Spinning up Infra](#step-8-spinning-up-infra)
      - [cdk synth](#cdk-synth)
      - [cdk bootstrap](#cdk-bootstrap)
      - [cdk deploy](#cdk-deploy)
- [Cleaning up the Demo Stack](#cleaning-up-the-demo-stack)
    - [cdk destroy](#cdk-destroy)
- [Important commands](#important-commands)
- [Conclusion](#conclusion)
- [References](#references)

## Introduction
Programming language based IaC tools becoming famous in recent times. We will see one such tool AWS CDK In this article. 

We will required steps on how to get started with creating infrastructure in AWS CDK for AWS. I'll be using `Python` language to create infrastructure in AWS using AWS CDK

AWS started supporting Programming language based Infrastructure as code (IaC in short) and named it as AWS Cloud Development Kit. Other similar tools are [CDKTF](https://www.terraform.io/cdktf) and [Pulumi](https://www.pulumi.com/docs/). 

---

## What is AWS CDK
> The AWS CDK lets you build reliable, scalable, cost-effective applications in the cloud with the considerable expressive power of a programming language

You can read more about it in [AWS CDK docs](https://docs.aws.amazon.com/cdk/v2/guide/home.html)

## Concepts and Key Components
- `Constructs` are the basic building blocks of AWS CDK apps. A construct represents a "cloud component" and encapsulates everything AWS CloudFormation needs to create the component.
- `App` is a construct, It is used to provision infrastructure resources. 
- `Stack` is the unit of deployment in the AWS CDK . All AWS resources defined within the scope of a stack, either directly or indirectly, are provisioned as a single unit. All constructs that represent AWS resources must be defined, directly or indirectly, within the scope of a Stack construct. 
- Go through [AWS CDK documentation](https://docs.aws.amazon.com/cdk/v2/guide/core_concepts.html) to know further about the Concepts and Components of AWS CDK 

---

## Steps to getting into AWS CDK
- We need to install  `NodeJS` 
- `Python and PIP` for developing Python language based infrastructure definition 
- Also we need to configure AWS credentials for setting up infra in AWS

## Step 1 Setting up Pre Requisites
### Install node package manager
- Go to `nodesource` repo in GitHub and [follow the instructions](https://github.com/nodesource/distributions/blob/master/README.md) to install NodeJS
- Also we can use,
```
sudo npm install -g npm@latest
```

### Install Python and Pip
- Refer Python docs to install [Python](https://www.python.org/downloads/)
- Refer Python PIP install documentation for [Pip installation](https://pip.pypa.io/en/stable/installation/)

### Configure AWS Cloud Credentials
- AWS by default reads the auth config details as per the precedence mentioned [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence)
- So we will be using `aws configure` to set the authentication details and it is getting added into `~/.aws/credentials and ~/.aws/config`
- Install AWS CLI from [docs](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)
- [Configure AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) 

## Step 2 Install AWS CDK

```
sudo python3 -m pip install aws-cdk-lib
sudo npm install -g aws-cdk
```
- Check `cdk` command
```
cdk version
```

## Step 3 Create CDK project
- Create directory and initialize AWS CDK
```
mkdir awscdk
cd awscdk/
```
### cdk init
- Since we are creating `python` based code, init app to have Python modules support
```
cdk init app --language python
```
- This command will initialize the empty directory and creates the necessary files required to getting started with AWS CDK development
- It also shows the possible next steps to proceed with AWS CDK as README content in console output
```
Applying project template app for python

# Welcome to your CDK Python project!

This is a blank project for CDK development with Python.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

This project is set up like a standard Python project.  The initialization
process also creates a virtualenv within this project, stored under the `.venv`
directory.  To create the virtualenv it assumes that there is a `python3`
(or `python` for Windows) executable in your path with access to the `venv`
package. If for any reason the automatic creation of the virtualenv fails,
you can create the virtualenv manually.

To manually create a virtualenv on MacOS and Linux:

``
$ python3 -m venv .venv
``

After the init process completes and the virtualenv is created, you can use the following
step to activate your virtualenv.

``
$ source .venv/bin/activate
``

If you are a Windows platform, you would activate the virtualenv like this:

``
% .venv\Scripts\activate.bat
``

Once the virtualenv is activated, you can install the required dependencies.

``
$ pip install -r requirements.txt
``

At this point you can now synthesize the CloudFormation template for this code.

``
$ cdk synth
``

To add additional dependencies, for example other CDK libraries, just add
them to your `setup.py` file and rerun the `pip install -r requirements.txt`
command.

## Useful commands

 * `cdk ls`          list all stacks in the app
 * `cdk synth`       emits the synthesized CloudFormation template
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk docs`        open CDK documentation

Enjoy!

Initializing a new git repository...
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint: 	git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint: 	git branch -m <name>
Please run 'python3 -m venv .venv'!
Executing Creating virtualenv...
✅ All done!
```

- Contents of the directory created by `init` command
```
$ ls -a
.  ..  app.py  awscdk  cdk.json  .git  .gitignore  README.md  requirements-dev.txt  requirements.txt  source.bat  tests  .venv
```

---

## Step 4 Setup Python Virtual Environment
- To work with the new cdk project, activate its `python` virtual environment. This allows the project's dependencies to be installed locally in the project folder, instead of globally.
- In `ubuntu` systems, Python `venv` can be installed using,
```
# in ubuntu this is needed
sudo apt install python3.9-venv
```
- Then run, 
```
python3 -m venv .venv
```
**or**
```
source .venv/bin/activate
```
## Step 5 Install Dependencies
- After we installed the python `venv`, we can install the project dependencies using the command,
```
python3 -m pip install -r requirements.txt
```
## Step 6 Verifying the project
### cdk ls
- Just before adding the code to setup our infrastructure, we can verify the CDK code setup by running the command below,
```
$ cdk ls

AwscdkStack
``` 
- It displays the AWS CDK stack, defined in the directory
`./awscdk/awscdk_stack.py`

## Step 7 Defining AWS Infrastructure using Python
- Now open the project directory in `vscode` or your preferred code editor to add the infrastructure code.
- I use  the command `code .` from current working directory to open the project in vscode editor
- Add the Python code to create `s3` bucket in the AWS account
- Open file `./awscdk/awscdk_stack.py`
```
import aws_cdk as cdk
import aws_cdk.aws_s3 as s3
            
class HelloCdkStack(cdk.Stack):

    def __init__(self, scope: cdk.App, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        bucket = s3.Bucket(self, "MyFirstBucket", versioned=True)
```
- Let us dissect the code blocks that are defined in the above code. This is the example code defined in the [docs](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html)

> `Bucket` is the first `construct` we've seen, so let's take a closer look. Like all constructs, the Bucket class takes three parameters.

> `scope`: Tells the bucket that the stack is its parent: it is defined within the scope of the stack. You can define constructs inside of constructs, creating a hierarchy (tree). Here, and in most cases, the scope is this (self in Python), meaning the construct that contains the bucket: the stack.

> `Id`: The logical ID of the Bucket within your AWS CDK app. 

> `props`: A bundle of values that define properties of the bucket. 

- Now proceed to next steps to begin deploying the CDK Stack

---

## Step 8 Spinning up Infra
- After adding the code, let us now try to synthesize the proposed infrastructure

### cdk synth
- Run the command below to synthesize,
```
$ cdk synth

Resources:
  MyFirstBucketB8884501:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: AwscdkStack/MyFirstBucket/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/yXI0QpAMBSA4Wdxvx0iyS0vIB5AzOQYZ7WdJcm7I1f/159CWkASDYeXajJywxGujgdlxLt6n8FVBWU0i3qmX/fHVnsbnNKfa0sTMlq6RXPyYinOoIQ8Wj2idIEYdw3t3wdyVYK2bwAAAA==
    Metadata:
      aws:cdk:path: AwscdkStack/CDKMetadata/Default
    Condition: CDKMetadataAvailable
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - af-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ca-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-northwest-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-2
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-3
          - Fn::Equals:
              - Ref: AWS::Region
              - me-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - sa-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-2
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
  CheckBootstrapVersion:
    Assertions:
      - Assert:
          Fn::Not:
            - Fn::Contains:
                - - "1"
                  - "2"
                  - "3"
                  - "4"
                  - "5"
                - Ref: BootstrapVersion
        AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
```

### cdk bootstrap
- Then run the `bootstrap` command
- Use the `cdk bootstrap` command to bootstrap one or more AWS environments. In its basic form, this command bootstraps one or more specified AWS environments.
```
$ cdk bootstrap

 ⏳  Bootstrapping environment aws://account-id/us-west-2...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
 ✅  Environment aws://account-id/us-west-2 bootstrapped.
```

### cdk deploy
- After bootstrapping the CDK environment, run `cdk deploy` command to add the infrastructure
```
$ cdk deploy

✨  Synthesis time: 3.83s

This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬───────────────────────────────────────────────────────────────┬────────┬───────────────────────────────────────┬───────────────────────────────────────────────────────────────────┬───────────┐
│   │ Resource                                                      │ Effect │ Action                                │ Principal                                                         │ Condition │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼───────────┤
│ + │ ${Custom::S3AutoDeleteObjectsCustomResourceProvider/Role.Arn} │ Allow  │ sts:AssumeRole                        │ Service:lambda.amazonaws.com                                      │           │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼───────────┤
│ + │ ${MyFirstBucket.Arn}                                          │ Allow  │ s3:DeleteObject*                      │ AWS:${Custom::S3AutoDeleteObjectsCustomResourceProvider/Role.Arn} │           │
│   │ ${MyFirstBucket.Arn}/*                                        │        │ s3:GetBucket*                         │                                                                   │           │
│   │                                                               │        │ s3:List*                              │                                                                   │           │
└───┴───────────────────────────────────────────────────────────────┴────────┴───────────────────────────────────────┴───────────────────────────────────────────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬───────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                                                  │ Managed Policy ARN                                                                           │
├───┼───────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Custom::S3AutoDeleteObjectsCustomResourceProvider/Role} │ {"Fn::Sub":"arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"} │
└───┴───────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
AwscdkStack: deploying...
[0%] start: Publishing 075615afa517203dd67c21:current_account-current_region
[0%] start: Publishing b3e30b6400895ee28d0614:current_account-current_region
[50%] success: Published 880615afa517203dd67c21:current_account-current_region
[100%] success: Published b3e30b6400895ee28d0614:current_account-current_region
AwscdkStack: creating CloudFormation changeset...

 ✅  AwscdkStack

✨  Deployment time: 77.86s

Stack ARN:
arn:aws:cloudformation:us-west-2:account-id:stack/AwscdkStack/398ef750-e70b-11ec-b89d-021a55f488dd

✨  Total time: 81.69s
```

---

## Cleaning up the Demo Stack
- Since we are creating the demo deployment, let's tear down the AWS resources 
- Use the command `cdk destroy` to delete the resources

### cdk destroy
```
$ cdk destroy

Are you sure you want to delete: AwscdkStack (y/n)? y
AwscdkStack: destroying...

 ✅  AwscdkStack: destroyed
```
## Important commands
| Command   |      Function      |
|----------|:-------------:|
| `cdk init` |  Creates a new CDK project in the current directory from a specified template | 
| `cdk list` or `ls` |  Lists the stacks in the app | 
| `cdk synthesize` or `synth` |    Synthesizes and prints the CloudFormation template for the specified stack(s)   | 
| `cdk bootstrap` | Deploys the CDK Toolkit staging stack | 
| `cdk deploy` | Deploys the specified stack(s) | 
| `cdk destroy` | Destroys the specified stack(s) | 
| `cdk diff` | Compares the specified stack with the deployed stack or a local CloudFormation template | 

## Conclusion
- We discussed how to get started with AWS CDK in this blog and created a sample s3 bucket as part of demo
- We can learn more about AWS CDK from the documentation and it has more examples to get practiced
- I've experimented with Python based IaC creation with both CDKTF and AWS CDK. Planning to write a comparison blog as the next step.

---

## References
- [AWS CDK Docs](https://docs.aws.amazon.com/cdk/v2/guide/home.html)
- [First CDK app](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html)
- [AWS CDK CLI command](https://docs.aws.amazon.com/cdk/v2/guide/cli.html)

## Community and Social Footprints
- [Dev](https://dev.to/chefgs)
- [GitHub](https://github.com/chefgs)
- [LinkedIn](https://www.linkedin.com/in/saravanan-gnanaguru-1941a919/)
- [Twitter](https://twitter.com/saransid)
- [gsaravanan.dev](https://gsaravanan.dev)