A sample CloudFormation template with Lambda configured in the CodePipeline deploy stage

4 minute read
Content level: Intermediate
0

On May 16, 2025, Lambda was added to CodePipeline's deploy stage.

On May 16, 2025, Lambda was added to CodePipeline's deploy stage.
https://aws.amazon.com/jp/about-aws/whats-new/2025/05/aws-codepipeline-deploying-lambda-traffic-shifting/

Previously, you needed to use CloudFormation or similar tools to update Lambda code through CodePipeline, but with this update, you can now directly update Lambda functions.

Sample CloudFormation template

When you deploy the following CloudFormation template, it will create a CodePipeline with Lambda configured in the deployment stage.
Please enable S3 data events in the CloudTrail trail to detect uploads to S3.
https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-cloudtrail-logging-for-s3.html

AWSTemplateFormatVersion: "2010-09-09"
Description: CodePipeline,Lambda

Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------# 
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties: 
      BucketEncryption: 
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
      OwnershipControls:
        Rules: 
          - ObjectOwnership: BucketOwnerEnforced
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact

  LambdaBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${AWS::StackName}-lambda-${AWS::AccountId}
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      VersioningConfiguration:
        Status: Enabled

# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------# 
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${AWS::StackName}-lambda-role-${AWS::AccountId}
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'

  EventBridgeIAMPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties: 
      PolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action:
              - "codepipeline:StartPipelineExecution"
            Resource: 
              - !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipeline}
      ManagedPolicyName: !Sub ${AWS::StackName}-eventbridge-policy-${AWS::AccountId}

  EventBridgeIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Principal: 
              Service: 
                - events.amazonaws.com
            Action: 
              - 'sts:AssumeRole'
      ManagedPolicyArns: 
        - !Ref EventBridgeIAMPolicy
      RoleName: !Sub ${AWS::StackName}-eventbridge-role-${AWS::AccountId}
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-eventbridge-role-${AWS::AccountId}

  CodePipelineIAMPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties: 
      PolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action:
              - "s3:GetBucketVersioning"
              - "s3:GetBucketAcl"
              - "s3:GetBucketLocation"
            Resource: 
              - !GetAtt ArtifactBucket.Arn
            Condition:
              StringEquals:
                aws:ResourceAccount: !Sub ${AWS::AccountId}
          - Effect: Allow
            Action:
              - "s3:PutObject"
              - "s3:PutObjectAcl"
              - "s3:GetObject"
              - "s3:GetObjectVersion"
            Resource: 
              - !Sub ${ArtifactBucket.Arn}/*
            Condition:
              StringEquals:
                aws:ResourceAccount: !Sub ${AWS::AccountId}
          - Effect: Allow
            Action:
              - "lambda:GetAlias"
              - "lambda:GetFunctionConfiguration"
              - "lambda:GetProvisionedConcurrencyConfig"
              - "lambda:PublishVersion"
              - "lambda:UpdateAlias"
              - "lambda:UpdateFunctionCode"
            Resource: 
              - !Sub ${Lambda.Arn}
              - !Sub ${Lambda.Arn}:*
          - Effect: Allow
            Action:
              - "logs:CreateLogGroup"
            Resource: 
              - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codepipeline/${AWS::StackName}-codepipeline
              - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codepipeline/${AWS::StackName}-codepipeline:*
          - Effect: Allow
            Action:
              - "logs:CreateLogStream"
              - "logs:PutLogEvents"
            Resource: 
              - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codepipeline/${AWS::StackName}-codepipeline:log-stream:*
          - Effect: Allow
            Action:
              - "s3:GetObject"
              - "s3:GetObjectVersion"
              - "s3:GetBucketVersioning"
              - "s3:GetBucketAcl"
              - "s3:GetBucketLocation"
              - "s3:GetObjectTagging"
              - "s3:GetObjectVersionTagging"
            Resource: 
              - !Sub ${LambdaBucket.Arn}
              - !Sub ${LambdaBucket.Arn}/*
            Condition:
              StringEquals:
                aws:ResourceAccount: !Sub ${AWS::AccountId}
      ManagedPolicyName: !Sub ${AWS::StackName}-codepipeline-policy-${AWS::AccountId}

  CodePipelineIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Principal: 
              Service: 
                - codepipeline.amazonaws.com
            Action: 
              - 'sts:AssumeRole'
      ManagedPolicyArns: 
        - !Ref CodePipelineIAMPolicy
      RoleName: !Sub ${AWS::StackName}-codepipeline-role-${AWS::AccountId}
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-codepipeline-role-${AWS::AccountId}

# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------# 
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub ${AWS::StackName}-lambda-${AWS::AccountId}
      Runtime: python3.13
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import json

          def lambda_handler(event, context):
              # TODO implement
              return {
                  'statusCode': 200,
                  'body': json.dumps('Hello from Lambda!')
              }
      Timeout: 10

# ------------------------------------------------------------#
# Codepipeline
# ------------------------------------------------------------# 
  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      ArtifactStore:
        Location: !Ref ArtifactBucket
        Type: S3
      Name: !Sub ${AWS::StackName}-codepipeline
      RoleArn: !GetAtt CodePipelineIAMRole.Arn
      Stages: 
        - Actions:
          - ActionTypeId: 
              Category: Source
              Owner: AWS
              Provider: S3
              Version: 1
            Configuration:
              S3Bucket: !Ref LambdaBucket
              S3ObjectKey: lambda.zip
            Name: Source
            Namespace: SourceVariables
            OutputArtifacts:
              - Name: SourceArtifact
            Region: ap-northeast-1
            RunOrder: 1
          Name: Source
        - Actions:
          - ActionTypeId: 
              Category: Deploy
              Owner: AWS
              Provider: Lambda
              Version: 1
            Configuration:
              FunctionName: !Ref Lambda
            Name: Deploy
            Namespace: DeployVariables
            InputArtifacts:
              - Name: SourceArtifact
            Region: ap-northeast-1
            RunOrder: 1
          Name: Deploy
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-codepipeline

# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------# 
  EventBridge:
    Type: AWS::Events::Rule
    Properties: 
      Description: for codepipeline
      EventPattern:
        source:
          - aws.s3
        detail-type:
          - 'AWS API Call via CloudTrail'
        detail:
          eventSource: 
            - s3.amazonaws.com
          event:
            - PutObject
            - CompleteMultipartUpload
            - CopyObject
          requestParameters:
            bucketName: 
              - !Ref LambdaBucket
            key:
              - lambda.zip
      Name: !Sub ${AWS::StackName}-eventbridge-${AWS::AccountId}
      State: ENABLED
      Targets: 
        - Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipeline}
          Id: CodePipeline
          RoleArn: !GetAtt EventBridgeIAMRole.Arn

Test

Once the CloudFormation template is deployed, please upload your zip-compressed Lambda function to the S3 bucket named "CloudFormationStackName-lambda-YourAccountID". Please name the zip file "lambda.zip".
Also, please name the Lambda function file "index.py".

Once you upload the file, you can confirm that CodePipeline is executed and the Lambda code is updated as shown below.
a

a