AWS Lambda
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

教程:使用 AWS CloudTrail 事件触发 Lambda 函数

您可以配置 Amazon S3 以在 AWS CloudTrail 存储 API 调用日志时将事件发布到 AWS Lambda。Lambda 函数可读取日志对象并处理由 CloudTrail 记录的访问记录。

使用以下说明创建一个 Lambda 函数,该函数在您的账户中进行特定的 API 调用时向您发送通知。该函数处理来自 Amazon S3 的通知事件,从存储桶中读取日志,并通过 Amazon SNS 主题发布警报。在本教程中,您将创建:

  • 一个 CloudTrail 跟踪和一个用于保存日志的 S3 存储桶。

  • 一个用于发布警报通知的 Amazon SNS 主题。

  • 一个 IAM 用户角色,具有从 S3 存储桶读取项目并将日志写入 Amazon CloudWatch 的权限。

  • 一个 Lambda 函数,用于处理 CloudTrail 日志并在创建 Amazon SNS 主题时发送通知。

要求

本教程假设您对基本 Lambda 操作和 Lambda 控制台有一定了解。如果尚不了解,请按照开始使用 AWS Lambda中的说明创建您的第一个 Lambda 函数。

开始之前,请确保您具有以下工具:

步骤 1:在 CloudTrail 中创建跟踪

在创建跟踪时,CloudTrail 将 API 调用记录在日志文件中,并将这些文件存储在 Amazon S3 中。CloudTrail 日志是 JSON 格式的一系列无序事件。对于支持的 API 操作的每次调用,CloudTrail 会记录请求信息,以及发出请求的实体。日志事件包含操作名称、参数、响应值以及有关请求者的详细信息。

创建跟踪

  1. 打开 CloudTrail 控制台的 Trails (跟踪) 页面

  2. 选择 Create trail (创建跟踪)

  3. 对于 Trail name (跟踪名称),输入一个名称。

  4. 对于 S3 bucket (S3 存储桶),输入一个名称。

  5. 选择 Create

  6. 保存存储桶 Amazon 资源名称 (ARN) 以将它添加到您稍后创建的 IAM 执行角色。

步骤 2:创建 Amazon SNS 主题

创建一个 Amazon SNS 主题,以在发生新的对象事件时发出通知。

要创建主题,请执行以下操作

  1. 打开 Amazon SNS 控制台的 Topics (主题)

  2. 选择 Create topic (创建主题)

  3. 对于 Topic name (主题名称),输入一个名称。

  4. 选择 Create topic (创建主题)

  5. 记录主题 ARN。您将在创建 IAM 执行角色和 Lambda 函数时需要它。

步骤 3:创建 IAM 执行角色

执行角色向您的函数授予访问 AWS 资源的权限。创建一个执行角色,该角色向函数授予访问 CloudWatch Logs、Amazon S3 和 Amazon SNS 的权限。

创建执行角色

  1. 打开 IAM 控制台的 Roles (角色)

  2. 选择创建角色

  3. 创建具有以下属性的角色:

    • 对于 Trusted entity (可信实体),选择 Lambda

    • 对于 Role Name (角色名称),输入 lambda-cloudtrail-role

    • 对于 Permissions (权限),使用以下语句创建自定义策略。将突出显示的值替换为存储桶和主题的名称。

      { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:*" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "s3:GetObject" ], "Resource": "arn:aws:s3:::my-bucket/*" }, { "Effect": "Allow", "Action": [ "sns:Publish" ], "Resource": "arn:aws:sns:us-west-2:123456789012:my-topic" } ] }
  4. 记录角色 ARN。您在创建 Lambda 函数时将需要它。

步骤 4:创建 Lambda 函数

以下 Lambda 函数处理 CloudTrail 日志,并在创建新的 Amazon SNS 主题时通过 Amazon SNS 发送通知。

创建函数

  1. 创建一个文件夹,并为该文件夹提供一个名称来指示它是您的 Lambda 函数(例如,lambda-cloudtrail)。

  2. 在该文件夹中,创建一个名为 index.js 的文件。

  3. 将以下代码粘贴到 index.js。将 Amazon SNS 主题 ARN 替换为 Amazon S3 在您创建 Amazon SNS 主题时创建的 ARN。

    var aws = require('aws-sdk'); var zlib = require('zlib'); var async = require('async'); var EVENT_SOURCE_TO_TRACK = /sns.amazonaws.com/; var EVENT_NAME_TO_TRACK = /CreateTopic/; var DEFAULT_SNS_REGION = 'us-east-2'; var SNS_TOPIC_ARN = 'arn:aws:sns:us-west-2:123456789012:my-topic'; var s3 = new aws.S3(); var sns = new aws.SNS({ apiVersion: '2010-03-31', region: DEFAULT_SNS_REGION }); exports.handler = function(event, context, callback) { var srcBucket = event.Records[0].s3.bucket.name; var srcKey = event.Records[0].s3.object.key; async.waterfall([ function fetchLogFromS3(next){ console.log('Fetching compressed log from S3...'); s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function uncompressLog(response, next){ console.log("Uncompressing log..."); zlib.gunzip(response.Body, next); }, function publishNotifications(jsonBuffer, next) { console.log('Filtering log...'); var json = jsonBuffer.toString(); console.log('CloudTrail JSON from S3:', json); var records; try { records = JSON.parse(json); } catch (err) { next('Unable to parse CloudTrail JSON: ' + err); return; } var matchingRecords = records .Records .filter(function(record) { return record.eventSource.match(EVENT_SOURCE_TO_TRACK) && record.eventName.match(EVENT_NAME_TO_TRACK); }); console.log('Publishing ' + matchingRecords.length + ' notification(s) in parallel...'); async.each( matchingRecords, function(record, publishComplete) { console.log('Publishing notification: ', record); sns.publish({ Message: 'Alert... SNS topic created: \n TopicARN=' + record.responseElements.topicArn + '\n\n' + JSON.stringify(record), TopicArn: SNS_TOPIC_ARN }, publishComplete); }, next ); } ], function (err) { if (err) { console.error('Failed to publish notifications: ', err); } else { console.log('Successfully published all notifications.'); } callback(null,"message"); }); };
  4. lambda-cloudtrail 文件夹中,运行以下脚本。它会创建一个 package-lock.json 文件和一个 node_modules 文件夹,处理所有依赖项。

    $ npm install async
  5. 运行以下脚本可创建部署程序包。

    $ zip -r function.zip .
  6. 使用 create-function 命令通过运行以下脚本来创建一个名为 CloudTrailEventProcessing 的 Lambda 函数。进行指示的替换。

    $ aws lambda create-function --function-name CloudTrailEventProcessing \ --zip-file fileb://function.zip --handler index.handler --runtime nodejs12.x --timeout 10 --memory-size 1024 \ --role arn:aws:iam::123456789012:role/lambda-cloudtrail-role

步骤 5:向 Lambda 函数策略添加权限

Lambda 函数的资源策略需要权限以允许 Amazon S3 调用函数。

向 Amazon S3 授予调用函数的权限

  1. 运行以下 add-permission 命令。将 ARN 和账户 ID 替换为您自己的 ARN 和账户 ID。

    $ aws lambda add-permission --function-name CloudTrailEventProcessing \ --statement-id Id-1 --action "lambda:InvokeFunction" --principal s3.amazonaws.com \ --source-arn arn:aws:s3:::my-bucket \ --source-account 123456789012

    此命令向 Amazon S3 服务委托人 (s3.amazonaws.com) 授予执行 lambda:InvokeFunction 操作的权限。仅在满足以下条件时向 Amazon S3 授予调用权限:

    • CloudTrail 将日志对象存储在指定的存储桶中。

    • 存储桶由指定的 AWS 账户拥有。如果存储桶拥有者删除一个存储桶,则其他 AWS 账户可以创建同名存储桶。该条件确保只有特定的 AWS 账户能调用您的 Lambda 函数。

  2. 要查看 Lambda 函数的访问策略,请运行以下 get-policy 命令,并替换函数名称。

    $ aws lambda get-policy --function-name function-name

步骤 6:在 Amazon S3 存储桶上配置通知

要请求 Amazon S3 将对象创建的事件发布到 Lambda,请将通知配置添加到 S3 存储桶。在配置中,指定以下内容:

  • 事件类型 – 任何创建对象的事件类型。

  • Lambda 函数 – 您希望 Amazon S3 调用的 Lambda 函数。

配置通知

  1. 打开 Amazon S3 控制台

  2. 选择源存储桶。

  3. 选择属性

  4. Events (事件) 下,使用以下设置配置通知:

    • Name (名称)lambda-trigger

    • Events (事件)All object create events

    • Send to (发送到)Lambda function

    • LambdaCloudTrailEventProcessing

当 CloudTrail 将日志存储在存储桶中时,Amazon S3 会向函数发送一个事件。该事件提供了信息,包括存储桶名称和 CloudTrail 创建的日志对象的键名称。