LoginSignup
1
0

More than 1 year has passed since last update.

CFnの別のスタックからの変更をブロックしたい

Last updated at Posted at 2022-03-15

やりたいこと

  1. CloudFormationでStackを1つ作る。
  2. 別のStackを作る。このStackの中で[1]で作成したResourceを変更する。
  3. [1]で作ったスタックをアップデートする。とどうなる?
  4. [2]の変更で[1]で作成したリソースが変更できないようにする。

※[4]は、今の所、できていない。もう少し模索する(ToDo)

1. CloudFormationでStackを1つ作る

AWSTemplateFormatVersion: "2010-09-09"
Description: 
  VPC, Subnet

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Project Name Prefix"
        Parameters: 
          - ClusterPrefix
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCCIDR
          - PublicSubnetCIDR
    ParameterLabels: 
      VPCCIDR: 
        default: "VPC CIDR"
      PublicSubnetCIDR: 
        default: "PublicSubnet CIDR"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  ClusterPrefix:
    Type: String
    Default: "foobar"

  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
  PublicSubnetCIDR:
    Type: String
    Default: "10.0.10.0/24"

Resources: 
# ------------------------------------------------------------#
#  VPC
# ------------------------------------------------------------#
# VPC
  VPC: 
    Type: "AWS::EC2::VPC"
    Properties: 
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      InstanceTenancy: default
      Tags: 
        - Key: Name
          Value: !Sub "${ClusterPrefix}-vpc"

# InternetGateway
  InternetGateway: 
    Type: "AWS::EC2::InternetGateway"
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${ClusterPrefix}-igw"

# IGW Attach
  InternetGatewayAttachment: 
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties: 
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

# DHCPOptions
  DHCPOptions:
    Type: AWS::EC2::DHCPOptions
    Properties:
      DomainName: ap-northeast-1.compute.internal
      DomainNameServers:
        - AmazonProvidedDNS
      Tags:
        - Key: Name
          Value: !Sub "${ClusterPrefix}-dhcp-options"
  DHCPOptionsAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    Properties:
      VpcId: !Ref VPC
      DhcpOptionsId: !Ref DHCPOptions

# ------------------------------------------------------------#
#  Subnet
# ------------------------------------------------------------#          
# PublicSubnet
  PublicSubnet: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PublicSubnetCIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${ClusterPrefix}-public-subnet-a"

# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#          
# PublicRouteTable
  PublicRouteTable: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${ClusterPrefix}-public-route-a"

# ------------------------------------------------------------#
# Route
# ------------------------------------------------------------# 
# PublicRouteA
  PublicRouteA: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway 

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicSubnetRouteTableAssociation
  PublicSubnetRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

# Outputs
Outputs:
  VPC:
    Value: !Ref VPC
  PublicSubnet:
    Value: !Ref PublicSubnet
  InternetGateway:
    Value: !Ref InternetGateway

OutputsでRouteTableとIGWとVPCのIDを出力しているので、コピーしておく。

image.png

別のStackを作る。このStackの中で[1]で作成したResourceを変更する。

[1]で作ったRouteTableをすげ替えるようなRouteの設定とは違う設定を突っ込む。

AWSTemplateFormatVersion: "2010-09-09"
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  ClusterPrefix:
    Type: String
    Default: "foobar"
  VPC:
    Type: String
    Default: ""
  InternetGateway:
    Type: String
    Default: ""
  PublicSubnet:
    Type: String
    Default: ""

Resources: 
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#          
# PublicRouteTableMod
  PublicRouteTableMod: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${ClusterPrefix}-public-route-a-mod"

# ------------------------------------------------------------#
# Route
# ------------------------------------------------------------# 
# PublicRouteMod
  PublicRouteMod: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTableMod
      DestinationCidrBlock: "192.168.0.0/24"
      GatewayId: !Ref InternetGateway 

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicSubnetARouteTableAssociationMod
  PublicSubnetARouteTableAssociationMod: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTableMod

RouteTableを確認するとあとから作ったやつが、Subnetに紐付けされており、

image.png

紐付けされているRouteもあとから作ったやつになっている。

image.png

3. [1]で作ったスタックをアップデートする。とどうなる?

先ずは、何も考えずに[1]のStackを更新しちゃう。
ここではPrivateSubnetを作る感じ。

36a37,39
>   PrivateSubnetCIDR:
>     Type: String
>     Default: "10.0.20.0/24"
97a101,110
> # PrivateSubnet
>   PrivateSubnet: 
>     Type: "AWS::EC2::Subnet"
>     Properties: 
>       AvailabilityZone: "ap-northeast-1a"
>       CidrBlock: !Ref PrivateSubnetCIDR
>       VpcId: !Ref VPC 
>       Tags: 
>         - Key: Name
>           Value: !Sub "${ClusterPrefix}-private-subnet-a"

StackのEventを見ると以下の通り。ん~、YAMLの差分更新しかしない感じなのね。

image.png

では、今度はPublicSubnetのRouteTableをアップデートしてみる。

132c132
<       DestinationCidrBlock: "0.0.0.0/0"
---
>       DestinationCidrBlock: "172.16.0.0/12"

この更新の場合の変更セットは以下のようになる。

image.png

むむむ、RouteTableが削除&再作成されている。

image.png

結果、RouteTableは再作成されて、意図したルーティング設定にはなっているものの、肝心のRouteTableがSubnetにアタッチされていないという、グッチャグチャの構成に...。stack01で作ったRouteTableがSubnetにアタッチされるのかと思いきや、やはりYAMLの差分のみの適用を行う動きをするようで、Associationし直すということはなかった。

image.png

4. [2]の変更で[1]で作成したリソースが変更できないようにする。

[2]の変更で[1]の構成を崩したが、これを阻止したいときに使うのが、stack policyらしい。

スタックを作成するとき、すべてのリソースですべての更新アクションが許可されます。デフォルトでは、スタック更新アクセス権限を持つユーザーであれば誰でもスタック内のすべてのリソースを更新できます。更新処理中、リソースの中断や完全な置き換えが必要になった場合は、新しい物理 ID やまったく新しいストレージが使用される結果になります。スタックポリシーを使用すると、スタックの更新中にスタックのリソースが意図せずに更新または削除されるのを防止できます。スタックポリシーは、指定したリソースに対して実行できる更新アクションを定義する JSON ドキュメントです。
スタックポリシーを設定すると、デフォルトでスタック内のすべてのリソースが保護されます。特定のリソースでの更新を許可するには、スタックポリシーでこれらのリソースに対して Allow ステートメントを明示的に指定します。1 つのスタックに定義できるスタックポリシーは 1 つのみですが、1 つのポリシー内で複数のリソースを保護することができます。スタックポリシーは、スタックを更新しようとするすべての AWS CloudFormation ユーザーに適用されます。異なるスタックポリシーを異なるユーザーに関連付けることはできません。
スタックポリシーは、スタックの更新時のみ適用されます。AWS Identity and Access Management (IAM) ポリシーのようなアクセスコントロールは提供しません。特定のスタックリソースを誤って更新しないように、スタックポリシーはフェイルセーフメカニズムとしてのみ使用してください。AWS リソースまたはアクションへのアクセスを制御するには、IAM を使用します。

[1]の実施時に、stack policyを設定する。
[2]では、新たにRouteTableを作ってアタッチするようなYAMLなので、これをブロックするポリシーにする。

stackpolicy
{
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "*"
    },
    {
      "Effect" : "Deny",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "LogicalResourceId/PublicSubnetRouteTableAssociation"
    }
  ]
}

再度、[2]を実施すると...
失敗させたかったけど、同一スタックの更新にのみ適用できるみたい?なのかな。普通に変更できてしまった。

image.png

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0