CloudFormationの変更セットで本番稼働中のEC2を削除しかけた話

記事タイトルとURLをコピーする

こんにちは、屋根裏エンジニアの折戸です。

最近自分と同じ名前(姓)の役名をドラマで見かけました。

下戸陸太(おりと・ろくた)

嬉しい反面、結構な凶悪犯役だったので複雑な気分になりました。

さて、今日はCloudFormation(以下、CFn)の変更セットで危うく本番稼働中のEC2インスタンスを削除しかけた話をします。

事の発端

とある業務で本番稼働中のEC2へインスタンスプロフファイルをアタッチする作業をしていました。

まずは、CFnでインスタンスプロファイルを専用のテンプレートで作成、EC2のスタックから参照できるようにExportしておきました。

次に、起動中のEC2もCFnで作成されていたため、当時のテンプレートへIamInstanceProfileパラメータを追記し、変更セットでインスタンスプロファイルをアタッチする計画を立てました。

変更セット作成前のテンプレートは以下のとおり

AWSTemplateFormatVersion: 2010-09-09
Description: test-instance

Parameters:
  ImageId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2

Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    DeletionPolicy: Delete
    Properties:
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            Encrypted: false
            VolumeSize: 8
            VolumeType: gp3
      DisableApiTermination: false
      ImageId: !Ref ImageId
      InstanceInitiatedShutdownBehavior: stop
      InstanceType: t4g.micro
      Monitoring: false
      KeyName: test-keypair
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !ImportValue SecurityGroup-web
          SubnetId:
            !ImportValue SubnetTestPrivateA

インスタンスプロファイルアタッチの追加差分は以下のとおり

            VolumeSize:8
            VolumeType: gp3
      DisableApiTermination: false
++    IamInstanceProfile: !ImportValue test-ec2-instance-profile-role
      ImageId: !Ref ImageId
      InstanceInitiatedShutdownBehavior: stop
      InstanceType: t4g.micro

開発環境でCFnを実行

さて、本番環境でいきなり変更セットを作成実行するのは言語道断、正気の沙汰ではありません(言い過ぎ

では開発環境で変更前のテンプレートでEC2を作成、その後インスタンスプロファイル追記したテンプレートで変更セットを作成実行し、起動中のEC2へ影響がないことを確認しましょう。

実行 & 確認

EC2作成用のCFn実行後、変更セットを作成して実行しましょう。

f:id:swx-orito:20220222150345p:plain ステータスがCREATE_COMPLETEになり、置換もFalseとなっています。

実行 をクリックし、起動中のEC2へインスタンスプロファイルがアタッチされていることも確認しました。

これで開発環境では起動中のEC2インスタンスへ影響なく更新できる確認が完了しました。

いざ、本番環境で作業です。

本番環境で変更セットを作成

開発環境と同じテンプレートで変更セットを作成しましょう。

f:id:swx-orito:20220222125947p:plain

さぁ、いよいよ実行のボタンをク、、、

おわかりいただけただろうか

置換がTrueとなっていることにお気づきでしょうか。

f:id:swx-orito:20220222130143p:plain

この状態でもし一息つかずに実行をクリックしていたら、本番稼働中のEC2が削除されてしまうところでした。

冷や汗がひいたところで、原因を調べましょう。

原因を確認

JSONの変更タブを確認

f:id:swx-orito:20220222153130p:plain

ImageIdが差し替えられる予定であることがわかりました。

ではなぜImageIdが差し替えられそうになったのか。

AMI名を確認

それぞれの環境のAMI名を確認してみます。

  • 本番環境のImageId f:id:swx-orito:20220228224447p:plain

  • 開発環境のImageId f:id:swx-orito:20220228231304p:plain

本番環境と開発環境でAMI名が異なることがわかりました。

時系列で整理

以下の通り、
本番環境のCFn更新のタイミングはImageIdが更新されるタイミングでした。

タイミング AMI 名
本番環境
初回CFn実行
amzn2-ami-hvm-2.0.20220121.0-arm64-gp2 AMI
作成
開発環境
初回CFn実行
amzn2-ami-hvm-2.0.20220207.1-arm64-gp2 AMI
作成
開発環境
変更セット実行
amzn2-ami-hvm-2.0.20220207.1-arm64-gp2
AMI
変更なし
本番環境
変更セット作成
amzn2-ami-hvm-2.0.20220207.1-arm64-gp2
AMI
変更あり

今回はImageIdプロパティの値を
AWS Systems Manager Parameter Store
/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2を参照して最新のAMI IDを取得して設定するテンプレートでした。

  ImageId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2

このテンプレートの仕組みにより、変更セット実行のタイミングによって
ImageIdの値が変わってしまう
ということが原因でした。

ちなみに

AWS::EC2::Instance の ImageIdプロパティの更新動作に関しては、リソースの置換が発生してしまうことがドキュメントにも明記されています。 f:id:swx-orito:20220301222601p:plain

docs.aws.amazon.com

置換
AWS CloudFormation は更新の際にリソースを再作成し、新しい物理 ID も生成されます。AWS CloudFormation は、通常まず置換リソースを作成し、他の従属するリソースからの参照が置換リソースを指すように変更してから、古いリソースを削除します。

対処方法

今回はCFnではなくコンソールから手動で追加されたインスタンスプロファイルをEC2へアタッチすることにしました。
また、変更セットが残ったままだと実行されるリスクがあるので、慎重に削除 しました。

最後に

今回は開発環境で影響なく更新できたという確証を得たこともあって、
まさか本番環境で影響が出る可能性があるとは思いもよりませんでした。

また、

  • 変更スタックによる更新の際は必ず置換の状態を確認すること
  • プロパティの Update requires を意識してリソースの運用管理をすること

この2点は非常に重要だということが実感できた経験でした。

では。

折戸 亮太(執筆記事の一覧)

2021年10月1日入社
クラウドインテグレーション部技術1課

屋根裏エンジニア