Amazon OpenSearch Service でマルチテナントサーバーレスアーキテクチャを構築する - AWS 規範ガイダンス

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Amazon OpenSearch Service でマルチテナントサーバーレスアーキテクチャを構築する

作成者: Tabby Ward (AWS)、Nisha Gambhir (AWS)

環境:PoC またはパイロット

テクノロジー: モダナイゼーション、SaaS、サーバーレス

ワークロード: オープンソース

AWS サービス: Amazon OpenSearch Service、AWS LambdaAmazon S3、Amazon API Gateway

[概要]

Amazon OpenSearch Service は、一般的なオープンソースの検索および分析エンジンである Elasticsearch のデプロイ、運用、スケーリングを容易にするマネージドサービスです。Amazon OpenSearch Service は、ログやメトリクスなどのストリーミングデータに対して、フリーテキスト検索とほぼリアルタイムの取り込みとダッシュボードを提供します。

Software as a Service (SaaS) プロバイダーは、Amazon OpenSearch Service を頻繁に使用して、複雑さとダウンタイムを削減しながら、スケーラブルで安全な方法で顧客インサイトを取得するなど、幅広いユースケースに対応します。

マルチテナント環境で Amazon OpenSearch Service を使用すると、SaaS ソリューションのパーティション化、分離、デプロイ、管理に影響する一連の考慮事項が導入されます。SaaS プロバイダーは、絶えず変化するワークロードに合わせて Elasticsearch クラスターを効果的にスケールする方法を検討する必要があります。また、階層化やノイズの多い隣接条件が、パーティショニングモデルにどのような影響を与えるかを考慮する必要があります。

このパターンでは、Elasticsearch コンストラクトを使用して、テナントデータを表現および隔離するために使用されるモデルを検討します。さらに、このパターンは、マルチテナント環境で Amazon OpenSearch Service を使用したインデックス作成と検索を示す例として、シンプルなサーバーレスリファレンスアーキテクチャに焦点を当てています。これにより、すべてのテナント間で同じインデックスを共有しながら、テナントのデータ分離を維持するプールデータパーティショニングのモデルが実現されます。このパターンでは、Amazon Web Services (AWS) サービスである Amazon API Gateway、AWS Lambda、Amazon Simple Storage Service (Amazon S3)、および Amazon OpenSearch Service を使用します。

プールモデルとその他のデータパーティショニングモデルの詳細については、「追加情報」セクションを参照してください。

前提条件と制限

前提条件

  • アクティブな AWS アカウント

  • macOS、Linux、または Windows に AWS コマンドラインインターフェイス (AWS CLI) バージョン 2.x がインストールされ、設定済み。

  • Python バージョン 3.7

  • pip3 — Python ソースコードは .zip ファイルとして提供され、Lambda 関数にデプロイされます。コードをローカルで使用またはカスタマイズする場合は、次の手順に従ってソースコードを開発して再コンパイルします。

    1. Python スクリプトと同じディレクトリでコマンド pip3 freeze > requirements.txt を実行して requirements.txt ファイルを生成します。

    2. 依存関係 pip3 install -r requirements.txt をインストールします。

機能制限

  • このコードは Python で実行され、現在、他のプログラミング言語はサポートされていません。 

  • サンプルアプリケーションには、AWS クロスリージョンまたはディザスタリカバリ (DR) はサポートされていません。 

  • このパターンは、デモンストレーションのみを目的としています。実稼働環境では使用しないでください。

アーキテクチャ

以下の図に、このパターンのアーキテクチャについて概要を示します。このアーキテクチャには、以下の項目が含まれます。

  • コンテンツのインデックス作成とクエリを実行する AWS Lambda  

  • 検索を実行する Amazon OpenSearch Service 

  • ユーザーとの API インタラクションを提供する Amazon API Gateway

  • (インデックスが付いていない) 未処理のデータを保存するための Amazon S3

  • ログをモニタリング CloudWatch する Amazon

  • テナントロールとポリシーを作成する AWS Identity and Access Management (IAM)

高レベルのマルチテナントのサーバーレスアーキテクチャ

自動化とスケール

わかりやすくするために、このパターンでは AWS CLI を使用してインフラストラクチャをプロビジョニングし、サンプルコードをデプロイします。AWS CloudFormation テンプレートまたは AWS Cloud Development Kit (AWS CDK) スクリプトを作成して、パターンを自動化できます。

ツール

AWS サービス

  • AWS CLI — AWS コマンドラインインターフェイス (AWS CLI) は、コマンドラインシェルのコマンドを使用して AWS サービスとリソースを管理するための統合ツールです。

  • AWS Lambda – AWS Lambda はサーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービスです。Lambda は必要に応じてコードを実行し、1 日あたり数個のリクエストから 1 秒あたり数千のリクエストまで自動的にスケールします。

  • Amazon API Gateway – Amazon API Gateway は、あらゆる規模で REST、HTTP、 WebSocket APIs を作成、公開、保守、モニタリング、保護するための AWS のサービスです。

  • Amazon S3 — Amazon Simple Storage Service (Amazon S3) は、ウェブ上のどこからでも、任意の量のデータを保存して取得できるようにするオブジェクトストレージサービスです。

  • Amazon OpenSearch Service – Amazon OpenSearch Service は、Elasticsearch を大規模にコスト効率良くデプロイ、保護、実行することを容易にするフルマネージドサービスです。

コード

添付ファイルには、このパターンのサンプルが記載されています。具体的には次のとおりです。

  • index_lambda_package.zip – プールモデルを使用して Amazon OpenSearch Service 内のデータをインデックスするための Lambda 関数。

  • search_lambda_package.zip – Amazon OpenSearch Service でデータを検索するための Lambda 関数。

  • Tenant-1-data — Tenant-1 の (インデックスが付いていない) 未処理のデータをサンプリングします。

  • Tenant-2-data — Tenant-2 の (インデックスが付いていない) 未処理のデータをサンプリングします。

重要: このパターンのストーリーには、UNIX、Linux、macOS 向けにフォーマットされた CLI コマンドの例が含まれています。Windows の場合は、各行末のバックスラッシュ (\) Unix 連結文字をキャレット (^) に置き換えてください。

エピック

タスク説明必要なスキル

S3 バケットを作成します。

AWS リージョンで S3 バケットを作成します。  このバケットには、インデックスが付いていないサンプルアプリケーションのテナントデータが格納されます。  名前空間はすべての AWS アカウントによって共有されているので、S3 バケット名はグローバルに一意であることを確認します。

S3 バケットを作成するには、以下のように AWS CLI create-bucket コマンドを使用できます。

aws s3api create-bucket \   --bucket tenantrawdata \   --region <your-AWS-Region>

tenantrawdata は S3 バケット名です。(「バケット命名ガイドライン」に従った任意の一意の名前を使用できます)。

クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

Amazon OpenSearch Service ドメインを作成します。

AWS CLI create-elasticsearch-domain コマンドを実行して Amazon OpenSearch Service ドメインを作成します。

aws es create-elasticsearch-domain \   --domain-name vpc-cli-example \   --elasticsearch-version 7.10 \   --elasticsearch-cluster-config InstanceType=t3.medium.elasticsearch,InstanceCount=1 \   --ebs-options EBSEnabled=true,VolumeType=gp2,VolumeSize=10 \   --domain-endpoint-options "{\"EnforceHTTPS\": true}" \   --encryption-at-rest-options "{\"Enabled\": true}" \   --node-to-node-encryption-options "{\"Enabled\": true}" \   --advanced-security-options "{\"Enabled\": true, \"InternalUserDatabaseEnabled\": true, \ \"MasterUserOptions\": {\"MasterUserName\": \"KibanaUser\", \ \"MasterUserPassword\": \"NewKibanaPassword@123\"}}" \   --vpc-options "{\"SubnetIds\": [\"<subnet-id>\"], \"SecurityGroupIds\": [\"<sg-id>\"]}" \   --access-policies "{\"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \ \"Principal\": {\"AWS\": \"*\" }, \"Action\":\"es:*\", \ \"Resource\": \"arn:aws:es:region:account-id:domain\/vpc-cli-example\/*\" } ] }"

テスト用ドメインであるため、インスタンス数は 1 に設定されています。ドメインの作成後は、詳細を変更できないため、advanced-security-options パラメータを使用してきめ細かいアクセス制御を有効にする必要があります。 

このコマンドは、Kibana コンソールにログインできるマスターユーザー名 (KibanaUser) とパスワードを作成します。

このドメインは仮想プライベートクラウド (VPC) の一部であるため、使用するアクセスポリシーを指定して、必ず Elasticsearch インスタンスにアクセスする必要があります。

詳細については、AWS ドキュメントの「VPC を使用した Amazon OpenSearch Service ドメインの起動」を参照してください。

クラウドアーキテクト、クラウド管理者

踏み台ホストをセットアップします。

Kibana コンソールにアクセスするための踏み台ホストとして、Amazon Elastic Compute Cloud (Amazon EC2) Windows インスタンスをセットアップします。Elasticsearch セキュリティグループは、Amazon EC2 セキュリティグループからのトラフィックを許可する必要があります。  手順については、ブログ記事「踏み台サーバーを使用して EC2 インスタンスへのネットワークアクセスを制御する」を参照してください。

踏み台ホストがセットアップされ、インスタンスに関連付けられているセキュリティグループが使用可能になったら、AWS CLI authorize-security-group-ingress コマンドを使用して Elasticsearch セキュリティグループにアクセス許可を追加して、Amazon EC2 (踏み台ホスト) セキュリティグループからのポート 443 を許可します。

aws ec2 authorize-security-group-ingress \ --group-id <SecurityGroupIdfElasticSearch> \ --protocol tcp \ --port 443 \ --source-group <SecurityGroupIdfBashionHostEC2>
クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

Lambda 実行ロールを作成します。

AWS CLI create-role コマンドを実行して、Lambda インデックス関数に AWS のサービスとリソースへのアクセスを許可します。

aws iam create-role \ --role-name index-lambda-role \ --assume-role-policy-document file://lambda_assume_role.json

ここで、lambda_assume_role.json は現在フォルダ内にある JSON ドキュメントで、以下のように、Lambda 関数に AssumeRole の権限を付与します。

{      "Version": "2012-10-17",      "Statement": [          {              "Effect": "Allow",              "Principal": {                  "Service": "lambda.amazonaws.com"                },              "Action": "sts:AssumeRole"          }      ]  }
クラウドアーキテクト、クラウド管理者

マネージドポリシーを Lambda ロールにアタッチします。

AWS CLI attach-role-policy コマンドを実行して、前のステップで作成したロールに管理ポリシーをアタッチします。これら 2 つのポリシーは、Elastic Network Interface を作成し、ログを Logs CloudWatch に書き込むアクセス許可をロールに付与します。

aws iam attach-role-policy \ --role-name index-lambda-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam attach-role-policy \ --role-name index-lambda-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole 
クラウドアーキテクト、クラウド管理者

Lambda インデックス関数に、S3 オブジェクトの読み取り権限を与えるポリシーを作成します。

AWS CLI create-policy コマンドを実行して、Lambda インデックス関数に S3 バケット内のオブジェクトを読み取る s3:GetObject 権限を付与します。

aws iam create-policy \   --policy-name s3-permission-policy \   --policy-document file://s3-policy.json

ファイル s3-policy.json は、現在のフォルダにある JSON ドキュメントで、S3 オブジェクトへの読み取りアクセスを許可する s3:GetObject 権限を付与します。S3 バケットを作成するときに別の名前を使用した場合は、次の Resource  セクションで正しいバケット名を指定します:

{     "Version": "2012-10-17",     "Statement": [         {            "Effect": "Allow",            "Action": "s3:GetObject",            "Resource": "arn:aws:s3:::tenantrawdata/*"         }     ] }
クラウドアーキテクト、クラウド管理者

Amazon S3 のアクセス許可ポリシーを Lambda 実行ロールにアタッチします。

AWS CLI attach-role-policy コマンドを実行して、前のステップで作成した Amazon S3 アクセス許可ポリシーを Lambda 実行ロールにアタッチします。

aws iam attach-role-policy \   --role-name index-lambda-role \   --policy-arn <PolicyARN>

ここで、PolicyARN は Amazon S3 のアクセス許可ポリシーの Amazon リソースネーム (ARN) です。前のコマンド出力からこの値を取得できます。

クラウドアーキテクト、クラウド管理者

Lambda インデックス関数を作成します。

AWS CLI create-function コマンドを実行して、Amazon OpenSearch Service にアクセスする Lambda インデックス関数を作成します。

aws lambda create-function \   --function-name index-lambda-function \   --zip-file fileb://index_lambda_package.zip \   --handler lambda_index.lambda_handler \   --runtime python3.7 \   --role "arn:aws:iam::account-id:role/index-lambda-role" \   --timeout 30 \   --vpc-config "{\"SubnetIds\": [\"<subnet-id1\>", \"<subnet-id2>\"], \     \"SecurityGroupIds\": [\"<sg-1>\"]}"
クラウドアーキテクト、クラウド管理者

Amazon S3 が Lambda インデックス関数を呼び出すことを許可します。 

AWS CLI の add-permission コマンドを実行して、Amazon S3 に Lambda インデックス関数を呼び出すアクセス権限を付与します。

aws lambda add-permission \ --function-name index-lambda-function \ --statement-id s3-permissions \ --action lambda:InvokeFunction \ --principal s3.amazonaws.com \ --source-arn "arn:aws:s3:::tenantrawdata" \ --source-account "<account-id>"
クラウドアーキテクト、クラウド管理者

Amazon S3 イベントの Lambda トリガーを追加します。

AWS CLI put-bucket-notification-configuration コマンドを実行して、Amazon S3 イベントが検出されたときに Lambda インデックス関数に通知を送信します。 ObjectCreatedインデックス関数は、オブジェクトが S3 バケットにアップロードされるたびに実行されます。  

aws s3api put-bucket-notification-configuration \ --bucket tenantrawdata \ --notification-configuration file://s3-trigger.json

ファイル s3-trigger.json は現在のフォルダにある JSON ドキュメントで、Amazon S3 ObjectCreated イベントが発生したときにリソースポリシーを Lambda 関数に追加します。

クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

Lambda 実行ロールを作成します。

AWS CLI create-role コマンドを実行して、Lambda 検索関数に AWS のサービスとリソースへのアクセスを許可します。

aws iam create-role \ --role-name search-lambda-role \ --assume-role-policy-document file://lambda_assume_role.json

ここで、lambda_assume_role.json は現在フォルダ内にある JSON ドキュメントで、以下のように、Lambda 関数に AssumeRole の権限を付与します。

{      "Version": "2012-10-17",      "Statement": [          {              "Effect": "Allow",              "Principal": {                  "Service": "lambda.amazonaws.com"                },              "Action": "sts:AssumeRole"          }      ]  }
クラウドアーキテクト、クラウド管理者

マネージドポリシーを Lambda ロールにアタッチします。

AWS CLI attach-role-policy コマンドを実行して、前のステップで作成したロールに管理ポリシーをアタッチします。これら 2 つのポリシーは、Elastic Network Interface を作成し、ログを Logs CloudWatch に書き込むアクセス許可をロールに付与します。

aws iam attach-role-policy \ --role-name search-lambda-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam attach-role-policy \ --role-name search-lambda-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole 
クラウドアーキテクト、クラウド管理者

Lambda 検索関数を作成します。

AWS CLI create-function コマンドを実行して、Amazon OpenSearch Service にアクセスする Lambda 検索関数を作成します。

aws lambda create-function \   --function-name search-lambda-function \   --zip-file fileb://search_lambda_package.zip \   --handler lambda_search.lambda_handler \   --runtime python3.7 \   --role "arn:aws:iam::account-id:role/search-lambda-role" \   --timeout 30 \   --vpc-config "{\"SubnetIds\": [\"<subnet-id1\>", \"<subnet-id2>\"], \     \"SecurityGroupIds\": [\"<sg-1>\"]}"
クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

テナントの IAM ロールを作成します。

AWS CLI create-role コマンドを実行して、検索機能のテストに使用する 2 つのテナントロールを作成します。

aws iam create-role \   --role-name Tenant-1-role \   --assume-role-policy-document file://assume-role-policy.json
aws iam create-role \   --role-name Tenant-2-role \   --assume-role-policy-document file://assume-role-policy.json

この assume-role-policy.json ファイルは、現在のフォルダ内にある JSON ドキュメントで、Lambda 実行ロールに AssumeRole のアクセス権限を付与します。

{     "Version": "2012-10-17",     "Statement": [         {             "Effect": "Allow",             "Principal": {                  "AWS": "<Lambda execution role for index function>",                  "AWS": "<Lambda execution role for search function>"              },             "Action": "sts:AssumeRole"         }     ] }
クラウドアーキテクト、クラウド管理者

新規 IAM ポリシーを作成します。

AWS CLI create-policy コマンドを実行して、Elasticsearch オペレーションへのアクセスを許可するテナントポリシーを作成します。

aws iam create-policy \   --policy-name tenant-policy \   --policy-document file://policy.json

この policy.json ファイルは、現在のフォルダ内の JSON ドキュメントで、Elasticsearch にアクセス権限を付与します。

{     "Version": "2012-10-17",     "Statement": [         {             "Effect": "Allow",             "Action": [                 "es:ESHttpDelete",                 "es:ESHttpGet",                 "es:ESHttpHead",                 "es:ESHttpPost",                 "es:ESHttpPut",                 "es:ESHttpPatch"             ],             "Resource": [                 "<ARN of Elasticsearch domain created earlier>"             ]         }     ] }
クラウドアーキテクト、クラウド管理者

テナント IAM ポリシーをテナントロールにアタッチします。

AWS CLI attach-role-policy コマンドを実行して、前のステップで作成した 2 つのテナントロールにテナント IAM ポリシーをアタッチします。

aws iam attach-role-policy \   --policy-arn arn:aws:iam::account-id:policy/tenant-policy \   --role-name Tenant-1-role aws iam attach-role-policy \   --policy-arn arn:aws:iam::account-id:policy/tenant-policy \   --role-name Tenant-2-role

ポリシー ARN は、前のステップの出力から取得されます。

クラウドアーキテクト、クラウド管理者

Lambda にロールを引き受ける権限を付与する IAM ポリシーを作成します。

AWS CLI create-policy コマンドを実行して、Lambda がテナントロールを引き受けるためのポリシーを作成します。

aws iam create-policy \   --policy-name assume-tenant-role-policy \ --policy-document file://lambda_policy.json

この lambda_policy.json ファイルは、現在のフォルダ内にある JSON ドキュメントで、AssumeRole にアクセス権限を付与します。

{     "Version": "2012-10-17",     "Statement": [        {             "Effect": "Allow",             "Action":  "sts:AssumeRole",             "Resource": "<ARN of tenant role created earlier>"        }     ] }

Resource には、ワイルドカード文字を使用すると、テナントごとに新しいポリシーを作成する必要がなくなります。

クラウドアーキテクト、クラウド管理者

Lambda インデックス ロールに Amazon S3 へのアクセスを許可する IAM ポリシーを作成します。

AWS CLI 「create-policy」 コマンドを実行して、Lambda インデックス関数に S3 バケット内のオブジェクトをリード権限を付与します。

aws iam create-policy \   --policy-name s3-permission-policy \   --policy-document file://s3_lambda_policy.json

この s3_lambda_policy.json ファイルは、現在のフォルダ内にある JSON ポリシードキュメントです。

{     "Version": "2012-10-17",     "Statement": [         {             "Effect": "Allow",             "Action": "s3:GetObject",             "Resource": "arn:aws:s3:::tenantrawdata/*"         }     ] }
クラウドアーキテクト、クラウド管理者

ポリシーを Lambda 実行ロールにアタッチします。

AWS CLI attach-role-policy コマンドを実行して、前のステップで作成したポリシーを、前に作成した Lambda インデックスと検索実行ロールにアタッチします。

aws iam attach-role-policy \   --policy-arn arn:aws:iam::account-id:policy/assume-tenant-role-policy \   --role-name index-lambda-role aws iam attach-role-policy \   --policy-arn arn:aws:iam::account-id:policy/assume-tenant-role-policy \   --role-name search-lambda-role aws iam attach-role-policy \   --policy-arn arn:aws:iam::account-id:policy/s3-permission-policy \   --role-name index-lambda-role

ポリシー ARN は、前のステップの出力から取得されます。

クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

API ゲートウェイで REST API を作成します。

CLI create-rest-api コマンドを実行して REST API リソースを作成します。

aws apigateway create-rest-api \   --name Test-Api \   --endpoint-configuration "{ \"types\": [\"REGIONAL\"] }"

エンドポイント設定タイプでは、REGIONAL ではなく EDGE を指定して、特定の AWS リージョンではなくエッジロケーションを使用できます。

コマンド出力の id フィールドの値に注目してください。これは、以降のコマンドで使用する API ID です。

クラウドアーキテクト、クラウド管理者

API リソースの検索を作成します。 

API リソースを検索し、Lambda 検索関数をリソース名 search で起動します。(Lambda インデックス関数の API は、オブジェクトが S3 バケットにアップロードされると自動的に実行されるため、作成する必要はありません)。

  1. AWS CLI get-resources コマンドを実行して、ルートパスの親 ID を取得します。

    aws apigateway get-resources \ --rest-api-id <API-ID>

    ID フィールドの値をメモします。この親 ID は次のコマンドで使用します。

    { "items": [ { "id": "zpsri964ck", "path": "/" } ] }
  2. AWS CLI create-resource コマンドを実行して、API リソースの検索を作成します。parent-id では、前のコマンドの ID を指定します。

    aws apigateway create-resource \   --rest-api-id <API-ID> \   --parent-id <Parent-ID> \   --path-part search
クラウドアーキテクト、クラウド管理者

検索 API の GET メソッドを作成します。

AWS CLI put-method コマンドを実行して、検索 API の GET  メソッドを作成します:

aws apigateway put-method \   --rest-api-id <API-ID> \   --resource-id <ID from the previous command output> \   --http-method GET \   --authorization-type "NONE" \ --no-api-key-required

resource-id では、create-resource コマンドの ID を指定します。

クラウドアーキテクト、クラウド管理者

検索 API の GET メソッドを作成します。

AWS CLI put-method-response コマンドを実行して、検索 API のメソッドレスポンスを追加します。

aws apigateway put-method-response \   --rest-api-id <API-ID> \   --resource-id  <ID from the create-resource command output> \   --http-method GET \   --status-code 200 \ --response-models "{\"application/json\": \"Empty\"}"

 resource-id では、前の create-resource コマンドの ID を指定します。

クラウドアーキテクト、クラウド管理者

検索 API のプロキシ Lambda 統合を設定します。

AWS CLI put-integration コマンドを実行して、Lambda 検索関数との統合を設定します。

aws apigateway put-integration \   --rest-api-id <API-ID> \   --resource-id  <ID from the create-resource command output> \   --http-method GET \   --type AWS_PROXY \   --integration-http-method GET \   --uri arn:aws:apigateway:region:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account-id>:function:<function-name>/invocations

resource-id では、前の create-resource コマンドの ID を指定します。

クラウドアーキテクト、クラウド管理者

API ゲートウェイに Lambda 検索関数を呼び出す権限を付与します。

AWS CLI add-permission コマンドを実行して、API ゲートウェイに検索機能を使用する権限を付与します。

aws lambda add-permission \   --function-name <function-name> \   --statement-id apigateway-get \   --action lambda:InvokeFunction \   --principal apigateway.amazonaws.com \ --source-arn "arn:aws:execute-api:<region>:<account-id>:api-id/*/GET/search

search ではなく別の API リソース名を使用している場合は、source-arn パスを変更します。

クラウドアーキテクト、クラウド管理者

検索 API をデプロイします。

AWS CLI create-deployment コマンドを実行して、dev という名前のステージリソースを作成します。

aws apigateway create-deployment \   --rest-api-id <API-ID> \ --stage-name dev

API を更新すると、同じ CLI コマンドを使用して同じステージに再デプロイできます。

クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

Kibana コンソールにログインします。

  1. Amazon OpenSearch Service コンソールのドメインダッシュボードで Kibana へのリンクを見つけます。この URL は <domain-endpoint>/_plugin/kibana/ の形式になります。

  2. 最初のエピックで設定した踏み台ホストを使用して Kibana コンソールにアクセスします。

  3. Amazon OpenSearch Service ドメインを作成したときに、前のステップのマスターユーザー名とパスワードを使用して Kibana コンソールにログインします。

  4. テナントを選択するよう求められた場合、[Private] を選択します。

クラウドアーキテクト、クラウド管理者

Kibana ロールの作成と設定

データを隔離し、あるテナントが別のテナントのデータを取得できないようにするには、ドキュメントセキュリティを使用する必要があります。ドキュメントセキュリティを使用すると、テナントがテナント ID を含むドキュメントのみにアクセスできるようになります。

  1. Kibana コンソールのナビゲーションペインで、[セキュリティ]、[ロール] を選択します。

  2. 新規テナントロールを作成します。

  3. クラスターのアクセス許可を に設定します。これによりindices_all、Amazon OpenSearch Service インデックスに対する作成、読み取り、更新、削除 (CRUD) のアクセス許可が付与されます。 

  4. インデックスへのアクセス権限を tenant-data インデックスに制限します。(インデックス名は Lambda 検索関数とインデックス関数の名前と一致する必要があります。) 

  5. インデックス権限を indices_all に設定して、インデックス関連のすべての操作をユーザーが実行できるようにします。(要件に応じて、よりきめ細かくアクセスできるように操作を制限できます)。 

  6. ドキュメントレベルのセキュリティを確保するには、次のポリシーを使用してテナント ID でドキュメントをフィルタリングし、共有インデックス内のテナントにデータを隔離します。

    {   "bool": {     "must": {       "match": {         "TenantId": "Tenant-1"       }     }   } }

    インデックス名、プロパティ、値では、大文字と小文字が区別されます。 

クラウドアーキテクト、クラウド管理者

ユーザーをロールにマッピングします。

  1. ロールについて [マッピングされたユーザー] タブを選択し、[ユーザーのマッピング] を選択します。

  2. [バックエンドロール] セクションで、前に作成した IAM テナントロールの ARN を指定してから、マップを選択します。これにより、IAM テナントロールが Kibana ロールにマッピングされ、テナント固有の検索ではそのテナントのデータのみが返されるようになります。たとえば、Tenant-1 の IAMロール名が Tenant-1-Role の場合、Tenant-1 の Kibana ロールの [バックエンドロール] ボックスで Tenant-1-Role の ARN を指定します(「テナントロールの作成および設定」エピックから)。

  3. テナント 2 では、ステップ 1 と 2 を繰り返します。

テナントのオンボーディング時に、テナントロールと Kibana ロールの作成を自動化することをお勧めします。

クラウドアーキテクト、クラウド管理者

テナント-データ インデックスを作成します。

ナビゲーションペインの [管理] で [開発ツール] を選択し、次のコマンドを実行します。このコマンドは、TenantId プロパティのマッピングを定義する tenant-data インデックスを作成します。

PUT /tenant-data {   "mappings": {     "properties": {       "TenantId": { "type": "keyword"}     }   } }
クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

Amazon S3 の VPC エンドポイントを作成します。

AWS CLI create-vpc-endpoint コマンドを実行して、Amazon S3 の VPC エンドポイントを作成します。エンドポイントにより、VPC の Lambda インデックス関数が Amazon S3 サービスにアクセスできるようになります。

aws ec2 create-vpc-endpoint \   --vpc-id <VPC-ID> \   --service-name com.amazonaws.us-east-1.s3 \   --route-table-ids <route-table-ID>

vpc-id には、Lambda インデックス関数に使用している VPC を指定します。service-name には、Amazon S3 エンドポイントの正しい URL を使用します。route-table-ids には、VPC エンドポイントに関連付けられているルートテーブルを指定します。

クラウドアーキテクト、クラウド管理者

AWS STS の VPC エンドポイントの作成

AWS CLI create-vpc-endpoint コマンドを実行して、AWS Security Token Service (AWS STS) の VPC エンドポイントを作成します。エンドポイントにより、VPC の Lambda インデックス関数と Lambda 検索関数が Amazon STS サービスにアクセスできるようになります。これらの関数は IAM ロールを引き受けるときに AWS STS を使用します。

aws ec2 create-vpc-endpoint \   --vpc-id <VPC-ID> \   --vpc-endpoint-type Interface \   --service-name com.amazonaws.us-east-1.sts \   --subnet-id <subnet-ID> \ --security-group-id <security-group-ID>

vpc-id には、Lambda インデックス関数と Lambda 検索関数に使用している VPC を指定します。subnet-id には、このエンドポイントを作成するサブネットを指定します。security-group-id には、このエンドポイントを関連付けるセキュリティグループを指定します。(Lambda が使用するセキュリティグループと同じである可能性があります)。 

クラウドアーキテクト、クラウド管理者
タスク説明必要なスキル

インデックス関数と検索関数の Python ファイルを更新します。 

  1. index_lambda_package.zip ファイル内で、 lamba_index.py ファイルを編集して、AWS アカウント ID、AWS リージョン、および Elasticsearch エンドポイント情報を更新します。

  2. search_lambda_package.zip ファイル内で、lambda_search.py ファイルを編集して、AWS アカウント ID、AWS リージョン、および Elasticsearch エンドポイント情報を更新します。

Elasticsearch エンドポイントは、Amazon OpenSearch Service コンソールの概要タブから取得できます。これは、<AWS-Region>.es.amazonaws.com という形式です。

クラウドアーキテクト、アプリ開発者

Lambda コードを作成します。

AWS CLI update-function-code コマンドを使用して、Python ファイルに加えた変更で Lambda コードを更新します。

aws lambda update-function-code \   --function-name index-lambda-function \   --zip-file fileb://index_lambda_package.zip aws lambda update-function-code \   --function-name search-lambda-function \   --zip-file fileb://search_lambda_package.zip
クラウドアーキテクト、アプリ開発者

S3 バケットに未処理のデータをアップロードします。

AWS CLI cp コマンドを使用して、Tenant-1 オブジェクトと Tenant-2 オブジェクトのデータを tenantrawdata バケットにアップロードします(この目的で作成された S3 バケットの名前を指定します)。

aws s3 cp tenant-1-data s3://tenantrawdata aws s3 cp tenant-2-data s3://tenantrawdata

S3 バケットは、データがアップロードされるたびに Lambda インデックス関数を実行するように設定されているため、ドキュメントには Elasticsearch でインデックスが付けられます。

クラウドアーキテクト、クラウド管理者

Kibana コンソールからデータを検索します。 

Kibana コンソールで、以下のクエリを実行します。

GET tenant-data/_search

このクエリは、Elasticsearch でインデックスに登録されているすべてのドキュメントを表示します。この場合、Tenant-1 と Tenant-2 の 2 つのドキュメントが別々に表示されます。

クラウドアーキテクト、クラウド管理者

API ゲートウェイ から検索 API をテストします。

  1. API ゲートウェイコンソールで、検索 API を開き、検索リソース内の GET メソッドを選択して、[テスト] を選択します。

  2. テストウィンドウで、テナント ID に次のクエリ文字列 (大文字と小文字を区別) を入力し、[テスト] を選択します。

    TenantId=Tenant-1

    Lambda 関数は、ドキュメントレベルのセキュリティに基づいてテナントドキュメントをフィルタリングするクエリを Amazon OpenSearch Service に送信します。このメソッドは Tenant-1 に属するドキュメントを返します。  

  3. クエリ文字列を次のように変更します。 

    TenantId=Tenant-2

    このクエリは Tenant-1 に属するドキュメントを返します。 

画面の図については、「追加情報」セクションを参照してください。

クラウドアーキテクト、アプリ開発者

関連リソース

追加情報

データパーティショニングのモデル

マルチテナントシステムで使用される一般的なデータパーティショニングモデルには、サイロ、プール、ハイブリッドの 3 つがあります。選択するモデルは、環境のコンプライアンス、ノイジーネイバー、運用、隔離の要件によって異なります。

サイロモデル

サイロモデルでは、各テナントのデータをテナントデータが混在しない個別のストレージエリアに保存します。Amazon OpenSearch Service でサイロモデルを実装するには、テナントごとのドメインとテナントごとのインデックスの 2 つのアプローチを使用できます。

  • テナントあたりのドメイン – テナントごとに個別の Amazon OpenSearch Service ドメイン (Elasticsearch クラスターと同義) を使用できます。各テナントを独自のドメインに配置することで、データをスタンドアロンコンストラクトに配置することに関連するすべてのメリットが得られます。しかし、このアプローチでは、管理とアジリティの面で課題が生じています。隔離型であるため、テナントの運営状況や活動を集計して評価することが難しくなっています。これは、各 Amazon OpenSearch Service ドメインに、少なくとも本番ワークロード用に 3 つのマスターノードと 2 つのデータノードが必要です。

マルチテナントのサーバーレスアーキテクチャのための「テナントごとのドメイン」サイロモデル
  • テナントあたりのインデックス – テナントデータを Amazon OpenSearch Service クラスター内の個別のインデックスに配置できます。このアプローチでは、テナント識別子をインデックス名にあらかじめ付けておくことで、インデックスを作成して名前を付けるときにテナント識別子を使用できます。テナントごとにインデックスを付けるアプローチでは、テナントごとに完全に分離したクラスターを導入しなくても、サイロの目標を達成できます。  しかし、インデックスの数が増えると、このアプローチではより多くのシャードが必要になり、マスターノードがより多くの割り当てとリバランスを処理する必要があるため、メモリの負荷がかかる可能性があります。

マルチテナントのサーバレスアーキテクチャのための「テナントごとのインデックス」サイロモデル

サイロモデルでの隔離 — サイロモデルでは、IAM ポリシーを使用して、各テナントのデータを保持するドメインまたはインデックスを隔離します。これらのポリシーは、あるテナントが別のテナントのデータにアクセスすることを防止します。サイロ隔離モデルを実装するには、テナントリソースへのアクセスを制御するリソースベースのポリシーを作成できます。通常、これはドメインアクセスポリシーで、Elasticsearch インデックスや API など、プリンシパルがドメインのサブリソースに対して実行できるアクションを指定します。IAM アイデンティティベースのポリシーでは、Amazon OpenSearch Service 内のドメイン、インデックス、または APIsに対して許可または拒否されたアクションを指定できます。IAM ポリシーの Action  要素は、ポリシーによって許可または拒否される特定のアクションを記述し、Principal  要素は、影響を受けるアカウント、ユーザー、またはロールを指定します。

以下のサンプルポリシーは、es:* で指定された tenant-1 ドメイン上のサブリソースへの完全なアクセス権を Tenant-1 にのみ付与します。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 を指定された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/*"       }    ] }

プールモデル

プールモデルでは、すべてのテナントデータが同じドメイン内のインデックスに保存されます。  テナント識別子はデータ (ドキュメント) に含まれ、パーティションキーとして使用されるため、どのデータがどのテナントに属しているか判断できます。このモデルでは、管理オーバーヘッドが削減されます。プールインデックスの操作と管理は、複数のインデックスを管理するよりも容易で効率的です。しかし、テナントデータが同じインデックスに混在しているため、サイロモデルが提供する自然なテナント隔離が失われます。このアプローチでは、ノイジーネイバー効果によりパフォーマンスが低下する可能性もあります。

マルチテナントのサーバレスアーキテクチャのためのプールモデル

プールモデルでのテナント隔離 — 一般的に、テナント隔離をプールモデルに実装するのは困難です。サイロモデルで使用されている IAM メカニズムでは、ドキュメントに保存されているテナント ID に基づいて隔離を記述することはできません。

代わりに、Open Distro for Elasticsearch で提供されるきめ細かなアクセス制御 (FGAC) サポートを使用する方法があります。FGAC では、インデックス、ドキュメント、またはフィールドレベルでアクセス許可を制御できます。  FGAC は、リクエストごとに、ユーザーの認証情報を評価し、ユーザーを認証するか、アクセスを拒否します。FGAC がユーザーを認証すると、そのユーザーにマッピングされているすべてのロールを取得し、アクセス許可のセット一式を使用してリクエストの処理方法を決定します。 

プールされたモデルで必要な隔離を実現するには、「ドキュメントレベルのセキュリティ」を使用できます。これにより、ロールをインデックス内のドキュメントのサブセットに制限できます。以下のサンプルロールは、クエリを Tenant-1 に制限します。このロールを Tenant-1 に適用することで、必要な隔離を実現できます。  

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

ハイブリッドモデル

ハイブリッドモデルでは、同じ環境でサイロモデルとプールモデルを組み合わせて、各テナントレイヤー (無料、標準、プレミアム階層など) に独自のエクスペリエンスを提供します。各層は、プールモデルで使用されているのと同じセキュリティプロファイルに従います。

マルチテナントのサーバレスアーキテクチャのためのハイブリッド モデル

ハイブリッドモデルでのテナント隔離 — ハイブリッドモデルでは、ドキュメントレベルで FGAC セキュリティモデルを使用することでテナントを隔離できるプールモデルと同じセキュリティプロファイルに従います。この戦略はクラスター管理を簡素化し、アジリティを提供しますが、アーキテクチャの他の側面が複雑になります。たとえば、どのモデルを各テナントに関連付けるか決めるには、コードをさらに複雑化する必要があります。また、単一テナントのクエリによってドメイン全体が飽和状態になり、他のテナントのエクスペリエンスが低下しないようにする必要があります。 

API ゲートウェイでのテスト

Tenant-1 クエリのテストウィンドウ

Tenant-1 クエリのテストウィンドウ

Tenant-2 クエリのテストウィンドウ

Tenant-2 クエリのテストウィンドウ

添付ファイル

このドキュメントに関連する追加コンテンツにアクセスするには、次のファイルを解凍してください。「attachment.zip