C# and AWS Lambdas, Part 4 – Storing the Zip in S3, Setup with Pulumi IaC

Full source code available here.

In the previous post, I showed how to use Pulumi to create a Lambda, API gateway and upload a zip of Web API application directly to the Lambda.

In the post I’m going to use S3 to store the zip of a simple .NET application (not a Web API app) and point the Lambda at it, bringing all the resources up using Pulumi. One drawback of using S3 to store the zip for a Lambda is that when you update the zip in S3, AWS doesn’t deploy the new zip to the Lambda, but I will show a way of handling that in the next blog post.

Every time I write these posts it feels like a lot of work to set up the infrastructure, learn about the AWS components, policies, etc. But then when I run pulumi destroy -y and pulumi up -y as I make changes I appreciate the speed and predictability.

What’s needed

  1. A Lambda role.
  2. A policy to execute the Lambda.
  3. An S3 bucket.
  4. Block all public access to the bucket - optional.
  5. Put the zip in the bucket.
  6. The Lambda function pointing to the zip in the bucket.

A few of these are the same as in the previous post, but the S3 resources are new.

Note that I included BucketPublicAccessBlock section, this makes the S3 bucket more secure than it would be under the default settings.

The code

Here is the code that sets it all up. I’ve included a helloworld.zip file in the attached source code zip. This is NOT how you would normally upload the zip to S3, but it’s easy for demonstration purposes. In a more realistic scenario, you would a CI/CD pipeline to compile the code and drop it in S3.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using Pulumi;
using S3 = Pulumi.Aws.S3;
using Aws = Pulumi.Aws;
class MyStack : Stack
{
    public MyStack()
    {

        var lambdaRole = new Aws.Iam.Role("PulumiHelloWorld_LambdaRole", new Aws.Iam.RoleArgs
        {
            AssumeRolePolicy =
@"{
    ""Version"": ""2012-10-17"",
    ""Statement"": [
        {
        ""Action"": ""sts:AssumeRole"",
        ""Principal"": {
            ""Service"": ""lambda.amazonaws.com""
        },
        ""Effect"": ""Allow"",
        ""Sid"": """"
        }
    ]
}",
        });

        var lambdaPolicyAttachment = new Aws.Iam.PolicyAttachment("PulumiHelloWorld_LambdaPolicyAttachment", new Aws.Iam.PolicyAttachmentArgs
        {
            Roles =
            {
                lambdaRole.Name
            },
            PolicyArn = Aws.Iam.ManagedPolicy.AWSLambdaBasicExecutionRole.ToString(),
        });

        var bucket = new S3.Bucket("PulumiHelloWorld_S3Bucket", new S3.BucketArgs
        {
            BucketName = "pulumi-hello-world-s3-bucket",
            Acl = "private"
        });

        var bucketPublicAccessBlock = new S3.BucketPublicAccessBlock("PulumiHelloWorld_PublicAccessBlock", new S3.BucketPublicAccessBlockArgs
        {
            Bucket = bucket.Id,
            BlockPublicAcls = true,
            BlockPublicPolicy = true,
            RestrictPublicBuckets = true,
            IgnorePublicAcls = true
        });

        var bucketObject = new S3.BucketObject("PulumiHelloWorld_ZipFile", new S3.BucketObjectArgs
        {
            Bucket = bucket.BucketName.Apply(name => name),
            Acl = "private",
            Source = new FileArchive("helloworld.zip")
        });

        var lambdaFunction = new Aws.Lambda.Function("PulumiHelloWorld_LambdaFunction", new Aws.Lambda.FunctionArgs
        {
            Handler = "HelloWorldLambda::HelloWorldLambda.Function::FunctionHandler",
            MemorySize = 128,
            Publish = false,
            ReservedConcurrentExecutions = -1,
            Role = lambdaRole.Arn,
            Runtime = Aws.Lambda.Runtime.DotnetCore3d1,
            Timeout = 4,
            S3Bucket = bucket.BucketName,
            S3Key = bucketObject.Key
        });

        this.LambdaFunctionName = lambdaFunction.Name;
    }

    [Output]
    public Output<string> LambdaFunctionName { get; set; }
}

To test out the Lambda, open it in the AWS console, navigate to the Lambda and add a test as described in part 1 of this series of posts.

Full source code available here.

comments powered by Disqus

Related