How to Create an AWS Lambda Function with CloudFormation

There are various ways to create AWS Lambda functions, such as with AWS Management Console, AWS CLI and third-party tools. The focus of this tutorial is AWS CloudFormation, an infrastructure-as-code tool that automates the launch and management of AWS infrastructure components in a scalable and reliable way.

CloudFormation supports most AWS resources, including Lambda functions, which are a widely used cloud-based component in many modern applications. Lambda functions implement compute resources in a serverless way, where developers don’t have to directly manage the underlying infrastructure. They are a reliable and agile way to implement software application logic.
It is important to become familiar with the entire process and take advantage of these tools that help application owners launch reliable software in the cloud. In this tutorial, I’ll focus on the necessary steps to launch Lambda functions using CloudFormation. We will look at how to create a template file and CloudFormation stack, which is the grouping of the AWS resources defined in the template.

Create a AWS CloudFormation template
A CloudFormation template has multiple sections that are used to define the stack, such as description, parameters, mappings, resources and outputs. The most relevant one is the resources section, which is where you define an AWS component. In the case of Lambda functions, it is done following the pattern below in YAML format:
Type: AWS::Lambda::Function

Properties:

<Lambda function configurations>
CloudFormation supports over 20 properties when defining a Lambda function. Strictly speaking, there are only two required ones: code and role. These configurations define the location of the source code that the function will use and the IAM role that will be allocated to grant permissions for the function to execute. In this example, I will configure code as a zip file stored in S3. The other options are to specify an Amazon Elastic Container Registry Docker image location or to specify the actual code inline.
Create an IAM role
This example will include a manually created IAM role with the minimum permissions required by a Lambda function. This can be done from the AWS IAM console. Trigger the Create Role flow and choose AWS service as an entity type:

The AWS managed policy AWSLambdaBasicExecutionRole provides the minimum set of permissions required by a Lambda function to operate, which includes writing data to CloudWatch Logs. In the case of more sophisticated Lambda functions that interact with other AWS services such as S3 and DynamoDB, assign additional IAM permissions to this IAM role. Also, allocate the minimum amount of permissions based on the purpose of each Lambda function.

Create a file with the source code
Once you complete this flow and create the IAM role, use the Amazon Resource Name (ARN) in the CloudFormation template. The other prerequisite for this example is to create a file with the source code of the Lambda function — in this case, I named it index.py — and package it into a .zip file then upload it to an S3 bucket. Below is an example of a very basic Python “Hello World” function code:
import json

def lambda_handler(event, context):

print(“Received event: ” + json.dumps(event))

print(“Hello World”)

return event
I use a zip file stored in S3 named my-source-code.zip. It requires the handler and runtime CloudFormation properties. In addition, it’s always useful to define other nonmandatory properties, such as FunctionName, description and tags. The Lambda function block will look like this:
Resources:
ExampleFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: ExampleFunction
Description: “Lambda example”
Code:
S3Bucket: s3-bucket-name
S3Key: my-source-code.zip
Role: arn:aws:iam::<aws-account-id>:role/<role-name>
Handler: index.lambda_handler
Runtime: python3.11
Tags:
– Key: stage
Value: <deployment-stage>
– Key: <other-key>
Value: <key-value>

It is a good practice to be familiar with other configurations, which are not covered in this example but can be potentially very useful, depending on your application needs. These include:

Architectures (x86_64 or arm64).
CodeSigningConfigArn.
DeadLetterConfig.
Environment.
EphemeralStorage.
FileSystemConfigs.
ImageConfig.
KmsKeyArn.
Layers.
LoggingConfig.
MemorySize.
ReservedConcurrentExecutions.
RuntimeManagementConfig
SnapStart.
Timeout.

Create the AWS CloudFormation stack
Once the template is ready and you upload the code zip file to S3, the next step is to create the CloudFormation stack. In the CloudFormation console, click on Create stack and select With new resources (standard).

The next step sets the options for the template. In this example, we use a template saved locally. Select Template is ready, Upload a template file and then select the specific template file.

The next step is to provide a stack name. If there are stack parameters defined in the template, they are set here.

The next step includes setting stack options, such as tags, permissions and stack failure options. In this example, we’ll leave the default configuration and proceed with the final confirmation step. From the events tab, you can see the status of the stack and resource creation.
Note that the resources tab shows the AWS components managed by the recently created stack. In most cases, it displays a link that takes you to the AWS service console for that specific resource. In this example, the link takes users to the Lambda console.

From the code tab, you can see the actual function source code, test the function and configure custom inputs with test events.
After you create the stack, define subsequent updates to existing AWS resources in the CloudFormation template and then apply them to the CloudFormation stack, as needed. You can do this through the UpdateStack operation which is triggered either through the CLI, SDK or the AWS console.

AWS CloudFormation vs. SAM
While AWS released the Serverless Application Model (SAM) as a simplified tool to manage Lambda functions and other serverless components, CloudFormation is the foundational AWS service to implement infrastructure-as-code in the cloud. The SAM framework is an extension of CloudFormation, it automatically generates CloudFormation templates and stacks when defining serverless components.
Even though SAM is a very useful and reliable way to manage serverless applications, using plain CloudFormation syntax is also a good way to launch Lambda functions, especially when there’s the need to manage non-serverless components in the same stack as Lambda functions.
Ernesto Marquez is the owner and project director at Concurrency Labs, where he helps startups launch and grow their applications on AWS. He particularly enjoys building serverless architectures, automating everything and helping customers cut their AWS costs.