はじめに:なぜすべてのテナントに個別のAWSアカウントを使うのか?
SaaSプラットフォームが成長する過程で最初に直面する課題は**テナント分離(Isolation)**です。初期段階では1つのAWSアカウント内でIAMポリシーとデータパーティショニングによってマルチテナンシーを構成するのが一般的です。しかし、テナント数が数百、数千に増えると以下の問題が発生します。
- ブラスト半径(Blast Radius):1つの設定ミスや脆弱性が複数のテナントを同時に露出させる
- サービスクォータ:単一アカウントのLambda同時実行数、APIレート制限などを全テナントで共有
- 運用複雑度:「このリソースは誰のものか」の追跡が困難
- コスト透明性の欠如:共有インフラコストをテナント別に正確に配分することが難しい
ProGloveはこの問題に対して 「テナントごとに個別のAWSアカウントを割り当てる」 方式で解決しました。現在約 6,000アカウントのうち50%(約3,000)がアクティブで、40のマイクロサービスが各アカウントにデプロイされ、合計12万以上のサービスインスタンス、約100万のLambda関数が運用されています。運用メンバーはわずか 3名です。
🧠 コアインサイト:「運用チームの規模を拡大せずにテナント数を増やす」というパラドックスを可能にしたのはプラットフォーム自動化です。複雑性をアプリケーションコードからプラットフォームエンジニアリングに移したのです。
本記事はAWS Architecture Blogに掲載された6000 AWS accounts, three people, one platform: Lessons learnedをベースに、日本のSaaS企業が参考にできる実践的インサイトをまとめました。

アカウント単位テナントモデルの実装:CI/CDと可観測性
CI/CD:1回のパイプラインで数千アカウントにデプロイ
最大の難関はデプロイ自動化です。1つのアカウントにデプロイすることと、数千アカウントに同時にデプロイすることは次元の異なる問題です。ProGloveは AWS CodePipeline + CloudFormation StackSets の組み合わせで解決しました。
# 例:StackSetsを使った大規模並列デプロイ構成(実際のProGlove構成を簡略化)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'テナントアカウントに共通マイクロサービスをデプロイするためのStackSet'
Parameters:
TenantAccountIds:
Type: CommaDelimitedList
Description: デプロイ対象テナントアカウントIDリスト
Default: "111111111111,222222222222,333333333333"
Resources:
# 各テナントアカウントに同一のLambda関数をデプロイ
TenantServiceStackSet:
Type: AWS::CloudFormation::StackSet
Properties:
StackSetName: !Sub "${AWS::StackName}-tenant-service"
TemplateBody: |
AWSTemplateFormatVersion: '2010-09-09'
Resources:
TenantFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "tenant-${AWS::AccountId}-processor"
Runtime: python3.12
Handler: index.handler
Code:
S3Bucket: my-artifact-bucket
S3Key: tenant-service.zip
Role: !GetAtt TenantExecutionRole.Arn
TenantExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
# 全テナントアカウントにデプロイ(組織単位またはアカウントIDリスト)
DeploymentTargets:
Accounts: !Ref TenantAccountIds
Regions:
- ap-northeast-1
# 中央アカウントでStackSetの管理ロールを実行
PermissionModel: SERVICE_MANAGED
AutoDeployment:
Enabled: true
RetainStacksOnAccountRemoval: false
⚠️ 注意点:StackSetsは強力ですが、部分的なロールアウト失敗時のロールバック戦略を明確に定義する必要があります。ProGloveは失敗したアカウントのみを再試行するカスタムリトライロジックをStep Functionsで実装したとのことです。
可観測性(Observability):集中と分離のジレンマ
モニタリングも大きな課題です。各アカウントが独立してCloudWatchログとメトリクスを生成すると、オペレーターは数千のダッシュボードを個別に見ることはできません。ProGloveのアプローチ:
- 集中可観測性プラットフォームの導入:全テナントアカウントのテレメトリー(ログ、メトリクス)を中央アカウントのサードパーティツール(例:Datadog、Grafana)に転送
- タグ付け戦略の統一:すべてのリソースに
TenantId、Environment、ServiceNameタグを強制し、フィルタリングと相関分析を容易に - アラーム重複防止:各アカウントに同一アラームを複製せず、ストリーミングと集約(Aggregation)方式を採用
# 例:中央可観測性アカウントへのメトリクス転送(Python + boto3)
import boto3
import json
from datetime import datetime
def put_metric_to_central_account(tenant_account_id, metric_name, value, unit="Count"):
"""
各テナントアカウントから中央モニタリングアカウントへカスタムメトリクスを転送
- tenant_account_id: ソースアカウントID(タグ付け用)
- metric_name: 例: 'TenantRequestLatency'
- value: 測定値
"""
# 中央アカウントのIAMロールをAssumeRole
sts_client = boto3.client('sts')
assumed_role = sts_client.assume_role(
RoleArn='arn:aws:iam::CENTRAL_ACCOUNT_ID:role/MetricForwarderRole',
RoleSessionName='TenantMetricForwarder'
)
cloudwatch = boto3.client(
'cloudwatch',
aws_access_key_id=assumed_role['Credentials']['AccessKeyId'],
aws_secret_access_key=assumed_role['Credentials']['SecretAccessKey'],
aws_session_token=assumed_role['Credentials']['SessionToken']
)
cloudwatch.put_metric_data(
Namespace='ProGlove/TenantMetrics',
MetricData=[
{
'MetricName': metric_name,
'Value': value,
'Unit': unit,
'Timestamp': datetime.utcnow(),
'Dimensions': [
{'Name': 'TenantAccountId', 'Value': tenant_account_id}
]
}
]
)

アカウント単位テナントモデルの影:コストと限界
コスト:「無料」と思っていたサービスが3,000ドルに
アカウントあたりわずかな固定費がかかるサービスは、テナント数が増えると指数関数的に増加します。例:
| サービス | 単一アカウントコスト | 1,000アカウントコスト(月額) | 備考 |
|---|---|---|---|
| EC2 t4g.nano(最小) | ~$3 | $3,000 | 使用量に関わらず課金 |
| RDS db.t4g.micro(最小) | ~$15 | $15,000 | 使用量に関わらず課金 |
| Lambda(リクエスト単位) | $0.20/100万リクエスト | $200(1000アカウント×1000リクエスト/日) | 実使用量ベース |
| DynamoDB(オンデマンド) | $1.25/100万WRU | $1,250(1000アカウント×1000WRU/日) | 実使用量ベース |
💡 実務ヒント:「サーバーレス」だからと安心してはいけません。LambdaやDynamoDBは使用量ベースですが、CloudWatchメトリクス収集コストはアカウントあたりの固定費として発生します。ProGloveは全てのメトリクスを収集せず、必要なものだけフィルタリングしてコスト最適化を行ったとのことです。
限界と注意点
- AWSサービスクォータの分散:各アカウントが独立しているため、クォータ超過は特定テナントに限定されるが、全体のクォータ使用状況を一覧で把握することが難しい
- 認証情報管理の複雑さ:数千のIAMロールとクロスアカウント信頼ポリシーを安全に管理する必要がある。長期クレデンシャルの使用は絶対に避けるべき
- 退役(Decommission)自動化の難しさ:アカウント作成は完全自動化可能だが、アカウント閉鎖はデータバックアップ、コンプライアンス確認など手動プロセスが必要
- 組織単位(OU)構造設計:AWS OrganizationsでOUをどう構成するかでSCP(サービスコントロールポリシー)の適用範囲が変わる。初期設計が重要
日本市場での適用コンテキスト
日本のクラウド/SaaS環境では以下の点を考慮する必要があります。
- アカウントあたりの最低コスト負担:日本のスタートアップの場合、初期は共有アカウントモデルで開始し、テナントあたりの売上が一定以上に達した時点でアカウント分割を検討するのが現実的です。
- 規制遵守:金融、医療など規制業界では、アカウント分割がかえってコンプライアンス証明を簡素化できる場合があります。各テナントアカウントに個別の監査ログを構成できるためです。
- 運用人員規模:ProGlove事例は「3名」という極端な効率性を示していますが、日本では最低5〜10名のプラットフォームエンジニアリングチームが必要になる可能性があります。初期投資コストを考慮してください。
合わせて読みたい記事
- PyTorch分散学習完全ガイド:Point-to-PointとCollective Operationsの実戦コード - 分散システムにおける通信パターンの理解
- NetflixがJDKベクトルAPIでレコメンデーションシステムを最適化した実例 - 大規模システム最適化アプローチの比較

結論:運用チームを増やさずにテナントを増やす方法
ProGloveの事例が与える最大の教訓は 「複雑性の移動(Shift Complexity)」 です。従来のアプローチでは各マイクロサービス開発者がマルチテナンシーを考慮する必要がありましたが、アカウント単位テナントモデルではプラットフォームチームがその複雑性を吸収します。
次のステップとしての学習方向:
- AWS Organizations + SCP の深堀り:OU設計、タグポリシー、バックアップポリシーなど
- CloudFormation StackSets + Terraform:大規模インフラ自動化ツールの比較
- Observability as Code:集中型モニタリングパイプラインの構築(OpenTelemetry、Grafana)
📌 最終アドバイス:このモデルは「すべてのSaaSにとっての正解」ではありません。テナントあたりの売上が高く、セキュリティ/規制要件が厳しく、運用自動化に投資できる余力がある企業に適しています。最初から6,000アカウントを目標にせず、10、100単位で段階的に拡張しながらプラットフォーム自動化のケイパビリティを高めていきましょう。