要点
「AWS Backup」というバックアップのためのサービスがあり、私の担当業務ではEC2インスタンスのバックアップ等でありがたく利用させて頂いています。
AWS Backupの関連リソース構築作業の手間を簡略化するためにCloudFormationテンプレートを作成しようと"AWS Backup CloudFormation"などで検索すると、"ListOfTags"でバックアップ対象のタグを指定する例が多く出てきますが、タグで対象リソースを指定できるプロパティは "Conditions"と"ListOfTags"の2種類 あります。
もし複数タグを指定した「バックアップ対象リソースの絞り込み」を行いたい場合、"ListOfTags"プロパティを使用すると期待に反する結果になる可能性があり、たいていは"Conditions"プロパティを使う方が適切であるように思います。
CloudFormationテンプレートのドキュメントはこちら↓
AWS::Backup::BackupSelection BackupSelectionResourceType
AWS Backupについてはこちら↓
AWS Backup データ保護の一元管理と自動化
"Conditions"と"ListOfTags"の違い
直感的には"Conditions"より"ListOfTags"の方が「タグの条件を指定するよ!」という感じがしてわかりやすい気がします。
しかし、"ListOfTags"で複数のタグを指定した場合「OR条件」でいずれかのタグが一致するリソースが対象となります。 つまり、複数タグの「AND条件」で絞り込みを行うイメージで"ListOfTags"を使ってしまうと、想定外の範囲のリソースまでバックアップ対象になってしまいます。
一方で"Conditions"で指定しておけば「AND条件」となるので全てのタグ条件に一致するリソースのみが対象になり、私が期待していたのはこちらの動作でした。
AND条件、OR条件の他にも"ListOfTags"は「StringEquals」の条件しか書けないのに対し"Conditions"は「StringLike」などのより柔軟な条件も設定できる違いがあり、CloudFormationテンプレートの書き方も異なります。
通常はOR条件ではなくAND条件で対象の絞り込みをしたいことの方が多いと思います。
しっかりとドキュメントを確認していれば防げるミスではありますが、"ListOfTags"はプロパティ名から仕様を勘違いしやすい気もしますし、個人的にはOR条件が必要なければ最初から"Conditions"だけを使っておいた方が余計な過ちを防げる気がします。
テンプレート例
"Conditions"を利用したEC2インスタンスのバックアップ用リソースのテンプレート例を参考までに載せておきます。
AWSTemplateFormatVersion: 2010-09-09
Description: >-
Create AWS Backup Plan(sample).
Parameters:
GroupName:
Type: String
Default: "sample-group"
Description: "the 'GroupName' tag value of target instance"
EnvName:
Type: String
Default: "dev"
Description: "the 'EnvName' tag value of target instance"
Resources:
BackupVault:
Type: AWS::Backup::BackupVault
Properties:
BackupVaultName: !Sub ${AWS::StackName}-vault
BackupPlan:
Type: AWS::Backup::BackupPlan
Properties:
BackupPlan:
BackupPlanName: !Sub ${AWS::StackName}-plan
BackupPlanRule:
- RuleName: !Sub ${AWS::StackName}-plan-rule
TargetBackupVault: !Ref BackupVault
# UTC setting required (JST -9h)
ScheduleExpression: "cron(0 15 ? * * *)"
StartWindowMinutes: 60
CompletionWindowMinutes: 300
Lifecycle:
DeleteAfterDays: 3
BackupSelectionEC2:
Type: AWS::Backup::BackupSelection
Properties:
BackupPlanId: !Ref BackupPlan
BackupSelection:
SelectionName: !Sub ${AWS::StackName}-selection
IamRoleArn: !GetAtt BackupRole.Arn
Resources:
- arn:aws:ec2:*:*:instance/*
Conditions:
StringEquals:
- ConditionKey: "aws:ResourceTag/GroupName"
ConditionValue: !Ref GroupName
- ConditionKey: "aws:ResourceTag/EnvName"
ConditionValue: !Ref EnvName
BackupRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${AWS::StackName}-role
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service: backup.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
- arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
上のCloudFormationテンプレートでは、毎日0時(UTCの15時)にBackupSelectionで指定した条件に一致するリソースを3日分バックアップする設定のAWS Backup関連リソースが作成されます。
当記事に関連するポイントは下記の部分で、"GroupName"タグと"EnvName"タグの両方がパラメータで指定したタグの値と一致する「EC2インスタンスのリソース」のみにバックアップ対象を限定しています。
Resources:
- arn:aws:ec2:*:*:instance/*
Conditions:
StringEquals:
- ConditionKey: "aws:ResourceTag/GroupName"
ConditionValue: !Ref GroupName
- ConditionKey: "aws:ResourceTag/EnvName"
ConditionValue: !Ref EnvName
下記参考URLに公式のサンプルもあります。
参考: バックアッププランへのリソースの割り当て
まとめ
よくドキュメントを読まずに直感で"ListOfTags"でタグの絞り込み条件を指定してしまうと「え?!」という結果になり得ますのでご注意を。
複数タグを使った絞り込み条件には"Conditions"を使いましょう。