aws/rds で暗号化された RDS DB インスタンスを別の AWS アカウントへ移行する方法

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

マネージドサービス部 佐竹です。
本日は「あるある」だけども地味に難しい、暗号化された RDS DB インスタンスの AWS アカウント間移行方法について記載します。

はじめに

AWS Organizations を利用したマルチアカウント管理を行っている場合に「Amazon RDS DB インスタンスを別の AWS アカウントに移行する」というシーンに稀に出くわします。

最近、本作業において少々ハマってしまったため、備忘録として仕様や全体像含め詳しく解説していきます。

暗号化されていない RDS を別の AWS アカウントに移動する

まず、暗号化が行われていない RDS DB インスタンスであれば、以下の3つの作業を行えば移動が完了します。

  1. 移行元の RDS DB インスタンスにおいて手動の DB スナップショットを作成する
  2. 移行先の AWS アカウントに作成した DB スナップショットを共有する
  3. 移行先の AWS アカウントにおいて、共有された DB スナップショットから RDS DB インスタンスを復元 (Restore snapshot) する

図で示すと以下のようになります。

暗号化されていない RDS を別の AWS アカウントに移動する

このように、RDS の暗号化が行われていなければ、本作業は比較的容易です。

AWS 公式ドキュメントのご紹介

また、本手順は以下にご紹介する通り AWS 公式ドキュメントにもまとまった記載があります。

docs.aws.amazon.com

先に少しの注意点

自動スナップショットは他のアカウントと共有できない

先に、細かい注意点の紹介になるのですが、以下にも記載があるように「Amazon RDS の自動スナップショットを、他の AWS アカウントと共有することはできません」という制限があります。

repost.aws

自動スナップショットを共有したい場合は、手動スナップショットとなるよう、一度コピー作業を行う必要があるという点も念のためご留意ください。

スナップショットからの復元直後は速度が劣化する

Amazon Aurora DB クラスターでは発生しませんが、Amazon RDS DB インスタンスの場合、スナップショット復元直後は「ファーストタッチペナルティ」と呼ばれる速度の劣化を引き起こす可能性があります*1

このため、RDS DB インスタンスのスナップショットを経由した移行作業では、復元直後の一時的な性能の劣化を想定して挑む必要があります*2

デフォルトサービスキーで暗号化された RDS を別の AWS アカウントに移動する

ということでメインテーマです。まずは用語と仕様から説明していきます。

デフォルトサービスキー/AWS managed key

「デフォルトサービスキー」は、RDS の場合では alias として「aws/rds」が割り当てられている「AWS managed key」のことを指しています。

先の AWS 公式ドキュメントに Amazon RDS のデフォルトサービスキーで暗号化されたスナップショットの共有は、現在サポートされていません。 と記載されているように「aws/rds」で暗号化されたスナップショットは他の AWS アカウントと共有ができません。

というのも「aws/rds」等の AWS managed key は、「その AWS アカウント内の同リージョンでのみ利用が可能」という制限になっているためです。何故そうなってしまっているかといいますと「キーポリシーが編集できない(かつ、Single-Region key である)」ためです。

AWS managed key はキーポリシーが固定されている

KMS のキーポリシーは Amazon S3 のバケットポリシーのように、アクセス権を管理する機能です。キーポリシーが修正できないことから、これを修正してその他のアカウントに共有することも不可能です。

ですが、「Customer managed key」であればキーポリシーを修正し、他のアカウントから利用させることが可能です。よって、まずは RDS のスナップショットを暗号化している鍵を「AWS managed key」から「Customer managed key」に切り替える必要があります。

RDS DB スナップショットは鍵の差し替えが可能

RDS DB インスタンスの暗号化に利用されている KMS の鍵を構築後に差し替えることはできせん。しかし、DB スナップショットにおいては、スナップショットのコピー機能を利用することで暗号化鍵の差し替えが可能です。

これにより、暗号化鍵を「AWS managed key」から「Customer managed key」に切り替えることが可能になります。そして、「Customer managed key」に切り替わってさえしまえば、アカウントを跨いで作業が可能となります。

AWS re:Post

参考まで、AWS re:Post の記事もご紹介します。

repost.aws

全体像(構成図)

これから実際に作業を行っていきますが、その前に全体像を掲載します。

暗号化されている RDS を別の AWS アカウントに移動する

暗号化が入るだけで、先の構成図からだいぶ複雑になった印象です。

どちらのアカウントの Customer managed key を利用するのか

本作業で利用する KMS の Customer managed key は、「移行元の AWS アカウント (A)」で作成しても「移行先の AWS アカウント (B)」で作成しても、どちらでも作業が可能です。

今回は「移行元の AWS アカウント (A)」が将来的に廃止されるというシナリオを検討する目的のため、「移行先の AWS アカウント (B)」で Customer managed key を作成することとしました。

もし、「移行元の AWS アカウント (A)」で Customer managed key を作成されたい場合は、これから記載する作業の一部を読み替えて対応ください。例えば「移行元の AWS アカウント (A)」が本番環境で、「移行先の AWS アカウント (B)」が検証環境の場合に、「移行元の AWS アカウント (A)」で Customer managed key を作成する場合もあるでしょう。

具体的な作業手順

それでは AWS マネジメントコンソールの画面キャプチャを添えながら、具体的な作業手順をご紹介していきます。

事前作業1. Customer managed key を作成する

まずは構成図右下にある「Customer managed key」を KMS のコンソールから作成します。黄色い矢印が指し示している箇所です。

ここでは Customer managed key の詳細な作成方法を割愛しますが、デフォルトの設定のまま進めて頂いて構いません。

参考まで、AWS 公式ドキュメントのリンクを以下に掲載します。

docs.aws.amazon.com

CrossAccountCMK

今回はエイリアスを「CrossAccountCMK」とした鍵を用意しました。以後、これを利用していきます。

補足ですが、RDS の DB スナップショットが存在するリージョンで鍵を作成してください。

事前作業2. 作成した鍵のキーポリシーを修正する

作成した「CrossAccountCMK」のキーポリシーを修正し、クロスアカウントで利用可能とします。

本作業における権限は以下の AWS 公式ドキュメント「他のアカウントのユーザーに KMS キーの使用を許可する」を参考にしました。

docs.aws.amazon.com

今回許可するアクションは以下としています。

    "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
    ],

上記に加え、以下も記載します。

    "Action": [
        "kms:CreateGrant",
        "kms:ListGrants",
        "kms:RevokeGrant"
    ],

特に kms:CreateGrant が重要です。これがない場合、後続のオペレーションで以下のエラーが発生し、作業に失敗します。

"errorMessage": "User: arn:aws:iam::00000000AAAA:user/administrator is not authorized to perform: kms:CreateGrant on this resource because the resource does not exist in this Region, no resource-based policies allow access, or a resource-based policy explicitly denies access"

なお以下は Neptune の「DB クラスターのスナップショットの共有」のドキュメントですが、実際に記載するポリシーの JSON についてはこちらも参考になります*3

docs.aws.amazon.com

キーポリシーを Edit していきます。

今回は以下の JSON をキーポリシーに追記しました。完全な JSONではないため、既存のキーポリシーに挿入してご利用ください。

00000000AAAA は移行元の AWS アカウント (A) のアカウント ID を指定しています。また「arn:aws:iam::00000000AAAA:role/Admin」は移行元アカウントに存在する IAM Role を指定しています。

        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::00000000AAAA:role/Admin"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::00000000AAAA:role/Admin"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }

このように記載することで、この鍵を「arn:aws:iam::00000000AAAA:role/Admin」が参照し RDS の スナップショットコピーに利用が可能となります。

作業が完了したら、継続作業のために KMS (CrossAccountCMK) の Arn を取得しておきます。今回は以下です。

  • arn:aws:kms:ap-northeast-1:00000000BBBB:key/a701f671-7950-4c54-b151-16c983066413

事前作業3. IAM User/Role に鍵の利用権限を付与する

移行元の AWS アカウント (A) にログインし、IAM ポリシーを作成します。

記載する JSON は以下の通りとしました。ポリシー名は「KMSCrossAccountAccess」としています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUseOfTheKey",
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey",
                "kms:CreateGrant",
                "kms:RetireGrant"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:00000000BBBB:key/a701f671-7950-4c54-b151-16c983066413"
            ]
        },
        {
            "Sid": "AllowAttachmentOfPersistentResources",
            "Effect": "Allow",
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:00000000BBBB:key/a701f671-7950-4c54-b151-16c983066413"
            ],
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": true
                }
            }
        }
    ]
}

作成した IAM ポリシーは忘れずに該当の IAM Role(今回は「arn:aws:iam::00000000AAAA:role/Admin」)へ付与してください。

ここまでで事前準備は完了です。

これらの準備作業で、「移行元の AWS アカウント (A)」の IAM Role が「移行先の AWS アカウント (B)」に作成された KMS の鍵(エイリアス名 CrossAccountCMK)を利用可能となりました。

① アカウント A で手動の DB スナップショットを作成する

まずは状況を再現するため、AWS managed key である「aws/rds」で暗号化された RDS for MySQL の DB インスタンスを作成しました。

aws/rds

この RDS DB インスタンスで手動の DB スナップショットを作成します。スナップショット名は「encrypted-cross-account-copy-from」としました。

上画像の通りスナップショットの作成が完了しました。このスナップショットの Arn を取得しておきます。

  • arn:aws:rds:ap-northeast-1:00000000AAAA:snapshot:encrypted-cross-account-copy-from

また「KMS key ID」には ID が記載されています。

この ID を KMS の管理画面から確認すると判明する通り、「aws/rds」となっています。

② 作成した DB スナップショットをコピーし鍵を差し替える

本手順全体で、ポイントとなる作業です。

「移行元の AWS アカウント (A)」の DB スナップショットを「移行先の AWS アカウント (B)」の KMS で暗号化しなおします。

また、この操作はマネジメントコンソールから実行が不可能なため、CloudShell を利用し AWS CLI で行うこととします。

実行するコマンドは以下の通りです。

aws rds copy-db-snapshot \
 --source-db-snapshot-identifier arn:aws:rds:ap-northeast-1:00000000AAAA:snapshot:encrypted-cross-account-copy-from \
 --target-db-snapshot-identifier encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413 \
 --kms-key-id arn:aws:kms:ap-northeast-1:00000000BBBB:key/a701f671-7950-4c54-b151-16c983066413

引数について説明します。

まず、source-db-snapshot-identifier が DB スナップショットです。次に、target-db-snapshot-identifier が新規にコピーして作成される DB スナップショットの名前です。最後に、kms-key-id がクロスアカウントして利用する鍵「CrossAccountCMK」を指定しています。

これを実行します。

正しく実行されると、以下のような返り値が得られます。画面キャプチャと実際の値、どちらをも掲載しておきます。

{
    "DBSnapshot": {
        "DBSnapshotIdentifier": "encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413",
        "DBInstanceIdentifier": "database-1",
        "Engine": "mysql",
        "AllocatedStorage": 20,
        "Status": "creating",
        "Port": 3306,
        "AvailabilityZone": "ap-northeast-1d",
        "Engine": "mysql",
        "AllocatedStorage": 20,
        "Status": "creating",
        "DBSnapshotIdentifier": "encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413",
        "DBInstanceIdentifier": "database-1",
        "Engine": "mysql",
        "AllocatedStorage": 20,
        "Status": "creating",
        "Port": 3306,
        "AvailabilityZone": "ap-northeast-1d",
        "VpcId": "vpc-0648be182dd94d124",
        "InstanceCreateTime": "2024-04-10T09:00:31.205000+00:00",
        "MasterUsername": "admin",
        "EngineVersion": "8.0.35",
        "LicenseModel": "general-public-license",
        "SnapshotType": "manual",
        "Iops": 3000,
        "OptionGroupName": "default:mysql-8-0",
        "PercentProgress": 0,
        "SourceRegion": "ap-northeast-1",
        "SourceDBSnapshotIdentifier": "arn:aws:rds:ap-northeast-1:00000000AAAA:snapshot:encrypted-cross-account-copy-from",
        "StorageType": "gp3",
        "Encrypted": true,
        "KmsKeyId": "arn:aws:kms:ap-northeast-1:00000000BBBB:key/a701f671-7950-4c54-b151-16c983066413",
        "DBSnapshotArn": "arn:aws:rds:ap-northeast-1:00000000AAAA:snapshot:encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413",
        "IAMDatabaseAuthenticationEnabled": false,
        "ProcessorFeatures": [],
        "DbiResourceId": "db-NCJCIBJ7RVINCU26VLA2MBDRJI",
        "TagList": [],
        "OriginalSnapshotCreateTime": "2024-04-10T09:02:48.917000+00:00",
        "SnapshotTarget": "region",
        "StorageThroughput": 125,
        "DedicatedLogVolume": false
    }
}

参考までに、以下は copy-db-snapshot のリファレンスです。

docs.aws.amazon.com

処理が完了すると「encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413」という名前のスナップショットが作成されます。

KMS key ID を確認すると、コピーされた DB スナップショットでは鍵が「移行先の AWS アカウント (B)」の KMS に差し替えられていることがわかります。

これで「aws/rds」で暗号化されていない DB スナップショットが手に入りました。

③ コピーした DB スナップショットをアカウント B に共有する

作成された DB スナップショット を選択し、Actions から 「Share snapshot」を押下します。

Snapshot permissions

ここでアカウント ID「00000000BBBB」を入力し、「移行先の AWS アカウント (B)」に共有を行います。

「Save」を押下し、作業を続けます。

④ 共有された DB スナップショットをコピーし鍵を差し替える

ここで、再度アカウント B の持つ AWS managed key である「aws/rds」へと KMS の暗号化鍵の差し替えをします。鍵の差し替えは必須ではないため鍵は「CrossAccountCMK」のままとして頂いても問題ありません。

ただし、「DB スナップショットのコピー」は手順として実施する必要があります。これは共有された DB スナップショットを利用して直接復元することができないためです。

もしそのようにした場合、以下のエラーが発生します。

Restoring db instance from cross account storage encrypted snapshot is not supported.

また本制約については以下のドキュメントにも記載があります。

共有され暗号化された DB スナップショットから、DB インスタンスを復元することはできません。代わりに、DB スナップショットのコピーを作成し、そのコピーから DB インスタンスを復元できます。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html

では、実際に作業を行います。

「移行先の AWS アカウント (B)」の RDS > Snapshots を開き「Shared with me」のタブを開きます。すると、「移行元の AWS アカウント (A)」である 00000000AAAA から共有された Snapshot「encrypted-cross-account-copy-a701f671-7950-4c54-b151-16c983066413」が表示され、利用可能となっていることが確認できます。

これを選択し、Action から「Copy snapshot」を押下します。

スナップショット名(New DB snapshot identifier)は「encrypted-cross-account-copy-awsrds」としました。

また、AWS KMS key において「aws/rds」が選択されていることを確認し、「Copy snapshot」を押下します*4

Manual snapshot の作成が完了しました。同様に、DB スナップショットの KMS key ID が変更されていることを確認します。

この KMS key ID は、aws/rds であることがわかります。

これで、RDS DB インスタンスの構築準備が整いました。

⑤ DB スナップショットから RDS を復元する

最後は完成したスナップショットを選択後、Action から「Restore snapshot」を押下し復元作業を行います。

「Restore DB instance」についてはここでは詳しく紹介しませんため、割愛させて頂きます。

参考まで、AWS 公式ドキュメントをご紹介します。

docs.aws.amazon.com

ということで、非常に長くなりましたがこれで移行作業は完了です。

移行後に実施したほうが良いこと

作業後、不要となった DB スナップショット等は追って削除することでコスト最適化もあわせて行ってください。

また、KMS のキーポリシーや IAM ポリシーも、今後利用する予定がない場合は権限を削除されたほうが良いでしょう。

まとめ

本ブログでは、デフォルトサービスキーである「aws/rds」で暗号化済みの RDS DB インスタンスを、その他の AWS アカウントへ移行する方法について記載しました。

暗号化されていない場合は上図の通り、DB スナップショットを利用した RDS のクロスアカウントマイグレーションはシンプルに見えます。

しかし暗号化されているとこの通り、手順が増え手間のかかる事態になります。

RDS DB インスタンスがデフォルトサービスキーである「aws/rds」で暗号化されている場合は、先に暗号化鍵を「Customer managed key」に切り替える必要が出ます。

また KMS のキーポリシーや、IAM ポリシーの権限設計が必要であり、加えて「共有され暗号化された DB スナップショットから、DB インスタンスを復元することができない」という制限事項など、ハマりポイントが複数あります。

本ブログがこれらのハマりポイントを回避し、クロスアカウントマイグレーションが実現可能になる助けになれば幸いです。

では、またお会いしましょう。

*1:Amazon Aurora はストレージに EBS ボリュームを利用していないため、ファーストタッチペナルティが発生しません https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.StorageReliability.html

*2:RDS の復元後に可能な限り早く最大のパフォーマンスへと戻すためには、例えば "pg_prewarm" を利用する対応方法等があります https://www.postgresql.jp/document/13/html/pgprewarm.html

*3:ただし "Sid=": "AllowUseOfTheKey", などと謎の「=」が入ってしまっており、これを削除しなければなりませんが

*4:Destination Region がデフォルトで選択されているように見えますが、選択されていないというエラーが出る場合があります。その場合は Destination Region を選択しなおしてみてください

佐竹 陽一 (Yoichi Satake) エンジニアブログの記事一覧はコチラ

マネージドサービス部所属。AWS資格全冠。2010年1月からAWSを利用してきています。2021-2022 AWS Ambassadors/2023 Japan AWS Top Engineers/2020-2023 All Certifications Engineers。AWSのコスト削減、最適化を得意としています。