16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CloudFormationをゼロから勉強する。(その7:変更セットとドリフト検出)

Last updated at Posted at 2020-10-17

はじめに

今回はスタック実行前に事前に変更箇所を確認できる変更セットと、スタック実行後に手動操作などで変更されたリソースを確認できるドリフト検出を試してみようと思います。

変更セットについて

前述の通り、スタック実行前に変更箇所を確認することができる機能です。

スタック実行前に変更されるリソースやパラメータを確認できるので、スタック実行することによって意図せずリソースが削除されたりする事故が防げます。

テスト環境ならともかく、サービスが動作している本番環境でスタックを実行する際には必須の機能かと思います。

ドリフト検出について

これも前述の通り、スタック実行後に手動操作などで変更されたリソースを確認できる機能です。

本来は環境をCloudFormationで管理しているのであればスタックで作成したリソースや設定に対して手動で操作することは極力避けるべきですが、何かしらの理由で手動操作した場合でも変更箇所を検出することができます。

例えば障害対応などで手動で変更した設定を、後日ドリフト検出で確認してCloudFormationテンプレートに落とし込む場合に便利です。

今回のシナリオ

変更セットドリフト検出を試すため、1つのVPCと2つのサブネットリソースのみのシンプルな構成とし、サブネットリソースだけタグ付けした構成をベースとして以下を実施します。

  1. サブネットのタグを修正して変更セットを作成する。
  2. 手動で1つのサブネットの削除、VPCのタグの追加とサブネットのタグを修正してドリフト検出する。
  3. テンプレートからサブネットの削除とタグの追加・修正を行い、再度変更セットを作成する。

また、コンソールやコマンドで実行する際のスタック名等は以下で行うため、適宜読み替えるようにして下さい。

項目 名前
スタック名 stack-test
変更セット名 change-set-test
テンプレートファイルパス /home/ec2-user/cf.yaml
パラメータファイルパス /home/ec2-user/param.yaml

ベーステンプレートの作成

今回はVPCサブネットのみのテンプレートとパラメータファイルを新たに作成します。

Metadataや不要な設定は削除して極力シンプルにしました。

ベーステンプレートの作成(展開して下さい)
/home/ec2-user/cf.yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:
  EC2VPC1:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: !Ref VPCRange
  EC2Subnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref EC2VPC1
      CidrBlock: !Ref SubnetRange1
      Tags:
        - Key: "Name"
          Value: "CloudFormation"
  EC2Subnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref EC2VPC1
      CidrBlock: !Ref SubnetRange2
      Tags:
        - Key: "Name"
          Value: "CloudFormation"
Parameters:
  VPCRange:
    Type: String
    Description: "VPC Subnet Range"
  SubnetRange1:
    Type: String
    Description: "Subnet Range1"
  SubnetRange2:
    Type: String
    Description: "Subnet Range2"
ベースパラメータファイルの作成(展開して下さい)
/home/ec2-user/param.json
[
  { "ParameterKey" : "VPCRange", "ParameterValue" : "172.24.0.0/16" },
  { "ParameterKey" : "SubnetRange1", "ParameterValue" : "172.24.0.0/24" },
  { "ParameterKey" : "SubnetRange2", "ParameterValue" : "172.24.1.0/24" }
]
テンプレートの作成
aws cloudformation create-stack --template-body file:///home/ec2-user/cf.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json

ベーステンプレートの修正

前準備として作成したベーステンプレートを以下の内容に修正します。

  1. サブネットリソースのタグをcf_Subnetという名前に修正する。

変更セットの作成

変更セットは作成済みスタックのテンプレートと修正したテンプレートの差分をチェックして変更となる項目を確認することができます。

AWSマネジメントコンソールから操作する場合は作成したスタックを選択し、変更セット変更セットの作成から修正したテンプレートをアップロードするか、直接編集を行います。

capture_28092020_073042.jpg

AWS CLIで実行する場合は以下コマンドを実行します。

変更セットの作成
aws cloudformation create-change-set --change-set-name change-set-test --template-body file:///home/ec2-user/cf.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json

変更セットを作成すると以下画面のような比較結果が表示され、どのリソースが変更されるかが確認できます。

capture_29092020_075226.jpg

コマンドの場合は以下。

変更セットの確認
aws cloudformation describe-change-set --change-set-name change-set-test --stack-name stack-test
コマンド実行結果(展開して下さい)
コマンド実行結果
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:335417439444:stack/stack-test/d5249730-01dc-11eb-8e2a-0af1581a9dde", 
    "Status": "CREATE_COMPLETE", 
    "ChangeSetName": "change-set-test", 
    "Parameters": [
        {
            "ParameterValue": "172.24.0.0/24", 
            "ParameterKey": "SubnetRange1"
        }, 
        {
            "ParameterValue": "172.24.1.0/24", 
            "ParameterKey": "SubnetRange2"
        }, 
        {
            "ParameterValue": "172.24.0.0/16", 
            "ParameterKey": "VPCRange"
        }
    ], 
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Subnet", 
                "PhysicalResourceId": "subnet-0c76cd08741e9b6af", 
                "Details": [
                    {
                        "ChangeSource": "DirectModification", 
                        "Evaluation": "Static", 
                        "Target": {
                            "Attribute": "Tags", 
                            "RequiresRecreation": "Never"
                        }
                    }
                ], 
                "Action": "Modify", 
                "Scope": [
                    "Tags"
                ], 
                "LogicalResourceId": "EC2Subnet1", 
                "Replacement": "False"
            }, 
            "Type": "Resource"
        }, 
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Subnet", 
                "PhysicalResourceId": "subnet-04755c355840e4956", 
                "Details": [
                    {
                        "ChangeSource": "DirectModification", 
                        "Evaluation": "Static", 
                        "Target": {
                            "Attribute": "Tags", 
                            "RequiresRecreation": "Never"
                        }
                    }
                ], 
                "Action": "Modify", 
                "Scope": [
                    "Tags"
                ], 
                "LogicalResourceId": "EC2Subnet2", 
                "Replacement": "False"
            }, 
            "Type": "Resource"
        }
    ], 
    "CreationTime": "2020-09-28T22:50:52.425Z", 
    "Capabilities": [], 
    "StackName": "stack-test", 
    "NotificationARNs": [], 
    "ExecutionStatus": "AVAILABLE", 
    "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:335417439444:changeSet/change-set-test/845b6229-3800-448c-9f80-d54cdf81f17d", 
    "RollbackConfiguration": {}
}

変更セットの実行

変更セットは作成しただけでは差分結果を表示するだけなので、差分結果に問題が無ければ実際に修正したテンプレートを反映させるため変更セットを実行します。

修正したテンプレートを実行するためには、コンソールからなら実行ボタン、コマンドからならexecute-change-setを実行します。

変更セットの実行
aws cloudformation execute-change-set --change-set-name change-set-test --stack-name stack-test

変更セット実行後は以下の様にタグが追加、修正されているのが確認できます。

capture_29092020_080047.jpg

サブネットリソースの手動削除とタグ追加・修正

ドリフト検出を試すため、SubnetRange2で作成したサブネットを手動で削除してみます。

コマンドで実行する場合は事前にサブネットIDを調べておいて下さい。

サブネットの削除
aws ec2 delete-subnet --subnet-id [サブネットID]
VPC、サブネットのタグ追加・修正
aws ec2 create-tags --resources [VPC ID] --tags Key=Name,Value=cf_VPC1
aws ec2 create-tags --resources [サブネットID] --tags Key=Name,Value=cf_Subnet1

ドリフト検出の実行

スタック一覧画面でスタックを選択し、スタックアクションからドリフトの検出を選択することで最新のテンプレートと異なる設定をチェックできます。

capture_28092020_083002.jpg

コマンドの場合は以下。

ドリフト検出の実行
aws cloudformation detect-stack-drift --stack-name stack-test

ドリフト結果の確認

スタック一覧画面でスタックを選択し、スタックアクションからドリフト結果を表示を選択することで先ほど実行したドリフト検出の結果を確認できます。

今回はEC2Subnet1のタグの修正とEC2Subnet2リソースを手動で削除しているので、それぞれMODIFIEDDELETEDと検出されていることが確認できます。

capture_29092020_082201.jpg

コマンドの場合は以下。

ドリフト結果の表示
aws cloudformation describe-stack-resource-drifts --stack-name stack-test
コマンド実行結果(展開して下さい)
コマンド実行結果
{
    "StackResourceDrifts": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:335417439444:stack/stack-test/d5249730-01dc-11eb-8e2a-0af1581a9dde", 
            "ActualProperties": "{\"CidrBlock\":\"172.24.0.0/24\",\"Tags\":[{\"Key\":\"Name\",\"Value\":\"cf_Subnet1\"}],\"VpcId\":\"vpc-0d228fc345e494e45\"}", 
            "ResourceType": "AWS::EC2::Subnet", 
            "Timestamp": "2020-09-28T23:20:59.182Z", 
            "PhysicalResourceId": "subnet-0c76cd08741e9b6af", 
            "StackResourceDriftStatus": "MODIFIED", 
            "ExpectedProperties": "{\"CidrBlock\":\"172.24.0.0/24\",\"Tags\":[{\"Key\":\"Name\",\"Value\":\"cf_Subnet\"}],\"VpcId\":\"vpc-0d228fc345e494e45\"}", 
            "PropertyDifferences": [
                {
                    "PropertyPath": "/Tags/0/Value", 
                    "ActualValue": "cf_Subnet1", 
                    "ExpectedValue": "cf_Subnet", 
                    "DifferenceType": "NOT_EQUAL"
                }
            ], 
            "LogicalResourceId": "EC2Subnet1"
        }, 
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:335417439444:stack/stack-test/d5249730-01dc-11eb-8e2a-0af1581a9dde", 
            "ResourceType": "AWS::EC2::Subnet", 
            "Timestamp": "2020-09-28T23:20:59.746Z", 
            "PhysicalResourceId": "subnet-04755c355840e4956", 
            "StackResourceDriftStatus": "DELETED", 
            "LogicalResourceId": "EC2Subnet2"
        }, 
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:335417439444:stack/stack-test/d5249730-01dc-11eb-8e2a-0af1581a9dde", 
            "ActualProperties": "{\"CidrBlock\":\"172.24.0.0/16\"}", 
            "ResourceType": "AWS::EC2::VPC", 
            "Timestamp": "2020-09-29T22:21:03.431Z", 
            "PhysicalResourceId": "vpc-0d228fc345e494e45", 
            "StackResourceDriftStatus": "IN_SYNC", 
            "ExpectedProperties": "{\"CidrBlock\":\"172.24.0.0/16\"}", 
            "PropertyDifferences": [], 
            "LogicalResourceId": "EC2VPC1"
        }
    ]
}

また、上記ドリフトの画面からリソースを選択し、ドリフトの詳細の表示をクリックするとJSON形式ですがテンプレートとの差分を確認することができるので、実際にテンプレートを修正する場合に便利です。

capture_29092020_082340.jpg

ドリフト検出の注意点

今回、手動修正した個所はEC2Subnet1のタグ修正、EC2Subnet2のリソース削除、EC2VPC1のタグ追加ですが、上記の画像を見るとEC2VPC1のタグ追加が検出されておりません。

はっきり調べていませんが、ドリフト検出はテンプレートにもともと記載されている設定に対する検出なので、記載されていた設定値の変更は検出できても、そもそも記載されていなかった設定を検出することはできないようです。

そのような設定変更を検出するためにはAWS Configで検出する必要があるのかな?

変更セットの更新

テンプレートとパラメータファイルからもEC2VPC1EC2Subnet1のタグ追加・修正とEC2Subnet2リソースを削除して先ほどと同様変更セットを実行します。

capture_30092020_074702.jpg

コマンドから実行する場合も、先ほどと同様のコマンドで実行できます。

変更セットの作成
aws cloudformation create-change-set --change-set-name change-set-test --template-body file:///home/ec2-user/cf.yaml --stack-name stack-test --parameters file:///home/ec2-user/param.json
変更セットの実行
aws cloudformation execute-change-set --change-set-name change-set-test --stack-name stack-test

おわりに

変更セットドリフト検出をこまめに行うことでシステムを運用していると常に付きまとう設計書と実機の差分を減らすことができるのは非常にありがたいですね。
CloudFormationで管理されていない設定については検出できませんが。

次回はスタックのネストを試してみようと思います。

16
8
0

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
16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?