AWS Lambda 上的 .NET 工作负载

模块 4

模块 4:使用其他 AWS 服务

 学习模块

请注意,您可以按照此处提供的示例进行操作,但这不是强制要求。

使用其他 AWS 服务的方法有多种。

如果您访问的服务是 AWS RDS 数据库(例如 SQL Server 或 Postgres),则您使用的库与您在自己的计算机或数据中心托管数据库时使用的库相同。您需要一个包含用户名和密码的连接字符串,或者您选择的其他身份验证方式。与您日常使用数据库的方式没有什么不同。您无需任何其他权限即可访问数据库服务器。唯一需要注意的是,如果数据库不可公开访问,则您需要将 Lambda 连接到 VPC(该过程需要额外的权限)。

如果您的 Lambda 函数使用的是 S3、DynamoDB、Kinesis 等,则您可以使用 AWS SDK 与这些服务进行交互。Lambda 函数以之运行的角色需要适当的权限才能与每项服务交互。例如,如果您想向 S3 桶添加项目,则该角色需要获取权限才能写入该桶。如果您想从 DynamoDB 表中获取项目,则该角色需要获取权限才能从该表中读取项目。

第三种情况是,您希望其他服务触发您的 Lambda 函数以响应某个事件。例如,您可能希望在向特定 S3 桶添加新项目,或者当事件到达 Kinesis 流时触发 Lambda 函数。为此,Lambda 函数必须使用“基于资源的策略”。此策略向其他服务提供调用您的 Lambda 函数的权限。

 所需时间

30 分钟 

通过 Lambda 函数访问 RDS 数据库服务器

使用熟悉的服务(如 SQL Server、Postgres、MySQL)的好处在于,从代码的角度来看,通过 Lambda 函数调用这些服务时无需任何不同于以往的操作。Entity Framework/ADO/NpgSql 等与 AWS 托管数据库一样适用于本地/机架式数据库。调用方式相同,您不需要 AWS SDK 库,当然您仍然需要将相关的 NuGet 包添加到您的项目中。但除此之外,都是一样的。

通过 Lambda 函数访问 AWS 服务

如需访问大多数 AWS 服务,您需要授予 Lambda 函数与相应服务交互的权限。为此,您可以向 Lambda 函数以之运行的角色添加策略。该策略需要授予 Lambda 函数与服务交互的权限。您可以通过两种方式创建策略:
1. 作为内联策略,您只能将其用于该角色。

2.作为独立策略,您可以将其附加到任何角色。在 AWS 中,后者被称为客户管理的策略。

向角色授予尽可能少的权限始终是良好实践。在以下示例中,您将从 DynamoDB 表中读取数据,您需要向 Lambda 角色授予两项权限:dynamodb:GetItem 和 dynamodb:DescribeTable。您可以将这些权限限于您感兴趣的特定表。

首先,创建一个名为“People”的新 DynamoDB 表。如果您使用的是 Windows 命令提示符,则以下命令将适用于 PowerShell,而 Linux Shell 需要对字符串进行不同的转义处理。

运行以下命令:
aws dynamodb create-table --table-name People --attribute-definitions AttributeName=PersonId,AttributeType=N --key-schema AttributeName=PersonId,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
注意 TableArn,稍后您将用到它。它将位于输出的底部附近。

向表中添加一些项目:
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"1"},"State":{"S":"MA"}, "FirstName": {"S":"Alice"}, "LastName": {"S":"Andrews"}}'
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"2"},"State":{"S":"MA"}, "FirstName": {"S":"Ben"}, "LastName": {"S":"Bradley"}}'
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"3"},"State":{"S":"MA"}, "FirstName": {"S":"Claire"}, "LastName": {"S":"Connor"}}'
您现在有一个表,其中有三个项目。

然后使用以下命令创建 Lambda 函数:
dotnet new lambda.EmptyFunction -n LambdaFunctionDynamoDB 
转至 LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB 目录,然后添加 AWSSDK.DynamoDBv2 NuGet 包:
cd LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB 
dotnet add package AWSSDK.DynamoDBv2
然后打开 Function.cs 并将代码替换为以下内容:
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace LambdaFunctionDynamoDB ;

public class Function
{
   public async Task<string> FunctionHandler(ILambdaContext lambdaContext)
 {
   AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig(); 
   AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
   DynamoDBContext dynamoDbContext = new DynamoDBContext(client);

   Person person = await dynamoDbContext.LoadAsync<Person>(1);

   return $"{person.FirstName} {person.LastName} lives in {person.State}";
 }
}

[DynamoDBTable("People")]
public class Person
{
    [DynamoDBHashKey]
    public int PersonId {get; set;}
    public string State {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
}
使用以下代码将 Lambda 函数部署至 AWS Lambda:
dotnet lambda deploy-function LambdaFunctionDynamoDB

使用以下代码将 Lambda 函数部署至 AWS Lambda:

dotnet lambda deploy-function LambdaFunctionDynamoDB

接下来,系统将询问您“选择为您的代码提供 AWS 凭证的 IAM 角色:”,您可能会看到之前创建的角色列表,但列表底部将显示“**创建新 IAM 角色***”选项,在该选项旁边输入该数字。

系统将要求您“输入新 IAM 角色的名称:”。输入“LambdaFunctionDynamoDBRole”。

然后,系统将要求您“选择要附加到新角色的 IAM Policy 并授予权限”,并显示策略列表。选择“AWSLambdaBasicExecutionRole”,它位于列表第 6 位。(我知道有一个名为“AWSLambdaDynamoDBExecutionRole”的策略,但是这个模块的目标是向您展示如何自行添加必要的权限)。

尝试使用以下命令调用 Lambda 函数:

dotnet lambda invoke-function LambdaFunctionDynamoDB 
您会收到一条很长的错误消息,但在顶部附近您会看到如下所示的内容:
 "errorMessage": "User: arn:aws:sts::YOUR_ACCOUNT_NUMBER:assumed-role/LambdaFunctionDynamoDB Role/LambdaFunctionDynamoDB  is not authorized to perform: dynamodb:DescribeTable on resource: arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People because no identity-based policy allows the dynamodb:DescribeTable action"
请注意以下消息:“...no identity-based policy allows the dynamodb:DescribeTable action”(……任何基于身份的策略都不允许 dynamodb:DescribeTable 操作)。

意思就是,Lambda 函数以之运行的角色未获得所需的 dynamodb:DescribeTable 权限。

要解决该问题,您需要添加一个策略,以向该角色授予 dynamodb:DescribeTable 权限。如上所述,您可以添加内联策略(仅适用于此角色)或独立策略(适用于所有角色)。

在 LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB 文件夹中创建一个名为“DynamoDBAccessPolicy.json”的文件。

编辑 DynamoDBAccessPolicy,但请使用您在资源中的账号:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DescribeTable"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People"
        }
    ]
}
运行以下命令:
aws iam put-role-policy --role-name LambdaFunctionDynamoDBRole --policy-name LambdaFunctionDynamoDBAccess --policy-document file://DynamoDBAccessPolicy.json
该策略可能需要过一段时间才能生效。您可以等待几分钟,也可以重新部署 Lambda 函数。如果您想重新部署该函数,请运行以下命令:
dotnet lambda deploy-function LambdaFunctionDynamoDB 
部署 Lambda 函数后,您可以使用以下方法再次调用它:
dotnet lambda invoke-function LambdaFunctionDynamoDB
又出错了!

这次的消息是:
"errorMessage": "User: arn:aws:sts::YOUR_ACCOUNT_NUMBER:assumed-role/LambdaFunctionDynamoDB Role/LambdaFunctionDynamoDB  is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People because no identity-based policy allows the dynamodb:GetItem action",
您需要在策略的一系列权限中添加“dynamodb:GetItem”。

使用以下内容更新 DynamoDBAccessPolicy.json 文件:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:DescribeTable",
        "dynamodb:GetItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People"
    }
  ]
}
重新部署 Lambda 函数:
dotnet lambda deploy-function LambdaFunctionDynamoDB
再次调用:
dotnet lambda invoke-function LambdaFunctionDynamoDB 
成功!
Amazon Lambda Tools for .NET Core applications (5.4.2)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Payload:
"Alice Andrews lives in MA"
当尝试授予角色尽可能少的权限时,Lambda 错误消息非常有用,但是正如您所看到的,您可能需要重复这个过程几次。

另一种选择是将鼠标悬停在您正在使用的 SDK 方法上,元数据可能包含有关权限的有用信息。并非所有方法元数据都包含权限信息。
您还应查阅 AWS 服务文档以获取有关所需权限的信息。

现在,您知道了如何查找您的函数所需的权限,以及如何向 Lambda 函数以之运行的角色授予正确的权限。

允许其他服务调用 Lambda 函数

在许多场景下,您需要其他服务来为您调用 Lambda 函数。一些常见场景包括消息到达队列、事件到达 Kinesis 流、更改 S3 中对象/桶、请求到达 API 网关。在每种情况下,Lambda 函数都将由另一项 AWS 服务调用。

在上一节中,您学习了如何向 Lambda 函数授予对其他服务执行操作的权限。在本节中,您将看到如何向其他服务授予调用您的 Lambda 函数的权限。

如果您使用的是 serverless.* 模板,则可能已经向 API 网关授予了调用 Lambda 函数所需的权限。如果您已经部署了此类函数,请转至“配置”选项卡,选择左侧的“权限”,然后滚动到“基于资源的策略”部分。您将看到允许 API 网关调用您的 Lambda 函数的策略。此策略由 dotnet lambda deploy-serverless 命令和项目中的 serverless.template 添加。

在下图中,您可以看到两个允许 API 网关调用 Lambda 函数的策略语句。
但是您将要研究的示例允许 S3 桶在您创建或删除该桶中的文件时调用您的 Lambda 函数。

创建 S3 桶

第一步是创建 S3 桶。

如果您希望自己的桶位于 us-east-1,可以使用以下命令:
aws s3api create-bucket --bucket my-unique-bucket-name-lambda-course
如果您想自己的桶位于其他区域,可以使用以下命令:
aws s3api create-bucket --bucket my-unique-bucket-name-lambda-course --create-bucket-configuration LocationConstraint=REGION
有关 LocationConstraint 的有效区域列表,请参见以下链接: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/create-bucket.html

注意:桶的名称必须是唯一的。更多信息请参见此处

创建 Lambda 函数

有一个 Lambda 函数模板可以帮助您处理 S3 事件。它已经添加了所需的 SDK NuGet 软件包。您仍然需要添加所需的角色权限并创建基于资源的策略以允许 S3 调用该函数。

从命令行运行:
dotnet new lambda.S3 -n S3EventHandler
切换至 S3EventHandler/src/S3EventHandler 目录:
cd S3EventHandler/src/S3EventHandler
打开 Function.cs 文件,将 FunctionHandler 方法替换为以下内容:
public async Task FunctionHandler(S3Event evnt, ILambdaContext context)
{
    context.Logger.LogInformation($"A S3 event has been received, it contains {evnt.Records.Count} records.");   
    foreach (var s3Event in evnt.Records)
    {
        context.Logger.LogInformation($"Action: {s3Event.EventName}, Bucket: {s3Event.S3.Bucket.Name}, Key: {s3Event.S3.Object.Key}");
       if (!s3Event.EventName.Contains("Delete"))
        {   
            try 
            {
                var response = await this.S3Client.GetObjectMetadataAsync(s3Event.S3.Bucket.Name, s3Event.S3.Object.Key);
                context.Logger.LogInformation( $"The file type is {response.Headers.ContentType}");
            } 
            catch (Exception e) 
            {
                context.Logger.LogError(e.Message);
                context.Logger.LogError($"An exception occurred while retrieving {s3Event.S3.Bucket.Name}/{s3Event.S3.Object.Key}. Exception - ({e.Message})");
            }
        } 
        else 
        {
            context.Logger.LogInformation($"You deleted {s3Event.S3.Bucket.Name}/{s3Event.S3.Object.Key}");
        }
    }
}
当 Lambda 函数收到 S3 事件时,Lambda 函数会将事件详细信息记录到 CloudWatch 中。如果 S3 事件是对已创建对象的响应,则该函数将使用 AWS SDK 调用 S3 以获取文件类型,然后记录详细信息。

如果 S3 事件是对已删除对象的响应,则该函数会将桶/密钥名称记录到 CloudWatch 中。

部署 Lambda 函数

从命令行运行:
dotnet lambda deploy-function S3EventHandler

接下来,系统将询问您“选择为您的代码提供 AWS 凭证的 IAM 角色:”,您可能会看到之前创建的角色列表,但列表底部将显示“**创建新 IAM 角色***”选项,在该选项旁边输入该数字。

系统将要求您“输入新 IAM 角色的名称:”。输入“S3EventHandlerRole”。

然后,系统将要求您“选择要附加到新角色的 IAM Policy 并授予权限”,并显示策略列表。选择“AWSLambdaBasicExecutionRole”,它位于列表第 6 位。您需要添加策略来授予对 S3 桶的访问权限,这样 GetObjectMetadataAsync(..) 调用才能生效。

授予 Lambda 函数获取对象元数据的权限

在前面的示例中,您创建了一个仅适用于您正在使用的角色的内联策略。这次,您将创建任何角色都可以使用的策略。

您将了解如何通过几种方式做到这一点。
命令行
 
在 S3EventHandler/src/S3EventHandler 文件夹中创建一个名为“S3AccessPolicyForCourseBucket.json”的文件。

策略如下所示,但资源中包含您的桶名称。注意最后的 /*,这意味着 s3:GetObject 适用于桶中的所有对象:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::my-unique-bucket-name-lambda-course/*"
        }
    ]
}
运行以下命令:
aws iam create-policy --policy-name S3AccessPolicyForCourseBucket --policy-document file://S3AccessPolicyForCourseBucket.json
记下该策略的 ARN。

然后将策略附加到您之前创建的角色。运行以下命令:
aws iam attach-role-policy --role-name S3EventHandlerRole --policy-arn arn:aws:iam::694977046108:policy/S3AccessPolicyForCourseBucket
AWS 管理控制台
 
转至 AWS 管理控制台中的 Lambda 函数。

单击“配置”选项卡、左侧的“权限”,然后单击角色名称。
这将打开一个包含该角色详细信息的新页面。

单击 添加权限,然后单击 附加策略

单击创建策略

在“服务”部分,在突出显示的文本框中输入 s3,然后选择 S3。

在“操作”部分输入 getobject,然后从列表中选择 GetObject。

在“资源”部分选择“特定”,然后单击添加 ARN

输入桶名称,然后为对象名称选择“任意”。
输入策略名称,然后单击“创建策略”

返回您单击“创建策略”的选项卡。请按照以下步骤执行操作:

1.重新加载策略列表

2.在过滤器中输入 S3AccessPolicyForCourseBucket

3.勾选策略旁边的方框

4.单击附加策略

此时,您有一个 S3 桶、Lambda 函数以及从 S3 桶获取对象元数据所需的权限。

现在是时候将 S3 桶连接到 Lambda 函数了,这样创建和删除事件便会触发 Lambda 函数。

从 S3 桶中触发 Lambda 函数

如您所见,能够使用 AWS 命令行工具和 UI 控制台真是太好了。在下一步中,您将使用 UI 控制台,因为这对此步骤而言更简单、更清晰。

打开 S3 中的桶列表 https://s3.console.thinkwithwp.com/s3/buckets。

单击您创建的桶。
打开“属性”选项卡。

向下滚动到“事件通知”部分。

单击创建事件通知

输入事件通知名称。

选择左侧的前两个复选框:所有对象创建事件所有对象移除事件

滚动到底部的“目标”部分。

选择 Lambda 函数作为目标。

在下拉列表中,输入您之前创建的 Lambda 函数的名称。

单击保存更改

完成后,您将在“事件通知”部分看到此新事件通知。

在 AWS 管理控制台中,转至您之前创建的 Lambda 函数。

请注意,S3 现在已列为了 Lambda 函数的触发器。

单击配置选项卡,然后单击左侧的权限

向下滚动到“基于资源的策略”部分

您将看到一条允许 S3 调用 Lambda 函数的策略语句。
单击“语句 ID”查看策略语句。

测试一下

此 Lambda 函数不向调用方(在本例中为 S3)返回任何内容。

相反,Lambda 函数会记录到 CloudWatch 中,因此您必须去 CloudWatch 查看您的函数是否正常运行。

在您的计算机上创建要上传到 S3 的文本文件。

从命令行运行:
aws s3api put-object --bucket my-unique-bucket-name-lambda-course --key Hello.txt --body Hello.txt --content-type "text/plain"
aws s3api delete-object --bucket my-unique-bucket-name-lambda-course --key Hello.txt

现在,在 AWS 管理控制台中转至您的 Lambda 函数并查看日志。

依次单击监控选项卡和在 CloudWatch 中查看日志

您将看到一个日志流列表,请选择最新的日志流。
您应该看到显示 S3 事件的日志条目和您记录至 CloudWatch 的文本。
另一种查看日志的方法是使用适用于 Visual Studio、Visual Studio Code 和 Rider 的 AWS 扩展程序。

这三款工具的过程相似,打开 AWS 扩展程序,单击 CloudWatch 日志,然后找到 /aws/lambda/S3EventHandler 的日志流/组。然后打开最近的流。
另一种查看日志的方法是使用适用于 Visual Studio、Visual Studio Code 和 Rider 的 AWS 扩展程序。

这三款工具的过程相似,打开 AWS 扩展程序,单击 CloudWatch 日志,然后找到 /aws/lambda/S3EventHandler 的日志流/组。然后打开最近的流。

结论

在这个相对简短的模块中,您了解了很多内容。有人会说,了解角色和策略是在 AWS 上学习的最重要的内容之一。希望这能为您在与 Lambda 函数相关的主题学习中打下良好的基础。

以下是关键要点:如果您希望自己的 Lambda 函数与其他 AWS 服务交互,则需要向您的函数在其他服务上运行的权限。

如果您希望其他服务调用您的函数,则需要使用基于资源的策略来授予这些服务访问您的函数的权限。

知识测验

您现在已经完成了“模块 4:使用其他 AWS 服务”。以下测试可让您检查到目前为止学到的内容。

1.若您想让其他服务调用 Lambda 函数,您需要做什么?(选择一项)

a.创建 ACL 文档,向其他服务以之运行的角色授予调用 Lambda 函数的权限5

b.创建基于资源的策略文档,向调用服务授予调用 Lambda 函数的权限

c.无需执行任何操作,因为 Lambda 信任所有其他 AWS 服务

d.向 Lambda 函数以之运行的角色添加正确的权限1

2.您需要向角色添加什么才能授予其访问 AWS 服务的权限?(选择一项)

a.无需添加任何内容,所有角色都可以访问其他 AWS 服务。

b.基于资源的策略

c.具有必要权限的策略

d.访问控制列表文档

3.创建与 Lambda 函数以之运行的角色一起使用的客户管理策略的两种方法是什么?(选择两项)

a.通过命令行

b.包含在函数的源代码中

c.通过 AWS 管理控制台

d.执行函数时将其添加到负载中

答案:1-b,2-c,3-ac

结论

在这个相对简短的模块中,您了解了很多内容。有人会说,了解角色和策略是在 AWS 上学习的最重要的内容之一。希望这能为您在与 Lambda 函数相关的主题学习中打下良好的基础。

以下是关键要点:如果您希望自己的 Lambda 函数与其他 AWS 服务交互,则需要向您的函数在其他服务上运行的权限。

如果您希望其他服务调用您的函数,则需要使用基于资源的策略来授予这些服务访问您的函数的权限。

此页内容对您是否有帮助?

单元测试和调试