AWS KMS再入門

# 概要
AWS認定セキュリティ - 専門知識の勉強の中でKMSは覚えることが多かったので、理解を深めるとともに後から見て思い出せるよう自分なりにまとめる。

↓参考にした資料

https://www.youtube.com/watch?v=4F5rSxzu0U4

# AWS KMS(Key Management Service)とは
データ暗号化に利用する暗号化キー(暗号鍵)の作成・管理を行うためのAWSのマネージドサービス

- AZをまたいだ冗長化により高可用性を担保
- CMK(マスターキー)の耐久性は99.999999999%(イレブンナイン)
- ~~共通鍵(対称鍵)暗号にのみ対応~~  
→ Black Beltの資料は2018/11時点のもののため、非対称鍵には非対応と言っているが2019/11に非対称鍵にも対応している

# KMSの仕組み
## エンベロープ暗号化
データを暗号化する鍵(データキー)とデータキーを暗号化する鍵(マスターキー)を利用する方式
データの暗号化用キーを更に暗号化するので、よりセキュリティが強化される
KMSではそれぞれのキーをCMK、CDKと呼ぶ

- CMK(Customer Master Key)：データキーを暗号化するキー、AWS管理のHSM内でこのキーも暗号化されている
- CDK(Customer Data Key)：データを暗号化するキー、都度生成される

↓KMSを利用したクライアントサイド暗号化の流れ
![スクリーンショット 2021-08-13 6.05.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/9b44e1fa-baf7-3b5b-b98a-4fe1a9ed67f0.png)

サーバサイド暗号化の場合、クライアントはデータをAWSに送信するだけでKMS内でこれらの処理を行ってくれる

# KMS API
KMSの主要なAPI

| API | 用途 |
|:-:|:-|
| GenerateDataKey | 暗号化済みCDK+プレーンなCDKを取得 |
| GenarateDataKeyWithoutPlaintext | 暗号化済みCDKのみ取得 |
| Decrypt | データを復号 |
| Encrypt | データを直接暗号化(4KBまでのデータに対応) |
| CreateKey | 新規CMKを作成 |
| CreateAlias | CMKにエイリアスをつける |
| DisableKey | CMKを無効化 |
| EnableKeyRotation | CMKのローテーションを有効化 |
| PutKeyPolicy | キーポリシー(CMKへのアクセス制御ポリシー)を設定 |
| ListKeys | アカウント内、リージョン内のCMKをリスト表示 |
| DescribeKey | 指定したCMKの詳細を表示 |
| Sign | デジタル署名を作成 |

# CMKの種類
- カスタマー管理CMK：キーローテーション(1年ごと)、ポリシーによるアクセス制御、エイリアス作成などができる
- AWS管理CMK：AWSサービスが作成・管理・使用するCMK。キーの名前が「aws/サービス名」このため、カスタマー管理CMKでは名前の先頭に「aws」を付けられない。3年ごとに自動ローテーション
- AWS所有CMK：サービスが裏側で利用するCMK、ユーザからは見えない

# CMKのキーローテーション
- カスタマー管理CMKは1年ごとの自動ローテーションを有効化できる。AWS管理CMKは3年のため1年にしたい場合、カスタマー管理CMKを利用(非対称鍵は自動ローテーションできない、手動でのローテーションが必要)
- ローテーション後のCMKは過去のキー情報をすべて保持しているため、自動ローテーションでキーが新しくなっても古いキーで暗号化されたデータは複合できる。これを「バッキングキー」と呼ぶ。
- 1年より短い周期でキーローテーションしたい場合、手動で新しいキーを生成する。この際アプリケーションの変更を不要にするため、エイリアスを設定しておきローテーション時はエイリアスの付け替えを行うといい。

# エイリアス
CMKにはエイリアス(別名)をつけることができる。
手動でキーをローテーションしたい場合、単純に新しいCMKを作成すると利用するアプリケーション側も更新が必要になってしまう。エイリアスは異なるCMKに付け替えることができるのでエイリアスを利用することで、アプリケーション側の更新が不要になる。
1つのCMKに複数のエイリアスをつけることも可能。

同一アカウント同一リージョン内で一意である必要がある。
↓のようなARNで指定するためリージョン+アカウント+名前が同一だと区別できないため。

```text:エイリアスの例
arn:aws:kms:ap-northeast-1:123456789012:alias/aliasName
```

# キーマテリアルのインポート
- CMKのメタデータを除く暗号・復号に利用する部分を「キーマテリアル」という。このキーマテリアルはキー本体であり、これを外部からインポートすることで暗号化アルゴリズムなどを自由に変更できる。オンプレや外部と共通のキーを利用することもできる。この機能を「BYOK(Bring Your Own Key)」と呼ぶ。256bitの対照キーのみ利用可能。
- キーマテリアルは同一キーのみ再インポートできる。
- インポートしたキーも自動削除、手動キーローテーションは可能。

↓実際はCMKは論理キーで内部で実際のキー(HBK:HSM Backing Key)が入れ替わっている
![スクリーンショット 2021-08-13 6.27.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/dbd09a6b-6e3f-5027-c7b0-3b4f8fac63db.png)

# KMSへのアクセスコントロール
KMSへのアクセス制御として3つの方法がある

- IAMによるユーザベースコントロール
- キーポリシーによるリソースベースコントロール
- 許可(Grants)によるリソースベースコントロール

## キーポリシー
CMKにはリソースベースのポリシーを定義することができる。これを「キーポリシー」と呼ぶ。
対称のCMKを特定のサービスからの利用のみ許可するなどの目的で利用する。

キーポリシーで指定できる条件キーは以下

https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/policy-conditions.html

約30種あるので主要なものを抜粋

| 条件キー | 内容 | 値 |
|:-:|:-|:-|
| kms:ViaService | リクエスト元のAWSサービスとリージョン | AWSサービスとリージョンを表す文字列(例："ec2.us-west-2.amazonaws.com") |
| kms:CallerAccount | 呼び出し元アカウント | アカウントID |
| kms:EncryptionAlgorithm | 暗号化アルゴリズム | 暗号化アルゴリズムを表す文字列(例：RSAES_OAEP_SHA_256) |
| kms:KeyOrigin | キーマテリアルの種類(CloudHSMのみ許可するなど) | AWS_KMS/AWS_CLOUDHSM/ EXTERNAL |
| kms:ValidTo | キーを失効させる日時 | UNIX時間 |

### デフォルトキーポリシー
CMK作成時にはAWS アカウント(ルートユーザー)でCMKへのフルアクセスを許可し、アカウントのIAM ポリシーでCMKへのアクセスを許可できるようにするポリシーが自動で追加される。(キー作成時にキー管理者、キーユーザーとしてIAMユーザから選択するとこれらの`Statement`もポリシーに記載される)

```json:デフォルトキーポリシーの例
{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/adminA"
            },
            "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"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/userA"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:DescribeKey",
                "kms:GetPublicKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/userA"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}
```

この「デフォルトキーポリシー」はAWSのアップデートによりバージョンが更新される可能性がある。この場合、マネコンでアラートが表示され、ワンアクションで更新可能。

## 許可(Grants)
特定のIAMユーザやIAMロールなどにCMKの利用を許可することができる機能
名前の通り、ホワイトリスト方式(拒否の明示ができない)

SDKやCLIで「許可」の作成を行うことで指定する

```bash:CLIによる許可の作成例
aws kms create-grant \
  --key-id <key_id> \
  --grantee-principal arn:aws:iam::<account_id>:user/<user_name> \
  --operations Decrypt \
  --retring-principal arn:iam::<account_id>:role/<admin_role_name>
```

※`retring-principal`引数で許可を無効にできるIAMを指定できる

# キーの削除
CMKは即時削除することができない。
キーの削除スケジュールを設定することで、一定期間後に削除される。
削除スケジュールに設定できる待機期間は7~30日間、この待機期間中であればいつでも削除をキャンセルできる。

# データキーキャッシュ
AWS Encryption SDKの機能として、「データキーキャッシュ」がある。
これを利用することでデータキー取得のAPIコールを減らすことができる。

# マルチリージョンキー
通常CMKは作成したリージョンでのみ保存、使用できる。リージョン間のエクスポート/インポートもできない。
CMK作成時にKMSマルチリージョンキーを選択することで複数のリージョンにキーをレプリケートすることができる。

# 別のAWSアカウントへの許可
CMKは異なるAWSアカウントからも利用できる。
マネコンから「別のAWSアカウント」に指定するとキーポリシーのキーユーザ用許可`Statement`の`Principal`にルートユーザが追加される。

```json:追加後のキーポリシー例(Statementオブジェクトのみ抜粋)
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:user/userA",
                    "arn:aws:iam::987654321098:root"
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        }
```