AWS Lambda での.NET ワークロード

モジュール 4

モジュール 4: 他の AWS サービスとの連携

 学習モジュール

ここで紹介した例を参考にしてもかまいませんが、その必要はありません。

他の AWS サービスと連携する方法はいくつかあります。

アクセスしているサービスが SQL Server や Postgres などの AWS RDS データベースである場合は、データベースを自分のコンピューターまたはデータセンターでホストする場合と同じライブラリを使用します。ユーザー名とパスワードを含む接続文字列、または任意の別の形式の認証が必要です。データベースを日常的に使用するのと何も変わりません。データベースサーバーにアクセスするには、追加の権限は必要ありません。唯一の注意点は、データベースがパブリックにアクセスできない場合、Lambda を VPC に接続する必要があることです (そのプロセスには追加の権限が必要です)。

Lambda 関数が S3、DynamoDB、Kinesis などを使用している場合は、AWS SDK を使用してそれらのサービスとやり取りします。Lambda 関数が実行されているロールには、各サービスとやり取りするための適切な権限が必要です。たとえば、S3 バケットに項目を追加する場合、ロールにはそのバケットへの書き込み権限が必要です。DynamoDB テーブルから項目を取得する場合、ロールにはそのテーブルから読み取る権限が必要です。

3 番目のシナリオは、あるイベントに応答して別のサービスに Lambda 関数をトリガーさせたい場合です。たとえば、特定の S3 バケットに新しい項目が追加されたときや、Kinesis ストリームにイベントが到着したときに、Lambda 関数をトリガーしたい場合があります。そのためには、Lambda 関数が「リソースベースのポリシー」を使用する必要があります。このポリシーは、他のサービスに Lambda 関数を呼び出す権限を与えます。

 所要時間

30 分 

Lambda 関数から RDS データベースサーバーにアクセスする

SQL Server、Postgres、MySQL などの使い慣れたサービスを使用するメリットは、コードの観点から見ると、Lambda 関数から呼び出すときに何も変更する必要がないことです。エンティティフレームワーク/ADO/NpgSql などは、AWS がホストするデータベースでも、ローカル/ラック型データベースでも同様に機能します。同じように呼びますが、AWS SDK ライブラリは必要ありません。もちろん、関連する NuGet パッケージをプロジェクトに追加する必要があります。しかし、それ以外はすべて同じです。

Lambda 関数から AWS サービスにアクセスする

ほとんどの AWS サービスにアクセスするには、Lambda 関数にそのサービスとやり取りする権限を与える必要があります。これを行うには、Lambda 関数が実行されているロールにポリシーを追加します。ポリシーでは、Lambda 関数にサービスとやり取りするためのアクセス権限を付与する必要があります。ポリシーを作成するには、次の 2 つの方法があります。
1. インラインポリシーとして、そのロールでのみ使用します。

2.任意のロールにアタッチできるスタンドアロンポリシーとして。AWS では、後者は顧客管理ポリシーと呼ばれます。

ロールにはできるだけ少ない権限を与えることをお勧めします。DynamoDB テーブルからデータを読み取る次の例では、Lambda ロールに DynamoDB: GetItem と dynamodb: DescribeTable という 2 つの権限を付与する必要があります。また、それらの権限を関心のある特定のテーブルに制限します。

まず、People という名前の新しい DynamoDB テーブルを作成します。Windows コマンドプロンプトを使用している場合は、次のコマンドが PowerShell でも機能します。Linux シェルでは、文字列に対して異なるエスケープ処理が必要になります。

次のクエリを実行します。
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"}}'
これで、3 つの項目を含むテーブルができました。

次に、以下を使用して 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 デプロイ - Lambda 関数 DynamoDB

次に、「コードに AWS 認証情報を提供する IAM ロールを選択してください」という質問が表示され、以前に作成したロールのリストが表示される場合がありますが、リストの一番下に「*** Create new IAM Role ***」というオプションがあり、そのオプションの横にその番号を入力します。

「新しい IAM ロールの名前を入力してください:」と表示されます。「LambdaFunctionDynamoDBRoleと入力します。」

次に、「新しいロールにアタッチして権限を付与する IAM ポリシーを選択」するように求められ、ポリシーのリストが表示されます。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"
「...dunamodb 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 Gateway へのリクエストの到着などがあります。いずれの場合も、Lambda 関数は別の AWS サービスによって呼び出されます。

前のセクションでは、他のサービスでアクションを実行する権限を Lambda 関数に付与する方法について説明しました。このセクションでは、他のサービスに Lambda 関数を呼び出すアクセス権限を与える方法を説明します。

serverless.* テンプレートを使用している場合は、Lambda 関数を呼び出すために必要なアクセス権限をすでに API Gateway に付与しているはずです。このような機能をデプロイした場合は、[設定] タブに移動し、左側の [権限] を選択し、[リソースベースのポリシー] セクションまでスクロールします。API ゲートウェイが Lambda 関数を呼び出すことを許可するポリシーが表示されます。このポリシーは、dotnet lambda デプロイサーバーレスコマンドと、プロジェクト内の serverless.template によって追加されました。

以下の画像では、API Gateway が Lambda 関数を呼び出すことを許可する 2 つのポリシーステートメントを示しています。
ただし、これから取り上げる例では、S3 バケットでファイルを作成または削除するたびに、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

Lambda 関数を作成する

S3 イベントの処理に役立つ Lambda 関数テンプレートがあります。必要な 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 ロールを選択してください」という質問が表示され、以前に作成したロールのリストが表示される場合がありますが、リストの一番下に「*** Create new IAM Role ***」というオプションがあり、そのオプションの横にその番号を入力します。

「新しい IAM ロールの名前を入力してください:」と表示されます。「S3EventHandlerRole」と入力します。

次に、「新しいロールにアタッチして権限を付与する IAM ポリシーを選択」するように求められ、ポリシーのリストが表示されます。AWSLambdaBasicExecutionRole を選択してください。私のリストの 6 番目です。GetObjectMetadataAsync (..) 呼び出しを機能させるには、S3 バケットへのアクセスを許可するポリシーを追加する必要があります。

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 関数に移動します。

[設定] タブをクリックし、左側の [権限] をクリックして、ロールの名前をクリックします。
これにより、ロールの詳細が記載された新しいページが開きます。

[ Add permissions (権限の追加)] と [ Attach policies (ポリシーを添付する)] をクリックします。

[Create Policy (ポリシーの作成)] をクリックします。

サービスセクションで、強調表示されたテキストボックスに「s3」と入力し、S3 を選択します。

「アクション」セクションで「getobject」と入力し、リストから「GetObject」を選択します。

リソースセクションで [特定] を選択し、[Add ARN (ARN の追加)] をクリックします。

バケット名を入力し、オブジェクト名として [Any] を選択します。
ポリシーの名前を入力し、[ポリシーの作成] をクリックします。

[ポリシーの作成] をクリックしたタブに戻ります。以下の手順を実行してください。

1.ポリシーのリストをリロードする

2.フィルタにS3AccessPolicyForCourseBucket を入力します

3.ポリシーの横にあるボックスにチェックを入れてください

4.[Attach policies (ポリシーを添付する)] をクリックします。

この時点で、S3 バケット、Lambda 関数、S3 バケットからオブジェクトメタデータを取得するために必要な権限が揃っています。

次は S3 バケットを Lambda 関数に接続して、作成イベントと削除イベントによって Lambda 関数がトリガーされるようにします。

S3 バケットから Lambda 関数をトリガーする

これまで見てきたように、AWS コマンドラインツールと UI コンソールを使用できるのは良いことです。次のステップでは、UI コンソールを使用します。これは、このステップの方が簡単でわかりやすいためです。

S3 https://s3.console.aws.amazon.com/s3/buckets のバケットのリストを開きます。

作成したものをクリックします。
[Properties] (プロパティ) タブを選択します。

「イベント通知」セクションまでスクロールします。

イベント通知を作成」をクリックします。

イベント通知の名前を入力します。

左側の最初の 2 つのチェックボックス ([すべてのオブジェクト作成イベント] と [すべてのオブジェクト削除イベント]) を選択します。

一番下の「目的地」セクションまでスクロールします。

送信先として Lambda 関数を選択します。

ドロップダウンリストに、以前に作成した Lambda 関数の名前を入力します。

[変更を保存] をクリックします。

完了すると、この新しいイベント通知がイベント通知セクションに表示されます。

AWS コンソールで、前に作成した Lambda 関数に移動します。

S3 が Lambda 関数のトリガーとしてリストされるようになったことに注意してください。

[設定] タブをクリックし、左側の [権限] をクリックします。

「リソースベースのポリシー」セクションまでスクロールします

S3 が Lambda 関数を呼び出すことを許可するポリシーステートメントが表示されます。
ポリシーステートメントを確認するには、ステートメント ID をクリックします。

テストしてみる

この Lambda 関数は呼び出し元 (この場合は S3) に何も返しません。

代わりに、Lambda 関数が 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 に記録したテキストを示すログエントリが表示されます。
ログを確認するもう 1 つの方法は、Visual Studio、Visual Studio Code、および Rider の AWS 拡張機能を使用することです。

手順は 3 つとも同様です。AWS 拡張機能を開き、CloudWatch ログをクリックして、/aws/Lambda/S3EventHandler のログストリーム/グループを探します。次に、最新のストリームを開きます。
ログを確認するもう 1 つの方法は、Visual Studio、Visual Studio Code、および Rider の AWS 拡張機能を使用することです。

手順は 3 つとも同様です。AWS 拡張機能を開き、CloudWatch ログをクリックして、/aws/Lambda/S3EventHandler のログストリーム/グループを探します。次に、最新のストリームを開きます。

まとめ

この比較的短いモジュールでは、多くの分野について説明しました。ロールとポリシーを理解することは、AWS で学ぶべき最も重要なことの 1 つだと言う人もいます。これで、Lambda 関数に関するトピックの基礎が理解できたと願っています。

ここで重要なポイントは、Lambda 関数が他の AWS サービスとやり取りできるようにするには、そのサービス上で動作するためのアクセス権限を関数に与える必要があるということです。

他のサービスで関数を呼び出したい場合は、リソースベースのポリシーを使用して、それらのサービスが関数にアクセスできるようにする必要があります。

知識のチェック

これで、モジュール 4「他の AWS サービスの使用」を完了しました。以下のテストでは、これまでに学んだことを確認できます。

1.別のサービスで Lambda 関数を呼び出したい場合、何をする必要がありますか?(1 つ選択してください)

a.他のサービスが実行するロールに、Lambda 関数 5 を呼び出す権限として付与する ACL ドキュメントを作成します。

b.呼び出し元サービスに Lambda 関数を呼び出すアクセス権限を与えるリソースベースのポリシードキュメントを作成する

c.何もありません。Lambda は他のすべての AWS サービスを信頼しています

d.Lambda 関数が 1 として実行するロールに正しいアクセス権限を追加します。

2.AWS サービスにアクセスする権限をロールに付与するには、ロールに何を追加する必要がありますか?(1 つ選択してください)

a.何もありません。すべてのロールが他の AWS サービスにアクセスできます。

b.リソースベースのポリシー

c.必要な権限を持つポリシー

d.アクセス制御リスト文書

3.Lambda 関数が実行されるロールで使用する顧客管理ポリシーを作成するには、次の 2 つの方法がありますか?(2 つ選択してください)

a.コマンドラインを使用する:

b.関数のソースコードに含める

c.その AWS コンソール経由

d.関数を実行するときにペイロードに追加します

回答:1-b、2-c、3-ac

まとめ

この比較的短いモジュールでは、多くの分野について説明しました。ロールとポリシーを理解することは、AWS で学ぶべき最も重要なことの 1 つだと言う人もいます。これで、Lambda 関数に関するトピックの基礎が理解できたと願っています。

ここで重要なポイントは、Lambda 関数が他の AWS サービスとやり取りできるようにするには、そのサービス上で動作するためのアクセス権限を関数に与える必要があるということです。

他のサービスで関数を呼び出したい場合は、リソースベースのポリシーを使用して、それらのサービスが関数にアクセスできるようにする必要があります。

このページは役に立ちましたか?

ローカルでのユニットテストおよびデバッグ