AWS Key Management Service (KMS) のまとめ

# はじめに
　Key Management Service (KMS) のサービスの理解を進めるために、KMSを利用した暗号化・復号化の流れを図式化し、基本的な機能に関してまとめる。

# エンベロープ暗号化と2種類のキー
　エンベロープ暗号化の挙動に関しては、手紙をポストに投函するときを想像すると良い。手紙に切手を貼ってを裸で投函するよりも、封筒（エンベロープ）に入れて投函した方が情報が外に見られないため安心できるだろう。
　エンベロープ暗号化もこれと同様で、鍵の情報が記された手紙をそのまま送る（平文）のではなく、封筒に入れて送る（暗号分）ことで安全性の向上を図る仕組みである。
　KMSでも鍵の受け渡し及び保管の際ににエンベロープ暗号化が用いられており、2種類の鍵に関して以下のような関係で呼称されている。

| 上記の例え | AWS での呼称 |
|:-----------|:------------|
| はがきの内容（鍵） | Customer Data Key (CDK) |
| 封筒（鍵の鍵） | Customer Master Key (CMK) |

# KMSの動き
　暗号化または復号化をする主体は、AWSのサービスやユーザーが開発したアプリケーションである場合が考えられる。以降AWSのサービスやアプリケーションをクライアントと称し、KMSとのやりとり及び暗号化と復号化のフローを見ていく。
　なお、暗号化・復号化の際に平文のCDKが存在する時間が一定ある。暗号化されたCDKはクライアント側で保存するが、平文のCDKは暗号化・復号化の仕事が終わったら即時削除する。

### 暗号化

![kms_encryption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/adc5c3b3-2e9d-d469-e5fa-e5b3072b4f2c.png)

| フロー | 説明 |
|:-----------|:------------|
| ① | 暗号化に必要なCDKの発行の依頼を行う（GenerateDataKey API） |
| ② | KMS内のHSMでCDKを作成する |
| ③ | 作成されたCDKをKMSホストに渡す |
| ④ | 暗号化されたCMKをHSMに取り出す |
| ⑤ | HMS内で暗号化されたCMSを復号する |
| ⑥ | CMKでCDKを暗号化したものをKMSホストに渡す |
| ⑦ | CDKと暗号化されたCDKをクライアントに返す |
| ⑧ | CDKでデータを暗号化する |
| ⑨ | 暗号化されたデータと暗号化されたCDKを保存する |

### 復号化

![kms_decryption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/841e0e05-0666-7861-0a41-c2c07dc83aac.png)

| フロー | 説明 |
|:-----------|:------------|
| ① | 暗号化されたCDKを復号するために必要なCMKの取り出しをKMSに依頼する（Decrypt API） |
| ② | 暗号化されたCMKをHSMに取り出す |
| ③ | HMS内で暗号化されたCMKを復号する |
| ④ | CMKをKMSホストに渡す |
| ⑤ | CMKをクライアントに返す |
| ⑥ | クライアント側に保管されている暗号化されたCDKを取り出し、CMKによって復号する |
| ⑦ | CDKによって暗号化されたデータを復号する |

# KMS の機能

### 自動キーローテーション
　自動的に新たなCMKを作成し、それ以降新たなCMKが暗号化・復号化に用いられるようにする機能。CMKは新しくなるが、CMKの識別子（key-id）は変わらないので、クライアント側での鍵の指定に関しては意識をすることがない。
　ユーザーが管理するCMK（カスタマー管理CMK）の場合は1年、AWSが管理するCMK（AWS管理CMK）の場合は3年の間隔でローテーションが行われる。
　なお、過去の暗号化に使用した情報はバッキングキーとして保存されており、過去のデータに対してはバッキングキーを元に復号化が行われる。

### 手動キーローテーション
　セキュリティ等の要件で要求されるローテーション期間が、自動キーローテーションの間隔よりも短い場合には、手動キーローテーションによって任意のタイミングでローテーションを行うことができる。
　なお、手動キーローテーションの場合は key-id も変わってしまう。そのためクライアント側で key-id を変更に対して対応する、もしくはエイリアスを設定する必要がある。

### キーポリシー
　アクセス制御に関する機能。S3のバケットポリシーと同じように、リソースベースのポリシーである。KMSのサービス側でもポリシーを設定することで、セキュリティの向上を図る。
　以下はデフォルトのキーポリシーである。

```json
{
  "Sid": "Enable IAM policies",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111122223333:root"
   },
  "Action": "kms:*",
  "Resource": "*"
}
```
　アカウント（111122223333）内の全ての`IAMユーザー`、`IAMロール`に対してフルアクセス権限が付与されている。

### 許可（Grant）
　アクセス制御に関する機能。IAMユーザー・ロールを指定してKMSのAPI操作に対する許可を与えることができる。

```
aws kms create-grant\
--key-id WWWWW --grantee-principal XXXXX\
--operation YYYYY --retiring-principal ZZZZZ
```
`WWWWW`: key-id, `XXXXX`: 許可する対象のARN, `YYYYY`: 許可するAPI名, `ZZZZZ`: 許可を取りやめる対象のARN

### Bring Your Own Key (BYOK)
　CMKは暗号化・復号化キーと作成日等のメタデータを合わせて持っている。この暗号化・復号化キーをキーマテリアルという。
　キーマテリアルはユーザーが用意し、KMSにインポートすることでCMKが作成され、使用することができる。

### 削除待機
　CMKを削除するとデータの復号化ができなくなり、致命的な状況を生じる可能性がある。そのためCMKを削除する際には`7-30`日の削除待機期間を設定しなければならない。デフォルトでは30日に設定されている。
　BYOKで作成したCMKは即時削除が可能。

# KMS の制限

- CMKで直接データの暗号化・復号化を行う際のデータの最大容量は4KB。ただし直接の暗号化・復号化は推奨されていない。
- APIのリクエストレートに制限がある。例えば GenerateDataKey API は 10000リクエスト/秒 の制限があり、これを超えたリクエストが行われると`ThrottlingException`エラーが返される。
- ~~リージョン間のCMKの共有ができない。CMKは生成したリージョン内でのみ利用ができる。~~ → 2021.6 のアップデートでマルチリージョンキーがサポート

# 参考

https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/concepts.html

https://aws.amazon.com/jp/about-aws/whats-new/2021/06/kms-multi-region-keys/