暗号化されたAuroraのスナップショットをAWS Backupで他リージョンにコピーする
本記事はAsiaQuest Advent Calendarの3日目です。
目次
当記事の対象者
- 暗号化されたAuroraのスナップショットをDR環境にコピーしたい人
- 上記のアーキテクチャをCloudFormationで構築したい人
- AWS BackupにアタッチするIAMロールの権限をある程度絞りたい人
当記事の執筆理由
暗号化されたAuroraのスナップショットをAWS Backupで他リージョンにコピーする機会がありました。
その際、権限周りで躓く事がありましたので備忘録として残しておこうと思い、当記事を執筆しました。
補足:RDSにはクロスリージョン自動バックアップ機能があります。
しかし、当記事執筆時点(2023年2月)では、Auroraは非対応です。
クロスリージョン自動バックアップ
アーキテクチャ図
今回の構成のポイントは以下の通りです。
- 東京リージョンのAWS BackupでAuroraのスナップショットを取得し、大阪リージョンのAWS Backup Vaultに向けてクロスリージョンコピー
- 東京リージョンでCMKを作成し、東京リージョンのCMKをプライマリーキーとしたレプリカキーを大阪リージョンに作成(リージョン間コピーのため)
- 東京リージョンのAWS Backup Vaultは東京リージョンのプライマリーキーを利用し、大阪リージョンのAWS Backup Vaultは大阪リージョンのレプリカキーを利用する
留意事項
- 「Auroraのスナップショット」と文中で表現していますが、厳密には「AWS Backup Vaultの復旧ポイント」です。
- 東京リージョン大規模障害から復旧した後のリストアを想定して、大阪リージョンから東京リージョンにスナップショットをコピーできるように権限を設定しています。
その際のコピー作業は手動作業となります。
CloudFormationテンプレート例
次にCloudFormationのテンプレート例です。
AWS Backup、KMS以外のリソースに関しては割愛させていただきます。ご了承ください。
東京リージョンでデプロイするCloudFormationテンプレート
source-backup.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Ap-northeast-1 Source AWS Backup Resources: BackupVault: Type: AWS::Backup::BackupVault Properties: BackupVaultName: source-backup-vault EncryptionKeyArn: Fn::ImportValue: primary-kms BackupPlan: Type: AWS::Backup::BackupPlan Properties: BackupPlan: BackupPlanName: source-backup-plan BackupPlanRule: - RuleName: source-backup-rule TargetBackupVault: !Ref BackupVault ScheduleExpression: cron(0 16 * * ? *) # JST 1:00 StartWindowMinutes: 60 CompletionWindowMinutes: 720 Lifecycle: DeleteAfterDays: 1 CopyActions: - DestinationBackupVaultArn: !Sub arn:aws:backup:ap-northeast-3:${AWS::AccountId}:backup-vault:destination-backup-vault Lifecycle: DeleteAfterDays: 1 BackupSelection: Type: AWS::Backup::BackupSelection Properties: BackupPlanId: !Ref BackupPlan BackupSelection: SelectionName: source-backup-selection IamRoleArn: !GetAtt BackupIamRole.Arn Resources: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster:クラスター名 BackupIamRole: Type: AWS::IAM::Role Properties: RoleName: source-backup-role AssumeRolePolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: backup.amazonaws.com BackupIamPolicy: Type: AWS::IAM::Policy Properties: PolicyName: source-backup-policy PolicyDocument: Statement: - Effect: Allow Action: - rds:CreateDBClusterSnapshot - rds:DescribeDBClusters - rds:DescribeDBClusterSnapshots - rds:AddTagsToResource - rds:ListTagsForResource - rds:CopyDBClusterSnapshot - rds:ModifyDBClusterSnapshotAttribute - rds:RestoreDBClusterFromSnapshot Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster:クラスター名* - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:subgrp:サブネットグループ名 - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-pg:クラスターパラメータグループ名 - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:* - Effect: Allow Action: - rds:DeleteDBClusterSnapshot Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:* - Effect: Allow Action: - backup:DescribeBackupVault - backup:CopyIntoBackupVault Resource: - !Sub arn:aws:backup:ap-northeast-1:${AWS::AccountId}:backup-vault:source-backup-vault - !Sub arn:aws:backup:ap-northeast-3:${AWS::AccountId}:backup-vault:destination-backup-vault - Effect: Allow Action: - kms:Decrypt - kms:Encrypt - kms:GenerateDataKey - kms:ReEncrypt* - kms:CreateGrant - kms:DescribeKey Resource: - Fn::ImportValue: primary-kms - 大阪リージョンのレプリカキーのArn - Effect: Allow Action: - kms:DescribeKey Resource: - !Sub arn:aws:kms:ap-northeast-1:${AWS::AccountId}:key/* - !Sub arn:aws:kms:ap-northeast-3:${AWS::AccountId}:key/* Condition: ForAnyValue:StringEquals: kms:ResourceAliases: - alias/aws/rds - alias/aws/backup Roles: - !Ref BackupIamRole
primary-kms.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Ap-northeast-1 Primary Kms Resources: KmsKey: Type: AWS::KMS::Key Properties: MultiRegion: true KeyPolicy: Version: 2012-10-17 Id: key-policy Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub arn:aws:iam::${AWS::AccountId}:root Action: "*" Resource: "*" - Sid: Allow administration of the key # 適宜ユーザかロールに権限を付与してください Effect: Allow Principal: AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/xxxxx Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion Resource: "*" KmsKeyAlias: Type: AWS::KMS::Alias Properties: AliasName: alias/primary-kms TargetKeyId: !Ref KmsKey Outputs: KmsKey: Value: !GetAtt KmsKey.Arn Export: Name: primary-kms
大阪リージョンでデプロイするCloudFormationテンプレート
destination-backup.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Ap-northeast-3 Destination AWS Backup Resources: BackupVault: Type: AWS::Backup::BackupVault Properties: BackupVaultName: destination-backup-vault EncryptionKeyArn: Fn::ImportValue: replica-kms
replica-kms.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Ap-northeast-3 Replica Kms Resources: KmsKey: Type: AWS::KMS::ReplicaKey Properties: PrimaryKeyArn: 東京リージョンのプライマリキーのArn KeyPolicy: Version: 2012-10-17 Id: key-policy Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub arn:aws:iam::${AWS::AccountId}:root Action: "*" Resource: "*" - Sid: Allow administration of the key # 適宜ユーザかロールに権限を付与してください Effect: Allow Principal: AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/xxxxx Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion Resource: "*" KmsKeyAlias: Type: AWS::KMS::Alias Properties: AliasName: alias/replica-kms TargetKeyId: !Ref KmsKey Outputs: KmsKey: Value: !GetAtt KmsKey.Arn Export: Name: replica-kms
上記のCloudFormationのテンプレートを元に、設定値をParametersで指定するようにしたり、Mappingsで設定値をまとめたりしてアレンジしてください。
以下の手順でデプロイしてください。
- 東京リージョンでKMS(プライマリーキー)作成
- 大阪リージョンでKMS(レプリカキー)作成
- 大阪リージョンでAWS Backup(送信先Backup Vault)作成
- 東京リージョンでAWS Backup(送信元Backup Vault、IAMロールなど)作成
CloudFormationテンプレート解説
上記のCloudFormationのテンプレートからいくつかのポイントをピックアップして解説します。
まずはKMSから解説します。
primary-kms.yml
Resources: KmsKey: Type: AWS::KMS::Key Properties: MultiRegion: true
今回、大阪リージョンにレプリカキーを作成するため、「MultiRegion」を「true」にします。
この設定は鍵作成時にしか設定できないため、要注意です。
キーポリシーは公式ドキュメントのポリシーをほぼそのまま利用しています。
適宜アクションやリソースを変更してください。
Create a symmetric encryption KMS key
Outputs: KmsKey: Value: !GetAtt KmsKey.Arn Export: Name: primary-kms
東京リージョンのAWS Backupデプロイ時にプライマリーキーのArnが必要なため、Outputsを利用しエクスポートします。
replica-kms.yml
Resources: KmsKey: Type: AWS::KMS::ReplicaKey Properties: PrimaryKeyArn: 東京リージョンのプライマリキーのArn
レプリカキーを作成するには「AWS::KMS::ReplicaKey」Typeを利用します。
その際、「PrimaryKeyArn」で東京リージョンのプライマリキーを指定するのですが、
基本的にリージョン間でクロススタック参照を行うことが出来ないためArnを直接入力しています。
しかし、SSMパラメータストアを利用したり、AWS CDKを利用することでリージョン間でクロススタック参照する方法があります。
その方法を解説した記事を紹介しておきます。
リージョン間のCloudFormationクロススタック参照を実現する
AWS CDKでリージョン間のクロススタック参照を簡単に実現!cdk-remote-stackを試してみた
Outputs: KmsKey: Value: !GetAtt KmsKey.Arn Export: Name: replica-kms
プライマリキー同様にレプリカキーのArnを、Outputsを利用してエクスポートしております。
次にAWS Backupを解説します。大阪リージョンのAWS Backupから解説します。
destination-backup.yml
Resources: BackupVault: Type: AWS::Backup::BackupVault Properties: BackupVaultName: destination-backup-vault EncryptionKeyArn: Fn::ImportValue: replica-kms
スナップショットのコピー先としてBackup Vaultを利用しますので、
東京リージョンより先に大阪リージョンにBackup Vaultを作成します。
「EncryptionKeyArn」では、Fn::ImportValueを利用してレプリカキーのArnを参照しています。
source-backup.yml
Resources: BackupVault: Type: AWS::Backup::BackupVault Properties: BackupVaultName: source-backup-vault EncryptionKeyArn: Fn::ImportValue: primary-kms
大阪リージョンのBackup Vault同様に、
「EncryptionKeyArn」において、Fn::ImportValueを利用してプライマリーキーのArnを参照しています。
BackupPlan: Type: AWS::Backup::BackupPlan Properties: BackupPlan: BackupPlanName: source-backup-plan BackupPlanRule: - RuleName: source-backup-rule TargetBackupVault: !Ref BackupVault ScheduleExpression: cron(0 16 * * ? *) # JST 1:00 StartWindowMinutes: 60 CompletionWindowMinutes: 720 Lifecycle: DeleteAfterDays: 1 CopyActions: - DestinationBackupVaultArn: !Sub arn:aws:backup:ap-northeast-3:${AWS::AccountId}:backup-vault:destination-backup-vault Lifecycle: DeleteAfterDays: 1
次にBackup Planです。
「BackupPlanRule」で、詳細なBackup Planのルールを定義します。
「TargetBackupVault」では、このBackup Planのルールを適用するBackup Vaultを指定します。
つまり、東京リージョンに作成する送信元Backup Vaultを指定することになります。
「ScheduleExpression」、「StartWindowMinutes」、「CompletionWindowMinutes」は、AWS Backupのジョブのスケジュールに関するプロパティです。
「ScheduleExpression」はcron式でジョブ開始のスケジュールを指定します。
今回の例では毎日午前1時(JST)にジョブを開始するように指定しています。(UTCで指定する点、ご注意ください。)
「ScheduleExpression」で指定したジョブ開始時刻ちょうどにジョブは開始されません。
ジョブ開始時刻をコントロールしたい場合、「StartWindowMinutes」で何分以内にジョブを開始させるか指定する必要があります。(デフォルトは8時間です。)
この「StartWindowMinutes」は、最低60分以上である必要があります。
また、指定した期間内にジョブが開始されなかった場合、ジョブはエラーとなります。
ジョブの完了時刻もコントロールしたい場合、「CompletionWindowMinutes」で何分以内にジョブを完了させるか指定する必要があります。(デフォルトは7日です。)
指定した期間内にジョブが完了されなかった場合、ジョブはエラーとなります。
AWS::Backup::BackupPlan BackupRuleResourceType
「Lifecycle」では、AWS Backupによって取得されたスナップショットをいつコールドストレージに移行するか、いつ削除するか指定する事が出来ます。
今回の例では、1日後に削除するように指定しています。
AWS::Backup::BackupPlan LifecycleResourceType
「CopyActions」で、AWS Backupによって取得されたスナップショットを他のBackup Vaultにコピーすることが出来ます。
「DestinationBackupVaultArn」では、送信先Backup VaultのArnを指定します。
つまり、大阪リージョンに作成する送信先Backup Vaultを指定することになります。
また、「Lifecycle」でコピーされたスナップショットのライフサイクルも指定する事が出来ます。
東京リージョンのスナップショット同様に、1日後に削除するように指定しています。
AWS::Backup::BackupPlan CopyActionResourceType
BackupSelection: Type: AWS::Backup::BackupSelection Properties: BackupPlanId: !Ref BackupPlan BackupSelection: SelectionName: source-backup-selection IamRoleArn: !GetAtt BackupIamRole.Arn Resources: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster:クラスター名
次にBackupSelectionです。
Backup Planを元にバックアップを取得するリソースを指定します。
リソースにアタッチされているタグを元にバックアップを取得するリソースを指定する方法もありますが、
今回の例では「BackupSelection」の「Resources」で直接AuroraのクラスターのArnを指定しています。
また「IamRoleArn」で、バックアップ取得の際に利用するIAMロールを指定します。
AWS::Backup::BackupSelection BackupSelectionResourceType
BackupIamRole: Type: AWS::IAM::Role Properties: RoleName: source-backup-role AssumeRolePolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: backup.amazonaws.com
AssumeRolePolicyDocumentに関しては、 AWS BackupのデフォルトロールであるAWSBackupDefaultServiceRoleを元にしています。
BackupIamPolicy: Type: AWS::IAM::Policy Properties: PolicyName: source-backup-policy PolicyDocument: Statement: - Effect: Allow Action: - rds:CreateDBClusterSnapshot - rds:DescribeDBClusters - rds:DescribeDBClusterSnapshots - rds:AddTagsToResource - rds:ListTagsForResource - rds:CopyDBClusterSnapshot - rds:ModifyDBClusterSnapshotAttribute - rds:RestoreDBClusterFromSnapshot Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster:クラスター名* - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:subgrp:サブネットグループ名 - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-pg:クラスターパラメータグループ名 - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:* - Effect: Allow Action: - rds:DeleteDBClusterSnapshot Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:*
最後にIAMポリシーです。
大きく分けて「Aurora」、「AWS Backup」、「KMS」でステートメントを分けています。
それぞれの一部アクションに関してはステートメントをさらに分割しております。
まず、Auroraに関するステートメントを解説します。
大元は下記公式ドキュメントの「カスタマー管理ポリシー」(「Amazon Aurora バックアップポリシー」、「Amazon Aurora のリストアポリシー」)を参考にしております。
「AWS Backup」、「KMS」のステートメントも同じく下記公式ドキュメントを参考にしております。
AWS Backup 用の管理ポリシー
しかし、この公式ドキュメントのポリシーでは、Resourceに「"*"」を利用しております。
セキュリティ要件でResourceに「"*"」が利用出来ない場合、Resourceは具体的に指定する必要があります。
その際、参考になるのがサービス認証リファレンスです。RDSのドキュメントは下記の通りです。
Amazon RDS のアクション、リソース、および条件キー
いくつかポイントをピックアップします。
Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster:クラスター名*
Auroraのクラスターを指定しているのは、もちろんAuroraからスナップショットを取得するためです。
しかし、なぜクラスター名の最後に*をつけているかと言いますと、リストアを考慮したためです。
リストアの際に元のクラスターが残っていた場合、別名でクラスターをリストアする必要があります。
例えば、{元のクラスター名}-backupといった具合です。
ここはリストアの際の運用方針にもよりますので、方針に合わせて変更してください。
- !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:subgrp:サブネットグループ名 - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-pg:クラスターパラメータグループ名
サブネットグループ、クラスターパラメーターグループを指定しているのも、リストアのためです。
ここでリストアについて補足しますと、RDSコンソールからリストアする時とAWS Backupからリストアする時の挙動が異なります。
簡単にまとめますと、以下の点が異なります。
- AWS Backupからのリストアはクラスターのみの作成となる。リストアの際、クラスターの名前を指定できる。インスタンスを作成するにはCLIでコマンド実行する必要がある。
- RDSコンソールからのリストアはクラスター、インスタンス共に作成される。リストアの際、インスタンス名は指定できるが、クラスター名は「インスタンス名-cluster」となる。
解説した記事を紹介しますので、どちらの方法でリストアするか検討してください。
RDSコンソールからとAWS backupからのAuroraクラスターリストア時の挙動の違い
- !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:*
スナップショット取得、コピーのためにスナップショットを指定します。
今回はAWS Backupによって取得されるスナップショットのため、普通のAuroraのスナップショットのArnにawsbackupが追加されています。
また最後のIDはランダム値(job-ランダム値)となるため、*で指定する必要があります。
arn:aws:rds:region:account-id:cluster-snapshot:awsbackup:*
アクセスコントロール
今回は、大阪リージョンにスナップショットをコピーしますので、大阪リージョンのスナップショットも指定しています。
- Effect: Allow Action: - rds:DeleteDBClusterSnapshot Resource: - !Sub arn:aws:rds:ap-northeast-1:${AWS::AccountId}:cluster-snapshot:awsbackup:* - !Sub arn:aws:rds:ap-northeast-3:${AWS::AccountId}:cluster-snapshot:awsbackup:*
事故防止のため「rds:DeleteDBClusterSnapshot」アクションに関しては別ステートメントに分けています。
- Effect: Allow Action: - backup:DescribeBackupVault - backup:CopyIntoBackupVault Resource: - !Sub arn:aws:backup:ap-northeast-1:${AWS::AccountId}:backup-vault:source-backup-vault - !Sub arn:aws:backup:ap-northeast-3:${AWS::AccountId}:backup-vault:destination-backup-vault
AWS Backupに関するステートメントです。
大阪リージョンの送信先Backup Vaultに対して「backup:CopyIntoBackupVault」アクションを許可しています。
「災害復旧後、大阪リージョンにコピーされたスナップショットを再度東京リージョンにコピーし、東京リージョンでリストアする」という想定のため、東京リージョンの送信元Backup Vaultも指定しています。 下記のサービス認証リファレンスによると、「backup:CopyIntoBackupVault」はリソースレベルのアクセス制御が出来ません。
AWS Backup のアクション、リソース、および条件キー
しかし、「backup:DescribeBackupVault」が許可されていないBackup Vaultに対してスナップショットをコピーすることは出来ませんので、アクセス制御としては上記のステートメントでも問題ないと考えております。
厳密な制御をしたい場合は、ドキュメント通り、条件キー「aws:RequestTag/${TagKey}」で制御するようにしてください。
- Effect: Allow Action: - kms:Decrypt - kms:Encrypt - kms:GenerateDataKey - kms:ReEncrypt* - kms:CreateGrant - kms:DescribeKey Resource: - Fn::ImportValue: primary-kms - 大阪リージョンのレプリカキーのArn - Effect: Allow Action: - kms:DescribeKey Resource: - !Sub arn:aws:kms:ap-northeast-1:${AWS::AccountId}:key/* - !Sub arn:aws:kms:ap-northeast-3:${AWS::AccountId}:key/* Condition: ForAnyValue:StringEquals: kms:ResourceAliases: - alias/aws/rds - alias/aws/backup
KMSに関するステートメントです。
AWS Backup 用のカスタマー管理ポリシーを参考にしております。
「kms:DescribeKey」に関しては、更に別ステートメントに分けています。
スナップショットを別リージョンにコピーする際、コピー先リージョンのAWSマネージド型キーである「aws/rds」「aws/backup」を参照する必要があります。
「alias/aws/rds」「alias/aws/backup」が既にコピー先リージョンにある場合、そのArnを直接指定しても問題ありません。
ただ、AWSマネージド型キーは必要となった時点でAWSが自動作成されますので、必要最低限のリソースしかないDR環境では「aws/rds」「aws/backup」が存在せず、Arnを事前に知ることが出来ない可能性もあります。
そのため、今回の例では、ResourceではKeyIDを*で指定するが、条件キー「kms:ResourceAliases」を利用することで、「aws/rds」「aws/backup」を指定するようにしています。
もし、「aws/rds」「aws/backup」が存在しない、かつ、Arnを直接指定したい場合は、CLIでdescribe-keyコマンドを実行し、「aws/rds」「aws/backup」を作成してください。
KMS AWSマネージド型キーを作成する方法を教えてください
実行結果
上手くいくとバックアップジョブが成功しています。
コピージョブも同じく成功しております。
大阪リージョンの送信先Backup Vaultを確認すると、スナップショットがコピーされている事が分かります。
大阪リージョンにコピーされたスナップショットを、東京リージョンにコピーしてみようと思います。
コピージョブが成功しました。
東京リージョンの送信元Backup Vaultを確認すると、スナップショットがコピーされている事が分かります。
(コピーされたスナップショットのIDは(copyjob-ランダム値)となります。)
このスナップショットからリストアしてみようと思います。
復元ジョブが成功しました。
RDSのコンソールを確認しますと、リストアによって新規作成されたクラスターがあります。
繰り返しとなりますが、AWS Backupからのリストアではクラスターのみの作成となる点、ご注意ください。
最後に
暗号化されたAuroraのスナップショットをAWS Backupで他リージョンにコピーするCloudFormationについて解説しました。
細かい部分は、運用方針によって変わると思いますので、運用方針に合わせて設計してください。
その際、当記事が参考になりましたら幸いです。
アジアクエスト株式会社では一緒に働いていただける方を募集しています。
興味のある方は以下のURLを御覧ください。