Ameba Platformにおけるマルチテナントの設計と反省
#SRG(Service Reliability Group)は、主に弊社メディアサービスのインフラ周りを横断的にサポートしており、既存サービスの改善や新規立ち上げ、OSS貢献などを行っているグループです。
本記事は、2023年から2024年にかけてAmeba Platformで行ったマルチテナント対応に向けた設計とその振り返りについてまとめたものです。
背景と課題移行できなかった理由設計再考のタイミング絶対要件の明確化設計における方針セキュリティ分離の観点セキュリティレベル例外対応アプローチと詳細1. 認証・認可の統合戦略2. ネットワークセキュリティの実装3. 共用リソース、ボリュームとバックアップの保護4. 監視とAPMのセキュリティ振り返りFine-Grained対応ができない各テナントの運用実態はもっと複雑Network Policyはかなり有用終わりに
背景と課題
Ameba Platformとは、AmebaBlogと周辺サービスのインフラ基盤(主にEKS)をコアとするプラットフォームです。2020年頃、開発デプロイフローの統一と技術スタックの簡素化を目指して始動し、多くのサービス群をより効率的で管理しやすいインフラに統合することがプロジェクトの中心的な目標でした。
プロジェクトの初期段階ではコア部分の移行に成功したものの、EKSとその他のセキュリティ上の課題により、認証系サービスやセキュリティレベルの高いサービスをAmeba Platformに移行することができませんでした。これらのサービスは、既存のインフラや別途用意されたEKS環境で継続的に運用せざるを得ない状況にありました。
移行できなかった理由
- EKS ネットワークセキュリティの脆弱性 デフォルト設定では、全てのPodが互いに通信可能です。2020~2021年当時、Pod間通信のセキュリティを確保するための成熟したツールが不足していました。やの導入コストが高く、ベンダー依存性などの問題で見送られました。
- 認証・認可システムの統合難題 社内認証認可基盤を用いて、Kubernetes RBACとAWSのIAM、全ての開発者ツール・監視運用ツールを完全に統合できる設計は理想でしたが、プラットフォーム化の初期段階である2020~2021年当時ではそこまでの余裕がありませんでした。
- IstioとEKSの相性問題
2020~2021年当時、PodとAWSリソース間のネットワーク通信を制限する機能を導入すると、Istioのサイドカーコンテナが起動できない問題が発生していました。AWSサポートに問い合わせたところ、Istioに原因があるかもしれないと結論づけられ、原因は不明のままIstioとSGPの併用を諦めました。IAM認証ができないサービスが存在するため、PodとAWSリソース間のネットワーク通信を制限できないと、セキュリティレベルが異なるサービス間の共存が極めて難しくなるため、導入を断念しました。
設計再考のタイミング
2023年、プラットフォーム化開始から約3年が経過し、人的リソースに余裕ができ、技術的な選択肢が広がったことで、マルチテナントの設計を根本から見直し、移行プロセスを再開する機会が訪れました。
まず、VPC CNIとSGPの動作の安定化が証明され、SGPの使用が可能になりました。また、2022年からVPC CNIがNetworkPolicyのネイティブサポートを開始し、ベンダー依存を最小限にすることができました。
2023年、私がサイバーエージェントに入社した直後にこのプロジェクトに参画し、認証連携とAWS・EKS上のマルチテナント設計を行いました。
絶対要件の明確化
プロジェクトの再設計において、以下の要件は譲れない絶対的な条件として定められました。
- セキュリティレベルに応じた完全な通信隔離
Pod ↔ Pod間、Pod ↔ AWSリソース間
- 共通認証基盤を通じたすべての通信の一元認証
AWS、EKS、Datadog、ArgoCD、Github Teams
- AWSリソースとKubernetesリソースの厳密なアクセスコントロール
RBACやABACなど活用
設計における方針
さらに、以下の方針を設計の指針としました。
- 特定のベンダー製品への依存を最小限に抑える
- 可能な限りKubernetes・AWSのデフォルト機能での実現を目指す
- 認証・認可プロセスのシンプルさとメンテナンス性の確保
セキュリティ分離の観点
セキュリティレベル
AWS上のサービスは、互いに独立しつつ、対等な関係を持っています。セキュリティ分離を実現するためには、IAMのABACを活用し、各サービスのセキュリティレベルを識別し、それに基づいて通信を制御することが重要です。リソースタグは、サービスのセキュリティレベルを識別する最適な手段の一つです。
Amebaのプラットフォームでは、マイクロサービスの特性を考慮し、サービスを以下のように分類しました。
- Protectedサービス:セキュリティ要件が高く、厳格な管理が必要なサービス
- Non-Protectedサービス:セキュリティ要件が比較的低いサービス
通信制御において、以下の原則を設定しました
- セキュリティレベルが高いサービス(Protected)
- Inbound(受信)通信は厳格に制限
- Outbound(送信)通信は比較的自由
- セキュリティレベルが低いサービス(Non-Protected)
- Inbound、Outbound共に比較的制限が緩い
例外対応
従来のマルチテナントモデルでは、各テナントに厳格な制限を設け、自身のリソースのみにアクセスを制限するのが一般的です。しかし、実際の運用においては、より複雑な要件が存在します。例えば、認証サービスを管理するチームは、日常的に異なるセキュリティレベルのサービスを横断的に扱う必要があります。
セキュリティレベルの高いサービスにおいても、一部のAPIを公開するなど、例外的なInbound通信を許可する必要があります。例外の通信を許可する場合、その対象の一部のセキュリティレベルを調整しました。
Amebaのプラットフォームでは、以下の通信制限を設定しました。
- Non-Protectedサービスは、Protectedサービスにアクセス不能
- Protectedサービスは、Non-Protectedサービスにアクセス可能
- 特定のエンドポイントを公開するProtectedサービスは、関連部分をNon-Protectedサービスに降格
アプローチと詳細
マルチテナント設計の具体的な実装アプローチは、以下の4つの主要な領域に焦点を当てて展開しました。
1. 認証・認可の統合戦略
認証基盤の統一
Ameba Platformでは、認証・認可の一元管理を実現するため、以下の統合アプローチを採用しました
- AWS、Datadog、Githubの認証: 社内SAML基盤を活用
- Node SSH アクセス: 社内LDAP基盤を利用
- ArgoCD: Github TeamsのOAuth2とOIDCを併用
社内認証基盤の機能上の制約により、認証の統合はこのプロジェクトの最も複雑な側面の一つでした。本来はOIDCで一元化できるものもありますが、社内認証基盤のOIDC機能が不足していたため、多岐にわたる方式を採用する必要がありました。
特にArgoCDの場合、dexのSAMLセキュリティ上の懸念から社内認証基盤と直接連携することができず、GitHub Teams経由のOIDC連携を行いました。GitHub Teamsは予めSAML連携しているため、ユーザの棚卸しは不要となります。
ArgoCD SAML連携の問題について、過去の記事をご参照ください。
ABAC: Role
IAMロール設計においては、従来のの3層構造から、の2層構造へと最適化しました。これは、実際の使用パターンを綿密に分析した結果です。他の組織でもよく見られることですが、viewerロールがほとんど使用されていないことが分かりました。また、既存のeditorとadminロールにおいて権限の分離が十分にできていない箇所もあったため、一本化することで構造がより明確になりました。
テナントの運用実態によって、のフォーマットでIAM Role対応を行いました。
例えば、Aというテナントの一般開発者ロールは になります。
Aというテナントにおいて、機密情報を扱う人のロールは、 になります。
運用実態に応じて、他のロールと対応する属性を追加することも可能な体制にしています。
ABAC: Policy
高度なアクセス制御を実現するため、Resource Tagベースの属性管理を導入しました
- : Protectedサービスの識別
- : 機密情報を含むサービスの識別
- : 部分的に公開するProtectedサービスの識別
これらのタグを利用し、などのConditionを活用することで、柔軟かつ粒度の高いIAMポリシーの設定を可能にしました。例えば、以下の例では、Non-Protectedのポリシーに対し、以下の工夫をしました
- AdminとDeveloperを区別するため、NotActionsを利用する
- とを利用し、「Protectedサービス以外のリソースに対し、以下のAction以外のActionは許可する」
- とを利用し、「部分的に公開するProtectedサービスは以下のAction以外のActionなら許可する」
ABACでほとんどのAWSサービスを制御できますが、一部Resource Tagで制御できないサービスもあります。その際、対応しているConditionで個別対応する必要があります。
例えば以下のサービスとAPI
詳細の情報はService Authorizationのドキュメントから調べられます。
EKS RBAC
IAM RoleとのMappingで連携しています。IAM Roleと同じく、からのロールになりました。
KubernetesのRoleは、すでに分離できるように整備されています。マルチテナント対応では、Namespaceごとに改めておよびリソースを作成する必要があります。
KubernetesのRBACは丁寧に作成することが可能ですが、複雑な事例ではリソースが多岐に渡り、かえってわかりづらくなることがあります。
2. ネットワークセキュリティの実装
Pod ↔ Pod間通信
Pod間通信の制御には、Kubernetes NetworkPolicyを採用しました。vpccniにおいて、NetworkPolicyを使用する際に、Addonsので有効化を設定する必要があります。
NetworkPolicyは、主にNamespaceごとに設定され、とで適用対象と制限対象を指定します。
IAMのABACと同様のタグ戦略を適用する際、以下の注意点があります。
- 全てのProtectedサービスを一括してルールを指定しない限り、protectedサービスを識別するTag の利用は不要となります
- ProtectedのNamespace内のPodを外部に公開する際のExpose Tagは必要になります
Ameba Platformの場合、が利用されており、Namespaceは事前に階層化されています。マルチテナントが追加される際に必ず新しいが追加されるため、NetworkPolicyのnamespace指定はかなり楽になります。
以下の例は、テナントAのChild-1 Namespaceに設定するNetwork Policyです。テナントA以外のNamespaceからのIngress通信をブロックしています。で、テナントAの全てのChild Namespaceを指定しています。
以下の例は一部公開のProtectedリソースの例です。のPodのみが対象となります。
また、Hierarchical Namespaceの継承機能を使えば、上記のように各Child Namespaceで作成する必要がなくなります。
Pod ↔ AWSリソース間通信
PodとAWSリソース間の通信においては、vpccniの機能を採用しました。Aurora、ElastiCacheなどの外部サービスと通信するPodに対して、専用のセキュリティグループを作成し、細かな通信制御を実現しました。
SGPの利用は、2つかのステップがあります。
- vpccniに以下の設定を変更します
- SGPのCustomResourceを利用します
SGPは、いくつかのリスクがあります。
- 適用可能のPod数に上限があります。
を有効化すると、NodeごとにSGP専用のENI()が作成されます。SGPの適用対象のPodが作成される際、が作成され、IPアドレスが付与される流れになります。
の数もNodeが搭載できるENI数に含まれるため、NodeのENI数は使用中のInstance TypeがサポートしているENI数に達した場合、Trunk ENI作成されないため、該当のNode上SGが適用したPodが作成されません。
- Podの起動速度が遅くなります。
が作成され、PodにIPアドレスが付与されるフローでは、初期化に必要な時間は通常のPodより5s~10sほど遅くなることがあります。
- 他のネットワーク系ベンダーと衝突する可能性
今では解決されましたが、過去ではIstioと衝突したこと(未確証ですが)がありました。AWSのサポート的にはIAM認証が推奨されるため、SGPは最後の手段として考慮した方がいいでしょう。
SGPの詳細に興味がある方は、過去記事をご参照ください。
3. 共用リソース、ボリュームとバックアップの保護
共用リソース
ECRやS3などの共用リソースについては、Sharedアカウントで一元管理されるため、Sharedアカウントにおいて、ResourceTagによるアクセス制御を実装しました。Resource Tagの制御が困難なサービス(例えばS3)に対しては、リソース名のプレフィックスによる識別方式を併用しています。
ストレージ層
全てのEBS Volume操作はResource Tagで制御できます。ただし、EKSで使う場合、一つの例外が発生します。
からEBS Volume生成する場合、デフォルトではTagがありません。一貫したタグ管理を実現するため、StorageClassにタグ指定ルールを追加しました。
バックアップ
全てのAWS Backupはcreate/copyなどのAPIは Resource Tagの制御対象になります。
4. 監視とAPMのセキュリティ
監視ツール、特にDatadogとの統合においては、認証基盤との連携を試みましたが、APMの権限制御には課題がありました。
APMの制限自体は存在していますが、細粒度の権限制御が難しいことがわかりました。以下の図のような粒度で分けると特定の権限がない人全員APMを見れなくするか全員見えるようにするかしかハンドリングができません。
そのため、機密データがAPMに入る前にマスキングを行うアプローチを採用しました。
振り返り
Ameba Platform全環境で対応して約半年が過ぎましたが、人的リソース不足で移行はまだ始まっていない状況です。この振り返りでは、これまでの試運用で感じたことや他社の事例を見て考えたことをまとめます。
Fine-Grained対応ができない
2本化されたdeveloperとadminのRoleは、一部特定のサービスとリソースをしか見ない人に対して、細かい権限設定に対応できていません。毎回追加を依頼された際、「こんな権限の強いロールを渡していいのか」と考えてしまいます。
IAM Roleと社内認証基盤のロールが一対一の関係にあるため、必要に応じて増やすことが現実的に難しい状況です。どうするべきかまだ悩んでいます。良い案がある方はぜひ教えてください。
各テナントの運用実態はもっと複雑
IAM Role的に、のフォーマットを決めたのですが、実態はもっと複雑で、このフォーマットで対応できるか正直なところ不安です。
例えば、一部のテナントが利用している認証基盤のロールは複数の用途で利用されており、メンバーの管理も連携管理も各自で運用していました。このようなロールをAmeba Platformに統合できないため、不完全なマルチテナントになってしまいそうです。
さらに、弊社の認証基盤にはロール間の参照上限があるため、メンバー管理をAmeba Platformに統合したいと考えても、どこまで実現できるのかは現時点では不明です。
Network Policyはかなり有用
近々、Ameba PlatformにZero Trustを導入しました。のアクセス範囲を制限することも、マルチテナント対応の範囲内に入れる必要がありました。
EKS内のは、Network Policyで柔軟に制限することで、特定のCloudflare Tunnelのみ経由でアクセスできるネットワーク設計を実現できました。Network Policyは想定以上に有用であり、マルチテナント対応でもっと良い用途があるのではないかと最近考え始めました。
終わりに
Amebaで行ったマルチテナント対応の始終を思い出しながら書きました。振り返ってみると、いろんなところで記憶が曖昧になってしまい、当時丁寧に書いたドキュメントに何度も救われました。
この記事はあくまでサイバーエージェント社内の一事例ですが、ご参考になれば幸いです。
SRG では一緒に働く仲間を募集しています。
ご興味ありましたらぜひこちらからご連絡ください。