CI/CD Pipeline for AWS Lambda Functions via zip file

Subhas Patil
4 min readOct 23, 2021

Lambda is a compute service that lets you run code without provisioning or managing servers. Lambda runs your code on a high-availability compute infrastructure and performs all of the administration of the compute resources, including server and operating system maintenance, capacity provisioning and automatic scaling, code monitoring and logging. With Lambda, you can run code for virtually any type of application or backend service.
In this article we will deploy a dotnetcore lambda function using the zip file created by the dotnet cli publish command.

A .zip file archive includes your application code and its dependencies. When you author functions using the Lambda console or a toolkit, Lambda automatically creates a .zip file archive of your code.

There are 2 conventional ways of deploying the zip file to lambda:

  1. Use aws toolkit for visual studio
  2. Upload the zip via console directly

While these options work great but think of a situation where each developer is working on their own machine and you want to control the deployment. There might be situations where you do not want to give permission to the lambda functions to all the developers as it can cause issues.

So we look at the other option of using S3 to store the zip file and deploy the code via AWS Codepipeline. With this method you only assign S3 permission to the developers to upload their code, rest of the permissions required for deployment is assigned to the Codebuild role.

Lets look at the steps to achieve this

STEP 1

Upload the zip file to the S3 bucket.
Lets use this path for reference S3://mybucket/lambda/app.zip

STEP 2

Create a role for codepipeline and attach the following policy
Role Name: codepipeline

{
"Statement": [
{
"Action": [
"iam:PassRole"
],
"Resource": "*",
"Effect": "Allow",
"Condition": {
"StringEqualsIfExists": {
"iam:PassedToService": [
"cloudformation.amazonaws.com",
"elasticbeanstalk.amazonaws.com",
"ec2.amazonaws.com",
"ecs-tasks.amazonaws.com"
]
}
}
},
{
"Action": [
"codecommit:CancelUploadArchive",
"codecommit:GetBranch",
"codecommit:GetCommit",
"codecommit:GetRepository",
"codecommit:GetUploadArchiveStatus",
"codecommit:UploadArchive"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codedeploy:CreateDeployment",
"codedeploy:GetApplication",
"codedeploy:GetApplicationRevision",
"codedeploy:GetDeployment",
"codedeploy:GetDeploymentConfig",
"codedeploy:RegisterApplicationRevision"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codestar-connections:UseConnection"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"elasticbeanstalk:*",
"ec2:*",
"elasticloadbalancing:*",
"autoscaling:*",
"cloudwatch:*",
"s3:*",
"sns:*",
"cloudformation:*",
"rds:*",
"sqs:*",
"ecs:*"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"lambda:InvokeFunction",
"lambda:ListFunctions"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"opsworks:CreateDeployment",
"opsworks:DescribeApps",
"opsworks:DescribeCommands",
"opsworks:DescribeDeployments",
"opsworks:DescribeInstances",
"opsworks:DescribeStacks",
"opsworks:UpdateApp",
"opsworks:UpdateStack"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"cloudformation:CreateStack",
"cloudformation:DeleteStack",
"cloudformation:DescribeStacks",
"cloudformation:UpdateStack",
"cloudformation:CreateChangeSet",
"cloudformation:DeleteChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:SetStackPolicy",
"cloudformation:ValidateTemplate"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild",
"codebuild:BatchGetBuildBatches",
"codebuild:StartBuildBatch"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"devicefarm:ListProjects",
"devicefarm:ListDevicePools",
"devicefarm:GetRun",
"devicefarm:GetUpload",
"devicefarm:CreateUpload",
"devicefarm:ScheduleRun"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"servicecatalog:ListProvisioningArtifacts",
"servicecatalog:CreateProvisioningArtifact",
"servicecatalog:DescribeProvisioningArtifact",
"servicecatalog:DeleteProvisioningArtifact",
"servicecatalog:UpdateProduct"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudformation:ValidateTemplate"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:DescribeImages"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"states:DescribeExecution",
"states:DescribeStateMachine",
"states:StartExecution"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"appconfig:StartDeployment",
"appconfig:StopDeployment",
"appconfig:GetDeployment"
],
"Resource": "*"
}
],
"Version": "2012-10-17"
}

STEP 3

  • Create Pipeline
  • Enter Name
  • Select the role created in Step 2
  • At the Source stage select S3 as source and provide the bucket and object path
  • At the build stage select AWS CodeBuild as the Build provider.
  • Create a build project
    - Select OS as Amazon Linux 2
    - Runtime Standard
    - Select any image
    - Provide a Role name and let codebuild create this role
    - In the buildspec stage, select Insert build commands and Switch to editor
    then enter the following
version: 0.2phases:
build:
commands:
- aws --version
- aws lambda update-function-code --function-name mylambda_functionname_here --s3-bucket mybucket --s3-key lambda/app.zip

Assign the following policy to the codebuild role (myrole) created by codebuild project:
- AWSLambda_FullAccess (Required to deploy function to lambda)
- AmazonS3FullAccess (Required to get the zip file from S3 bucket)

  • Select the codebuild project just created in the codepipeline build stage
  • Click Next and Skip deploy stage
  • Review the Pipeline and create

Now your pipeline will start the execution and within few minutes you will see that your function is deployed successfully.

--

--

Subhas Patil

Devops Engineer - Prodt Consulting Services, AWS Certified Solutions Architect | Terraform Certified