1. Service Catalog概要とプラットフォームエンジニアリング文脈

- 本連載は、AWS Service Catalogを使って「開発者が承認済みのIaCテンプレートをセルフサービスで起動できる基盤(Internal Developer Platform / IDP)」を本番運用する設計を扱います。
- Vol1では、ポートフォリオ/製品設計・起動制約による権限分離・TagOptions・Organizations跨ぎ共有という土台を整理します。
1-1. Service Catalogが解く課題
AWS Service Catalogは、「中央チームが承認したCloudFormationテンプレート(製品)だけを、開発者が強いIAM権限を持たずにセルフサービスで起動できる」仕組みを提供します。
AWSリソースを自由にプロビジョニングできる環境では、次の問題が生じます。
- 野良CloudFormationスタックや手動作成リソースが増殖し、ガバナンスが失われる(シャドーIT)
- セキュリティポリシーや命名規則・タグ付けルールが守られないリソースが本番環境に混在する
- プラットフォームチームが承認していないIaCが展開され、障害・コスト超過の温床になる
- 開発者ごとに独自のIAMポリシーを発行し続けることで、権限管理が肥大化する
Service Catalogは「承認済みのIaCテンプレートのみをカタログとして公開し、エンドユーザーはそこから起動するだけ」というモデルでこれらの課題を解決します。起動制約(Launch Constraints)により、エンドユーザー自身には強いIAM権限を与えず、プロビジョニング時だけ事前定義したロールを使う仕組みが中核です。開発者は「何を起動するか」だけを選択し、「どんなIAM権限で動くか」はプラットフォームチームが制御します。
1-2. プラットフォームエンジニアリング/IDP文脈での位置づけ
プラットフォームエンジニアリングの文脈では、Internal Developer Platform(IDP)が「開発者が自律的に、しかし組織のルール内で動ける環境」を提供します。Service Catalogはこの「セルフサービス」と「ガバナンス」を両立する中心的な機能を担います。
- ゴールデンパス提供: プラットフォームチームが承認済みのIaCテンプレートをPortfolioとして公開し、開発チームはその中から選ぶだけでリソースを起動できる
- ガバナンス強制: TagOptions・TemplateConstraint・LaunchRoleConstraintにより、ポリシー準拠のリソースしか作れない環境を強制できる
- 委任とスケール: Organizations跨ぎのPortfolio共有により、1箇所でメンテした製品を全メンバーアカウントへ即時配信できる
- 可視性: どのアカウントで誰が何をプロビジョニングしたかをCloudTrailで統一的に把握できる
IDPの代表的なOSSツールとして知られるBackstageと比較することで、Service Catalogの位置づけがより明確になります。
| 観点 | AWS Service Catalog | Backstage(OSS) |
|---|---|---|
| 運用形態 | AWSマネージド(設定のみ) | セルフホスト(Kubernetes等の周辺インフラ整備が必要) |
| 対象テンプレート | CloudFormation / Terraform / CDK / External | Cookiecutter / Pulumi / カスタムアクション |
| AWSサービス統合 | IAM / Organizations / TagOptions とネイティブ統合 | AWSプラグイン経由(追加設定が必要) |
| エンドユーザーUI | Service Catalogコンソール / API | Backstageポータル(カスタマイズ可能) |
| 導入コスト | 低(AWSアカウントがあれば即利用可) | 高(DBやGitHub等の周辺インフラ整備が必要) |
| 向いている用途 | AWSリソースのセルフサービス提供と権限分離に特化 | 全社横断ポータル・サービス登録・ドキュメント管理を包含 |
Service Catalogは「AWSリソースのプロビジョニング統制」に特化した設計であり、フルスタックのIDP基盤が不要な組織でも低コストで導入できます。既存のAWSアカウント管理フロー(Organizations・SCP・Control Tower)とネイティブに統合できる点が、プラットフォームエンジニアリングの「最初の一手」として採用しやすい理由です。大規模なポータル基盤が必要になった段階でBackstageを採用し、そのバックエンドとしてService Catalog APIを呼び出す構成も選択肢のひとつです。
AWS Protonが2026年10月7日にサポート終了(新規受付は2025年10月7日終了)となる中で、セルフサービス型のIaC提供・プラットフォーム基盤の選択肢としてService Catalogを位置づける読者が増えています。本連載はProtonの解説ではなく、Service Catalogでセルフサービス基盤をどう本番運用するかに集中します。
1-3. コアコンポーネント概要
Service Catalogは4つのコアコンポーネントで構成されます。それぞれの関係を把握することで、後続セクションの設計詳細が理解しやすくなります。
Portfolio(ポートフォリオ)
1つ以上の製品と、そのアクセス権および制約をまとめた論理コンテナです。IAMプリンシパル(ユーザー・グループ・ロール)をPortfolioに関連付けることで、対象プリンシパルがPortfolio内の製品を閲覧・起動できるようになります。Portfolioは「誰がどの製品を使えるか」を管理する単位であり、チーム・環境・機能ドメインごとに設計します。Organizations跨ぎの共有機能により、1つのPortfolioを複数のメンバーアカウントに配信できます。
Product(製品)
CloudFormationテンプレート(またはTerraform・CDK・外部プロバイダーのテンプレート)をラップした再利用可能な単位です。エンドユーザーには「VPC標準テンプレート」「RDS MySQLスターターキット」のような形でカタログに表示されます。1つのProductは複数のProductVersionを持ち、テンプレートの変更履歴を管理します。
ProvisionedProduct(プロビジョニング済み製品)
エンドユーザーがProductを起動したときに生成されるインスタンスです。内部ではCloudFormationスタックとして管理され、起動・更新・削除のライフサイクルをService Catalogコンソールから追跡できます。エンドユーザーは「マイプロダクト」ビューで自身が起動したProvisionedProductの状態(AVAILABLE / UNDER_CHANGE / ERROR / TAINTED等)をリアルタイムで確認できます。
Constraint(制約)
PortfolioとProductに付与するルールセットです。Service Catalogでは4種類の制約が提供されます。
| 制約タイプ | 役割 |
|---|---|
| LaunchRoleConstraint | 製品起動時に使用するIAMロールを指定する(権限分離の核) |
| TemplateConstraint | 起動パラメータの許容値を制限する(インスタンスタイプ・AZなど) |
| StackSetConstraint | 製品をStackSets経由でマルチアカウント/マルチリージョンに展開する |
| NotificationConstraint | プロビジョニングイベントをSNSトピックへ通知する |
これら4つのコンポーネントが組み合わさることで、「承認済みテンプレートだけをセルフサービスで安全に起動できる」基盤が成立します。
1-4. 開発者の利用フロー(コンソールでVPCを起動するまで)
Service Catalogを使ったセルフサービスプロビジョニングの具体的な流れを、「開発者がコンソールからVPCを起動する」シナリオで整理します。
前提:プラットフォームチームが準備すること
- CloudFormationテンプレート(VPCスタック)をS3に格納し、Productとして登録する
- LaunchRoleConstraintを設定し、起動時に使用するIAMロールを紐付ける
- TemplateConstraintで使用可能なCIDRレンジ・AZ数などの許容値を定義する
- TagOptionsでCostCenter・Environment等の必須タグの許容値を設定する
- 開発者IAMロールをPortfolioにPrincipal Associationとして追加する
エンドユーザーの操作手順(開発者)
- AWSコンソール → Service Catalog → 「製品」タブを開く
- 「VPC Standard」など対象製品を選択し「製品の起動」をクリックする
- ProvisionedProduct名(例:
myteam-vpc-prod)を入力し、ProductVersionを選択する - パラメータ入力画面でCIDRブロック・AZ数などをTemplateConstraintで定義された許容値から選択する
- TagOptionsが設定されている場合は、CostCenter・Teamなどを一覧から選択する
- 「起動」をクリックする
CloudFormationスタックが自動作成され、数分でVPCが利用可能になります。エンドユーザーは ec2:CreateVpc などの直接権限を一切持たずに、承認済みの標準VPCをセルフサービスで起動できます。実際のリソース作成はLaunchRoleを引き受けたService Catalogが代行するためです。
1-5. 読者像とこの記事のゴール
本記事の想定読者は以下の通りです。
- マルチアカウント環境のプラットフォームチーム / クラウド基盤チームエンジニア
- 開発チームにセルフサービスプロビジョニングを提供したいアーキテクト
- シャドーITやIaC野良運用の抑制策を検討している組織のクラウド管理者
Vol1を読み終えた読者は以下の設計判断軸を持ち帰れます。
- PortfolioとProductの設計原則(アクセス制御の粒度・命名規則・バージョン管理)
- Launch Constraintsによる最小権限設計のパターンと、エンドユーザーへの権限委任設計
- TagOptionsによるコスト配賦タグの強制方法
- Organizations跨ぎのPortfolio共有によるマルチアカウント配信の構成
▶ 関連: AWS Organizations × Control Tower によるマルチアカウント統制
2. ポートフォリオと製品設計の実践

2-1. Portfolio / Product / ProductVersion の概念
図2はPortfolio・Product・ProductVersionの3層構造を示しています。
Portfolio(ポートフォリオ) は、1つ以上の製品とアクセス権・制約をまとめた論理グループです。IAMプリンシパル(ユーザー・グループ・ロール)をPortfolioに関連付けることで、対象プリンシパルがPortfolio内の製品を閲覧・起動できるようになります。Portfolio粒度はチームまたは機能ドメイン単位が推奨です(細粒度すぎると管理コスト増、粗粒度すぎるとアクセス制御が難しくなります)。同一の製品を複数のPortfolioに追加することも可能で、チームや環境(開発/本番)ごとに異なるアクセス権と制約を付与できます。
Product(製品) は、CloudFormationテンプレートをラップした再利用可能な単位です。1つのProductは1つ以上のProductVersionを持ちます。ProductにはOwner・Description・SupportEmail/URLなどのメタデータを設定でき、エンドユーザーが選択しやすいよう、わかりやすい名称と説明文を付けることが重要です。命名規則の例として、{チーム}-{用途}-{環境}(例: platform-vpc-standard)のような一貫したパターンを組織内で統一することが推奨されます。
製品の説明文(Description)は、エンドユーザーがカタログから製品を選択する際の主要な判断材料となります。説明文には「製品が作成するリソースの概要」「想定利用シナリオ」「起動パラメータで選択可能なオプションの説明」を含めることを推奨します。また、SupportEmail と SupportUrl は製品の「サポート情報」としてService Catalogエンドユーザービューに表示されます。運用担当チームのメールアドレスや内部Wikiへのリンクを設定しておくことで、エンドユーザーが問い合わせ先を即座に把握できるようになります。
ProductVersion(製品バージョン) はProductの特定バージョンで、エンドユーザーが起動を選択する実体です。バージョン名(例: v1.0.0)と説明文を付与し、CloudFormationテンプレートのS3 URLまたはインラインテンプレートを関連付けます。新しいテンプレートを同一Productに追加するだけで新バージョンが公開され、既存の起動済みスタックには影響しません。
2-2. 製品バージョン管理
ProductVersionは追加・Active/Inactive切替ができます。削除は対象バージョンを使用した起動済みプロビジョニング済み製品が存在しない場合のみ可能です。
バージョン管理の主なポイントは以下の通りです。
- 段階的な移行: 新バージョン公開後も旧バージョンをActiveのままにしておくと、既存のプロビジョニング済みスタックへの影響を最小化しつつ段階的な移行が可能です
- ガイダンスメッセージ: ProductVersionに
GuidanceとしてDEPRECATEDを設定すると、エンドユーザーが古いバージョンを選択したときに非推奨の警告が表示されます。旧バージョンを完全に非表示にするにはActive: false(非アクティブ化)を使います - 非アクティブ化の挙動: バージョンを非アクティブ化すると、エンドユーザーの新規起動画面からは非表示になりますが、既存のプロビジョニング済みスタックには影響しません
- CI/CD連携: CloudFormationテンプレートをS3バケットに配置し、CI/CDパイプラインから
aws servicecatalog create-provisioning-artifactを実行して新ProductVersionを追加するパターンが一般的です。テンプレートのGitプッシュをトリガーに新バージョンを自動公開する構成は、§3で詳説します
エンドユーザーは製品を起動する際にActive状態のProductVersionの一覧から任意のバージョンを選択します。バージョン管理方針を社内で統一することで、運用担当者が意図せず旧バージョンを展開するリスクを下げられます。
エンドユーザーへの新バージョン通知
Service CatalogはProductVersionが追加されたことをエンドユーザーにプッシュ通知する機能を提供しません。新バージョンが利用可能になったことを通知するには、以下のアプローチを組み合わせます。
- Notification Constraint(通知制約): プロビジョニングイベント(起動・更新・完了・失敗)をSNSトピックへ通知する制約を設定する。SNSからLambdaやSlack Webhookへ転送することで、起動完了通知や失敗通知のパイプラインを構築できます。ただし、Notification ConstraintはProductVersion追加イベントではなく、プロビジョニング操作イベントを通知するものである点に注意が必要です。
- EventBridge連携: CloudTrailイベント(
CreateProvisioningArtifact)をEventBridgeルールで受信し、Lambdaから社内Slackチャンネルに「新バージョンが登録されました」と自動通知する構成で補完できます。 - 社内ポータルの更新: 新バージョンのリリースノートを社内ポータルやWikiに掲載し、既存のプロビジョニング済み製品のユーザーにアップデートを案内するオペレーション手順を定型化しておくことが推奨されます。
2-3. 制約付き公開とアクセス権設計
PortfolioへのIAMプリンシパル割当(Principal Association)は、IAMユーザー・IAMグループ・IAMロールをPortfolioに関連付けることで行います。関連付けられたプリンシパルだけが Service Catalog エンドユーザービューで製品を閲覧・起動できます。
製品の公開範囲設計のベストプラクティスを以下に示します。
- IAMロールを使ったPrincipal Association: IAMユーザーやIAMグループを直接割り当てると、組織変更のたびに再設定が必要になります。IAMロールへの割当を基本とし、開発者はそのロールを引き受けるかSSOで割り当てを受ける設計が推奨です
- Portfolio粒度: チームまたは機能ドメイン単位(例:
platform-infra-portfolio・data-platform-portfolio)が管理しやすい粒度です。環境(開発/本番)ごとにPortfolioを分けることで、本番用製品に開発チームがアクセスできないよう制御することも可能です - Organizations共有時のPrincipal設計: メンバーアカウントがPortfolioを受諾(AcceptPortfolioShare)した後、そのアカウント内で独自のPrincipal Associationを設定できます。共有元(管理アカウント)側でPrincipalを定義する必要はありません。各メンバーアカウントのアカウント管理者が自アカウントの開発者ロールと紐付ける運用が標準的です
AWS CLIでのPrincipal Association例(参考):
aws servicecatalog associate-principal-with-portfolio \
--portfolio-id port-xxxxxxxxxxxxxxx \
--principal-arn arn:aws:iam::123456789012:role/DeveloperRole \
--principal-type IAM
IAM Identity Center(SSO)との連携
IAM Identity Centerを使って開発者のアカウントアクセスを管理している場合、Permission Setに紐付いたロールをPortfolioにPrincipal Associationとして登録します。IAM Identity Centerが各アカウントに自動作成するロール(AWSReservedSSO_ プレフィックス)のARNを取得し、associate-principal-with-portfolio に指定します。これにより、SSOでログインした開発者が自動的にService Catalogポートフォリオへのアクセス権を持てる構成を実現できます。
Principal AssociationのCloudFormationリソース定義
Infrastructure as Codeで管理する場合は、CloudFormationの AWS::ServiceCatalog::PortfolioPrincipalAssociation リソースを使います。
{
"Type": "AWS::ServiceCatalog::PortfolioPrincipalAssociation",
"Properties": {
"PortfolioId": "port-xxxxxxxxxxxxxxx",
"PrincipalARN": "arn:aws:iam::123456789012:role/DeveloperRole",
"PrincipalType": "IAM"
}
}
この定義をStackSetでメンバーアカウント全体にデプロイすると、Organizations内のアカウント追加に合わせてPortfolioアクセス権を自動付与するAccount Vendingパターンを構成できます。Organizations共有と --share-principals true を組み合わせる場合は、管理アカウント側のPrincipal設定がメンバーアカウントに引き継がれるため、メンバーアカウントでの個別設定が不要になります。
Service CatalogのAdmin UIからも同様の操作が可能です。Portfolioの「アクセス権」タブでIAMプリンシパルの追加・削除ができます。
2-4. 製品タイプの種類(CloudFormation / Terraform / CDK / External)
Service Catalogは4種類の製品タイプに対応しています。
| 製品タイプ | 内容 | 利用シナリオ |
|---|---|---|
| CLOUD_FORMATION_TEMPLATE | CloudFormationテンプレートを使う標準タイプ | AWSリソースのプロビジョニングに最も一般的。追加エンジン不要 |
| TERRAFORM_OPEN_SOURCE | Terraform Reference Engine経由でTerraformモジュールを管理する | 既存Terraformモジュール資産をカタログとして公開したい場合 |
| TERRAFORM_CLOUD | Terraform Cloudワークフローとの統合 | Terraform Cloudを組織で採用しており、カタログUI統合が必要な場合 |
| EXTERNAL | カスタムプロビジョナー(Lambda等)を使う | Ansible等CloudFormation/Terraform以外のIaCを管理する場合 |
CloudFormation型(CLOUD_FORMATION_TEMPLATE)の選択基準
CloudFormation型は追加エンジンの導入が不要で最もシンプルです。CDK L2 Construct(CloudFormationProduct / ProductStack)によるコード管理にも対応しており、CDKで定義したConstructをそのままProductVersionとして登録できます。AWSリソースのプロビジョニングが主目的であれば、CloudFormation型を基本選択とすることが推奨されます。なお、CDKを使って製品を管理する場合も、最終的にはCloudFormationテンプレートに合成されてService Catalogに登録されます(製品タイプはCLOUD_FORMATION_TEMPLATE)。CDK専用の独立した製品タイプは存在しません。
Terraform型を選択する場合の前提条件
TERRAFORM_OPEN_SOURCE型を使用するには、AWS Service Catalog Terraform Reference Engineをアカウントにデプロイする必要があります。このエンジンはLambdaとCodeBuildで構成され、Service CatalogからTerraformプランの実行を中継します。追加コスト(CodeBuild実行時間等)と運用オーバーヘッドが発生するため、既存Terraform資産の再利用メリットと比較した上で採用判断を行います。
External型の利用シナリオ
EXTERNAL型では、AWS Lambdaやカスタムワーカーをプロビジョニングエンジンとして登録し、Service Catalog経由でカスタム処理を呼び出す構成が可能です。CloudFormationやTerraform以外のIaC(Ansible等)を組織全体のカタログに統合したい場合や、既存の外部オーケストレーションツールとの連携が必要な場合に採用します。
2-5. コンソール操作フロー(ポートフォリオ作成から製品公開まで)
Service Catalogコンソールでポートフォリオを作成し、製品を公開するまでの基本操作フローを整理します。
Step 1: ポートフォリオの作成
AWSコンソール → Service Catalog → 「管理」→「ポートフォリオ」→「ポートフォリオを作成」を選択します。ポートフォリオ名(例: platform-engineering-portfolio)・説明・所有者(プラットフォームチームの連絡先)を入力します。
Step 2: 製品の作成とポートフォリオへの登録
「製品を作成」から新規製品を作成します。製品名・オーナー・説明・SupportEmail/URLを入力し、製品タイプとして「CloudFormation」を選択します。製品バージョン(ProvisioningArtifact)の名称(例: v1.0.0)とCloudFormationテンプレートのS3 URLを入力して製品を作成します。
製品作成後、「製品をポートフォリオに追加」から対象ポートフォリオに関連付けます。1つの製品を複数のポートフォリオに追加することも可能です。
Step 3: アクセス権の設定(Principal Association)
ポートフォリオの「アクセス権」タブを開き、「ユーザー・グループ・ロールを追加」から開発者IAMロール(例: DeveloperRole)を追加します。追加されたプリンシパルがポートフォリオ内の製品を閲覧・起動できるようになります。
Step 4: 制約の設定
ポートフォリオの「制約」タブから「制約を作成」を選択し、LaunchRoleConstraintを設定します。製品を選択し、Launch RoleのARNを入力します。TemplateConstraintを追加する場合は「テンプレート制約」タイプを選択してRulesのJSONを入力します。
Step 5: 動作確認
開発者IAMロールでAWSコンソールにログインし、Service Catalog → 「製品」タブで登録した製品が表示されることを確認します。製品を起動してProvisionedProductが AVAILABLE 状態になれば、基本設定の完了です。
3. 承認済みIaCテンプレートの配布とバージョン管理
3-1. CloudFormationテンプレートのProduct登録フロー(S3バケット経由)
AWS Service CatalogでCloudFormation製品を登録する際は、テンプレートをS3に格納し、そのHTTPS URLを参照させるのが基本フローです。
① テンプレートをS3へ格納する
バージョンごとにS3オブジェクトキーを分けて管理します。
s3://your-catalog-bucket/templates/vpc/v1.0.0/template.yaml
s3://your-catalog-bucket/templates/vpc/v1.1.0/template.yaml
バケットポリシーでService Catalogサービスプリンシパル(servicecatalog.amazonaws.com)からの s3:GetObject を許可します。aws:SourceAccount 条件を付けると自アカウント外からの読み取りを制限できます。S3バケットにはバージョニングを有効化しておくことで、テンプレートの変更履歴をオブジェクト単位でも管理できます。
テンプレートのURLは HTTPS形式(https://s3.amazonaws.com/{bucket}/{key} またはリージョン固有エンドポイント)を使用します。s3:// プロトコルは使用できません。
② ProductとProductVersionを作成する
# 新規Product(v1.0.0を同時登録)の作成
aws servicecatalog create-product \
--name "Standard VPC" \
--owner "Platform Team" \
--product-type CLOUD_FORMATION_TEMPLATE \
--provisioning-artifact-parameters '{
"Name": "v1.0.0",
"Info": {
"LoadTemplateFromURL": "https://s3.amazonaws.com/your-catalog-bucket/templates/vpc/v1.0.0/template.yaml"
},
"Type": "CLOUD_FORMATION_TEMPLATE",
"DisableTemplateValidation": false
}'
DisableTemplateValidation: false(デフォルト)にすると、Service Catalogが登録時にテンプレートの構文検証を実行します。検証エラーがある場合はProduct作成が失敗するため、CI/CDでの事前チェックと二重の安全網になります。
既存Productへの新バージョン追加は create-provisioning-artifact を使います。
aws servicecatalog create-provisioning-artifact \
--product-id prod-xxxxxxxxxxxx \
--parameters '{
"Name": "v1.1.0",
"Info": {
"LoadTemplateFromURL": "https://s3.amazonaws.com/your-catalog-bucket/templates/vpc/v1.1.0/template.yaml"
},
"Type": "CLOUD_FORMATION_TEMPLATE"
}'
③ ポートフォリオへ関連付ける
aws servicecatalog associate-product-with-portfolio \
--product-id prod-xxxxxxxxxxxx \
--portfolio-id port-xxxxxxxxxxxx
一つのProductを複数のPortfolioに関連付けることができます。例えば「開発環境ポートフォリオ」と「本番環境ポートフォリオ」で同一Productを共有しつつ、ポートフォリオごとに異なるLaunchRoleConstraintを設定することで、環境ごとの権限分離を実現できます。
ProductVersionのライフサイクル管理:
古いバージョンは update-provisioning-artifact --guidance DEPRECATED でDeprecatedとしてマークできます。Deprecatedのバージョンは既存プロビジョニング済みスタックに影響しませんが、新規起動の選択肢から除外されます。完全削除には delete-provisioning-artifact を使用します(アクティブなプロビジョニング済みProductが存在するバージョンは削除不可)。
3-2. CDK統合:aws-cdk-lib/aws-servicecatalog L2 Constructの活用

aws-cdk-lib/aws-servicecatalog モジュールのL2 Constructを使うと、ポートフォリオ・製品・制約をコードで宣言的に管理でき、CI/CDパイプラインとの統合が容易になります。
精度上の重要前提 — L2 ConstructはCloudFormation型製品のみ対応
aws-servicecatalog L2 Constructがサポートする製品タイプは CloudFormation型のみ です。Terraform Reference Engine製品や外部プロビジョナーを使用する製品など、CloudFormation以外の製品タイプをCDKで扱う場合は、L1 Construct(CfnProduct、CfnPortfolio 等)またはL2のエスケープハッチ(cfnResource.addPropertyOverride())を使用して補完します。
主要L2 Construct一覧:
| Construct | 役割 |
|---|---|
Portfolio | ポートフォリオを定義・管理する。shareWithAccount() でアカウント間共有を設定 |
CloudFormationProduct | CloudFormation型製品を定義する。productVersions 配列で複数バージョンを宣言 |
CloudFormationTemplate | テンプレートソースのファクトリクラス。fromUrl() / fromAsset() / fromProductStack() の3形式 |
ProductStack | CDKアプリ内でCFnテンプレートをStackとして定義し、Productバージョンに直接参照させるパターン |
TagOptions | ポートフォリオや製品に紐付けるTagOptionオブジェクトを生成する |
CDK実装例(TypeScript):
import * as cdk from 'aws-cdk-lib';
import * as servicecatalog from 'aws-cdk-lib/aws-servicecatalog';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
// ProductStack: CDKアプリ内でCFnテンプレートをStackとして定義
class VpcProductStack extends servicecatalog.ProductStack {
constructor(scope: Construct, id: string) {
super(scope, id);
new ec2.Vpc(this, 'Vpc', { maxAzs: 2 });
}
}
export class ServiceCatalogStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const portfolio = new servicecatalog.Portfolio(this, 'DevPortfolio', {
displayName: 'Platform Engineering Portfolio',
providerName: 'Platform Team',
});
const product = new servicecatalog.CloudFormationProduct(this, 'VpcProduct', {
productName: 'Standard VPC',
owner: 'Platform Team',
productVersions: [
{
productVersionName: 'v1.0',
cloudFormationTemplate:
servicecatalog.CloudFormationTemplate.fromProductStack(
new VpcProductStack(this, 'VpcProductStack')
),
},
],
});
portfolio.addProduct(product);
// LaunchRoleConstraintの適用(エンドユーザーへの強い権限付与を不要にする)
const launchRole = iam.Role.fromRoleArn(
this,
'LaunchRole',
`arn:aws:iam::${this.account}:role/ServiceCatalogLaunchRole`
);
portfolio.setLaunchRole(product, launchRole);
}
}
fromProductStack() を使うと、CDKアプリ内で定義したConstructをそのままCFnテンプレートに合成してProductバージョンに紐付けられます。外部リポジトリにCFnテンプレートを置かなくてよいため、Product定義とそのCFnリソースを同一CDKリポジトリで一元管理できます。
L1補完が必要なケース: L2 Constructに存在しないプロパティ(例: SupportEmail、SupportUrl 等の詳細属性)は、(product.node.defaultChild as servicecatalog.CfnCloudFormationProduct).addPropertyOverride('SupportEmail', 'platform@example.com') のようにエスケープハッチでL1レベルに直接アクセスして設定します。
3-3. バージョン更新の自動化(CodePipeline連携)
テンプレートの変更をCIパイプラインで自動的にService Catalogの新バージョンとして反映するには、CodePipelineと create-provisioning-artifact を組み合わせます。
パイプライン構成:
- Source: CodeCommit / S3 — テンプレートリポジトリへの変更をトリガーとしてパイプラインを起動します。
- Build(テンプレート検証): CodeBuildで
aws cloudformation validate-templateおよび cfn-lint / cfn-nag を実行します。検証NGの場合はここでパイプラインを停止します。 - Deploy(S3へ格納): 検証済みテンプレートを
templates/{product}/{version}/template.yamlのキー体系でS3にアップロードします。 - Register(ProductVersion登録): CodeBuildまたはLambda内で
create-provisioning-artifactAPIを呼び出し、Service Catalogに新バージョンを登録します。バージョン名はGitタグやコミットSHAから自動生成します。 - Deprecate(旧バージョン管理): 新バージョン登録後、直前のバージョンを
update-provisioning-artifact --guidance DEPRECATEDでDeprecatedとしてマークします。
CodeBuildでのProductVersion登録スクリプト例:
PRODUCT_ID="prod-xxxxxxxxxxxx"
VERSION_NAME="$(git describe --tags --abbrev=0)-$(git rev-parse --short HEAD)"
TEMPLATE_URL="https://s3.amazonaws.com/${BUCKET}/templates/vpc/${VERSION_NAME}/template.yaml"
aws servicecatalog create-provisioning-artifact \
--product-id "${PRODUCT_ID}" \
--parameters "{
\"Name\": \"${VERSION_NAME}\",
\"Info\": {\"LoadTemplateFromURL\": \"${TEMPLATE_URL}\"},
\"Type\": \"CLOUD_FORMATION_TEMPLATE\"
}"
# 旧バージョンをDeprecated化(直前のArtifact IDを取得して実行)
OLD_ARTIFACT_ID=$(aws servicecatalog list-provisioning-artifacts \
--product-id "${PRODUCT_ID}" \
--query 'ProvisioningArtifactDetails[?Guidance==`DEFAULT`][-2].Id' \
--output text)
if [ -n "${OLD_ARTIFACT_ID}" ]; then
aws servicecatalog update-provisioning-artifact \
--product-id "${PRODUCT_ID}" \
--provisioning-artifact-id "${OLD_ARTIFACT_ID}" \
--guidance DEPRECATED
fi
エンドユーザーへの新バージョン通知:
- コンソール上の自動表示: 新バージョンが登録されると、エンドユーザーがService Catalogコンソールで製品を起動する際のバージョンドロップダウンに自動的に表示されます。追加設定は不要です。
- SNS Notification Constraint:
create-constraintAPIでType: NOTIFICATIONの制約を作成してSNSトピックを指定すると、プロビジョニング開始・完了・失敗の各イベントがSNSに通知されます。エンドユーザーへの完了通知として活用できます。
aws servicecatalog create-constraint \
--portfolio-id port-xxxxxxxxxxxx \
--product-id prod-xxxxxxxxxxxx \
--type NOTIFICATION \
--parameters '{"NotificationArns": ["arn:aws:sns:ap-northeast-1:123456789012:catalog-notify"]}'
4. 起動制約(Launch Constraints)とIAM権限分離

4-1. LaunchRoleConstraint による最小権限設計
Launch Constraints の中核が LaunchRoleConstraint(起動ロール制約)です。管理者がポートフォリオ内の製品に対して IAM ロール(Launch Role)を関連付けると、エンドユーザーが製品を起動する際に Service Catalog がその Launch Role を自動で AssumeRole し、代理で CloudFormation スタックを作成します。
エンドユーザー自身には CloudFormation の権限や、プロビジョニングで作成されるリソース(EC2、S3、RDS 等)への直接 IAM 権限が不要になります。これが Service Catalog の権限分離の核心であり、エンドユーザー ≒ Service Catalog 操作権限のみ、実リソース作成 ≒ Launch Role が担うという設計原則を実現します。
Launch Role に付与する最小権限セット:
Launch Role に必要な権限は、製品テンプレートが作成するリソースに応じて決定しますが、共通して必要な CloudFormation 権限が基礎となります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:CreateStack",
"cloudformation:UpdateStack",
"cloudformation:DeleteStack",
"cloudformation:DescribeStacks",
"cloudformation:DescribeStackEvents",
"cloudformation:GetTemplate",
"cloudformation:ValidateTemplate",
"cloudformation:SetStackPolicy"
],
"Resource": "arn:aws:cloudformation:*:*:stack/SC-*"
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::sc-*"
}
]
}
上記に加えて、製品テンプレートが EC2 を起動するなら ec2:RunInstances 等、テンプレートの内容に応じたサービス固有権限を付与します。iam:PassRole が必要な場合(テンプレートが EC2 インスタンスプロファイル等を指定する場合)は Launch Role にも iam:PassRole が必要です。
信頼関係(Trust Policy)の設定:
Launch Role の信頼ポリシーには servicecatalog.amazonaws.com を Principal として許可します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "servicecatalog.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
エンドユーザーに付与する Service Catalog 操作権限:
エンドユーザーには Service Catalog のセルフサービス操作に絞った権限を付与します。CloudFormation や対象 AWS サービスへの直接権限は不要です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"servicecatalog:DescribeProduct",
"servicecatalog:DescribeProductView",
"servicecatalog:DescribeProvisioningParameters",
"servicecatalog:ListLaunchPaths",
"servicecatalog:ProvisionProduct",
"servicecatalog:ScanProvisionedProducts",
"servicecatalog:DescribeProvisionedProduct",
"servicecatalog:DescribeRecord",
"servicecatalog:ListRecordHistory",
"servicecatalog:TerminateProvisionedProduct",
"servicecatalog:UpdateProvisionedProduct"
],
"Resource": "*"
}
]
}
エンドユーザーポリシーには cloudformation:* も ec2:* も記述しません。これにより、エンドユーザーが Service Catalog 外で直接リソースを作成することを抑止できます。
CDK で LaunchRoleConstraint を設定する場合は Portfolio.setLaunchRole() メソッドを使用します(クロスアカウント共有時はローカルロール名を指定する setLocalLaunchRole() / setLocalLaunchRoleName() を使います)。
portfolio.setLaunchRole(product, launchRole);
- AssumeRole の主体は Service Catalog: エンドユーザーが直接ロールを引き受けるのではなく、Service Catalog サービスが代理 AssumeRole してから CloudFormation を呼び出す。
- スタック名プレフィックス制御: Service Catalog が作成するスタックは
SC-{AccountId}-{ProvisionedProductId}形式のプレフィックスが付く。Launch Role の CloudFormation アクションのリソース ARN をarn:aws:cloudformation:*:*:stack/SC-*で絞ると最小権限を維持しやすい。 - 製品ごとの Launch Role 分離: ポートフォリオに複数製品がある場合、製品ごとに Launch Role を分けると権限爆発を防げる。
4-2. TemplateConstraint(Rule)とStackSetConstraint
TemplateConstraint(テンプレート制約):
TemplateConstraint は、CloudFormation テンプレートの Rules 仕様を使って、エンドユーザーが製品起動時に指定できるパラメータ値を制限します。たとえば、使用できる EC2 インスタンスタイプを t3.small と t3.medium のみに絞る、選択できるアベイラビリティゾーン(AZ)を特定 AZ に限定するといった制御が可能です。
Service Catalog コンソールから制約を追加する際は、制約ルールの JSON を直接入力します。
{
"Rules": {
"AllowedInstanceTypes": {
"Assertions": [
{
"Assert": {
"Fn::Contains": [
["t3.small", "t3.medium"],
{"Ref": "InstanceType"}
]
},
"AssertDescription": "許可されたインスタンスタイプは t3.small と t3.medium のみです。"
}
]
}
}
}
CDK では Portfolio.constrainCloudFormationParameters() で TemplateConstraint を設定できます。エンドユーザーが制約違反の値を指定しようとすると、起動前のパラメータ検証フェーズでエラーになります。
StackSetConstraint(StackSet制約):
StackSetConstraint は、製品を複数の AWS アカウントおよびリージョンへ同時にプロビジョニングするためのマルチアカウント/マルチリージョン展開機能です。CloudFormation StackSets の仕組みを内部で利用します。
- 管理アカウントで製品に StackSetConstraint を設定すると、エンドユーザーが起動時に展開先アカウントとリージョンを選択できるようになります。
- StackSetConstraint には
adminRole(StackSets 管理ロール)とexecutionRole(ターゲットアカウント実行ロール)の設定が必要です。 - Organizations 統合(service-managed permissions)では、管理アカウントが自動で適切なロールを用意するため、ターゲットアカウント側での手動ロール準備が不要です。
LaunchRoleConstraint と StackSetConstraint は、同一の製品に対して同時に設定できません。どちらか一方のみ有効です。
- LaunchRoleConstraint を使う場合: 単一アカウント内での起動時権限分離を実現。StackSetConstraint は使用不可。
- StackSetConstraint を使う場合: マルチアカウント/マルチリージョン展開を実現。Launch Role による権限分離はできない。StackSets 自体の実行ロール(adminRole / executionRole)で権限を制御する設計になる。
マルチアカウント展開かつ権限分離の両立が必要な場合は、Organizations の service-managed StackSets の実行ロール設計で権限を制御するか、設計を分離することが求められます。
NotificationConstraint(通知制約):
NotificationConstraint はプロビジョニング中の CloudFormation スタックイベントを SNS トピックへ送信する設定です。スタックの作成・更新・削除のイベントが通知対象となり、ITSM ツール連携や Slack 通知への橋渡しに使えます。LaunchRoleConstraint と組み合わせて使用可能です。
4-3. 権限分離のアンチパターン
アンチパターン: エンドユーザーへの直接権限付与
Service Catalog を導入しながら、エンドユーザーに直接 CloudFormation や対象サービスの権限を付与してしまうパターンが最も多い失敗例です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:*",
"ec2:*",
"iam:*"
],
"Resource": "*"
}
]
}
この設計では、エンドユーザーが Service Catalog を使わずに CloudFormation や AWS コンソールから直接リソースを作成・変更できてしまいます。ガバナンス統制が形骸化し、承認済みテンプレート以外のリソースが野良で増殖します。
正しい設計: Launch Role への権限集約
エンドユーザーは servicecatalog:ProvisionProduct 等の Service Catalog 操作権限のみを持ち、CloudFormation や AWS リソースへの直接権限を持たない設計が正解です。権限の実体はすべて Launch Role に集約します。
| 主体 | 付与権限 | 目的 |
|---|---|---|
| エンドユーザー | servicecatalog:ProvisionProduct 等 SC 操作のみ | Service Catalog 経由でのみ操作可能にする |
| Launch Role | CloudFormation + 対象サービスの必要最小限 | 製品テンプレートで許可されたリソースのみ作成 |
| 製品管理者 | Portfolio/Product の管理権限 | テンプレートと制約の管理 |
アンチパターン: Launch Role への過剰権限付与
Launch Role に iam:* や *:* を付与するアンチパターンも注意が必要です。Launch Role が引き受ける権限は、テンプレートが作成するリソースに必要な最小限に絞ります。たとえば EC2 インスタンスを作成するだけなら iam:PassRole は不要なケースも多く、テンプレートを精査した上で必要なアクションのみを許可する設計を採用します。
設計確認チェックリスト:
- [ ] エンドユーザーポリシーに
cloudformation:*やec2:*等の直接権限がないか - [ ] Launch Role のリソース ARN に
SC-*プレフィックス等の絞り込みを入れているか - [ ] LaunchRoleConstraint と StackSetConstraint を同一製品に設定していないか(併用不可)
- [ ] Launch Role の信頼ポリシーが
servicecatalog.amazonaws.comのみを Principal にしているか - [ ] 製品ごとに Launch Role を分離しているか(大きな単一ロールによる権限爆発の回避)
5. TagOptionsとコスト配賦戦略

5-1. TagOptionsの仕組み(重要な前提)
TagOptionsはIAMポリシーでタグを強制するしくみではありません。TagOptionオブジェクトをポートフォリオまたは製品に「アソシエーション(関連付け)」することで機能します。エンドユーザーが製品を起動するときに、Service CatalogコンソールがTagOptionで定義された許容値リストを表示し、そこから選択させます。IAMの aws:RequestTag 条件キーや SCP とは別のレイヤーです。
TagOptionとは何か
TagOptionは「タグキー(Key)と、そのキーに対して許容される値の集合(Value Set)」を定義するオブジェクトです。AWSタグそのものではなく、タグを生成するためのテンプレートと理解するのが正確です。
TagOptionsの構成要素は以下のとおりです。
| 要素 | 内容 |
|---|---|
| Key | タグキー(例: CostCenter) |
| Value | 許容される値のひとつ(例: engineering) |
| Active | TagOptionが有効かどうかのフラグ |
同一Keyに対して複数のValueを持つTagOptionをそれぞれ作成し、ポートフォリオ/製品に関連付けることで、「このKeyに対して選択できる値の候補一覧」が形成されます。
TagOptionのアソシエーション(関連付け)
TagOptionを機能させるには、ポートフォリオまたは製品への関連付け(AssociateTagOptionWithResource)が必須です。TagOptionを作成するだけでは何も起きません。
アソシエーション先の選択基準は以下のとおりです。
- ポートフォリオへの関連付け: ポートフォリオ内の全製品に一括適用したい場合に使う。例:
Environmentタグを全製品で強制したい場合。 - 製品への関連付け: 特定の製品にのみ固有のタグを強制したい場合に使う。例: データベース製品のみに
DataClassificationタグを強制する場合。 - 両方への関連付け: ポートフォリオと製品の両方にTagOptionを関連付けると、エンドユーザーにはその和集合が提示されます。
エンドユーザーの体験
製品を起動するとき、Service CatalogコンソールはTagOptionに定義された許容値の一覧をドロップダウンで表示します。エンドユーザーは一覧から選択するのみで、自由なテキスト入力はできません。これにより、タグの表記揺れ(Dev / dev / development の混在など)を構造的に排除できます。
CDKでのTagOptions定義例
import * as servicecatalog from 'aws-cdk-lib/aws-servicecatalog';
const tagOptionEnv = new servicecatalog.TagOptions(this, 'EnvTagOption', {
allowedValuesForTags: {
Environment: ['production', 'staging', 'development'],
CostCenter: ['cc-1001', 'cc-1002', 'cc-2001'],
},
});
// ポートフォリオへの関連付け
portfolio.associateTagOptions(tagOptionEnv);
CDK L2 Constructの associateTagOptions メソッドで、ポートフォリオまたは製品への関連付けを記述できます。内部的には AWS::ServiceCatalog::TagOptionAssociation リソースが生成されます。
TagOptionsの有効・無効管理
TagOptionは Active: false に設定することで無効化できます。無効化したTagOptionはエンドユーザーに表示されなくなりますが、既存のプロビジョニング済み製品のタグには影響しません。環境やコストセンターの廃止時に、タグを削除するのではなく無効化するオペレーションが安全です。
AWS CLIでのTagOption操作
コンソール操作だけでなく、AWS CLIやAPIでTagOptionをプログラマティックに管理できます。以下はTagOptionの作成からアソシエーションまでの基本フローです。
# 1. TagOptionの作成
aws servicecatalog create-tag-option \
--key CostCenter \
--value cc-1001
# 2. 作成したTagOptionのIDを確認
aws servicecatalog list-tag-options \
--filters Key=CostCenter
# 3. ポートフォリオにアソシエーション
aws servicecatalog associate-tag-option-with-resource \
--resource-id port-xxxxxxxxxxxx \
--tag-option-id tag-xxxxxxxxxxxx
同一のタグキーに複数の許容値を持たせる場合は、create-tag-option を値の数だけ繰り返し、それぞれを associate-tag-option-with-resource でアソシエーションします。TagOptionを一括で管理するスクリプトをCI/CDパイプラインに組み込むことで、許容値の追加・廃止をコードレビュープロセスに乗せることができます。
TagOptions制約の注意点
TagOptionsには以下の制限事項があります(公式ドキュメント準拠)。
- 1つのポートフォリオまたは製品に関連付けられるTagOptionの数には上限があります。アカウントのサービスクォータを事前に確認してください。
- TagOptionsはService Catalog経由で起動した製品にのみ適用されます。CloudFormationコンソールから直接スタックを作成した場合はTagOptionsの制約を受けません。TagOptions単独でタグの完全強制を実現するには、CloudFormation直接実行をSCPで制限するアーキテクチャが必要です。
- TagOptionで指定したタグはProvisionedProductリソースに付与されますが、製品内のCloudFormationスタックが作成する個々のAWSリソース(EC2インスタンス、S3バケット等)へのタグ伝播はCloudFormationテンプレート側の
Tagsプロパティ設計に依存します。
5-2. コスト配賦タグ設計パターン
TagOptionsを最大限活用するには、コスト配賦の要件から逆算してタグ設計を行うことが重要です。
推奨タグ設計の4軸
| タグキー | 役割 | TagOptions許容値の例 |
|---|---|---|
CostCenter | 請求先コストセンター | cc-1001(インフラ), cc-2001(開発チームA), cc-2002(開発チームB) |
Team | オーナーチーム | platform, backend, frontend, data |
Environment | 環境種別 | production, staging, development |
Project | プロジェクト識別子 | proj-alpha, proj-beta, internal-tool |
これらのタグをTagOptionsで強制することで、全プロビジョニング済みリソースに統一されたコスト配賦軸が付与されます。
Cost Allocation Tags との連携
TagOptionsで付与されたタグは、AWS請求コンソールの「コスト配賦タグ(Cost Allocation Tags)」として有効化することでAWS Cost Explorerでの集計に使えます。
連携手順は以下のとおりです。
- Cost Allocation Tags の有効化: AWSマネジメントコンソール → 請求 → コスト配賦タグ → TagOptionsで使用するキー(
CostCenter,Teamなど)をユーザー定義タグとして有効化する。 - Cost Explorerでのフィルタリング: 有効化から約24時間後に、Cost Explorerのフィルタ条件としてタグキーが使えるようになる。
CostCenterで絞り込み、コストセンターごとの月次コストをレポートできる。 - 予算アラート: AWS Budgetsでタグフィルタを設定し、
CostCenter=cc-2001の月次コストが閾値を超えたらSNS通知するアラートを組み合わせる。
Organizations タグポリシーとの使い分け
TagOptionsとOrganizationsのタグポリシー(Tag Policy)は補完関係にあります。
| 観点 | TagOptions | タグポリシー(Organizations) |
|---|---|---|
| 適用対象 | Service Catalogから起動したリソースのみ | Organizations配下のAWSリソース全体 |
| 強制方法 | アソシエーションにより、コンソールで許容値から選択させる | タグキー/値のフォーマット定義(評価はCloudTrailを通じた監査) |
| タグ自由入力の抑制 | 完全に抑制(コンソールからの自由入力不可) | 抑制はしない(フォーマット違反を検知・報告するのみ) |
| 向いている用途 | セルフサービスポータル経由のプロビジョニング統制 | 全アカウントのタグ標準化・コンプライアンス報告 |
実運用では両方を組み合わせるのがベストプラクティスです。Service Catalog経由のプロビジョニングはTagOptionsで許容値を絞り、CFn直接実行や他ツール経由のリソースはタグポリシーで標準に合っているか監査します。
TagOptions運用のベストプラクティス
- TagOptionはポートフォリオ単位で関連付けを基本とし、製品固有タグは製品側に追加する。これによりCostCenter/Team/Environmentなど横断タグの管理を一元化できる。
- 許容値はコードレビューで管理する。CDK定義をGitリポジトリで管理し、新しいCostCenterやTeam追加はPRレビューを必須とすることで、タグ乱立を防ぐ。
- Active:falseを活用する。廃止したコストセンターのTagOptionを削除すると既存プロビジョニング済みリソースのタグは変わらないが、新規起動での選択肢からは除外できる。削除ではなく
Active: falseで運用するほうが安全。 - タグの有無を定期確認する。Service Catalog外で作成されたリソースにTagOptionsは適用されない。AWS Configの
required-tagsマネージドルールと組み合わせ、タグ未付与リソースを定期的に検出することで、TagOptions適用外のリソースも網羅できる。
マルチアカウント環境でのTagOptions共有
Organizations跨ぎでポートフォリオを共有する場合、TagOptionsも共有ポートフォリオに含めてスポークアカウントに伝播します。スポークアカウントでは共有されたTagOptionsを変更できないため、許容値の追加・修正はすべてハブアカウント(管理アカウントまたはdelegated admin)側で行います。
この制約を活用することで、「許容値の変更権限はプラットフォームチームのみが持つ」というガバナンス設計を自然に実現できます。開発チームが誤ってコストセンターコードを追加・変更することを構造的に防止できます。
Cost Explorerでの配賦確認フロー
実際の運用では以下のサイクルでコスト配賦を確認します。
- 毎月初: Cost Explorerで前月分を
CostCenterタグ軸で集計し、チームごとのAWSコストを確定する。 - 異常値検知: 前月比で大きくコストが増加したチームを特定し、プロビジョニング済み製品の内訳を Service Catalog コンソール → プロビジョニング済み製品一覧で確認する。
- タグ未付与リソースの是正: AWS Configのコンプライアンスレポートでタグ未付与リソースを抽出し、TagOptions適用外のルートを閉じる(SCPやSCP以外の統制手段で補完)。
この一連のフローを定型化しておくことで、組織のAWSコスト透明性が継続的に担保されます。
- TagOptionsはIAMポリシーではなくアソシエーションで機能する。作成だけでは何も起きない。ポートフォリオまたは製品への関連付けが必須。
- エンドユーザーは許容値リストから選択するのみ。自由入力不可により、タグの表記揺れを構造的に排除できる。
- コスト配賦タグ(CostCenter / Team / Environment / Project)をTagOptionsで標準化し、Cost Allocation Tags → Cost Explorerで配賦レポートを自動化する。
- TagOptionsとOrganizationsタグポリシーは補完関係。TagOptionsはService Catalog経由のみ、タグポリシーは全リソースへの標準化監査に使う。
- マルチアカウント共有時、TagOptionsの許容値変更はハブアカウント側でのみ可能。権限の集権化がガバナンス設計の自然な帰結となる。
6. AWS Organizations跨ぎ共有と多アカウント展開

6-1. ポートフォリオ共有とAcceptPortfolioShare
管理アカウント(または委任管理アカウント)が共有元となり、Organizations 内の OU または Organization ルートに対してポートフォリオ共有を発行します。
共有の発行(管理アカウント側)
コンソールでは対象ポートフォリオの「共有」タブから「AWS Organizations を介して共有」を選択し、共有先として OU ARN または Organization ルート ID を指定します。API では CreatePortfolioShare を使い、OrganizationNode(Type: ORGANIZATIONAL_UNIT | ORGANIZATION)を指定します。
aws servicecatalog create-portfolio-share \
--portfolio-id port-xxxxxxxxxxxx \
--organization-node Type=ORGANIZATIONAL_UNIT,Value=ou-xxxx-xxxxxxxx \
--share-principals true
--share-principals true を指定すると、管理アカウントで設定したプリンシパル関連付け(IAM ロール/ユーザー/グループ)が共有先アカウントにも引き継がれます。省略した場合、各メンバーアカウントでプリンシパルを個別に設定する必要があります。
受諾の明示的実行(メンバーアカウント側)
ポートフォリオが共有されても、メンバーアカウントでは自動的に利用可能になりません。Service Catalog がポートフォリオを「受諾済み(accepted)」状態にするには、メンバーアカウント内で AcceptPortfolioShare を明示的に呼び出す必要があります。
aws servicecatalog accept-portfolio-share \
--portfolio-id port-xxxxxxxxxxxx \
--portfolio-share-type AWS_ORGANIZATIONS
PortfolioShareType=AWS_ORGANIZATIONS を指定することで、Organizations 経由の共有であることを示します。コンソール操作では、Service Catalog の「インポートされたポートフォリオ」タブに表示される共有通知に対して「受諾」をクリックします。
「Organizations 共有はメンバーアカウントに自動配布される」という誤解は危険なトラップです。デフォルト状態では AcceptPortfolioShare の明示的呼び出しが必要です。例外として、Organizations 統合(EnableAWSOrganizationsAccess)を事前に有効化した場合のみ、OU スコープの共有で自動受諾が機能します。自動受諾を当てにした設計は、統合設定の有無でまったく異なる動作になるため注意してください。
インポート済みポートフォリオの挙動
受諾後、メンバーアカウントには「インポート済みポートフォリオ(Imported Portfolio)」が表示されます。これは共有元(ハブ)ポートフォリオへの読み取り専用の参照コピーであり、以下の特性を持ちます。
- 読み取り専用: メンバーアカウントからポートフォリオ定義(製品一覧・制約・TagOptions)を変更することはできません。
- 自動同期: 管理アカウント側で製品追加・バージョン更新・TagOptions 変更・制約追加を行うと、受諾済みのすべてのメンバーアカウントに自動的に同期されます。
- ローカル追加は可能: メンバーアカウントでは、インポートされたポートフォリオに対してプリンシパル関連付けやローカルの制約を上乗せ追加できます。
この「ハブ変更がスポーク全体に即座に反映される」挙動こそが Organizations 共有の最大の利点です。製品バージョンを管理アカウントで1回更新するだけで、数十〜数百のメンバーアカウント全体に新バージョンが展開されます。
委任管理アカウントの設定
管理アカウントにログインせずに共有操作を実行するため、メンバーアカウントを Service Catalog の委任管理者(Delegated Administrator)として登録できます。
# 管理アカウントで実行
aws organizations register-delegated-administrator \
--account-id 123456789012 \
--service-principal servicecatalog.amazonaws.com
委任管理アカウントは、Organization 全体のポートフォリオ共有・製品共有・プリンシパル関連付けを管理できます。ただし Organizations そのもの(OU 作成・SCP 適用等)は委任範囲に含まれません。プラットフォームチームのアカウントを委任管理者にしておくことで、管理アカウントへのアクセス頻度を最小限に抑えられます。
6-2. StackSets連携とOU単位の配信
StackSet constraints を Organizations 共有ポートフォリオと組み合わせることで、製品起動時に CloudFormation StackSets を自動的に利用する設定(StackSetConstraint)を各 OU に適用できます。
service-managed permissions(組織管理型)
PERMISSION_MODEL=SERVICE_MANAGED で StackSet を作成すると、AWS Organizations と CloudFormation が直接連携します。対象 OU 配下のアカウント全体にスタックインスタンスが自動デプロイされ、OU に新アカウントが追加された際も自動的にデプロイ対象に含まれます。
aws cloudformation create-stack-set \
--stack-set-name prod-network-baseline \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
AUTO_DEPLOYMENT を有効にした場合の挙動:
– OU へのアカウント追加 → スタックインスタンス自動デプロイ
– OU からのアカウント移動(削除) → RetainStacksOnAccountRemoval=false の場合はスタックも削除
管理アカウントまたは委任管理アカウントのみが service-managed StackSet を操作できます。メンバーアカウントに IAM ロールを事前作成する必要がない点が、self-managed との最大の違いです。
self-managed permissions(手動管理型)
PERMISSION_MODEL=SELF_MANAGED では、管理アカウントに AWSCloudFormationStackSetAdministrationRole、各メンバーアカウントに AWSCloudFormationStackSetExecutionRole を手動で作成します。
# メンバーアカウントに作成する実行ロール(JSON は CloudFormation テンプレートの抜粋)
# AWSCloudFormationStackSetExecutionRole に以下の信頼ポリシーを付与
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::MANAGEMENT_ACCOUNT_ID:root"
},
"Action": "sts:AssumeRole"
}]
}
新規アカウントが追加された場合は手動でロール作成が必要であるため、Organizations 統合が進んだ環境では service-managed permissions が推奨されます。ただし、Organizations 外のアカウントにデプロイする場合や、既存の IAM ロール管理フローに合わせる場合は self-managed が適しています。
StackSetConstraint と LaunchRoleConstraint の相互排他
同一の製品バージョンに LaunchRoleConstraint(起動ロール制約)と StackSetConstraint を同時に適用することはできません。マルチリージョン展開が必要な場合は StackSetConstraint を選択し、単一アカウント内での最小権限起動が主目的であれば LaunchRoleConstraint を選択します。両方の要件がある場合は、製品を用途別に分割するか、StackSet 側の実行ロール(StackSetExecutionRole)に必要な最小権限のみを付与することで対応します。
OU 単位の配信パターン
Organizations の OU 階層を活用した典型的な配信パターン:
ou-prod-*: 本番用ポートフォリオ(厳格な TagOptions + 承認制約あり)ou-dev-*: 開発用ポートフォリオ(起動パラメータを広めに許容)ou-sandbox-*: 実験用ポートフォリオ(制約を最小化、コスト上限制約のみ適用)
各 OU に適切なポートフォリオを共有し、プリンシパル関連付けで開発者グループを紐付けることで、環境ごとのセルフサービス範囲をコード不要で制御できます。
共有の解除と拒否
ポートフォリオの共有を解除するには DeletePortfolioShare を使います。共有先アカウントの状態(受諾済み / 未受諾)に関わらず解除できます。解除後、メンバーアカウントのインポート済みポートフォリオは自動的に削除されます。ただし、そのポートフォリオ経由でプロビジョニング済みの製品(Provisioned Product)は削除されません。
メンバーアカウント側からもポートフォリオの受諾を拒否できます(RejectPortfolioShare)。拒否するとメンバーアカウントからインポート済みポートフォリオが削除されますが、管理アカウント側の共有設定は維持されます。
Organizations 統合(EnableAWSOrganizationsAccess)
Organizations 統合を有効化すると、OU スコープのポートフォリオ共有で自動受諾が機能し、新規アカウントが OU に参加した際も自動的にポートフォリオが利用可能になります。
# 管理アカウントで Organizations 統合を有効化
aws servicecatalog enable-aws-organizations-access
有効化の前提条件:
– 実行者が Organizations の管理アカウントであること
– Service Catalog で AWSServiceRoleForServiceCatalog サービスリンクロールが作成済みであること(初回操作時に自動作成)
統合を有効化すると ListOrganizationPortfolioAccess で共有先の受諾状態をクロスアカウントで一覧できるようになり、未受諾アカウントの特定が容易になります。
AcceptPortfolioShare の自動化
大規模マルチアカウント環境では、メンバーアカウントの数が多く手動受諾は現実的でありません。以下の方法で自動化できます。
- CloudFormation StackSets:
AWS::ServiceCatalog::AcceptedPortfolioShareリソースを含む BootstrapTemplate を全アカウントに StackSet でデプロイし、受諾を自動化する。 - Lambda + Organizations イベント: EventBridge で
CreateAccount/MoveAccountイベントを受け取り、Lambda から対象アカウントにクロスアカウント AssumeRole してAcceptPortfolioShareを実行する。 - AWS Control Tower Customizations for Control Tower (CfCT): AFT や CfCT を使って Account Vending パイプラインに受諾ステップを組み込む。
# CloudFormation テンプレート例(BootstrapStack として StackSet デプロイ)
# Resources:
#AcceptPlatformPortfolio:
# Type: AWS::ServiceCatalog::AcceptedPortfolioShare
# Properties:
# AcceptLanguage: jp
# PortfolioId: port-xxxxxxxxxxxx
自動化により、新規アカウント作成から数分以内にポートフォリオが利用可能な状態になる Account Vending ワークフローを実現できます。
7. 運用モニタリングとガバナンス強化
7-1. CloudTrail監査とイベント検知
CloudTrail による API 監査
Service Catalog の操作はすべて CloudTrail に記録されます。本番環境では以下の API イベントを優先的に監視・アラート対象にします。
| API アクション | 監査のポイント |
|---|---|
ProvisionProduct | 誰が・いつ・どの製品を起動したか(発注追跡) |
UpdateProvisionedProduct | 稼働中製品への変更操作(意図しない構成変更の検知) |
TerminateProvisionedProduct | 製品の削除操作(意図しない削除・誤操作の検知) |
CreatePortfolioShare | ポートフォリオ共有の発行(カタログ配布の監査) |
AssociateProductWithPortfolio | カタログ構成変更(製品追加/削除の証跡) |
CreateConstraint / DeleteConstraint | 制約変更(セキュリティポリシー変更の検知) |
CloudTrail の証跡(Trail)を S3 バケットに出力し、Athena のパーティション分割テーブルを使うことで、特定アカウントや日時での絞り込みクエリを低コストで実行できます。証跡はすべての AWS リージョンを対象にする(Multi-Region Trail)ことを推奨します。
EventBridge によるプロビジョニング状態変化の検知
Service Catalog はプロビジョニング済み製品の状態変化を EventBridge イベントとして発行します。イベントソースは aws.servicecatalog です。
プロビジョニング済み製品の状態遷移:
UNDER_CHANGE→ 操作進行中(プロビジョニング・更新・削除の実行中)AVAILABLE→ 正常完了(製品が利用可能な状態)ERROR→ 失敗(起動・更新・削除の失敗。スタックイベントに詳細あり)TAINTED→ 製品は存在するが設定に問題がある(ドリフト検出や手動変更を示す)
ERROR または TAINTED への遷移を EventBridge ルールで検知し、SNS トピック経由で運用チームに通知する設定例:
{
"source": ["aws.servicecatalog"],
"detail-type": ["AWS Service Catalog Resource State Change"],
"detail": {
"status": ["ERROR", "TAINTED"]
}
}
このルールを CloudWatch アラームや Lambda と組み合わせることで、失敗したプロビジョニングの自動ロールバックや、Slack/Teams への通知パイプラインを構築できます。
CloudWatch によるメトリクス監視
Service Catalog は標準の CloudWatch メトリクスを提供しませんが、CloudTrail Insights を有効化することで、API 呼び出しの異常なスパイク(例: 短時間に大量の ProvisionProduct)を自動検知できます。また、ProvisionedProductStatus の状態を Lambda で定期的にポーリングし、長期間 UNDER_CHANGE のままになっている製品をアラートすることで、スタック操作がスタックした状態を早期発見できます。
7-2. ServiceActionsとコンプライアンス管理
Service Actions(ServiceAction)
Service Actions は、プロビジョニング済み製品(Provisioned Product)に対して実行できる定義済みの運用操作です。SSM Automation ドキュメントを製品バージョンに関連付けることで、エンドユーザーがコンソールから Day-2 Operations(パッチ適用・インスタンス起動・停止・コンプライアンスチェック等)をセルフサービスで実行できるようになります。
# ServiceAction の作成(SSM Automation ドキュメント連携)
aws servicecatalog create-service-action \
--name "RestartEC2Instance" \
--action-type SSM_AUTOMATION \
--definition '{
"Name": "AWSRestartEC2Instance",
"Version": "1",
"AssumeRole": "arn:aws:iam::123456789012:role/ServiceCatalogSSMRole",
"Parameters": {
"InstanceId": {"Type": "TARGET"}
}
}'
# 製品バージョン(Provisioning Artifact)への関連付け
aws servicecatalog associate-service-action-with-provisioning-artifact \
--product-id prod-xxxxxxxxxxxx \
--provisioning-artifact-id pa-xxxxxxxxxxxx \
--service-action-id act-xxxxxxxxxxxx
SSM Automation の実行には AssumeRole で指定した IAM ロールが使用されます。このロールにはターゲットリソース(EC2・RDS 等)への最小権限のみを付与します。エンドユーザー自身の IAM 権限は不要であり、LaunchRoleConstraint と同様の最小権限原則が適用されます。
Day-2 Operations の典型例:
- パッチ適用:
AWS-RunPatchBaselineSSM ドキュメントでパッチベースライン適用 - インスタンス再起動:
AWSRestartEC2Instanceでセルフサービス再起動 - コスト最適化: 開発環境の夜間停止(
AWS-StopEC2Instance) - コンプライアンス修復:
AWSConfigRemediation-*ドキュメントでの自動修復
SNS 通知制約(Notification Constraint)
通知制約を使うと、プロビジョニング済み製品の状態変化(起動完了・更新完了・失敗・承認要求等)を SNS トピックへ通知できます。
aws servicecatalog create-constraint \
--portfolio-id port-xxxxxxxxxxxx \
--product-id prod-xxxxxxxxxxxx \
--type NOTIFICATION \
--parameters '{
"NotificationArns": [
"arn:aws:sns:ap-northeast-1:123456789012:ServiceCatalogAlerts"
]
}'
承認制約(Approval Constraint / LAUNCH with approval workflow)と組み合わせると、製品起動時にレビューアによる明示的な承認を必須にできます。承認リクエスト発行時に通知制約の SNS トピックへ通知が届き、承認者が Service Catalog コンソールから承認/拒否を実行します。
AWS Config との連携(コンプライアンス管理)
Service Catalog 経由で作成されたリソースは、通常の AWS リソースと同様に AWS Config のルール評価対象になります。Config Conformance Pack をアカウントに適用することで、Service Catalog で起動した CloudFormation スタックのリソース設定が継続的にポリシー準拠かどうかを評価できます。
Service Catalog がプロビジョニング時に自動付与するタグを Config ルールのスコープに活用できます:
| 自動付与タグ | 内容 |
|---|---|
aws:servicecatalog:portfolioId | 所属ポートフォリオ ID |
aws:servicecatalog:productId | 製品 ID |
aws:servicecatalog:provisioningPrincipalArn | 起動者の ARN |
これらのタグをタグ条件とした Config ルールを設定することで、「Service Catalog 経由で起動されたリソースのみを対象にしたコンプライアンスレポート」を作成できます。また、TAINTED 状態の製品(手動変更によるドリフト検出)と Config の NON_COMPLIANT リソースを突き合わせることで、ガバナンス逸脱の原因を特定しやすくなります。
ドリフト検出とリストア
Service Catalog は CloudFormation スタックのドリフト検出を内部で活用しています。エンドユーザーが Service Catalog を経由せずに直接 AWS コンソールやインフラツールでリソースを変更した場合、そのプロビジョニング済み製品は TAINTED 状態になります。
TAINTED 状態の製品に対する対処:
- 現状確認:
DescribeProvisionedProductで詳細を確認し、どのリソースが変更されたかを特定する - UpdateProvisionedProduct: 同じバージョンで Update をかけると CloudFormation がドリフトを解消し、AVAILABLE 状態に戻す(ただし手動変更は上書きされる)
- TerminateProvisionedProduct: 是正が困難な場合は製品を削除し、正規の手順で再プロビジョニングする
TAINTED 製品の放置は「誰が何を変更したか分からない状態」が続くため、EventBridge で TAINTED 遷移を検知したら即時チケットを発行するフローを組み込むことを推奨します。
CloudTrail Athena クエリ例
Athena で CloudTrail ログを分析する際の典型クエリ(過去7日分の ProvisionProduct 操作一覧):
SELECT
eventtime,
useridentity.arn AS requester,
requestparameters
FROM cloudtrail_logs
WHERE eventsource = 'servicecatalog.amazonaws.com'
AND eventname = 'ProvisionProduct'
AND eventtime > date_add('day', -7, now())
ORDER BY eventtime DESC
LIMIT 100;
このクエリを Athena Saved Query として保存しておくと、インシデント発生時に「直近1週間で誰がどの製品を起動したか」を即座に確認できます。
8. まとめと次回予告
8-1. 本記事のまとめ
Vol1 では、AWS Service Catalog でセルフサービスプロビジョニング基盤を本番運用するための土台として、以下の設計を整理しました。
ポートフォリオ / 製品設計
– Portfolio は製品・アクセス権・制約の論理コンテナ。チームまたは機能ドメイン単位で設計し、IAM ロールを Principal Association に使うと組織変更に強い。
– ProductVersion でテンプレートをバージョン管理し、CI/CD から自動追加することで、IaC の更新ワークフローをカタログに統合できる。
– 同一製品を複数の Portfolio に追加し、環境(開発/本番)ごとに異なる制約・アクセス権を適用するパターンが推奨。
起動制約(LaunchRoleConstraint)による権限分離
– エンドユーザー自身に IAM 強権限を与えず、Service Catalog が Launch Role を AssumeRole して代理プロビジョニングする設計が権限分離の核。
– Launch Role には製品テンプレートで作成するリソース分の最小権限のみを付与。エンドユーザーには servicecatalog:ProvisionProduct 等の操作権限のみで完結する。
– TemplateConstraint(Rule)で起動パラメータの許容値を制限し、意図しない設定のリソース作成を防ぐ。
– LaunchRoleConstraint と StackSetConstraint は同一製品に併用不可。マルチリージョン展開が必要な場合は StackSetConstraint を選択する。
TagOptions とコスト配賦
– TagOption は「タグのテンプレート(key + 許容 value 集合)」であり、IAM ポリシーではなくポートフォリオ / 製品へのアソシエーションで機能する。
– 起動時にエンドユーザーが許容 value から選択することで、コスト配賦タグ(CostCenter / Project / Environment)を組織標準に強制できる。
Organizations 跨ぎ共有
– 管理アカウントが CreatePortfolioShare で OU / Organization へ共有し、メンバーアカウントが AcceptPortfolioShare(type=AWS_ORGANIZATIONS)で明示的に受諾して初めて利用可能になる(自動受諾は Organizations 統合有効化が前提)。
– 受諾後は「インポート済みポートフォリオ」として管理アカウント変更が自動同期されるため、大規模マルチアカウント環境でも製品のメンテナンスが集中化できる。
運用モニタリング
– CloudTrail で ProvisionProduct / UpdateProvisionedProduct / TerminateProvisionedProduct を監査し、EventBridge で ERROR / TAINTED 状態への遷移をリアルタイム検知する。
– Service Actions(SSM Automation 連携)で Day-2 Operations をセルフサービス化し、SNS 通知制約で起動完了・承認要求の通知パイプラインを構築する。
- [ ] Portfolio は機能ドメイン単位で分割し、Principal Association に IAM ロールを使用している
- [ ] LaunchRoleConstraint で Launch Role を設定し、エンドユーザーへの直接権限付与を排除している
- [ ] TemplateConstraint で起動パラメータの許容値を制限している
- [ ] TagOptions で必須コスト配賦タグ(CostCenter / Project / Environment)を強制している
- [ ] Organizations 共有設定済み、メンバーアカウントの AcceptPortfolioShare 受諾も確認済み
- [ ] CloudTrail 証跡が Multi-Region で有効、S3 出力と Athena クエリを設定している
- [ ] EventBridge ルールで ERROR / TAINTED 状態への遷移アラートを設定している
- [ ] CI/CD パイプラインから ProductVersion 自動追加のフローを確立している
8-2. 次回予告
Vol1 では基盤(ポートフォリオ設計・起動制約・TagOptions・Organizations 共有・運用監視)を固めました。Vol2 では以下のテーマを深掘りします。
- StackSets による大規模マルチリージョン展開: service-managed permissions を活用した全 OU 自動デプロイと、新規アカウント自動参加の設計パターン。大規模マルチリージョン展開での同時デプロイ数制御(
MaxConcurrentCount/MaxConcurrentPercentage)や失敗時の自動ロールバックの設定も解説します。 - Service Actions 運用自動化: SSM Automation ドキュメントの設計・Day-2 Operations フロー・承認ワークフローの実装例。パッチベースライン自動適用フローと、承認制約(LAUNCH constraint with approval)によるプロビジョニング承認ゲートも取り上げます。
- Terraform 製品タイプ(External): CloudFormation 以外の IaC を Service Catalog で管理する方法と、CloudFormation 型との使い分け指針。Terraform CLI Wrapper と Service Catalog の連携アーキテクチャを設計例とともに解説します。
- Service Catalog AppRegistry: アプリケーション単位でのリソース可視化と Cost Explorer との連携。複数のプロビジョニング済み製品を1つのアプリケーションとしてグルーピングし、コスト分析の粒度を高める手法を紹介します。
本連載の対象 AWS 試験
本連載で扱う内容は、以下の AWS 認定試験のドメインに対応します。
- AWS Certified Solutions Architect – Professional(SAP): 高可用性・セキュリティ・コンプライアンスを組み合わせたアーキテクチャ設計(Domain 1, 2)
- AWS Certified DevOps Engineer – Professional(DOP): IaC の継続的デリバリー・モニタリング・ガバナンス(Domain 2, 3)
認定試験向けの実践問題は CertTrend LMS で提供しています。
▶ CertTrend LMS: AWS Service Catalog 実践コースで理解を深める
Service Catalog の利用コスト
AWS Service Catalog 自体の利用料金は無料です。コストが発生するのは Service Catalog を通じてプロビジョニングされた AWS リソース(EC2・RDS・VPC 等)の利用料金のみです。ただし、Organizations 共有を活用したマルチアカウント展開では、CloudFormation StackSets のスタックインスタンス数に応じたコストが発生する点は考慮が必要です。
採用判断の目安
Service Catalog が特に効果を発揮するシナリオ:
- 開発者が IAM 強権限を持たない状態でセルフサービスプロビジョニングを実現したい場合
- 承認済み IaC テンプレートのみを複数アカウントに展開する「ゴールデンパス」を整備したい場合
- コスト配賦タグや起動パラメータを標準化し、野良リソースを抑制したい場合
逆に、単一アカウントで少数の開発者が使う用途や、IaC テンプレートの更新頻度が極めて低いケースでは、直接 CloudFormation を使うシンプルな構成で十分なことも多いです。
- マルチアカウント統制の土台: AWS Organizations × Control Tower
- ランディングゾーン: Control Tower / AFT / CfCT / SCP