How To Setup AWS Lambda Using AWS CDK Python

Introduction

How To Setup AWS Lambda Using AWS CDK Python
How To Setup AWS Lambda Using AWS CDK Python

We will cover How To Setup AWS Lambda Using AWS CDK Python.

Did you know that AWS CDK is a programmers entry point to DevOps?

I will break this review in the following sections:

  • Why setting up an AWS Lambda using CDK is helpful
  • Walk through step by step on How To Setup AWS Lambda Using AWS CDK Python

I have been using this code successfully on all my Python AWS CDK deployments to launch new Lambda Functions.

Going to keep things simple and straight to the point on how to get up and running in less than 5 minutes.

All source found in this guide can be found in the GitHub repo here.

Why Should You Use AWS CDK Python To Setup A Lambda vs Terraform

There are several reasons as to why you may want to use AWS CDK Python to deploy your Lambdas, I will list them below and see if one of them suits your needs or you find yourself still needing to do that.

  • You do not want to learn Terraform and have already background in Python
  • You are from a programming background rather than DevOps so programming makes more sense to you
  • The descriptive format of Terraform can be confusing sometimes
  • You have conditional and business logic on how you want to deploy your Lambdas and when
  • You want to do a lot of Dynamic work such as destroying creating Lambdas inside your existing code base that’s already written in Python (essentially extending an existing project to include DevOps work on it)

If any of the above reasons is you then keep reading and I’ll help you get started and going super fast.

How To Setup AWS CDK Python Environment

I have written a detailed step by step guide here which you can follow and get up and running in less than a few minutes. Please follow this before proceeding into writing code. If you already have AWS CDK setup in your system there’s no need to do this.

How To Setup AWS CDK With Python

How To Setup AWS Lambda Using AWS CDK Python

Now that we have the environment all setup we will do the following:

  • Create a new project
  • Initialize our Environment file
  • Write the Code that Sets up our Stack

Create New AWS CDK Python Lambda Project

If followed the previous guide and want to re-use the project you have created that’s fine. We will be doing a slight twist to this here and basically initializing it with a different name since it’s going to be dedicated for an AWS Lambda creation using AWS CDK Python.

To avoid repeating the steps here we simply use the name lambda_deploy. If everything went well you should have ended up with the following file structure as shown below.

$ ls -al
drwxr-xr-x  12 user  staff   384 Feb 22 14:47 .git
-rw-r--r--   1 user  staff   119 Feb 22 14:47 .gitignore
drwxr-xr-x   6 user  staff   192 Feb 22 14:47 .venv
-rw-r--r--   1 user  staff  1658 Feb 22 14:47 README.md
-rw-r--r--   1 user  staff   955 Feb 22 14:47 app.py
-rw-r--r--   1 user  staff   780 Feb 22 14:47 cdk.json
drwxr-xr-x   4 user  staff   128 Feb 22 14:47 lambda_deploy
-rw-r--r--   1 user  staff    14 Feb 22 14:47 requirements-dev.txt
-rw-r--r--   1 user  staff    47 Feb 22 14:47 requirements.txt
-rw-r--r--   1 user  staff   437 Feb 22 14:47 source.bat
drwxr-xr-x   4 user  staff   128 Feb 22 14:47 tests

Setting Up AWS Environment Credentials

In order to do this I have made a detailed guide which you can find here:

Boto3 Session: Setup Profile, Create, Close and Mock sessions

You can follow the steps listed above to add a new iam user and configure your .env file accordingly.

The permission you want to use is the following in this case:

IAM - AWS CDK Role Permissions
IAM – AWS CDK Role Permissions

Other than the change above you can follow the guide as is to initialize the AWS SDK permissions. Do note you may not need the Lambda permission this is only if you plan to using the same user to programmatic upload new code or changes to Lambda the Administrator permission supersedes it here.

Once this is done you also need to setup your credentials sections in your config, in this example I will be using a profile named test_deploy_lambda.

The typical values such as the secret key and access keys need to be entered. Mine looks something like this:

$ cat credentials
[test_deploy_lambda]
aws_access_key_id=YOUR ID
aws_secret_access_key=YOUR KEY
aws_default_region=us-east-1

$ cat config
[test_deploy_lambda]
region=us-east-1

Modifying The AWS CDK Environment File

Besides that we need to add two more attributes to our AWS CDK environment file and those are related to the CDK.

More specifically this would look like this:

CDK_DEFAULT_ACCOUNT=YOURACCOUNT
CDK_DEFAULT_REGION=us-east-1

Make sure to replace the CDK_DEFAULT_ACCOUNT and CDK_DEFAULT region accordingly with your information which you can retrieve from the AWS console.

How To Synthesize And Deploy/Bootstrap Your Lambda Using AWS CDK Python

The final step is to basically run our code to:

  • Synthesize
  • Bootstrap
  • Deploy

How To Synthesize Your AWS Lambda Using AWS CDK Python

The first step as mentioned above is to Synthesize your environment with code.

This can be done in three steps:

  • Modify the app.py initialization file
  • Create a sample Lambda file
  • Write the code to deploy the Lambda we created

How To Modify app.py To Initialize AWS CDK

Lets examine the code that implements this.

#!/usr/bin/env python3
import os
from dotenv import load_dotenv

# load our env file
print ('Loading env file')
load_dotenv()

import aws_cdk as cdk
from lambda_deploy.lambda_deploy_stack import LambdaDeployStack

# initialize cdk_env with variables from env file
print ('Creating environment')
cdk_env = cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION'))

# get app handler for cdk
print ('Getting App handler')
app = cdk.App()

# describe our stack
print ('Describing lambda stack')
LambdaDeployStack(
    app, 
    "LambdaDeployStack",
    env=cdk_env
)

# synthesize it
print ('Synthesizing stack')
app.synth()

As noted we are using python-dotenv to load the environment variables we had created previously in this guide. This is to let the CDK know where we will be deploying our code. Also we will be naming in our case the stack LambdaDeployStack.

And to test it out we run the synthesize command:

$ cdk synthesize
Loading env file
Creating environment
Getting App handler
Describing lambda stack
Synthesizing stack
Resources:
  UnbiasedCoderLambdaServiceRole5BCB1ECB:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Metadata:
      aws:cdk:path: LambdaDeployStack/Unbiased-Coder-Lambda/ServiceRole/Resource
  UnbiasedCoderLambdaD21DE2C2:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: cdk-hnb659fds-assets-ACCOUNT-us-east-1
        S3Key: d7f827a081dcf499398ebf8912a02cc8dfdc96ba6ca4c036a6451f58db65c1eb.zip
      Role:
        Fn::GetAtt:
          - UnbiasedCoderLambdaServiceRole5BCB1ECB
          - Arn
      Handler: lambda_handler.handler
      Runtime: python3.9
    DependsOn:
      - UnbiasedCoderLambdaServiceRole5BCB1ECB
    Metadata:
      aws:cdk:path: LambdaDeployStack/Unbiased-Coder-Lambda/Resource
      aws:asset:path: asset.d7f827a081dcf499398ebf8912a02cc8dfdc96ba6ca4c036a6451f58db65c1eb.zip
      aws:asset:is-bundled: false
      aws:asset:property: Code
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/zWMQQ6CMBBFz8K+HcGuXIqJa4MHIEOpOBbahGljTMPdbTGu3p/38+cIjYK6wjdLPVo50wDpHlBbkVWfZlyGESFdo9OBvBOXh/vnTRAukDo/m6ILN8GqR2YTGM4F+YY2amtCi5zrXeb/E7lpHxn2cdW5uX3C07uDghM0dfViIrlGF2gx0P34BdI/UwyrAAAA
    Metadata:
      aws:cdk:path: LambdaDeployStack/CDKMetadata/Default
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.

This creates the pre-step for deployment.

Create Sample Lambda Handler For AWS CDK

The next step is to define a simple lambda and pack it into a zip file that we will later be loading as a resource into our AWS infrastructure.

In order to do this we will be using the following AWS Lambda function that simply returns success 200 with a message we define.

def handler(event, context):
    tmsg = 'Hello from AWS Lambda Deployed Using AWS CDK Written By Unbiased Coder'
    print (tmsg)

    return {
        'statusCode': 200,
        'body': tmsg
    }

One thing to note is that you will need to create a zip file containing the AWS lambda handler code. In Mac/Linux you can do this using the built in command.

$ zip lambda_deploy/lambda_handler.zip lambda_deploy/lambda_handler.py
$ ls -al lambda_deploy/lambda_handler.zip
-rw-r--r--  1 user  staff  334 Feb 22 17:04 lambda_deploy/lambda_handler.zip

How To Implement Code To Describe AWS Lambda Using AWS Python CDK

The final step we need to do is to implement the code that will be deploying our AWS Lambda.

from aws_cdk import (
    Stack,
    aws_lambda,
)
from constructs import Construct

class LambdaDeployStack(Stack):
    """
    Simple Stack to Deploy an AWS Lambda Using CDK

    Args:
        Stack (AWS Stack): Deploys an AWS Lambda Function
    """
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        aws_lambda.Function(
                                self, 'Unbiased-Coder-Lambda',
                                handler = 'lambda_handler.handler', 
                                runtime = aws_lambda.Runtime.PYTHON_3_9, 
                                code    = aws_lambda.Code.from_asset('lambda_deploy/lambda_handler.zip'))

A few notes in the code above:

  • The handler you specify must match the one in the file (the one in the GitHub repo is already defined as is)
  • You can use any Python Runtime you prefer in this case I used Python 3.9
  • Finally the location of the zip should exist as we created it earlier, this will get uploaded into the Lambda function

How To Bootstrap Your AWS Lambda Using AWS CDK Python

The next step in the process is starting to bootstrap the AWS Lambda using our AWS CDK Python code that we wrote earlier in this guide.

$ cdk bootstrap --profile test_deploy_lambda
Loading env file
Creating environment
Getting App handler
Describing lambda stack
Synthesizing stack
 ⏳  Bootstrapping environment aws://ACCOUNT/us-east-1...
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/us-east-1 bootstrapped.

As it can be seen above the bootstrapping was successful. If you are following the code from the Github repo you should be good.

How To Deploy Your AWS Lambda Using AWS CDK Python

The final step is to actually deploy our code into the AWS Stack. This is a lengthy process and syncs all the changes you made in your code to the AWS server infrastructure.

To do this run the cdk deploy command as shown below.

$ cdk deploy --profile test_deploy_lambda
Loading env file
Creating environment
Getting App handler
Describing lambda stack
Synthesizing stack
✨  Synthesis time: 3.32s
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 │
├───┼──────────────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${Unbiased-Coder-Lambda/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.amazonaws.com │           │
└───┴──────────────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬──────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                             │ Managed Policy ARN                                                             │
├───┼──────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Unbiased-Coder-Lambda/ServiceRole} │ 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
LambdaDeployStack: deploying...
[0%] start: Publishing d7f827a081dcf499398ebf8912a02cc8dfdc96ba6ca4c036a6451f58db65c1eb:033533902081-us-east-1
[50%] success: Published d7f827a081dcf499398ebf8912a02cc8dfdc96ba6ca4c036a6451f58db65c1eb:033533902081-us-east-1
[50%] start: Publishing 2cfee3bddd3535ecae8a9c4856e4bf87c86c59dd77e3884b3d420a548e0b977c:033533902081-us-east-1
[100%] success: Published 2cfee3bddd3535ecae8a9c4856e4bf87c86c59dd77e3884b3d420a548e0b977c:033533902081-us-east-1
LambdaDeployStack: creating CloudFormation changeset...
 ✅  LambdaDeployStack
✨  Deployment time: 82.08s
Stack ARN:
arn:aws:cloudformation:us-east-1:ACCOUNT:stack/LambdaDeployStack/3ae94740-93f5-11ec-bd56-0e1cc3882b05
✨  Total time: 85.4s

As it can be seen above the LambdaDeployStack was successfully deployed.

In order to do an extra check and verify everything works we need to visit the AWS console and see if our Lambda was created.

To do this navigate into the AWS Lambda section and we should see our Lambda.

AWS Lambda Deployed Using AWS CDK
AWS Lambda Deployed Using AWS CDK

As it can be seen the AWS CDK has picked a random name extension based on the prefix we provided which was Lambda Deploy Stack.

If we examine the contents of this we will see the Sample Lambda code we created earlier in this guide.

AWS Lambda Deployed With Python CDK
AWS Lambda Deployed With Python CDK

The code is identical to what we had in our sample code earlier.

Just to test it out we can also execute a run for it. Before that simply create an empty test event in the AWS console putting {} is fine in this case.

When we execute we see the output below:

AWS CDK Deployed Lambda Execution
AWS CDK Deployed Lambda Execution

The return status runs as expected so our Lambda has been successfully deployed and executed.

How To Destroy Your AWS Lambda Using AWS CDK Python

As a bonus we will go over how to clean up and destroy any resources you setup in your infrastructure up to now.

To do that CDK offers a very simple destroy command which basically will remove everything we added.

If we were to execute this would look like this:

$ cdk destroy --profile test_deploy_lambda
Loading env file
Creating environment
Getting App handler
Describing lambda stack
Synthesizing stack
Are you sure you want to delete: LambdaDeployStack (y/n)? y
LambdaDeployStack: destroying...
 ✅  LambdaDeployStack: destroyed

AWS CDK goes into our AWS infrastructure and deletes everything that it had previously created.

In order to verify this we go also in our AWS console and see if the Lambda is gone.

An updated view looks like this:

AWS CDK Python Destroy AWS Lambda Function
AWS CDK Python Destroy AWS Lambda Function

It must be noted here that the user you created earlier and associated roles to it will not be deleted. This is something we did outside this context and you will have to navigate to the iam section and delete the user manually.

Conclusion

We were able to successfully show you How To Setup AWS Lambda Using AWS CDK Python and why you may want to use it over using Terraform.

If you found this useful and you think it may have helped you please drop me a cheer below I would appreciate it.

If you have any questions, comments please post them below or send me a note on my twitter. I check periodically and try to answer them in the priority they come in. Also if you have any corrections please do let me know and I’ll update the article with new updates or mistakes I did.

Do you find dynamically creating Lambdas necessary?

I have had a few projects in the past that required me adding and creating resources dynamically. AWS CDK was the answer to these so I’ve used it when needed. If I’m just creating a Lambda as part of a static system I prefer to use vanilla terraform scripts.

If you would like to find more DevOps and to setup specific AWS resources please check the articles below:

Leave a Comment

Your email address will not be published. Required fields are marked *