はじめに
SKYPCEの各種サービスエンドポイントのサーバー群はAWS EC2インスタンスで動作しています。
これらのサーバーは、OSとアプリケーションを含むAMIとして固めたものが成果物となっています。
この成果物を評価し、問題がなければ運用チームに受け渡す流れになっています。
「評価用AWSアカウント」から「本番用AWSアカウント」への受け渡しは、AMIを使用して行います。
本記事では、AMIを暗号化したままセキュアに受け渡すためのKMSのキー関連の設定について解説します。
調査した結果、この図のような構成にたどり着きました。
※図は「AWSアカウントB」側が本番環境として読んでください。

前提となる知識
AMIの構造
AMIは1つのリソースで完結していません。
AMIと関連するEBSスナップショットのペアで構成されています。
業務システムでは、EBSスナップショットは暗号化することになります。

EBSスナップショット暗号化キーの種類
以下が比較表です。「クロスアカウント利用」には「カスタマー管理のキー(CMK)」を使う必要があります。
| 項目 | AWS管理のキー | カスタマー管理のキー(CMK) |
|---|---|---|
| 管理者 | AWS | カスタマー |
| 設定の柔軟性 | 低い | 高い |
| 利用可能なAWSサービス | AWSサービスの自動暗号化用に限定 | すべてのAWSサービスで利用可能 |
| クロスリージョン利用 | 不可 | 可能 |
| クロスアカウント利用 | 不可 | 可能 |
| 利用開始の容易さ | 非常に簡単 | 設定が必要 |
AWS管理のキー
意識されていないかもしれませんが、普段、AMIを作成する際、暗号化のチェックボックスをONにした時には、こちらの「AWS管理のキー」でEBSスナップショットが暗号化されています。
クロスアカウントで引き渡しする必要がなければ、この鍵だけで問題なく運用できます。
カスタマー管理のキー(CMK)
今回のような特別な目的が無い限りは作成することはありませんので、ご存知ない方もいらっしゃるでしょう。
クロスアカウントで引き渡ししたいスナップショットを暗号化するには、こちらを作成する必要があります。
クロスアカウントでのAMI共有のパターン
いきなりCMKで暗号化する構成図が出てくるとややこしいので、暗号化しない構成から順を追って説明します。
暗号化しないパターン(セキュアでないので、今回はこちらはボツ)

「AWS管理のキー」を使うパターン(これはAWSの仕様上無理なパターンです)

CMKを使うパターン(完成形)

権限設定
CMKのリソースに設定するリソースポリシー (AWSアカウントA側)
この設定で鍵のユーザーとして「起動操作ロールB」を追加しています。
※「AWSアカウントA」は実際のAWSアカウントIDに、「起動操作ロールB」は実際のロール名に読み替えてください。
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWSアカウントA:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWSアカウントA:role/アドミンに相当するロールA"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion",
"kms:RotateKeyOnDemand"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AWSアカウントA:role/AMI化操作ロールA",
"arn:aws:iam::AWSアカウントB:role/起動操作ロールB"
]
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AWSアカウントA:role/AMI化操作ロールA",
"arn:aws:iam::AWSアカウントB:role/起動操作ロールB"
]
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
「起動操作ロールB」に付与するポリシー (AWSアカウントB側)
カスタマー管理ポリシーとして作成する想定のJSONです。
この設定でCMKの利用を許可しています。
※「AWSアカウントA」は実際のAWSアカウントIDに、「カスタマー管理CMKのGUID」は実際のGUIDに読み替えてください。
{
"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:AWSアカウントA:key/カスタマー管理CMKのGUID"
]
},
{
"Sid": "AllowAttachmentOfPersistentResources",
"Effect": "Allow",
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": [
"arn:aws:kms:ap-northeast-1:AWSアカウントA:key/カスタマー管理CMKのGUID"
],
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": true
}
}
}
]
}
Q&A
技術調査で解決したQ&Aを共有します。
Q. AMIの提供元AWSアカウントと提供先AWSアカウントで、どちらのCMKを使うか?
A. 提供元AWSアカウント側のCMKを使う。理由は以下のQ&A項目で説明する。
Q. 「AWS管理のキー」を別アカウントから参照できるか?(貸し出すことができるか)
A. できない。「AWS管理のキー」にはリソースポリシーの設定機能がないため、別AWSアカウントから参照可能な設定ができない。
Q. CMKを別のAWSアカウントにエクスポートできるか?
A. できない。秘密鍵を取り出す手段が提供されていない。(安全上の仕様だそうです)
Q. 別のAWSアカウントのCMKを使って、自分のAWSアカウントのEBS暗号化ができるか?
A. できない。別のAWSアカウントのCMKで復号化はできるが暗号化はできない。(これもAWSの安全上の仕様だそうです)
Q. CMKの鍵タイプは?
A. 「対称暗号化キー」を利用する。EBSスナップショットには「対称暗号化キー」でないと適合しない。
Q. 「AWS管理のキー」で暗号化されたスナップショットをCMKで暗号化し直すことはできるか?
A. 「AMIコピーのEBSスナップショットを暗号化」の操作でコピー時に暗号化方式を変更して暗号化することが可能。
以上です。
長編の記事になってしまいましたが、今後同様の対応が必要になった際に参考にして頂ければと思います。

