

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

# 在 Amazon 服务中构建多租户无服务器架构 OpenSearch
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service"></a>

*Tabby Ward 和 Nisha Gambhir，Amazon Web Services*

## Summary
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-summary"></a>

Amazon S OpenSearch ervice 是一项托管服务，可以轻松部署、操作和扩展 Elasticsearch，这是一款流行的开源搜索和分析引擎。 OpenSearch 该服务为日志和指标等流式数据提供自由文本搜索以及近乎实时的摄取和仪表板管理。

软件即服务 (SaaS) 提供商经常使用 OpenSearch 服务来解决各种用例，例如以可扩展和安全的方式获取客户见解，同时降低复杂性和停机时间。

在多租户环境中使用 OpenSearch 服务会引入一系列注意事项，这些注意事项会影响 SaaS 解决方案的分区、隔离、部署和管理。SaaS 提供程序必须考虑如何随着不断变化的工作负载有效扩展其 Elasticsearch 集群。他们还需要考虑分层和嘈杂的邻居条件如何影响他们的分区模型。

此模式介绍了用于通过 Elasticsearch 构造表示和隔离租户数据的模型。此外，该模式以简单的无服务器参考架构为例，演示在多租户环境中使用 Serv OpenSearch ice 进行索引和搜索。它实现了池数据分区模型，在所有租户之间共享相同的索引，同时保持租户的数据隔离。此模式使用以下 AWS 服务：亚马逊 API Gateway AWS Lambda、亚马逊简单存储服务 (Amazon S3) Service 和服务。 OpenSearch 

有关池模型和其他数据分区模型的更多信息，请参阅[其他信息](#build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-additional)部分。

## 先决条件和限制
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-prereqs"></a>

**先决条件**
+ 活跃的 AWS 账户
+ [AWS Command Line Interface (AWS CLI) 版本 2.x](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)，已在 macOS、Linux 或 Windows 上安装和配置
+ [Python 版本 3.9](https://www.python.org/downloads/release/python-3921/)
+ [pip3](https://pip.pypa.io/en/stable/) — Python 源代码以.zip 文件形式提供，要部署至 Lambda 函数中。若要在本地使用代码或对其进行自定义，请按照以下步骤开发和重新编译源代码：

  1. 通过在与 Python 脚本相同的目录中运行以下命令以生成 `requirements.txt` 文件：`pip3 freeze > requirements.txt`

  1. 安装依赖项：`pip3 install -r requirements.txt`

**限制**
+ 此代码在 Python 中运行，当前不支持其他编程语言。 
+ 示例应用程序不包括 AWS 跨区域或灾难恢复 (DR) 支持。 
+ 此模式仅用于演示目的。不应在生产环境中使用。

## 架构
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-architecture"></a>

下图展示了此模式的高级架构。该架构包括以下内容：
+ Lambda，用于对内容进行索引和查询 
+ OpenSearch 执行搜索的服务 
+ API Gateway，用于提供与用户的 API 交互
+ Amazon S3，用于存储原始（未编入索引）的数据
+ 亚马逊 CloudWatch 将监控日志
+ AWS Identity and Access Management (IAM) 用于创建租户角色和策略

![\[高级多租户无服务器架构。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/1a8501e7-0776-4aca-aed3-28e3ada1d15d.png)


**自动化和扩展**

为简单起见，该模式 AWS CLI 用于配置基础架构和部署示例代码。您可以创建一个 CloudFormation 或多个 AWS Cloud Development Kit (AWS CDK) 脚本来自动执行该模式。

## 工具
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-tools"></a>

**AWS 服务**
+ [AWS CLI](https://aws.amazon.com/cli/)是一个统一的工具，用于通过在命令行外壳中使用命令来管理和 AWS 服务 资源。
+ [Lambda](https://aws.amazon.com/lambda/) 是一项计算服务，可使您无需预调配或管理服务器即可运行代码。只有在需要时 Lambda 才运行您的代码，并且能自动扩展，从每天几个请求扩展到每秒数千个请求。
+ [API Gateway](https://aws.amazon.com/api-gateway/) AWS 服务 用于创建、发布、维护、监控和保护任何规模的 RES WebSocket APIs T、HTTP。
+ [Amazon S3](https://aws.amazon.com/s3/) 是一种对象存储服务，可让您随时从任何位置在 Web 上存储和检索任意数量的信息。
+ [OpenSearch 服务](https://aws.amazon.com/opensearch-service/)是一项完全托管的服务，可让您轻松地大规模部署、保护和运行 Elasticsearch，经济实惠。

**代码**

附件提供了此模式的示例文件。这些方法包括：
+ `index_lambda_package.zip`— Lambda 函数，用于使用池模型对 OpenSearch 服务中的数据进行索引。
+ `search_lambda_package.zip`— 用于在服务中搜索数据的 Lambda 函数。 OpenSearch 
+ `Tenant-1-data` ‒ Tenant-1 的原始（非索引）数据示例。
+ `Tenant-2-data` ‒ Tenant-2 的原始（非索引）数据示例。

**重要**  
这种模式中的故事包括针对 Unix、Linux 和 macOS 进行格式化的 AWS CLI 命令示例。对于 Windows，请将每行末尾的反斜杠 (\$1) Unix 行继续符替换为脱字号 (^)。

**注意**  
在 AWS CLI 命令中，将尖括号 (<>) 内的所有值替换为正确的值。

## 操作说明
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-epics"></a>

### 创建和配置 S3 存储桶
<a name="create-and-configure-an-s3-bucket"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 S3 存储桶。 | 在您的中创建 S3 存储桶 AWS 区域。此存储桶将保存示例应用程序未编入索引的租户数据。确保 S3 存储桶的名称是全球唯一的，因为命名空间由所有人共享 AWS 账户。要创建 S3 存储桶，您可以按如下方式使用 AWS CLI [create-bu](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/create-bucket.html) cket 命令：<pre>aws s3api create-bucket \<br />  --bucket <tenantrawdata> \<br />  --region <your-AWS-Region></pre>其中 `tenantrawdata` 是 S3 存储桶名称。(您可使用任何符合[存储桶命名准则的](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)唯一名称。) | 云架构师、云管理员 | 

### 创建和配置 Elasticsearch 集群
<a name="create-and-configure-an-elasticsearch-cluster"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 OpenSearch 服务域。 | 运行 AWS CLI [create-elasticsearch-domain](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/es/create-elasticsearch-domain.html)命令创建 OpenSearch 服务域：<pre>aws es create-elasticsearch-domain \<br />  --domain-name vpc-cli-example \<br />  --elasticsearch-version 7.10 \<br />  --elasticsearch-cluster-config InstanceType=t3.medium.elasticsearch,InstanceCount=1 \<br />  --ebs-options EBSEnabled=true,VolumeType=gp2,VolumeSize=10 \<br />  --domain-endpoint-options "{\"EnforceHTTPS\": true}" \<br />  --encryption-at-rest-options "{\"Enabled\": true}" \<br />  --node-to-node-encryption-options "{\"Enabled\": true}" \<br />  --advanced-security-options "{\"Enabled\": true, \"InternalUserDatabaseEnabled\": true, \<br />    \"MasterUserOptions\": {\"MasterUserName\": \"KibanaUser\", \<br />    \"MasterUserPassword\": \"NewKibanaPassword@123\"}}" \<br />  --vpc-options "{\"SubnetIds\": [\"<subnet-id>\"], \"SecurityGroupIds\": [\"<sg-id>\"]}" \<br />  --access-policies "{\"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \ <br />    \"Principal\": {\"AWS\": \"*\" }, \"Action\":\"es:*\", \<br />    \"Resource\": \"arn:aws:es:<region>:<account-id>:domain\/vpc-cli-example\/*\" } ] }"</pre>实例计数设置为 1，因为该域用于测试。您需要使用 `advanced-security-options` 参数启用精细的访问控制，因为创建域后无法更改详细信息。 此命令会创建主用户名 (`KibanaUser`) 和密码，您可使用这些用户名和密码登录 Kibana 控制台。由于该域是虚拟私有云（VPC）的组成部分，因此您必须通过指定要使用的访问策略来确保可以访问 Elasticsearch 实例。有关更多信息，请参阅 AWS 文档中的在 [VPC 内启动您的 Amazon OpenSearch 服务域](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html)。 | 云架构师、云管理员 | 
| 设置堡垒主机。 | 将亚马逊弹性计算云 (亚马逊 EC2) Windows 实例设置为访问 Kibana 控制台的堡垒主机。Elasticsearch 安全组必须允许来自亚马逊 EC2 安全组的流量。有关说明，请参阅博客文章[使用堡垒服务器控制对 EC2 实例的网络访问](https://aws.amazon.com/blogs/security/controlling-network-access-to-ec2-instances-using-a-bastion-server/)。设置堡垒主机并且您拥有与可用实例关联的安全组后，请使用 AWS CLI [authorize-security-group-ingress](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/authorize-security-group-ingress.html)命令向 Elasticsearch 安全组添加权限，允许从 Amazon EC2 （堡垒主机）安全组中访问 443 端口。<pre>aws ec2 authorize-security-group-ingress \<br />  --group-id <SecurityGroupIdfElasticSearch> \ <br />  --protocol tcp \<br />  --port 443 \<br />  --source-group <SecurityGroupIdfBashionHostEC2></pre> | 云架构师、云管理员 | 

### 创建并配置 Lambda 索引函数
<a name="create-and-configure-the-lam-index-function"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 Lambda 执行角色。 | 运行 AWS CLI [create-role](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-role.html) 命令以授予 Lambda 索引函数访问和资源的权限： AWS 服务 <pre>aws iam create-role \<br />  --role-name index-lambda-role \<br />  --assume-role-policy-document file://lambda_assume_role.json</pre>其中 `lambda_assume_role.json` 是用于授予 Lambda 函数 `AssumeRole` 权限的 JSON 文档，如下所示：<pre>{<br />     "Version": "2012-10-17",		 	 	 <br />     "Statement": [<br />         {<br />             "Effect": "Allow",<br />             "Principal": {<br />                 "Service": "lambda.amazonaws.com"<br />               },<br />             "Action": "sts:AssumeRole"<br />         }<br />     ]<br /> }</pre> | 云架构师、云管理员 | 
| 将托管式策略附加到 Lambda 角色。 | 运行 AWS CLI [attach-role-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html)命令将托管策略附加到上一步中创建的角色。这两个策略授予角色创建弹性网络 interface 和向日志写入 CloudWatch 日志的权限。<pre>aws iam attach-role-policy \<br />  --role-name index-lambda-role \<br />  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole<br /><br />aws iam attach-role-policy \<br />  --role-name index-lambda-role \<br />  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole </pre> | 云架构师、云管理员 | 
| 创建策略，以授予 Lambda 索引函数读取 S3 对象的权限。 | 运行 AWS CLI [create-pol](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-policy.html) icy 命令以授予 Lambda 索引函数读取 S3 存储桶中对象的`s3:GetObject`权限：<pre>aws iam create-policy \<br />  --policy-name s3-permission-policy \<br />  --policy-document file://s3-policy.json</pre>文件 `s3-policy.json` 是下面显示的 JSON 文档，它授予允许 `s3:GetObject` 对 S3 对象进行读取访问的权限。如果创建 S3 存储桶时使用了其他名称，请在 `Resource ` 部分中提供正确的存储桶名称：<pre>{<br />    "Version": "2012-10-17",		 	 	 <br />    "Statement": [<br />        {<br />           "Effect": "Allow",<br />           "Action": "s3:GetObject",<br />           "Resource": "arn:aws:s3:::<tenantrawdata>/*"<br />        }<br />    ]<br />}</pre> | 云架构师、云管理员 | 
| 将 Amazon S3 权限策略附加至 Lambda 执行角色。 | 运行 AWS CLI [attach-role-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html)命令将您在上一步中创建的 Amazon S3 权限策略附加到 Lambda 执行角色：<pre>aws iam attach-role-policy \<br />  --role-name index-lambda-role \<br />  --policy-arn <PolicyARN></pre>其中 `PolicyARN` 是 Amazon S3 权限策略的 Amazon 资源名称（ARN）。您可从上一条命令的输出中获得此值。 | 云架构师、云管理员 | 
| 创建 Lambda 索引函数。 | 运行 AWS CLI [create-fun](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) ction 命令创建 Lambda 索引函数，该函数将访问服务： OpenSearch <pre>aws lambda create-function \<br />  --function-name index-lambda-function \<br />  --zip-file fileb://index_lambda_package.zip \<br />  --handler lambda_index.lambda_handler \<br />  --runtime python3.9 \<br />  --role "arn:aws:iam::account-id:role/index-lambda-role" \<br />  --timeout 30 \<br />  --vpc-config "{\"SubnetIds\": [\"<subnet-id1\>", \"<subnet-id2>\"], \<br />    \"SecurityGroupIds\": [\"<sg-1>\"]}"</pre> | 云架构师、云管理员 | 
| 允许 Amazon S3 调用 Lambda 索引函数。 | 运行 add-p AWS CLI [ermission 命令授](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/add-permission.html)予 Amazon S3 调用 Lambda 索引函数的权限：<pre>aws lambda add-permission \<br />  --function-name index-lambda-function \<br />  --statement-id s3-permissions \<br />  --action lambda:InvokeFunction \<br />  --principal s3.amazonaws.com \<br />  --source-arn "arn:aws:s3:::<tenantrawdata>" \<br />  --source-account "<account-id>" </pre> | 云架构师、云管理员 | 
| 为 Amazon S3 事件添加 Lambda 触发器。 | 运行 AWS CLI [put-bucket-notification-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-notification-configuration.html)命令以在检测到 Amazon S3 `ObjectCreated` 事件时向 Lambda 索引函数发送通知。每当将对象上传至 S3 存储桶时，索引函数就会运行。 <pre>aws s3api put-bucket-notification-configuration \<br />  --bucket <tenantrawdata> \<br />  --notification-configuration file://s3-trigger.json</pre>文件 `s3-trigger.json` 是当前文件夹中的一个 JSON 文档，用于在 Amazon S3 `ObjectCreated` 事件发生时向 Lambda 函数添加资源策略。 | 云架构师、云管理员 | 

### 创建并配置 Lambda 搜索函数
<a name="create-and-configure-the-lam-search-function"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 Lambda 执行角色。 | 运行 AWS CLI [create-role](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-role.html) 命令以授予 Lambda 搜索函数访问和资源的权限： AWS 服务 <pre>aws iam create-role \<br />  --role-name search-lambda-role \<br />  --assume-role-policy-document file://lambda_assume_role.json</pre>其中 `lambda_assume_role.json` 是当前文件夹中用于授予 Lambda 函数 `AssumeRole` 权限的 JSON 文档，如下所示：<pre>{<br />     "Version": "2012-10-17",		 	 	 <br />     "Statement": [<br />         {<br />             "Effect": "Allow",<br />             "Principal": {<br />                 "Service": "lambda.amazonaws.com"<br />               },<br />             "Action": "sts:AssumeRole"<br />         }<br />     ]<br /> }</pre> | 云架构师、云管理员 | 
| 将托管式策略附加到 Lambda 角色。 | 运行 AWS CLI [attach-role-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html)命令将托管策略附加到上一步中创建的角色。这两个策略授予角色创建弹性网络 interface 和向日志写入 CloudWatch 日志的权限。<pre>aws iam attach-role-policy \<br />  --role-name search-lambda-role \<br />  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole<br /><br />aws iam attach-role-policy \<br />  --role-name search-lambda-role \<br />  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole </pre> | 云架构师、云管理员 | 
| 创建 Lambda 搜索函数。 | 运行 AWS CLI [create-fun](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) ction 命令创建 Lambda 搜索函数，该函数将访问服务： OpenSearch <pre>aws lambda create-function \<br />  --function-name search-lambda-function \<br />  --zip-file fileb://search_lambda_package.zip \<br />  --handler lambda_search.lambda_handler \<br />  --runtime python3.9 \<br />  --role "arn:aws:iam::account-id:role/search-lambda-role" \<br />  --timeout 30 \<br />  --vpc-config "{\"SubnetIds\": [\"<subnet-id1\>", \"<subnet-id2>\"], \<br />    \"SecurityGroupIds\": [\"<sg-1>\"]}"</pre> | 云架构师、云管理员 | 

### 创建和配置租户角色
<a name="create-and-configure-tenant-roles"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建租户 IAM 角色。 | 运行 AWS CLI [create-](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-role.html) role 命令创建两个用于测试搜索功能的租户角色：<pre>aws iam create-role \<br />  --role-name Tenant-1-role \<br />  --assume-role-policy-document file://assume-role-policy.json</pre><pre>aws iam create-role \<br />  --role-name Tenant-2-role \<br />  --assume-role-policy-document file://assume-role-policy.json</pre>文件 `assume-role-policy.json` 是当前文件夹中的一个 JSON 文档，用于向 Lambda 执行角色授予 `AssumeRole` 权限：<pre>{<br />    "Version": "2012-10-17",		 	 	 <br />    "Statement": [<br />        {<br />            "Effect": "Allow",<br />            "Principal": {<br />                 "AWS": "<Lambda execution role for index function>",<br />                 "AWS": "<Lambda execution role for search function>"<br />             },<br />            "Action": "sts:AssumeRole"<br />        }<br />    ]<br />}</pre> | 云架构师、云管理员 | 
| 创建租户 IAM 策略。 | 运行 AWS CLI [create-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-policy.html) 命令来创建授予对 Elasticsearch 操作的访问权限的租户策略：<pre>aws iam create-policy \<br />  --policy-name tenant-policy \<br />  --policy-document file://policy.json</pre>文件 `policy.json` 是当前文件夹中授予对 Elasticsearch 的权限的 JSON 文档：<pre>{<br />    "Version": "2012-10-17",		 	 	 <br />    "Statement": [<br />        {<br />            "Effect": "Allow",<br />            "Action": [<br />                "es:ESHttpDelete",<br />                "es:ESHttpGet",<br />                "es:ESHttpHead",<br />                "es:ESHttpPost",<br />                "es:ESHttpPut",<br />                "es:ESHttpPatch"<br />            ],<br />            "Resource": [<br />                "<ARN of Elasticsearch domain created earlier>"<br />            ]<br />        }<br />    ]<br />}</pre> | 云架构师、云管理员 | 
| 将租户 IAM policy 附加至租户角色。 | 运行 AWS CLI [attach-role-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html)命令将租户 IAM 策略附加到您在前面的步骤中创建的两个租户角色：<pre>aws iam attach-role-policy \<br />  --policy-arn arn:aws:iam::account-id:policy/tenant-policy \<br />  --role-name Tenant-1-role<br /><br />aws iam attach-role-policy \<br />  --policy-arn arn:aws:iam::account-id:policy/tenant-policy \<br />  --role-name Tenant-2-role</pre>策略 ARN 来自上一步中的输出。 | 云架构师、云管理员 | 
| 创建 IAM 策略，以向 Lambda 授予代入角色的权限。 | 运行 AWS CLI [create-pol](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-policy.html) icy 命令为 Lambda 创建担任租户角色的策略：<pre>aws iam create-policy \<br />  --policy-name assume-tenant-role-policy \<br />  --policy-document file://lambda_policy.json</pre>文件 `lambda_policy.json` 是当前文件夹中的一个 JSON 文档，用于授予对 `AssumeRole` 的权限。<pre>{<br />    "Version": "2012-10-17",		 	 	 <br />    "Statement": [<br />       {<br />            "Effect": "Allow",<br />            "Action":  "sts:AssumeRole",<br />            "Resource": "<ARN of tenant role created earlier>"<br />       }<br />    ]<br />}</pre>对于 `Resource`，您可使用通配符来避免为每个租户创建新策略。 | 云架构师、云管理员 | 
| 创建 IAM 策略，向 Lambda 索引角色授予 Amazon S3 访问权限。 | 运行 AWS CLI [create-pol](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-policy.html) icy 命令以授予 Lambda 索引角色访问 S3 存储桶中对象的权限：<pre>aws iam create-policy \<br />  --policy-name s3-permission-policy \<br />  --policy-document file://s3_lambda_policy.json</pre>文件 `s3_lambda_policy.json` 是当前文件夹中以下 JSON 策略文档：<pre>{<br />    "Version": "2012-10-17",		 	 	 <br />    "Statement": [<br />        {<br />            "Effect": "Allow",<br />            "Action": "s3:GetObject",<br />            "Resource": "arn:aws:s3:::tenantrawdata/*"<br />        }<br />    ]<br />}</pre> | 云架构师、云管理员 | 
| 将该策略附加到 Lambda 执行角色。 | 运行 AWS CLI [attach-role-policy](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html)命令将上一步中创建的策略附加到您之前创建的 Lambda 索引和搜索执行角色：<pre>aws iam attach-role-policy \<br />  --policy-arn arn:aws:iam::account-id:policy/assume-tenant-role-policy \<br />  --role-name index-lambda-role<br /><br />aws iam attach-role-policy \<br />  --policy-arn arn:aws:iam::account-id:policy/assume-tenant-role-policy \<br />  --role-name search-lambda-role<br /><br />aws iam attach-role-policy \<br />  --policy-arn arn:aws:iam::account-id:policy/s3-permission-policy \<br />  --role-name index-lambda-role</pre>策略 ARN 来自上一步中的输出。 | 云架构师、云管理员 | 

### 创建和配置搜索 API
<a name="create-and-configure-a-search-api"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 在 API Gateway 中创建 REST API。 | 运行 AWS CLI [create-rest-api](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/create-rest-api.html)命令创建 REST API 资源：<pre>aws apigateway create-rest-api \<br />  --name Test-Api \<br />  --endpoint-configuration "{ \"types\": [\"REGIONAL\"] }"</pre>对于端点配置类型，您可指定 `EDGE`（而不是 `REGIONAL`）使用边缘站点，而不是某个 AWS 区域。记录命令输出中 `id` 字段的值。这是您将在后续命令使用的 API ID。 | 云架构师、云管理员 | 
| 创建资源，以用于搜索 API。 | 搜索 API 资源使用名为 `search` 的资源启动 Lambda 搜索函数。（您不必为 Lambda 索引函数创建 API，因为当对象上传到 S3 存储桶时，它会自动运行。）[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html) | 云架构师、云管理员 | 
| 为搜索 API 创建 GET 方法。 | 运行 AWS CLI [put-met](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-method.html) hod 命令为搜索 API 创建`GET `方法：<pre>aws apigateway put-method \<br />  --rest-api-id <API-ID> \<br />  --resource-id <ID from the previous command output> \<br />  --http-method GET \<br />  --authorization-type "NONE" \<br />  --no-api-key-required</pre>对于 `resource-id`，请从 `create-resource` 命令输出中指定 ID。 | 云架构师、云管理员 | 
| 为搜索 API 创建响应方法。 | 运行 AWS CLI [put-method-response](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-method-response.html)命令为搜索 API 添加方法响应：<pre>aws apigateway put-method-response \<br />  --rest-api-id <API-ID> \<br />  --resource-id  <ID from the create-resource command output> \<br />  --http-method GET \<br />  --status-code 200 \<br />  --response-models "{\"application/json\": \"Empty\"}"</pre>对于 `resource-id`，请从先前 `create-resource` 命令的输出中指定 ID。 | 云架构师、云管理员 | 
| 为搜索 API 设置代理 Lambda 集成。 | 运行 AWS CLI [put-](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-integration.html) integration 命令设置与 Lambda 搜索函数的集成：<pre>aws apigateway put-integration \<br />  --rest-api-id <API-ID> \<br />  --resource-id  <ID from the create-resource command output> \<br />  --http-method GET \<br />  --type AWS_PROXY \<br />  --integration-http-method GET \<br />  --uri arn:aws:apigateway:region:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account-id>:function:<function-name>/invocations</pre>对于 `resource-id`，请指定先前 `create-resource` 命令中的 ID。 | 云架构师、云管理员 | 
| 授予 API Gateway 调用 Lambda 搜索函数的权限。 | 运行 add-p AWS CLI [ermission 命令授](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/add-permission.html)予 API Gateway 使用搜索功能的权限：<pre>aws lambda add-permission \<br />  --function-name <function-name> \<br />  --statement-id apigateway-get \<br />  --action lambda:InvokeFunction \<br />  --principal apigateway.amazonaws.com \<br />  --source-arn "arn:aws:execute-api:<region>:<account-id>:api-id/*/GET/search</pre>如果您使用其他名为 `search` 的 API 资源，则更改 `source-arn` 路径。 | 云架构师、云管理员 | 
| 部署搜索 API。 | 运行 AWS CLI [create-dep](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/create-deployment.html) loyment 命令创建名为：`dev`<pre>aws apigateway create-deployment \<br />  --rest-api-id <API-ID> \<br />  --stage-name dev</pre>如果您更新 API，则可以使用相同的 AWS CLI 命令将其重新部署到同一阶段。 | 云架构师、云管理员 | 

### 创建和配置 Kibana 角色
<a name="create-and-configure-kibana-roles"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 登录到 Kibana 控制台。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html) | 云架构师、云管理员 | 
| 创建和配置 Kibana 角色。 | 为了提供数据隔离并确保一个租户无法检索另一租户的数据，您需要使用文档安全性，它允许租户仅访问包含其租户 ID 的文档。[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html) | 云架构师、云管理员 | 
| 将用户映射至角色。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html)我们建议您在租户入职时自动创建租户与 Kibana 角色。 | 云架构师、云管理员 | 
| 创建 tenant-data 索引。 | 在导航窗格的**管理**下，选择**开发工具**，然后运行以下命令。此命令创建 `tenant-data` 索引，以定义 `TenantId` 属性的映射。<pre>PUT /tenant-data<br />{<br />  "mappings": {<br />    "properties": {<br />      "TenantId": { "type": "keyword"}<br />    }<br />  }<br />}</pre> | 云架构师、云管理员 | 

### 为 Amazon S3 创建 VPC 终端节点和 AWS STS
<a name="create-vpc-endpoints-for-s3-and-sts"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 为 Amazon S3 创建和配置 VPC 端点。 | 运行 AWS CLI [create-vpc-endpoint](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc-endpoint.html)命令为 Amazon S3 创建 VPC 终端节点。该端点允许 VPC 中的 Lambda 索引函数访问 Amazon S3。<pre>aws ec2 create-vpc-endpoint \<br />  --vpc-id <VPC-ID> \<br />  --service-name com.amazonaws.us-east-1.s3 \<br />  --route-table-ids <route-table-ID></pre>对于 `vpc-id`，请指定您用于 Lambda 索引函数的 VPC。对于 `service-name`，请使用 Amazon S3 端点的正确网址。对于 `route-table-ids`，请指定与 VPC 端点关联的路由表。 | 云架构师、云管理员 | 
| 为创建 VPC 终端节点 AWS STS。 | 运行 AWS CLI [create-vpc-endpoint](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc-endpoint.html)命令为 AWS Security Token Service (AWS STS) 创建 VPC 终端节点。该端点允许 VPC 中的 Lambda 索引和搜索函数访问 AWS STS。这些函数在担任 IAM 角色 AWS STS 时使用。<pre>aws ec2 create-vpc-endpoint \<br />  --vpc-id <VPC-ID> \<br />  --vpc-endpoint-type Interface \<br />  --service-name com.amazonaws.us-east-1.sts \<br />  --subnet-id <subnet-ID> \<br />  --security-group-id <security-group-ID></pre>对于 `vpc-id`，请指定您用于 Lambda 索引和搜索功能的 VPC。对于 `subnet-id`，请提供应在其中创建此端点的子网。对于 `security-group-id`，请指定要与该端点关联的安全组。（它可能与 Lambda 使用的安全组相同。） | 云架构师、云管理员 | 

### 测试多租户与数据隔离
<a name="test-multi-tenancy-and-data-isolation"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 更新索引与搜索函数的 Python 文件。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html)您可以从 OpenSearch 服务控制台的**概述**选项卡获取 Elasticsearch 终端节点。其格式为 `<AWS-Region>.es.amazonaws.com`。 | 云架构师、应用程序开发人员 | 
| 更新 Lambda 代码。 | 使用 AWS CLI [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html)命令使用您对 Python 文件所做的更改来更新 Lambda 代码：<pre>aws lambda update-function-code \<br />  --function-name index-lambda-function \<br />  --zip-file fileb://index_lambda_package.zip<br /><br />aws lambda update-function-code \<br />  --function-name search-lambda-function \<br />  --zip-file fileb://search_lambda_package.zip</pre> | 云架构师、应用程序开发人员 | 
| 将原始数据上传到 S3 存储桶。 | 使用 AWS CLI [cp](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/cp.html) 命令将 Tenant-1 和 Tenant-2 对象的数据上传到`tenantrawdata`存储桶（指定您为此目的创建的 S3 存储桶的名称）：<pre>aws s3 cp tenant-1-data s3://tenantrawdata<br />aws s3 cp tenant-2-data s3://tenantrawdata</pre>S3 存储桶设置为每当上传数据时运行 Lambda 索引函数，便在 Elasticsearch 中为文档编制索引。 | 云架构师、云管理员 | 
| 在 Kibana 控制台搜索数据。 | 在 Kibana 控制台上，运行以下查询：<pre>GET tenant-data/_search</pre>此查询显示了 Elasticsearch 中编制索引的所有文档。在这种情况下，您应该会看到两个单独 Tenant-1 和 Tenant-2 文档。 | 云架构师、云管理员 | 
| 从 API Gateway 中测试搜索 API。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service.html)有关屏幕插图，请参阅[其他信息](#build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-additional)部分。 | 云架构师、应用程序开发人员 | 
| 清理资源。 | 清理您创建的所有资源，以防止对您的账户收取额外费用。 | AWS DevOps、云架构师、云管理员 | 

## 相关资源
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-resources"></a>
+ [AWS SDK for Python (Boto)](https://aws.amazon.com/sdk-for-python/)
+ [AWS Lambda 文档](https://docs.aws.amazon.com/lambda/)
+ [API Gateway 文档](https://docs.aws.amazon.com/apigateway/)
+ [Amazon S3 文档](https://docs.aws.amazon.com/s3/)
+ [亚马逊 OpenSearch 服务文档](https://docs.aws.amazon.com/elasticsearch-service/)
  + [Amazon 服务中的精细访问控制 OpenSearch ](https://docs.amazonaws.cn/en_us/elasticsearch-service/latest/developerguide/fgac.html)
  + [使用 Amazon OpenSearch 服务创建搜索应用程序](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/search-example.html)
  + [在 VPC 内启动您的亚马逊 OpenSearch 服务域](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html)

## 附加信息
<a name="build-a-multi-tenant-serverless-architecture-in-amazon-opensearch-service-additional"></a>

**数据分区模型**

多租户系统中常用的数据分区模型包含三种：孤岛、池和混合。您选择的模型取决于环境合规性、噪音邻居、操作和隔离需求。

*孤岛模型*

在孤岛模型中，每个租户数据都存储在不同的存储区域中，租户数据不会混合。您可以使用两种方法通过 Serv OpenSearch ice 实现孤岛模型：每个租户的域和每个租户的索引。
+ **每个租户的域名** — 您可以为每个租户使用单独的 OpenSearch 服务域（与 Elasticsearch 集群同义）。将每个租户置于自己的域内，可以获得将数据置于独立构造中的所有好处。但是这种方法带来了管理和敏捷性方面的挑战。它的分布性质使得汇总和评测租户的运营状况和活动变得更困难。这是一个成本高昂的选项，要求每个 OpenSearch 服务域至少有三个主节点和两个数据节点来处理生产工作负载。

![\[多租户无服务器架构每租户域孤岛模型。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/c2195f82-e5ed-40bb-b76a-3b0210bf1254.png)


 
+ **每个租户的索引**-您可以将租户数据放在 OpenSearch 服务集群内的单独索引中。使用这种方法，您可在创建索引和命名索引时使用租户标识符，方法是在索引名称之前添加租户标识符。按租户编制索引的方法可帮助实现孤岛目标，而无需为每个租户引入完全独立的集群。但是，如果索引数量增加，您可能会遇到内存压力，因为这种方法需要更多分片，而主节点必须处理更多的分配和重新平衡。

![\[多租户无服务器架构中的每租户索引孤岛模型。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/354a9463-25bb-422b-84de-d4875a7c8ea2.png)


 

**孤岛模型中的隔离** — 在孤岛模型中，您可使用 IAM 策略来隔离存放每个租户数据的域或索引。这些策略阻止一个租户访问另外一个租户的数据。要实现您的孤岛隔离模型，您可创建基于资源的策略来控制对租户资源的访问权限。这通常是一个域访问策略，用于指定委托人可以对域的子资源（包括 Elasticsearch 索引和）执行哪些操作。 APIs借助基于 IAM 身份的策略，您可以指定在域、索引或服务中*允许*或* APIs 拒绝*的操作。 OpenSearch IAM 策略的 `Action` 元素描述该策略允许或拒绝的特定操作，并且 `Principal ` 元素指定受影响的账户、用户或角色。

以下示例策略仅授予 Tenant-1 对 `tenant-1` 域中子资源的完全访问权限（如所指定 `es:*`）。`Resource` 元素中的尾随 `/*` 指示此策略适用于域的子资源，而不是域本身。此策略生效后，不允许租户在现有域创建新域或修改设置。

```
{
   "Version": "2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {
            "AWS": "arn:aws:iam::<aws-account-id>:user/Tenant-1"
         },
         "Action": "es:*",
         "Resource": "arn:aws:es:<Region>:<account-id>:domain/tenant-1/*"
      }
   ]
}
```

若要实现每个索引孤岛模型的租户，您需要修改此示例策略，通过指定索引名称，进一步将 Tenant-1 限制在指定的索引或索引范围内。以下示例策略将 Tenant-1 限制为 `tenant-index-1` 索引。 

```
{
   "Version": "2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {
            "AWS": "arn:aws:iam::123456789012:user/Tenant-1"
         },
         "Action": "es:*",
         "Resource": "arn:aws:es:<Region>:<account-id>:domain/test-domain/tenant-index-1/*"
      }
   ]
}
```

*池模型*

在池模型中，所有租户数据都存储至同一域内的索引中。租户标识符包含在数据（文档）中并用作分区键，因此您可确定哪些数据属于哪个租户。此模式减少了管理开销。操作和管理池索引比管理多个索引更加容易、更高效。但是，由于租户数据混合在同一个索引，因此您将失去孤岛模型提供的自然租户隔离。这种方法还可能会因为邻居噪音效应而降低性能。

![\[适用于多租户无服务器架构的池模型。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/c2c3bb0f-6ccd-47a7-ab67-e7f3f8c7f289.png)


 

**池模型中的租户隔离** — 通常，租户隔离难以在池模型中实现。与孤岛模型一起使用的 IAM 机制不允许您根据存储在文档内的租户 ID 来描述隔离。

另一种方法是使用开放发行版为 Elasticsearch 提供的[精细访问控制](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/fgac.html) (FGAC) 支持。FGAC 允许您控制索引、文档或字段级别权限。对于每个请求，FGAC 都会评估用户凭证，然后对用户执行身份验证或拒绝访问。如果 FGAC 对用户进行身份验证，它将获取映射到该用户的所有角色，并使用完整的权限集来确定如何处理请求。 

要在池化模型中实现所需隔离，您可使用[文档级安全性](https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/document-level-security/)，这样可以将角色限制为索引中文档的子集。以下示例角色将查询限制为 Tenant-1。通过将此角色应用于 Tenant-1，您可实现必要的隔离。 

```
{
   "bool": {
     "must": {
       "match": {
         "tenantId": "Tenant-1"
       }
     }
   }
 }
```

*混合模型*

混合模型在同一环境中使用孤岛和池模型的组合，为每个租户级别（例如免费、标准和高级等级）提供独特的体验。每层均遵循池模型中使用的相同安全配置文件。

 

![\[适用于多租户无服务器架构混合模型。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/e7def98a-38ef-435a-9881-7e95ae4d4940.png)


**混合模型中的租户隔离** — 在混合模型中，您应遵循与池模型相同的安全配置文件，其中在文档级别使用 FGAC 安全模型可提供租户隔离。尽管此策略简化了集群管理并提供了敏捷性，但它使架构的其他方面变得复杂。例如，您的代码需要额外的复杂性来确定哪个模型与每个租户关联。您还必须确保单租户查询不会饱和整个域并降低其他租户的体验。 

**在 API Gateway 中测试**

*测试 Tenant-1 查询窗口*

![\[测试 Tenant-1 查询窗口。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/a6757d3f-977a-4ecc-90cb-83ab7f1c3588.png)


*测试 Tenant-2 查询窗口*

 

![\[测试 Tenant-2 查询窗口。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/750196bb-03f6-4b6e-92cd-eb7141602547/images/31bfd656-33ca-4750-b6e6-da4d703c2071.png)


## 附件
<a name="attachments-750196bb-03f6-4b6e-92cd-eb7141602547"></a>

要访问与此文档相关联的其他内容，请解压以下文件：[attachment.zip](samples/p-attach/750196bb-03f6-4b6e-92cd-eb7141602547/attachments/attachment.zip)