動的なポリシー生成を使ったテナント分離

SaaS on AWS を成功に導くためのポイントとは ? 第 3 回

2021-07-05
ビジネス x クラウド

青嶋 智久

前回の投稿 ではテナント分離における代表的なパターン (サイロモデル、プールモデル) の特徴と、AWS Identity and Access Management (IAM) を使ったサイロモデルにおける基本的なテナント分離の実装をご紹介しました。どのようなビジネス要件にどのようなテナント分離戦略が適しているのか、IAM を使ったテナント分離とはどのような手法なのかのイメージを掴んでいただけたのではないでしょうか。またプールモデルには、サイロモデルとは違ったテナント分離のアプローチが必要であることも同時にご理解いただけたのではと思います。

SaaS on AWS の連載第 3 回では、このプールモデルにおける IAM を使ったテナント分離を取り上げていきます。リソースが共有されるプールモデルにおいて、異なるテナントからのリソース使用を分離するにはどのような手法があるのか、テナントコンテキストや動的なポリシー生成といった考え方がどのような意味を果たすのかを解説していきます。前回の投稿 でご自身が考えた方法と比較しながら楽しんでいただければと思います。


プールモデルにおけるテナント分離のポイント

プールモデルへ動的にポリシーを適用する方法を解説する前に、まずはプールモデルにおけるテナント分離において、なにがポイントになるか整理していきたいと思います。プールモデルはリソースを複数のテナントで共有することで、スケールした際のリソースとオペレーションの効率化を図るテナント分離戦略です。特に成長中のサービスにとってメリットが大きく、導入を検討されている方も多いと思いますが、テナントという抽象度の高い概念と共有リソースの分離というテーマが混ざっていることから、どのようなメカニズムで捉えたら良いか迷いがちです。ここでは便宜的に「アクセス先の共有」と「アクセス元の共有」 の二つの視点から、プールモデルにおけるテナント分離のポイントを整理していきます。

アクセス先の共有

アクセス先が共有されている構成とは、ストレージなど接続先のリソースが複数テナントで共有されている構成です。テナント別ではなく目的別にデータベースをまとめたいなど、プールモデルへの移行の第一段階として、この形を検討されている方も多いのではないでしょうか。ここで注目すべきは「共有リソースをどうテナント分離するか」になります。接続元がテナントごとに別れており、そのアクセスがどのテナントによるものなのかは判断できますので、どのようにテナントごとにリソースを割り当て、どのように境界をセキュアに保ち、クロステナントアクセスを防ぐかが主な関心ごととなります。

img_tenant-isolation-dynamic-policy_01

図 1 : Amazon DynamoDB をテナント分離する例

同じ Amazon DynamoDB のテーブルを複数テナントで領域を分割して利用するケースを考えてみましょう。図 1 はテナントごとの Amazon Elastic Compute Cloud (Amazon EC2) のインスタンスの集まりから、同じ DynamoDB のテーブルを利用する構成を表しています。

IAM ポリシーを利用した枠組みですと、例えば DynamoDB でのテーブルごとのアクセス制御や条件キーを用いた行レベルのアクセス制御、Amazon Simple Storage Service (Amazon S3) のバケットやフォルダごとのアクセス制御などで分ける方法が挙げられます。管理面やセキュリティ面の観点から、基本的には IAM ポリシーを活用できる構成を推奨しますが、ビジネス要件に応じて専用のシステムを用意するのも良いかもしれません。リソースを共有することによるパフォーマンス問題や、ノイジーネイバーなどにも注意を払っておいた方が良いでしょう。


アクセス元の共有

次にアクセス元の共有を見てみましょう。アクセス元が共有されている構成とは、複数のテナントからのアクセスが同じ接続元から行われる構成です。この場合「そのアクセスはどのテナントのものであると判断するか」が注目すべきポイントになります。なぜならば前節のアクセス先が共有されている構成では、アクセス元からの接続がどのテナントによるものか判断できましたが、アクセス元が共有されている場合では接続元からテナントを判断することができないためです。

リソース分離やアクセス制御をアクセス先で行うためには、その処理がどのテナントによるものなのか判断できる情報 (テナントコンテキスト) をシステムに伝える必要があります。

img_tenant-isolation-dynamic-policy_02

図 2 : アクセス元が同じ例


テナントコンテキストの伝え方

テナントコンテキストをシステムに伝える方法ですが、一つのアプローチとしてアイデンティティプロバイダでのサインイン後に得られるトークンにテナント固有情報を加える方法が挙げられます。例えばサインイン後に渡されるユーザー認証情報 (トークン) にカスタム属性を追加するといった方法です。このトークンには JSON Web Token (JWT) が用いられることが一般的です。JWT はクレーム (属性情報) を JSON で取り扱うためのオープン標準ですが、同じくオープン標準である JSON Web Signature (JWS) によるトークンのデジタル署名や、JSON Web Encryption (JWE) によるトークンの暗号化と併せて利用されることもあります。

具体的な例として Amazon Cognito を用いた方法を考えてみましょう。Amazon Cognito は認証・認可の機能を提供する AWS のサービスです。Amazon Cognito のサインイン後に取得できるトークンにも JWT が用いられており、カスタム属性を持つユーザプールを作成することでテナントの固有情報を JWT に含めることができます。

ユーザーはこのトークンを HTTP の Authorization ヘッダに加えてリクエストすることにより、自分が属するテナントの固有情報をシステムに伝えることができるようになります。システム側でもこの Authorization ヘッダに付与されているトークンからテナントの固有情報を抽出することで、このアクセスかどのテナントによるものか判断できるようになります。

img_tenant-isolation-dynamic-policy_03

図 3 : Amazon Cognito を使ったテナントの固有情報の伝え方

しかしここで一つ問題があります。図 3 のように Amazon Cognito を使ってテナントの固有情報をシステム側に伝えるわけですが、アクセスを受け取る、共有する EC2 インスタンスから DynamoDB にアクセスするための IAM ポリシーがテナントごとにアタッチされているわけではありません。そのため、そのままではテナントコンテキストは伝えたものの、DynamoDB に対して Amazon EC2 からアクションを取ることができないという状況になります。

アクセスがどのテナントによるものかは判断できますので、あとは適切な IAM ポリシーをアタッチできればいいのですがどのような方法があるでしょうか。ここでは次に動的なポリシー生成によるテナントごとの IAM ポリシーのアタッチを紹介していきたいと思います。


動的なポリシー生成

テナントコンテキストに応じて IAM ポリシーをアタッチする方法について、ここではAWS Security Token Service (AWS STS) を使用した動的なポリシー生成のメカニズムを紹介したいと思います。

AWS STS は一時的なセキュリティ認証情報を発行することができるサービスで、AssumeRole アクションによりAWS リソースへのアクセスに必要なセキュリティ認証情報のセットを一時的に取得できる機能を持っています。この IAM ポリシーの取り扱いには、あらかじめテナントごとにカスタムポリシーを設定しておく方法と、テナントコンテキストをテンプレートに注入して動的に生成する方法があります。

しかし、テナント増加時に管理すべきポリシーが増加してオペレーションミスが増える可能性を鑑みると、特にテナント数が多くなる状況では、後者の選択肢、動的にポリシー生成する方法が運用しやすいのではないかと考えます。

img_tenant-isolation-dynamic-policy_04

図 4 : AWS Security Token Service (AWS STS) を使った動的なポリシー生成

図 4 は STS を使った動的なポリシー生成、クレデンシャル発行をもって DynamoDB にアクセスする手続きを表しています。手続きの流れは次のようになります。

Amazon Cognito でのサインイン後、ユーザーは取得したトークンと共にシステムにアクセスします。リクエストの HTTPヘッダには Authorization ヘッダが含まれており、この例では JWT が付与されています。システムでは受け取ったテナント固有情報を JWT から取得し、テンプレートに注入することで IAM ポリシーを生成し、STS に対してこのポリシーに応ずるクレデンシャルの発行を依頼します。クレデンシャルが発行された後は、テナントごとのポリシーに基づいて DynamoDB の操作を行い、ユーザに対してレスポンス結果を返却します。

以下のスニペットは動的なポリシー生成に用いられる IAM ポリシーのテンプレート例になります。

{
    "Version": "2012-10-17",
    "Effect": "Allow",
    "Action": [
        "dynamodb:GetItem",
        "dynamodb:BatchGetItem",
        "dynamodb:Query",
    ],
    "Resource": [
        "arn:aws:dynamodb:*:*:table/MyTable"
    ],
    "Condition": {
        "ForAllValues:StringEquals": {
            "dynamodb: LeadingKeys": [ "{{tenant}}" ]
        }
    }
}

この例ですとテナントコンテキストの注入で “{{tenant}}” を置き換えることで、DynamoDB のパーティションキーが一致する行のみにアクセスを許可することができ、 DynamoDB に対してテナントごとの行レベルのアクセス制御が行えるようになります。

例えば以下のテーブルの場合、注入されたテナントコンテキストが “Tenant-1” なのであれば、赤色背景の行のみがアクセス可能になります。

img_tenant-isolation_06

このテンプレートへの注入を用いた方法は、テナントごとに管理するポリシーを設定する必要がないため、テナント増加によっての管理するべきポリシーが増えすぎてしまったり、オペレーションが煩雑になったりといった影響を受けることはありません。そのため静的なポリシーを利用する場合と比べて、ポリシー管理の負担が大きく減ります。

また、このテンプレートではテナント識別子のみがプレースホルダーに指定されていますが、プレースホルダーを追加したり、適用するテナントコンテキストを変えたりすることで、より複雑なテナント分離を実現することも可能です。サービス特性に合ったリソース選択、分離戦略を見定めテンプレートを進化させていくのが重要になります。


まとめ

複雑になりがちなマルチテナントアーキテクチャにおいて、動的なポリシー生成を利用したテナント分離手法は SaaS プロバイダーにとってとても強力な手段です。IAM の仕組みを活用することにより、セキュアで一貫したアクセス制御を横断的に展開することができるようになります。

本稿ではプールモデルのテナント分離から動的なポリシー生成の必要性やその効果について紹介させていただきました。今回は説明に用いた構成として、Amazon Cognito、Amazon EC2、DynamoDB、AWS STS の組み合わせを用いましたが、DynamoDB の代わりに Amazon Relational Database Service (Amazon RDS) for PostgreSQL を使ったり、Amazon EC2 の代わりに AWS Lambda を使ったりなど、基本的なメカニズムが変わらない限り、異なる組み合わせにも応用できます。皆さまのマルチテナントアーキテクチャの設計に本稿の知識がお役に立てば幸いです。

これからも皆さまのご意見をもとに役立つ SaaS の情報をどんどん発信していきたいと思います。それでは次回もお楽しみに !


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

プロフィール

photo_aoshima-tomohisa

青嶋 智久
アマゾン ウェブ サービス ジャパン株式会社 パートナーソリューションアーキテクト

モバイルアプリケーションエンジニアとしてキャリアをスタートする。その後、ウェブアプリケーション、Mobile Backend as a Service (MBaaS)、DevOps システムに携わり 2021 年にアマゾン ウェブ サービス ジャパン株式会社に入社。
現在は SaaS 担当のパートナーソリューションアーキテクトとして、主に ISV のお客様を支援。

AWS のベストプラクティスを毎月無料でお試しいただけます

さらに最新記事・デベロッパー向けイベントを検索

下記の項目で絞り込む
絞り込みを解除 ≫
フィルタ
フィルタ
1

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する