Module 6: Hands-on Lab: Create and Deploy Lambda Functions
HANDS-ON LAB
Lab Objectives
In these labs you will put into practice what you have learned in this course
You will create a variety of .NET 6/7 Lambda functions, deploy, and invoke them.
There are 3 labs in this module:
Lab 1: .NET 6 Web App running on Arm64
Lab 2: Invoking a Lambda function from a C# program on your computer
Lab 3: Invoking one Lambda function from another
Prerequisites
You have an AWS account.
You have an AWS user with the AdministratorAccess policy attached, see the section - A note on permissions, in module 3 for more details./p>
You have installed the .NET 6 SDK.
You have installed the AWS Extensions for .NET CLI (dotnet lambda ...).
You have installed the AWS Lambda for .NET Core Templates.
You have installed PowerShell. If you need to install it for Window/Mac/Linux, see https://github.com/PowerShell/PowerShell.
You can find more information on the above tooling in module 2.
You have an S3 bucket for CloudFormation stacks. If you do not, follow the below instructions.
Time to Complete
45 minutes
Lab 1: A .NET 6 Web App running on Arm64
Step 1: Create the project
1. Create serverless .NET project
dotnet new serverless.AspNetCoreWebApp -n AspNetCoreWebApp
Step 2: Make a few changes to the code
You can leave the using statement and namespace as is, but replace the IndexModel class with the following:
public class IndexModel : PageModel
{
public string? Architecture { get; set; }
public string? DotnetVersion { get; set; }
public void OnGet()
{
Architecture = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString();
DotnetVersion = Environment.Version.ToString();
}
}
2. Update Index.cshtml
Replace the content of the file down to the </h2> with:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome to .NET Lambda functions on AWS!</h1>
<h2>Your application is using .NET <code>@Model.DotnetVersion</code>, <code>@Model.Architecture</code>.</h2>
</div>
These changes will let you see what version of .NET you are running, and the type of processor you are using
Step 3: Configure Processor Architecture
Open the serverless.template file.
Find the "Handler" key, and the next line add:
"Architectures": ["arm64"],
"AspNetCoreFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "AspNetCoreWebApp::AspNetCoreWebApp.LambdaEntryPoint::FunctionHandlerAsync",
"Architectures": ["arm64"],
Step 4: Deploy the function
dotnet lambda deploy-serverless --stack-name AspNetCoreWebApp --s3-bucket your-unique-bucket-name1234
You will see output as each step of the deployment as it is worked on, and completed.
8/9/2022 1:45 PM AspNetCoreFunctionProxyResourcePermissionProd CREATE_COMPLETE
8/9/2022 1:45 PM AspNetCoreWebApp CREATE_COMPLETE
Stack finished updating with status: CREATE_COMPLETE
Output Name Value
------------------------------ --------------------------------------------------
ApiURL https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/
Step 5: Clean up
dotnet lambda delete-serverless --stack-name AspNetCoreWebApp
Lab 2: Invoking a Lambda function from a C# program on your computer
Step 1: Create the Lambda function
In this step, you will create an empty Lambda project.
1. Create the project
If you are still in the directory you created for the previous lab, move out of that to a clean directory. Create a new Lambda function from the command line:
dotnet new lambda.EmptyFunction -n GetS3Buckets
Step 2: Code changes
In this step, you will modify the generated project code.
1. Add package
Change to the GetS3Buckets\src\ GetS3Buckets folder and add the AWS SDK S3 package to the project:
cd GetS3Buckets\src\ GetS3Buckets
dotnet add package AWSSDK.S3
2. Update Function.cs
Open Function.cs in your IDE, and replace the code with:
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace GetS3Buckets;
public class Function
{
public async Task<IEnumerable<string>> FunctionHandler(ILambdaContext context)
{
var s3Client = new AmazonS3Client();
ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
ListBucketsResponse listBucketsResponse = await s3Client.ListBucketsAsync(listBucketsRequest);
var bucketNames = listBucketsResponse.Buckets.Select(b => b.BucketName);
return bucketNames;
}
}
Step 3: Deploy the function
In this step, you'll deploy and test your Lambda function.
1. Deploy function to AWS
Deploy the function to AWS using:
dotnet lambda deploy-function GetS3Buckets
When asked to select a role, choose the option to create a new one. Use the name GetS3BucketsRole, for the role name.
When asked to attach a policy, choose the option for AWSLambdaBasicExecutionRole, it is number 6 on my list.
Step 4: Add permission to ListAllMyBuckets
In this step, you'll add permissions to list your S3 buckets.
1. Create IAM policy
The policy you attached to the role does not have the required permission to list your S3 buckets.
Create a new file called S3ListAllMyBucketsPolicy.json.
Paste the following into the file -
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
}
]
}
2. Add policy to role
Add the policy to the GetS3BucketsRole:.
aws iam put-role-policy --role-name GetS3BucketsRole --policy-name ListAllMyBuckets --policy-document file://S3ListAllMyBucketsPolicy.json
Wait a few moments for the permissions to be applied.
Step 5: Invoke Lambda function from the command line
In this step, you'll deploy and test your Lambda function.
1. Invoke function from the command line
Before creating a C# program to invoke the function, try invoking it from the command line:
dotnet lambda invoke-function --function-name GetS3Buckets
You should see output that lists all your buckets.
This verifies that the Lambda function works as expected.
Step 6: Invoke Lambda function from the command line
In this step, you'll create a C# program that invokes yur Lambda function.
1. Create a console application
Create a .NET console application using:
dotnet new console -n GetS3BucketsCallFromLocal
2. Add AWSSDK.Lambda package
Change to the GetS3BucketsCallFromLocal folder.
cd GetS3BucketsCallFromLocal
Add the AWS SDK Lambda package, this lets you invoke Lambda functions:
dotnet add package AWSSDK.Lambda
3. Update Program.cs
Open the Program.cs file and replace it with:
using System.Text.Json;
using Amazon.Lambda;
using Amazon.Lambda.Model;
AmazonLambdaClient client = new AmazonLambdaClient();
var request = new InvokeRequest
{
FunctionName = "GetS3Buckets"
};
var result = await client.InvokeAsync(request);
var buckets = JsonSerializer.Deserialize<IEnumerable<string>>(result.Payload);
foreach (var bucket in buckets)
{
Console.WriteLine(bucket);
}
Step 7: Try it out
In this step, you'll test the console program and invoke your Lambda function.
1. Run the console application
From the command line of the GetS3BucketsCallFromLocal directory, run:
dotnet run
You should see a list of bucket names.
Step 8: Clean up
You are going to use this function in the next lab, so no clean up for now.
Lab 3: Invoking one Lambda function from another
Step 1: Create the GetS3Buckets function
Complete the previous lab.
Step 2: Create a Lambda function
In this step, you will create a Lambda function to call the GetS3Buckets functions.
1. Create empty Lambda project
From the command line run:
dotnet new lambda.EmptyFunction -n GetS3BucketsCallFromLambdaFunction
2. Change folder
Change to the GetS3BucketsCallFromLambdaFunction\src\GetS3BucketsCallFromLambdaFunction directory.
Step 3: Update code
In this step, you will update the project code.
1. Add AWSSDK.Lambda package
Add the AWS SDK Lambda package to the project:
dotnet add package AWSSDK.Lambda
2. Update Function.cs
Open the Function.cs file, and replace the code with:
using Amazon.Lambda;
using Amazon.Lambda.Core;
using Amazon.Lambda.Model;
using System.Text.Json;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace GetS3BucketsCallFromLambdaFunction;
public class Function
{
public async Task<IEnumerable<string>> FunctionHandler(ILambdaContext context)
{
AmazonLambdaClient client = new AmazonLambdaClient();
var request = new InvokeRequest
{
FunctionName = "GetS3Buckets",
};
var result = await client.InvokeAsync(request);
var bucketNames = JsonSerializer.Deserialize<IEnumerable<string>>(result.Payload);
return bucketNames;
}
}
In this example, the GetS3BucketsCallFromLambdaFunction Lambda function is calling the GetS3Buckets function, and returning the response, making no changes to the response.
Step 4: Deploy GetS3BucketsCallFromLambdaFunction
In this step, you will deploy the GetS3BucketsCallFromLambdaFunction Lambda function to AWS.
1. Deploy the function
From the command line, run:
dotnet lambda deploy-function GetS3BucketsCallFromLambdaFunction
2. Create role
Create a new role for the function named
GetS3BucketsCallFromLambdaFunctionRole.
3. Attach policy to role
Attach the AWSLambdaBasicExecutionRole policy to the role.
Step 5: Try to invoke GetS3BucketsCallFromLambdaFunction
In this step, you will try invoking the function.
1. Deploy the function
Try invoking GetS3BucketsCallFromLambdaFunctionRole:
dotnet lambda invoke-function --function-name GetS3BucketsCallFromLambdaFunction
You will get an error like the below:
Payload:
{
"errorType": "AmazonLambdaException",
"errorMessage": "User: arn:aws:sts::000000000000:assumed-role/GetS3BucketsCallFromLambdaFunctionRole/GetS3BucketsCallFromLambdaFunction
is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-1:000000000000:function:GetS3Buckets because no
identity-based policy allows the lambda:InvokeFunction action",
This is because GetS3BucketsCallFromLambdaFunction requires permissions to invoke GetS3Buckets.
In the next step you will add an inline policy granting GetS3BucketsCallFromLambdaFunction the permission it needs
Step 6: Give GetS3BucketsCallFromLambdaFunction permission to invoke GetS3Buckets
In this step, you will give GetS3BucketsCallFromLambdaFunction permissions to invoke GetS3Buckets.
1. Get ARN of GetS3Buckets
Before you can grant invocation rights to GetS3BucketsCallFromLambdaFunction, you need to get the Amazon Resource Name (ARN) of GetS3Buckets.
You can do this in a couple of ways. First from the AWS Console. Get to the Lambda service, and select the GetS3Buckets function
You can click Copy ARN from both of the highlighted areas.
To get the ARN of GetS3Buckets from the command line, run:
dotnet lambda get-function-config GetS3Buckets
You will see output that looks like -
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli,
https://github.com/aws/aws-lambda-dotnet
Name: GetS3Buckets
Arn: arn:aws:lambda:us-east-1:000000000000:function:GetS3Buckets
Package Type: Zip
Runtime: dotnet6
Function Handler: GetS3Buckets::GetS3Buckets.Function::FunctionHandler
Last Modified: 2022-08-10T13:58:29.211+0000
Memory Size: 256
Ephemeral Storage Size: 512
Role: arn:aws:iam::000000000000:role/GetS3Buckets
Timeout: 30
Version: $LATEST
State: Active
Last Update Status: Successful
KMS Key ARN: (default) aws/lambda
Lots of useful information, but what you want is on the second line of the table, the Arn.
Create a file named InvokeGetS3Buckets.json, add the following to it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action":[
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:us-east-1:000000000000:function:GetS3Buckets"
}
]
}
Repl
Replace the "Resource" with the ARN of your Lambda function that you got from the command line or from the Console UI.
2. Update permissions
Run the following:
aws iam put-role-policy --role-name GetS3BucketsCallFromLambdaFunctionRole
--policy-name InvokeGetS3BucketsFunction
--policy-document file://InvokeGetS3Buckets.json
It may take a few minutes for the permissions to update on AWS.
Step 7: Invoke GetS3BucketsCallFromLambdaFunction again
In this step, you will again invoke the function.
1. Invoke the function with dotnet lambda invoke-function
This time you will be able to invoke the function:
dotnet lambda invoke-function --function-name GetS3BucketsCallFromLambdaFunction
Conclusion
In these labs you put what you have learned into practice. You first created a web application that is accessible from anywhere in the world. You then deployed a Lambda function which you invoked directly from a C# program on your computer. Then you built on the second lab by deploying another Lambda function and invoking one Lambda function from another. You also had to resolve permission issues as they arose.
From here you can experiment with using other AWS services with Lambda functions and building more complex Lambda applications.