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

教程:将 AWS Lambda 与 AWS CloudTrail 结合使用

在这种情况下,AWS CloudTrail 将保留对您的账户进行的 AWS API 调用的记录(日志),并在每次发生用于创建 SNS 主题的 API 调用时通知您。由于 API 是在您的账户中调用的,CloudTrail 会将日志写入到您配置的 Amazon S3 存储桶中。在这种情况下,您希望 Amazon S3 在 CloudTrail 创建日志对象时将对象创建事件发布到 AWS Lambda 并调用 Lambda 函数。

下图概述了该流程:

  1. AWS CloudTrail 将日志保存到 S3 存储桶(对象创建事件)。

  2. Amazon S3 检测到对象创建事件。

  3. 按照存储桶通知配置的规定,Amazon S3 通过调用 Lambda 函数将 s3:ObjectCreated:* 事件发布到 AWS Lambda。由于 Lambda 函数的访问权限策略包括 Amazon S3 调用该函数的权限,因此 Amazon S3 可调用该函数。

  4. AWS Lambda 通过代入您在创建 Lambda 函数时指定的执行角色来执行 Lambda 函数。

  5. Lambda 函数读取其作为参数接收的 Amazon S3 事件、确定 CloudTrail 对象的位置、读取 CloudTrail 对象,然后处理 CloudTrail 对象中的日志记录。

  6. 如果日志包含带有特定 eventTypeeventSource 值的记录,即将该事件发布到您的 Amazon SNS 主题。在教程:将 AWS Lambda 与 AWS CloudTrail 结合使用中,您使用电子邮件协议订阅该 SNS 主题,因此您会收到电子邮件通知。

当 Amazon S3 调用 Lambda 函数时,它会传递标识存储桶名称和 CloudTrail 创建的对象的键名称等的 S3 事件。Lambda 函数可读取该日志对象,并了解日志中报告的 API 调用。

CloudTrail 在 S3 存储桶中创建的每个对象都是包含一个或多个事件记录的 JSON 对象。此外,每条记录提供的内容都包括 eventSourceeventName

{ "Records":[ { "eventVersion":"1.02", "userIdentity":{ ... }, "eventTime":"2014-12-16T19:17:43Z", "eventSource":"sns.amazonaws.com", "eventName":"CreateTopic", "awsRegion":"us-east-2", "sourceIPAddress":"72.21.198.64", ... }, { ... }, ... }

为了展示这个过程,如果日志中报告了用于创建 Amazon SNS 主题的 API 调用,Lambda 函数会通过电子邮件向您发送通知。也就是说,Lambda 函数在分析日志时会查找包含以下内容的记录:

  • eventSource = "sns.amazonaws.com"

  • eventName = "CreateTopic"

如果找到,该函数会将该事件发布到 Amazon SNS 主题(您配置此主题以通过电子邮件向您发送通知)。

Lambda 函数将使用一个 S3 事件,该事件提供了存储桶名称和 CloudTrail 创建的对象的键名称。Lambda 函数随后读取该对象以处理 CloudTrail 记录。

先决条件

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

为了遵循本指南中的步骤,您需要命令行终端或外壳,以便运行命令。命令显示在列表中,以提示符 ($) 和当前目录名称(如果有)开头:

~/lambda-project$ this is a command this is output

对于长命令,使用转义字符 (\) 将命令拆分到多行中。

在 Linux 和 macOS 中,可使用您首选的外壳程序和程序包管理器。在 Windows 10 中,您可以 安装 Windows Subsystem for Linux,获取 Ubuntu 和 Bash 与 Windows 集成的版本。

启用 CloudTrail

在 AWS CloudTrail 控制台中,通过为 CloudTrail 指定存储桶来保存日志,从而在您的账户中启用跟踪。配置跟踪时,不要启用 SNS 通知。

有关说明,请参阅 AWS CloudTrail User Guide 中的创建和更新您的跟踪

创建执行角色

创建执行角色,向您的函数授予访问 AWS 资源的权限。

创建执行角色

  1. 打开 IAM 控制台中的“角色”页面

  2. 选择 Create role (创建角色)

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

    • 可信任的实体AWS Lambda

    • 角色名称 (角色名称)lambda-cloudtrail-role

    • 权限 – 自定义策略。

      { "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" } ] }

此策略具有该函数从 Amazon S3 中读取项目并将日志写入 CloudWatch Logs 所需的权限。

创建函数

以下示例处理 CloudTrail 日志,并在创建 Amazon SNS 主题时发送通知。

例 index.js

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"); }); };

创建函数

  1. 将示例代码复制到名为 lambda-cloudtrail 的文件夹中名为 index.js 的文件。

  2. 使用 npm 安装 async

    ~/lambda-cloudtrail$ npm install async
  3. 创建部署程序包。

    ~/lambda-cloudtrail$ zip -r function.zip .
  4. 使用 create-function 命令创建 Lambda 函数。

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

向函数策略添加权限

向 Lambda 函数的资源策略添加权限以允许 Amazon S3 调用该函数。

  1. 运行下面的 add-permission 命令以向 Amazon S3 服务委托人 (s3.amazonaws.com) 授予执行 lambda:InvokeFunction 操作的权限。请注意,向 Amazon S3 授予权限,使其只能在满足以下条件时调用该函数:

    • 在特定的存储桶上检测到对象创建事件。

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

    $ 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
  2. 使用 get-policy 命令验证函数的访问策略。

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

在存储桶上配置通知

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

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

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

    arn:aws:lambda:us-east-2:123456789012:function:CloudTrailEventProcessing

有关向存储桶添加通知配置的说明,请参阅 Amazon Simple Storage Service 控制台用户指南 中的启用事件通知

测试设置

现在,可以按以下方式测试设置:

  1. 创建一个 Amazon SNS 主题。

  2. AWS CloudTrail 在存储桶中创建日志对象。

  3. Amazon S3 会通过将该日志对象的位置作为事件数据传递来调用 Lambda 函数。

  4. Lambda 执行您的函数。函数将检索日志,查找 CreateTopic 事件,并发送通知。