使用 AWS Lambda 代币自动售货机为 Amazon S3 实施 SaaS 租户隔离 - AWS Prescriptive Guidance

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 AWS Lambda 代币自动售货机为 Amazon S3 实施 SaaS 租户隔离

由 Tabby Ward (AWS)、Sravan Periyathambi () 和 Thomas Davis () AWS 创作 AWS

环境:PoC 或试点

技术:现代化

AWS服务:AWSIdentity and Access Management;AWSLambda;Amazon S3;AWSSTS

Summary

多租户 SaaS 应用程序必须实施系统,以确保保持租户隔离。当您将租户数据存储在同一 Amazon Web Services (AWS) 资源上时,例如多个租户将数据存储在同一个亚马逊简单存储服务 (Amazon S3) 存储桶中,则必须确保不会发生跨租户访问。代币自动售货机 (TVMs) 是提供租户数据隔离的一种方式。这些机器提供了一种获取令牌的机制,同时减少了这些令牌生成方式的复杂性。开发人员可以在不详细了解如何生成代币TVM的情况下使用。

此模式TVM通过使用 AWS Lambda 实现了。TVM生成一个令牌,该令牌由临时安全令牌服务 (STS) 凭证组成,这些凭证限制对 S3 存储桶中单个 SaaS 租户数据的访问。

TVMs,以及此模式提供的代码,通常用于源自 JSON Web Tokens (JWTs) 的声明,以将AWS资源请求与租户范围的 Ident AWS ity and Access Management (IAM) 策略关联起来。您可以使用此模式中的代码作为基础来实现 SaaS 应用程序,该应用程序根据JWT令牌中提供的声明生成限定范围的临时STS证书。

先决条件和限制

先决条件

限制

  • 此代码在 Java 中运行,当前不支持其他编程语言。 

  • 示例应用程序不包括AWS跨区域或灾难恢复 (DR) 支持。 

  • 此模式演示了 SaaS 应用程序的 Lambd TVM a 如何提供限定范围的租户访问权限。它不用于生产环境。

架构

目标技术堆栈

  • AWSLambda

  • Amazon S3

  • IAM

  • AWS安全令牌服务 (AWSSTS)

目标架构

生成令牌以获取访问 S3 存储桶中数据的临时STS证书。

工具

AWS服务

代码

此模式的源代码以附件形式提供,包含以下文件:

  • s3UploadSample.jar提供用于将JSON文档上传到 S3 存储桶的 Lambda 函数的源代码。

  • tvm-layer.zip提供了一个可重复使用的 Java 库,该库为 Lambda 函数提供用于访问 S3 存储桶和上传文档的令牌(STS临时证书)。JSON

  • token-vending-machine-sample-app.zip 提供了用于创建这些构件的源代码和编译说明。

要使用这些文件,请按照下一节中的说明操作。

操作说明

任务描述所需技能

确定变量值。

此模式的实现包含几个必须一致使用的变量名。确定每个变量应使用的值,并在后续步骤请求时提供该值。

< AWS 账户 ID> ─ 与您实施此模式的账户关联的 12 位数AWS账户 ID。有关如何查找您的AWS账号 ID 的信息,请参阅IAM文档中的您的AWS账户 ID 及其别名

< AWS Region> ─ 您正在实施此模式的AWS区域。有关AWS区域的更多信息,请参阅AWS网站上的区域和可用区

< sample-tenant-name > ─ 要在应用程序中使用的租户的名称。为简单起见,我们建议您在此值仅使用字母数字字符,但您可以为 S3 对象密钥使用任何有效名称

< sample-tvm-role-name > ─ 附加到运行TVM和示例应用程序的 Lambda 函数的IAM角色名称。角色名称是由大小写字母数字字符组成的字符串(不包含空格)。您还可以包含以下任何字符:下划线(_)、加号(+)、等号(=)、逗号(,)、句号(.)、@(@)、连字符(-)。角色名称在账户中必须是唯一的。

< sample-app-role-name > ─ Lambda 函数在生成限定范围的临时证书时所扮演的IAM角色的名称。STS角色名称是由大小写字母数字字符组成的字符串(不包含空格)。您还可以包含以下任何字符:下划线(_)、加号(+)、等号(=)、逗号(,)、句号(.)、@(@)、连字符(-)。角色名称在账户中必须是唯一的。

< sample-app-function-name > ─ Lambda 函数的名称。这是一个长度最多 64 个字符的字符串。

< sample-app-bucket-name > ─ 必须使用限定于特定租户的权限访问的 S3 存储桶的名称。S3 存储桶名称:

  • 长度必须介于 3-63 个字符之间。

  • 只能由小写字母、数字、句点 (.) 和连字符 (-) 组成。

  • 必须以字母或数字开头和结尾。

  • 不得采用 IP 地址格式(例如,192.168.5.4)。

  • 在分区中必须是唯一的。分区是一组区域。AWS目前有三个分区:aws (标准区域)、aws-cn(中国区域)和aws-us-gov(AWS GovCloud [美国] 区域)。

云管理员
任务描述所需技能

为示例应用程序创建一个 S3 存储桶。

使用以下AWSCLI命令创建 S3 存储桶。在代码片段中提供 < sample-app-bucket-name > 值:

aws s3api create-bucket --bucket <sample-app-bucket-name>

Lambda 示例应用程序将JSON文件上传到此存储桶。

云管理员
任务描述所需技能

创建TVM角色。

使用以下AWSCLI命令之一创建IAM角色。在命令中提供 < sample-tvm-role-name > 值。

对于 macOS 或 Linux shell:

aws iam create-role \ --role-name <sample-tvm-role-name> \ --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ]}'

对于 Windows 命令行:

aws iam create-role ^ --role-name <sample-tvm-role-name> ^ --assume-role-policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Principal\": {\"Service\": \"lambda.amazonaws.com\"}, \"Action\": \"sts:AssumeRole\"}]}"

调用应用程序时,Lambda 示例应用程序将代入此角色。通过范围策略代入应用程序角色的能力,为代码提供了更广泛的权限来访问 S3 存储桶。

云管理员

创建内联TVM角色策略。

使用以下AWSCLI命令之一创建IAM策略。在命令中提供 < sample-tvm-role-name > 、< AWS 账户 ID sample-app-role-name > 和 < > 值。

对于 macOS 或 Linux shell:

aws iam put-role-policy \ --role-name <sample-tvm-role-name> \ --policy-name assume-app-role \ --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::<AWS Account ID>:role/<sample-app-role-name>" } ]}'

对于 Windows 命令行:

aws iam put-role-policy ^ --role-name <sample-tvm-role-name> ^ --policy-name assume-app-role ^ --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": \"sts:AssumeRole\", \"Resource\": \"arn:aws:iam::<AWS Account ID>:role/<sample-app-role-name>\"}]}"

该策略已附加到该TVM角色。它使代码能够代入应用程序角色,该角色具有更广泛的 S3 存储桶访问权限。

云管理员

附加托管 Lambda 策略。

使用以下AWSCLI命令附加AWSLambdaBasicExecutionRole IAM策略。在命令中提供 < sample-tvm-role-name > 值:

aws iam attach-role-policy \ --role-name <sample-tvm-role-name> \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

对于 Windows 命令行:

aws iam attach-role-policy ^ --role-name <sample-tvm-role-name> ^ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

此托管策略附加到该TVM角色,允许 Lambda 向亚马逊发送日志。 CloudWatch

云管理员
任务描述所需技能

创建应用程序角色。

使用以下AWSCLI命令之一创建IAM角色。在命令中提供 < sample-app-role-name > 、< AWS 账户 ID sample-tvm-role-name > 和 < > 值。

对于 macOS 或 Linux shell:

aws iam create-role \ --role-name <sample-app-role-name> \ --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<AWS Account ID>:role/<sample-tvm-role-name>" }, "Action": "sts:AssumeRole" } ]}'

对于 Windows 命令行:

aws iam create-role ^ --role-name <sample-app-role-name> ^ --assume-role-policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": \"arn:aws:iam::<AWS Account ID>:role/<sample-tvm-role-name>\"},\"Action\": \"sts:AssumeRole\"}]}"

Lambda 示例应用程序通过限定范围的策略代入此角色,以获得基于租户的 S3 存储桶访问权限。

云管理员

创建内联应用程序角色策略。

使用以下AWSCLI命令之一创建IAM策略。在命令中提供 < sample-app-role-name sample-app-bucket-name > 和 < > 值。

对于 macOS 或 Linux shell:

aws iam put-role-policy \ --role-name <sample-app-role-name> \ --policy-name s3-bucket-access \ --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::<sample-app-bucket-name>/*" }, { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::<sample-app-bucket-name>" } ]}'

对于 Windows 命令行:

aws iam put-role-policy ^ --role-name <sample-app-role-name> ^ --policy-name s3-bucket-access ^ --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObject\"], \"Resource\": \"arn:aws:s3:::<sample-app-bucket-name>/*\"}, {\"Effect\": \"Allow\", \"Action\": [\"s3:ListBucket\"], \"Resource\": \"arn:aws:s3:::<sample-app-bucket-name>\"}]}"

此策略附加在应用程序角色上。提供了对 S3 存储桶中对象的广泛访问权限。当示例应用程序担任该角色时,这些权限将限定为具有动态生成的策略TVM的特定租户。

云管理员
任务描述所需技能

下载编译后源文件。

下载 s3UploadSample.jartvm-layer.zip 文件,它们包含在附件内。token-vending-machine-sample-app.zip 中提供了用于创建这些构件的源代码和编译说明。

云管理员

创建 Lambda 层。

使用以下AWSCLI命令创建 Lambda 层,这样 Lambda 就可以TVM访问了。 

注意:如果您不是从下载位置运行此命令  tvm-layer.zip,请在 --zip-file 参数中提供正确的 tvm-layer.zip 路径。 

aws lambda publish-layer-version \ --layer-name sample-token-vending-machine \ --compatible-runtimes java11 \ --zip-file fileb://tvm-layer.zip

对于 Windows 命令行:

aws lambda publish-layer-version ^ --layer-name sample-token-vending-machine ^ --compatible-runtimes java11 ^ --zip-file fileb://tvm-layer.zip

此命令创建包含可重复使用的TVM库的 Lambda 层。

云管理员、应用程序开发人员

创建 Lambda 函数。

使用以下AWSCLI命令创建 Lambda 函数。在命令中提供 < sample-app-function-name >< AWS 账户 ID>< AWS Reg i on sample-tvm-role-name >< sample-app-bucket-name >、< > 和 < sample-app-role-name > 值。 

注意:如果您不是从下载 s3UploadSample.jar 的位置运行此命令,请在 --zip-file 参数中提供正确的 s3UploadSample.jar 路径。 

aws lambda create-function \ --function-name <sample-app-function-name> \ --timeout 30 \ --memory-size 256 \ --runtime java11 \ --role arn:aws:iam::<AWS Account ID>:role/<sample-tvm-role-name> \ --handler com.amazon.aws.s3UploadSample.App \ --zip-file fileb://s3UploadSample.jar \ --layers arn:aws:lambda:<AWS Region>:<AWS Account ID>:layer:sample-token-vending-machine:1 \ --environment "Variables={S3_BUCKET=<sample-app-bucket-name>, ROLE=arn:aws:iam::<AWS Account ID>:role/<sample-app-role-name>}"

对于 Windows 命令行:

aws lambda create-function ^ --function-name <sample-app-function-name> ^ --timeout 30 ^ --memory-size 256 ^ --runtime java11 ^ --role arn:aws:iam::<AWS Account ID>:role/<sample-tvm-role-name> ^ --handler com.amazon.aws.s3UploadSample.App ^ --zip-file fileb://s3UploadSample.jar ^ --layers arn:aws:lambda:<AWS Region>:<AWS Account ID>:layer:sample-token-vending-machine:1 ^ --environment "Variables={S3_BUCKET=<sample-app-bucket-name>,ROLE=arn:aws:iam::<AWS Account ID>:role/<sample-app-role-name>}"

此命令使用示例应用程序代码和附加TVM层创建一个 Lambda 函数。它还设置了两个环境变量:S3_BUCKETROLE。示例应用程序使用这些变量来确定要扮演的角色以及要将JSON文档上传到的 S3 存储桶。

云管理员、应用程序开发人员
任务描述所需技能

调用 Lambda 示例应用程序。

使用以下AWSCLI命令之一以预期的有效负载启动 Lambda 示例应用程序。在命令中提供 < sample-app-function-name sample-tenant-name > 和 < > 值。

对于 macOS 和 Linux shell:

aws lambda invoke \ --function <sample-app-function-name> \ --invocation-type RequestResponse \ --payload '{"tenant": "<sample-tenant-name>"}' \ --cli-binary-format raw-in-base64-out response.json

对于 Windows 命令行:

aws lambda invoke ^ --function <sample-app-function-name> ^ --invocation-type RequestResponse ^ --payload "{\"tenant\": \"<sample-tenant-name>\"}" ^ --cli-binary-format raw-in-base64-out response.json

此命令调用 Lambda 函数并在 response.json 文档中返回结果。在许多基于 Unix 的系统上,您可以将 response.json 更改为 /dev/stdout,将结果直接输出到 Shell,而无需创建其他文件。 

注意:在后续调用此 Lambda 函数时更改 < sample-tenant-name > 值会更改JSON文档的位置和令牌提供的权限。

云管理员、应用程序开发人员

查看 S3 存储桶,以查看创建的对象。

浏览到您之前创建的 S3 存储桶 (< sample-app-bucket-name >)。此存储桶包含一个 S3 对象前缀,其值为 < sample-tenant-name >。在该前缀下,您将找到一个名为的JSON文档UUID。多次调用示例应用程序会添加更多JSON文档。

云管理员

查看示例应用程序 Cloudwatch 日志。

查看与名为 sample-app-function-name < > 的 Lambda 函数关联的 Cloudwatch 日志。有关说明,请参阅 Lambda 文档中的访问 AWS Lambda 的亚马逊 CloudWatch 日志。AWS您可以在这些日志中查看由生成的租户范围策略TVM。此租户范围策略向 Amazon S3、、、和授予使用示例应用程序的权限 PutObjectGetObjectDeleteObjectListBucketAPIs,但仅限于与 < > 关联的对象前缀。sample-tenant-name在后续调用示例应用程序时,如果您更改 < sample-tenant-name >,则会TVM更新作用域策略,使其与调用负载中提供的租户相对应。这个动态生成的策略显示了如何在 TVM SaaS 应用程序中维护租户范围的访问权限。 

该TVM功能在 Lambda 层中提供,因此无需复制代码即可将其附加到应用程序使用的其他 Lambda 函数。

有关动态生成的策略的说明,请参阅其他信息部分。

云管理员

相关资源

其他信息

以下 Amazon Cloudwatch 日志显示了由该模式中的TVM代码生成的动态生成的策略。在此屏幕截图中,< sample-app-bucket-name >DOC-EXAMPLE-BUCKET< sample-tenant-name >test-tenant-1。除了与对象 key pref test-tenant-1 ix 关联的对象外,此范围策略返回的STS凭证无法对 S3 存储桶中的对象执行任何操作。

JSON policy document allowing S3 actions on a specific bucket with prefix conditions.

附件

要访问与此文档相关联的其他内容,请解压以下文件:attachment.zip