投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。
手動で変更した場合の対応は、以下に記述があるとおりテンプレートに合わせて環境を手動でイジる必要があります。
リソースに対する変更が AWS CloudFormation 外で加えられた
元のスタックテンプレートと一致するようにリソースを手動で同期した後、更新のロールバックを続けます。たとえば、AWS CloudFormation がロールバックしようとしているリソースを手動で削除した場合、元のスタックで使用していたのと同じ名前およびプロパティを使用してそのリソースを手動で作成する必要があります。
セキュリティグループを例にどのような対応が必要になるか記載したいと思います。
基本なるテンプレートは以下です。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: 0.0.0.0/0
##ユースケースごとに挙動の違いを確認する
以下の様なユースケースを考えてみました。
ケース1)セキュリティグループを削除
ケース2)セキュリティグループのルール内容を変更
ケース3)セキュリティグループのルールを追加
ケース4)複数リソースを定義してあり、一つを削除して、片方の値を更新した場合
ケース5)手動で変更後にテンプレートを変更しない場合
###ケース1)セキュリティグループを削除
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: 0.0.0.0/0
セキュリティグループを手動で削除してみるとDriftは以下になります。
HTTPSからHTTPに変更してupdate stackしてみます。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
リソースが存在しないためUpdateに失敗し、UpdateのRollbackも失敗します。
このようなケースは、スキップしたいリソースを指定して更新のロールバックを続ける
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-continueupdaterollback.html
ロールバックが完了しました。新規にルールを作成するためにリソース名を変更します。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
update stack実行します。
無事新しいリソースが作成できた。
###ケース2)セキュリティグループのルール内容を変更
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
CidrIpを変更する
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 192.168.0.7/32
Updateは成功し、新規にルールが作成される
###ケース3)セキュリティグループのルールを追加
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 192.168.0.7/32
HTTPからHTTPSに変更する
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: 443'
CidrIp: 192.168.0.7/32
手動で削除するとDriftは解消できる
###ケース4)複数リソースを定義してあり、一つを削除して、片方の値を更新した場合
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup1:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup1
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 192.168.0.7/32
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup2
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: 192.168.0.7/32
SecurityGroup1を手動で削除し、SecurityGroup2を443から22に手動で変更します。
Driftを確認すると、DeletedとModifiedとなっています。
SecurityGroup1を削除して、SecurityGroup2のポートをHTTPSからHTTPSに変更してUpdateStackします。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup2
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 192.168.0.7/32
###ケース5)手動で変更後にテンプレートを変更しない場合
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: vpc-26505643
GroupDescription: SecurityGroup2
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 192.168.0.7/32
テンプレートに変更がないと、そもそもcFnは実行されません。
aws cloudformation update-stack --template-body file://test3.yaml --stack-name teststack
An error occurred (ValidationError) when calling the UpdateStack operation: No updates are to be performed.
##まとめ
Driftで差分を把握することが容易になりましたが、手動で変更した場合は、リソースごとに対応方法がことなるため、うやはり運用者にはリソースを変更するIAM権限を付与せず、変更はcFnから実施するようにした方が混乱は少なくなるかと思います。やはり前提として、cFnでの変更作業を実施する場合、cFnからしか変更できないようにすべきだと考えています。
cFnでの管理が向いているもの
大前提としてステートを持たないもの→DBなどは障害時のリストアがあるためcFnでの管理に向かない
初期構築のみでcFnで一気に構築し、運用は手動or別のツールを使用する
Blue/Green的に切り替える場合の環境構築
テンプレートを細かく分けて、update stackの変更の範囲を局所化するといった設計が必要
cFnでの運用に向かいないもの
ネストしたStack構成。割り切ってImport/Exportなしでべた書きで運用した方が結合度は低くなり運用負荷が下がる場合もある