こんにちは、屋根裏エンジニアの折戸です。
最近自分と同じ名前(姓)の役名をドラマで見かけました。
下戸陸太(おりと・ろくた)
嬉しい反面、結構な凶悪犯役だったので複雑な気分になりました。
さて、今日は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実行後、変更セットを作成して実行しましょう。
ステータスがCREATE_COMPLETEになり、置換もFalseとなっています。
実行 をクリックし、起動中のEC2へインスタンスプロファイルがアタッチされていることも確認しました。
これで開発環境では起動中のEC2インスタンスへ影響なく更新できる確認が完了しました。
いざ、本番環境で作業です。
本番環境で変更セットを作成
開発環境と同じテンプレートで変更セットを作成しましょう。

さぁ、いよいよ実行のボタンをク、、、
・
・
・
・
・
・
・
・
・
・
おわかりいただけただろうか
置換がTrueとなっていることにお気づきでしょうか。

この状態でもし一息つかずに実行をクリックしていたら、本番稼働中のEC2が削除されてしまうところでした。
冷や汗がひいたところで、原因を調べましょう。
原因を確認
JSONの変更タブを確認

ImageIdが差し替えられる予定であることがわかりました。
ではなぜImageIdが差し替えられそうになったのか。
AMI名を確認
それぞれの環境のAMI名を確認してみます。
本番環境のImageId

開発環境のImageId

本番環境と開発環境で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プロパティの更新動作に関しては、リソースの置換が発生してしまうことがドキュメントにも明記されています。

置換
AWS CloudFormation は更新の際にリソースを再作成し、新しい物理 ID も生成されます。AWS CloudFormation は、通常まず置換リソースを作成し、他の従属するリソースからの参照が置換リソースを指すように変更してから、古いリソースを削除します。
対処方法
今回はCFnではなくコンソールから手動で追加されたインスタンスプロファイルをEC2へアタッチすることにしました。
また、変更セットが残ったままだと実行されるリスクがあるので、慎重に削除 しました。
最後に
今回は開発環境で影響なく更新できたという確証を得たこともあって、
まさか本番環境で影響が出る可能性があるとは思いもよりませんでした。
また、
- 変更スタックによる更新の際は必ず置換の状態を確認すること
- プロパティの Update requires を意識してリソースの運用管理をすること
この2点は非常に重要だということが実感できた経験でした。
では。