Service Catalogでスタックをネストした製品を起動してみた

2022.11.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Service Catalogでは製品を起動すると内部でCloudFormationによってスタックが作成されますが、スタックをネストして製品を起動できるのか試してみました。

やってみる

構成

以下の構成でやってみました。製品にはVPCとそこからネストしてサブネットを作成するものを用意しました。

テンプレート

VPCスタック

サブネットスタックをネストしていて、subnet.yamlをS3に保存してオブジェクトURLを指定しています。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Env:
    Type: String
    Default: dev
    AllowedValues:
      - prod
      - stg
      - dev
  VpcCidr:
    Type: String
    Default: 10.0.0.0/16
  TemplateSubnet:
    Description: "Object URL for Subnet Template"
    Type: String
    Default: https://{bucketname}.s3.ap-northeast-1.amazonaws.com/Vpc-Portfolio/subnet.yaml

Resources:
  # VPC
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${Env}-vpc

  # Subnet Stack
  Subnet:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Ref TemplateSubnet
      Parameters:
        Env: !Ref Env
        VpcId: !Ref Vpc

Outputs:
  Vpc:
    Value: !Ref Vpc
    Export:
      Name: !Sub ${AWS::StackName}-Vpc
  VpcCidr:
    Value: !Ref VpcCidr
    Export:
      Name: !Sub ${AWS::StackName}-VpcCidr

Subnetスタック

VPCスタックからネストされて作成されるスタックです。任意のS3バケットに保存しておきます。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Env:
    Type: String
    Default: dev
    AllowedValues:
      - prod
      - stg
      - dev
  VpcId:
    Description: "VPC id of Subnet"
    Type: String
  SubnetAZ1Cidr:
    Type: String
    Default: 10.0.0.0/24
  SubnetAZ2Cidr:
    Type: String
    Default: 10.0.1.0/24
Resources:
  # Subnets
  ##  Subnets
  SubnetAZ1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref "AWS::Region"
      VpcId: !Ref VpcId
      CidrBlock: !Ref SubnetAZ1Cidr
      Tags:
        - Key: Name
          Value: !Sub ${Env}--subnet1
  SubnetAZ2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref "AWS::Region"
      VpcId: !Ref VpcId
      CidrBlock: !Ref SubnetAZ2Cidr
      Tags:
        - Key: Name
          Value: !Sub ${Env}--subnet2

製品の作成

Service Catalogのコンソールから製品(VPC)を作成します。

今回はテンプレートが手元にあるので、アップロードして作成しました。

製品を作成したら適当なポートフォリオを作成するか紐付けしてください。アクセス権をポートフォリオに付与して準備完了です。

製品の起動

それでは製品を起動してみます。

起動すると、リソースにVPCとサブネットのネストされたスタックが表示されていました。Service Catalogでもスタックをネストして利用するのは問題なさそうです。

共有されたポートフォリオからクロスアカウントで起動

単一のアカウント内では問題なくネストできたので、次にポートフォリオを共有してクロスアカウントでネストしたスタックが起動できるか試してみます。

ポートフォリオの共有

検証している環境はOrganizations環境のため、組織内に共有して試してみます。

共有先のアカウントで製品を起動すると、予想通りエラーとなりました。

CloudFormationで詳細を確認してみると、S3バケットへのアクセスが拒否されたとあります。

ここでエラーとなるのは、共有先アカウントでSubnetスタックを作成するためのテンプレートが取得できないためです。

バケットポリシーの変更

現状を整理すると、このような形になっています。共有先アカウントからみると共有元アカウントのS3バケットを参照しているため、クロスアカウントでの許可が必要です。

そのため、共有先アカウントのネストスタックでもテンプレートを取得できるように、共有元アカウントでS3バケットのバケットポリシーを変更します。

今回は組織内に共有しているため、同じ組織であれば取得を許可しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalOrgID": "o-xxxxxxxxxx"
                }
            }
        }
    ]
}

バケットポリシーを変更したので、もう一度製品を起動してみると正常に作成できました。

起動制約を利用しない場合は、製品を起動するユーザー(ロール)にs3:GetObjectの権限が必要なので注意しましょう。

おわりに

Service Catalogでネストしたスタックを使ってみました。内部的にはCloudFormationを動かしているだけなので、Service Catalogが分かれば直感的に使えそうですね。

マルチアカウントで利用する場合も、バケットポリシーで上手く制御してあげることでテンプレートの管理を共有元だけでできそうです。