AWS事業本部コンサルティング部のイシザワです。
CloudFormationからService Catalogの製品を起動することができるようなので、実際に試してみました。 作成したテンプレートから製品を作成することで、他製品を起動する製品を作成してみます。
テンプレート
以下のコード断片が製品の起動を行う箇所になります。
Resources:
Network:
Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct
Properties:
ProductName: NetworkComponent
ProvisioningArtifactName: !Ref NetworkComponentVersion
ProvisioningParameters:
- Key: SystemId
Value: !Ref SystemId
- Key: VpcCidr
Value: !Ref VpcCidr
ProductName
で製品名を指定します。製品名で製品を特定できない場合(同じ製品名の製品がある場合)は、ProductId
に製品IDを指定することで製品を特定します。
ProvisioningArtifactName
で製品のバージョン名を指定します。製品名と同様にバージョン名でバージョンを特定できない場合は、ProvisioningArtifactId
にバージョンIDを指定することでバージョンを特定します。
ProvisioningParameters
は製品に渡すパラメータです。
起動する製品はこのテンプレートのプロビジョニングを実行するプリンシパルから起動可能である必要があります。 つまり、製品はそのプリンシパルからアクセス可能なポートフォリオに含まれている必要があります。
使用感としてはネストスタックとほとんど同じで、Outputsアトリビュートで製品のOutputを参照することができます。
以下がテンプレートの全体です。このテンプレートは2層構造のWebシステムを作成します。起動する製品のバージョン名をパラメータとして受け取ることでユーザー側で製品の個別更新を行えるようにしています。
AWSTemplateFormatVersion: 2010-09-09
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Global Configuration
Parameters:
- SystemId
- Label:
default: Network Configuration
Parameters:
- NetworkComponentVersion
- VpcCidr
- Label:
default: Security Group Configuration
Parameters:
- SecurityGroupComponentVersion
- Label:
default: Web Server Configuration
Parameters:
- WebServerComponentVersion
- Label:
default: Database Configuration
Parameters:
- DatabaseComponentVersion
- DatabaseAdminUserPassword
Parameters:
SystemId:
Type: String
Default: sample
NetworkComponentVersion:
Type: String
SecurityGroupComponentVersion:
Type: String
WebServerComponentVersion:
Type: String
DatabaseComponentVersion:
Type: String
VpcCidr:
Type: String
DatabaseAdminUserPassword:
Type: String
NoEcho: true
Resources:
Network:
Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct
Properties:
ProductName: NetworkComponent
ProvisioningArtifactName: !Ref NetworkComponentVersion
ProvisioningParameters:
- Key: SystemId
Value: !Ref SystemId
- Key: VpcCidr
Value: !Ref VpcCidr
SecurityGroup:
Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct
Properties:
ProductName: SecurityGroupComponent
ProvisioningArtifactName: !Ref SecurityGroupComponentVersion
ProvisioningParameters:
- Key: SystemId
Value: !Ref SystemId
- Key: VpcId
Value: !GetAtt Network.Outputs.VpcId
WebServer:
Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct
Properties:
ProductName: WebServerComponent
ProvisioningArtifactName: !Ref WebServerComponentVersion
ProvisioningParameters:
- Key: SystemId
Value: !Ref SystemId
- Key: VpcId
Value: !GetAtt Network.Outputs.VpcId
- Key: PublicSubnetAId
Value: !GetAtt Network.Outputs.PublicSubnetAId
- Key: PublicSubnetCId
Value: !GetAtt Network.Outputs.PublicSubnetCId
- Key: PrivateSubnetAId
Value: !GetAtt Network.Outputs.PrivateSubnetAId
- Key: PrivateSubnetCId
Value: !GetAtt Network.Outputs.PrivateSubnetCId
- Key: SGLoadBalancerId
Value: !GetAtt SecurityGroup.Outputs.SGLoadBalancerId
- Key: SGWebServerId
Value: !GetAtt SecurityGroup.Outputs.SGWebServerId
Database:
Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct
Properties:
ProductName: DatabaseComponent
ProvisioningArtifactName: !Ref DatabaseComponentVersion
ProvisioningParameters:
- Key: SystemId
Value: !Ref SystemId
- Key: IsolatedSubnetAId
Value: !GetAtt Network.Outputs.IsolatedSubnetAId
- Key: IsolatedSubnetCId
Value: !GetAtt Network.Outputs.IsolatedSubnetCId
- Key: SGDatabaseId
Value: !GetAtt SecurityGroup.Outputs.SGDatabaseId
- Key: DatabaseAdminUserPassword
Value: !Ref DatabaseAdminUserPassword
このテンプレートから製品名WebSystem
、バージョン名1.0
としてService Catalogの製品を作成します。
このテンプレートから起動される製品のテンプレートは以下の通りです。バージョン名は全て1.0
とします。
NetworkComponent
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
VpcCidr:
Type: String
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${SystemId}-vpc
# ------------------------------------------------------------#
# サブネット
# ------------------------------------------------------------#
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1a
CidrBlock: !Select [ 0, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-public-subnet-a
PublicSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1c
CidrBlock: !Select [ 1, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-public-subnet-c
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1a
CidrBlock: !Select [ 2, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-private-subnet-a
PrivateSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1c
CidrBlock: !Select [ 3, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-private-subnet-c
IsolatedSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1a
CidrBlock: !Select [ 4, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-isolated-subnet-a
IsolatedSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: ap-northeast-1c
CidrBlock: !Select [ 5, !Cidr [ !Ref VpcCidr, 6, 6]]
Tags:
- Key: Name
Value: !Sub ${SystemId}-isolated-subnet-c
# ------------------------------------------------------------#
# インターネットゲートウェイ
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${SystemId}-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref Vpc
InternetGatewayId: !Ref InternetGateway
# ------------------------------------------------------------#
# NATゲートウェイ
# ------------------------------------------------------------#
NatGatewayA:
Type: AWS::EC2::NatGateway
Properties:
SubnetId: !Ref PublicSubnetA
AllocationId: !GetAtt NatGatewayEipA.AllocationId
Tags:
- Key: Name
Value: !Sub ${SystemId}-ngw-a
NatGatewayC:
Type: AWS::EC2::NatGateway
Properties:
SubnetId: !Ref PublicSubnetC
AllocationId: !GetAtt NatGatewayEipC.AllocationId
Tags:
- Key: Name
Value: !Sub ${SystemId}-ngw-c
NatGatewayEipA:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: Name
Value: !Sub ${SystemId}-ngw-eip-a
NatGatewayEipC:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: Name
Value: !Sub ${SystemId}-ngw-eip-c
# ------------------------------------------------------------#
# ルートテーブル
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${SystemId}-public-rtb
PrivateRouteTableA:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${SystemId}-private-rtb-a
PrivateRouteTableC:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${SystemId}-private-rtb-c
IsolatedRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${SystemId}-isolated-rtb
PublicRouteTableAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRouteTable
PublicRouteTableAssociationC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicRouteTable
PrivateRouteTableAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref PrivateRouteTableA
PrivateRouteTableAssociationC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateRouteTableC
IsolatedRouteTableAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref IsolatedSubnetA
RouteTableId: !Ref IsolatedRouteTable
IsolatedRouteTableAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref IsolatedSubnetC
RouteTableId: !Ref IsolatedRouteTable
RouteToInternetGateway:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteToNatGatewayA:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableA
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayA
RouteToNatGatewayC:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableC
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayC
Outputs:
VpcId:
Value: !Ref Vpc
PublicSubnetAId:
Value: !Ref PublicSubnetA
PublicSubnetCId:
Value: !Ref PublicSubnetC
PrivateSubnetAId:
Value: !Ref PrivateSubnetA
PrivateSubnetCId:
Value: !Ref PrivateSubnetC
IsolatedSubnetAId:
Value: !Ref IsolatedSubnetA
IsolatedSubnetCId:
Value: !Ref IsolatedSubnetC
SecurityGroupComponent
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
VpcId:
Type: String
Resources:
# ------------------------------------------------------------#
# セキュリティグループ
# ------------------------------------------------------------#
SGLoadBalancer:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Load Balancer SG
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: "-1"
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub ${SystemId}-loadbalancer-sg
SGWebServer:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Web Server SG
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref SGLoadBalancer
SecurityGroupEgress:
- IpProtocol: "-1"
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub ${SystemId}-web-server-sg
SGDatabase:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Database SG
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
SecurityGroupEgress:
- IpProtocol: "-1"
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub ${SystemId}-database-sg
Outputs:
SGLoadBalancerId:
Value: !Ref SGLoadBalancer
SGWebServerId:
Value: !Ref SGWebServer
SGDatabaseId:
Value: !Ref SGDatabase
WebServerComponent
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
VpcId:
Type: String
PublicSubnetAId:
Type: String
PublicSubnetCId:
Type: String
PrivateSubnetAId:
Type: String
PrivateSubnetCId:
Type: String
SGLoadBalancerId:
Type: String
SGWebServerId:
Type: String
Mappings:
RegionMap:
ap-northeast-1:
ImageId: ami-05112363dbe951480
Resources:
# ------------------------------------------------------------#
# EC2インスタンス
# ------------------------------------------------------------#
WebServerInstanceA:
Type: AWS::EC2::Instance
Properties:
SubnetId: !Ref PrivateSubnetAId
InstanceType: t2.micro
ImageId: !FindInMap
- RegionMap
- !Ref AWS::Region
- ImageId
SecurityGroupIds:
- !Ref SGWebServerId
Tags:
- Key: Name
Value: !Sub ${SystemId}-web-server-a
WebServerInstanceC:
Type: AWS::EC2::Instance
Properties:
SubnetId: !Ref PrivateSubnetCId
InstanceType: t2.micro
ImageId: !FindInMap
- RegionMap
- !Ref AWS::Region
- ImageId
SecurityGroupIds:
- !Ref SGWebServerId
Tags:
- Key: Name
Value: !Sub ${SystemId}-web-server-c
# ------------------------------------------------------------#
# ELB
# ------------------------------------------------------------#
TGWebServers:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${SystemId}-web-server-tg
VpcId: !Ref VpcId
TargetType: instance
Protocol: HTTP
ProtocolVersion: HTTP1
Port: 80
Targets:
- Id: !Ref WebServerInstanceA
- Id: !Ref WebServerInstanceC
LBWebServers:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${SystemId}-web-server-lb
Type: application
Scheme: internet-facing
Subnets:
- !Ref PublicSubnetAId
- !Ref PublicSubnetCId
SecurityGroups:
- !Ref SGLoadBalancerId
LBWebServersListnener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Protocol: HTTP
Port: 80
LoadBalancerArn: !Ref LBWebServers
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TGWebServers
DatabaseComponent
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
IsolatedSubnetAId:
Type: String
IsolatedSubnetCId:
Type: String
SGDatabaseId:
Type: String
DatabaseAdminUserPassword:
Type: String
NoEcho: true
Resources:
# ------------------------------------------------------------#
# RDS
# ------------------------------------------------------------#
RDSInstance:
Type: AWS::RDS::DBInstance
Properties:
Engine: mysql
EngineVersion: "8.0"
DBInstanceClass: db.t3.micro
StorageType: gp2
AllocatedStorage: 20
MultiAZ: false
VPCSecurityGroups:
- !Ref SGDatabaseId
DBParameterGroupName: !Ref PGDatabase
OptionGroupName: !Ref OGDatabase
DBSubnetGroupName: !Ref DatabaseSubnetGroup
MasterUsername: admin
MasterUserPassword: !Ref DatabaseAdminUserPassword
PGDatabase:
Type: AWS::RDS::DBParameterGroup
Properties:
DBParameterGroupName: !Sub ${SystemId}-db-pg
Description: MySQL Database PG
Family: mysql8.0
OGDatabase:
Type: AWS::RDS::OptionGroup
Properties:
OptionGroupName: !Sub ${SystemId}-db-og
OptionGroupDescription: MySQL Database OG
EngineName: mysql
MajorEngineVersion: "8.0"
DatabaseSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupName: !Sub ${SystemId}-db-subnet-group
DBSubnetGroupDescription: MySQL Database SubnetGroup
SubnetIds:
- !Ref IsolatedSubnetAId
- !Ref IsolatedSubnetCId
各製品の作成が完了したら、ポートフォリオを作成して製品を登録します。 以下のテンプレートをプロビジョニングしてポートフォリオを作成します。
ポートフォリオ
AWSTemplateFormatVersion: 2010-09-09
Parameters:
AccessSystemPortfolioPrincipalArn:
Type: String
ProviderName:
Type: String
Mappings:
Components:
NetworkComponent:
ProductId: <NetworkComponentの製品ID>
SecurityGroupComponent:
ProductId: <SecurityGroupComponentの製品ID>
WebServerComponent:
ProductId: <WebServerComponentの製品ID>
DatabaseComponent:
ProductId: <DatabaseComponentの製品ID>
Systems:
WebSystem:
ProductId: <WebSystemの製品ID>
Portfolios:
ComponentsPortfolio:
Name: Components
SystemsPortfolio:
Name: Systems
Resources:
# ------------------------------------------------------------#
# ポートフォリオ
# ------------------------------------------------------------#
ComponentsPortfolio:
Type: AWS::ServiceCatalog::Portfolio
Properties:
DisplayName: !FindInMap
- Portfolios
- ComponentsPortfolio
- Name
ProviderName: !Ref ProviderName
AcceptLanguage: jp
SystemsPortfolio:
Type: AWS::ServiceCatalog::Portfolio
Properties:
DisplayName: !FindInMap
- Portfolios
- SystemsPortfolio
- Name
ProviderName: !Ref ProviderName
AcceptLanguage: jp
# ------------------------------------------------------------#
# 製品の登録
# ------------------------------------------------------------#
NetworkComponentAssociation:
Type: AWS::ServiceCatalog::PortfolioProductAssociation
Properties:
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- NetworkComponent
- ProductId
AcceptLanguage: jp
SecurityGroupComponentAssociation:
Type: AWS::ServiceCatalog::PortfolioProductAssociation
Properties:
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- SecurityGroupComponent
- ProductId
AcceptLanguage: jp
WebServerComponentAssociation:
Type: AWS::ServiceCatalog::PortfolioProductAssociation
Properties:
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- WebServerComponent
- ProductId
AcceptLanguage: jp
DatabaseComponentAssociation:
Type: AWS::ServiceCatalog::PortfolioProductAssociation
Properties:
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- DatabaseComponent
- ProductId
AcceptLanguage: jp
WebSystemAssociation:
Type: AWS::ServiceCatalog::PortfolioProductAssociation
Properties:
PortfolioId: !Ref SystemsPortfolio
ProductId: !FindInMap
- Systems
- WebSystem
- ProductId
AcceptLanguage: jp
# ------------------------------------------------------------#
# 起動制約
# ------------------------------------------------------------#
NetworkComponentLaunchRoleConstraint:
Type: AWS::ServiceCatalog::LaunchRoleConstraint
Properties:
LocalRoleName: !Ref ComponentsPortfolioAssociationRole
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- NetworkComponent
- ProductId
AcceptLanguage: jp
SecurityGroupComponentLaunchRoleConstraint:
Type: AWS::ServiceCatalog::LaunchRoleConstraint
Properties:
LocalRoleName: !Ref ComponentsPortfolioAssociationRole
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- SecurityGroupComponent
- ProductId
AcceptLanguage: jp
WebServerComponentLaunchRoleConstraint:
Type: AWS::ServiceCatalog::LaunchRoleConstraint
Properties:
LocalRoleName: !Ref ComponentsPortfolioAssociationRole
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- WebServerComponent
- ProductId
AcceptLanguage: jp
DatabaseComponentLaunchRoleConstraint:
Type: AWS::ServiceCatalog::LaunchRoleConstraint
Properties:
LocalRoleName: !Ref ComponentsPortfolioAssociationRole
PortfolioId: !Ref ComponentsPortfolio
ProductId: !FindInMap
- Components
- DatabaseComponent
- ProductId
AcceptLanguage: jp
WebSystemLaunchRoleConstraint:
Type: AWS::ServiceCatalog::LaunchRoleConstraint
Properties:
LocalRoleName: !Ref SystemsPortfolioAssociationRole
PortfolioId: !Ref SystemsPortfolio
ProductId: !FindInMap
- Systems
- WebSystem
- ProductId
AcceptLanguage: jp
# ------------------------------------------------------------#
# ポートフォリオへのアクセス権限
# ------------------------------------------------------------#
ComponentsPortfolioPrincipalAssociation:
Type: AWS::ServiceCatalog::PortfolioPrincipalAssociation
Properties:
PortfolioId: !Ref ComponentsPortfolio
PrincipalType: IAM
PrincipalARN: !GetAtt SystemsPortfolioAssociationRole.Arn
AcceptLanguage: jp
SystemsPortfolioPrincipalAssociation:
Type: AWS::ServiceCatalog::PortfolioPrincipalAssociation
Properties:
PortfolioId: !Ref SystemsPortfolio
PrincipalType: IAM
PrincipalARN: !Ref AccessSystemPortfolioPrincipalArn
AcceptLanguage: jp
# ------------------------------------------------------------#
# 起動制約用のIAMロール
# ------------------------------------------------------------#
ComponentsPortfolioAssociationRole:
Type: AWS::IAM::Role
Properties:
RoleName: components-portfolio-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- servicecatalog.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2FullAccess
- arn:aws:iam::aws:policy/AmazonRDSFullAccess
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
- !Ref ServiceCatalogManagedBucketAccessPolicy
SystemsPortfolioAssociationRole:
Type: AWS::IAM::Role
Properties:
RoleName: systems-portfolio-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- servicecatalog.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSServiceCatalogEndUserFullAccess
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
- !Ref ServiceCatalogManagedBucketAccessPolicy
ServiceCatalogManagedBucketAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: service-catalog-managed-bucket-access-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:GetObject
Resource: "*"
Condition:
StringEquals:
s3:ExistingObjectTag/servicecatalog:provisioning: true
このテンプレートによりSystem
ポートフォリオとComponents
ポートフォリオが作成されます。System
ポートフォリオは製品WebSystem
のみを登録し、Components
ポートフォリオにはWebSystem
から起動される製品群が登録されます。
起動制約によりユーザーから起動できる製品をSystem
ポートフォリオに含まれる製品、すなわちWebSystem
のみに設定しています。
起動してみた
以下のパラメータでWebSystem
を起動します。
プロビジョニング完了後、複数の製品がプロビジョニングされていることが確認できました。
テンプレート分割をした製品について
CloudFormationProvisionedProductを使うことで製品どうしを組み合わせることができます。 その応用として、今回やったように製品から他製品を起動する(以下、ネスト起動)ことでテンプレートの分割をすることができます。
他にテンプレート分割をした製品を作成する方法として、下記ブログにあるようにネストスタックを行う方法があります。
この方法と比較して、今回のネスト起動によるテンプレート分割のメリット・デメリットを挙げていきます。
メリット
同じバージョンの製品で同じ構造のスタックがプロビジョニングされることを保証しやすい
ネストスタックを使った方法だと、Service Catalogの製品である参照元のテンプレートはバージョン管理されますが、S3バケットにある参照先のテンプレートはバージョン管理されていません。 そのため、同じバージョンの製品を同じパラメータで起動したとしても、参照先のテンプレートに更新があった場合に異なる構造のスタックがプロビジョニングされてしまう可能性があります。
その点、ネスト起動だと参照元と参照先の両方がバージョン管理されているため、同じ構造のスタックがプロビジョニングされることを保証しやすいです。
デメリット
Service Catalogの利用料金が増える
Service Catalogの利用料金はAPIの呼び出し回数によって決まるので、製品の起動回数が多いネスト起動の方が利用料金が増えます。
マルチリージョンでの管理が煩雑になる
Service Catalogはリージョン間で製品を共有することはできないので、他リージョンで製品を利用したい場合は製品を再作成する必要があります。
ネスト起動の場合は参照元と参照先の製品を再作成する必要がありますが、ネストスタックの場合は参照元のみを再作成するだけで済みます。
ネスト起動は管理する製品数が多いので、リージョン間で製品の同一性を管理するためのコストも増大します。
まとめ
CloudFormationProvisionedProductを使った製品起動を実際に試し、製品のテンプレート分割に関する考察を行いました。 CloudFormationProvisionedProductの利用の参考になれば幸いです。
他の利用例として以下のAWSブログ記事を挙げます。