AWS KMS (Key Management Service) に関する私的メモ

「[AWS認定 セキュリティ – 専門知識](https://aws.amazon.com/jp/certification/certified-security-specialty/)」を受験するにあたって、KMSについて個人的にまとめたメモです。

#各CMKの比較表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/bfaf3d51-6bb7-0afa-b9ae-6b291e042fb2.png)

#Envelope enryption
「[S3データ格納時のサーバ側暗号化（SSE-S3、SSE-KMS、SSE-C）と、クライアント側暗号化（CSE-KMS、CSE-C）](https://qiita.com/yz2cm/items/ca33ced6e1f5fbcff459#cdk)」を参照。

#BYOK (Bring Your Own Key)のインポート
**BYOKのポイント**

* 外部キーのインポートは**対称暗号のみ**可能。
* 外部キーは**自動ローテーション不可**。
* 再インポートするキーマテリアルは、**前回インポートしたものと同じキーマテリアル**である必要がある。前回と異なるキーマテリアルをインポートすると`IncorrectKeyMaterialException`が発生する。
* 前回と同じキーマテリアルを再インポートできて何が嬉しいの？と思うかもしれないが、再インポートは**誤って削除したキーマテリアルを復旧したり、有効期限を過ぎたキーマテリアルを延命する目的**で行う。
* BYOKの手動ローテーションを実現する手段は**CMKの再作成**になる。
* インポートトークンと公開鍵は取得後**24時間有効**である。

以下に、AWS CLIを使用してBYOKを作成する手順を示します。
（作成するCMKのキーIDは、仮に`12345678-abcd-1234-abcd-123456789012`とします）

## 1. CMKの作成
### マネージメントコンソールを使用したCMKの作成
AWSマネージメントコンソールのKMSから、キーマテリアルオリジンに外部を指定してCMKを作成します。

### AWS CLIを使用したCMKの作成
AWS CLIを使用する場合、以下のコマンドラインを実行します。標準出力の内容に含まれるキーIDを取得します。

```bash:
KEY_ID=$(aws kms create-key --origin EXTERNAL | jq -r '.KeyMetadata.KeyId')
echo ${KEY_ID}  # 12345678-abcd-1234-abcd-123456789012 
```

なお、残念ながら、AWS CLIではCMK作成時にエイリアスを作成・アタッチすることはできません。

## 2. 公開鍵とインポートトークンのダウンロード
公開鍵のアルゴリズムによって、以下のいずれかを実行します。

* RSAES_PKCS1_V1_5
* RSAES_OAEP_SHA_1
* RSAES_OAEP_SHA_256

```bash:RSAES_PKCS1_V1_5
# 公開鍵とインポートトークンのダウンロード（RSAES_PKCS1_V1_5）
aws kms get-parameters-for-import \
  --key-id 12345678-abcd-1234-abcd-123456789012\
  --wrapping-algorithm RSAES_PKCS1_V1_5 \
  --wrapping-key-spec RSA_2048 \
  >kms_get-parameters-for-import.txt
```

```bash:RSAES_OAEP_SHA_1
# 公開鍵とインポートトークンのダウンロード（RSAES_OAEP_SHA_1）
aws kms get-parameters-for-import \
  --key-id 12345678-abcd-1234-abcd-123456789012\
  --wrapping-algorithm RSAES_OAEP_SHA_1 \
  --wrapping-key-spec RSA_2048 \
  >kms_get-parameters-for-import.txt
```

```bash:RSAES_OAEP_SHA_256
# 公開鍵とインポートトークンのダウンロード（RSAES_OAEP_SHA_256）
aws kms get-parameters-for-import \
  --key-id 12345678-abcd-1234-abcd-123456789012\
  --wrapping-algorithm RSAES_OAEP_SHA_256 \
  --wrapping-key-spec RSA_2048 \
  >kms_get-parameters-for-import.txt
```
## 3. 公開鍵とインポートトークンのBASE64デコード 

```bash:
cat kms_get-parameters-for-import.txt | jq -r '.PublicKey' >PublicKey.b64
cat kms_get-parameters-for-import.txt | jq -r '.ImportToken' >ImportToken.b64

openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin

```
## 4. キーマテリアルの生成
```bash:キーマテリアルの生成
printf "0123456789ABCDEF0123456789ABCDEF" > PlaintextKeyMaterial.bin
```

## 5. キーマテリアルの暗号化

「**2. 公開鍵とインポートトークンのダウンロード**」で選択した公開鍵のアルゴリズムによって、以下のいずれかを実行します。

```bash:RSAES_PKCS1_V1_5
# 公開鍵でキーマテリアルの暗号化（RSAES_PKCS1_V1_5）
openssl rsautl -encrypt \
  -in PlaintextKeyMaterial.bin \
  -pkcs \
  -inkey PublicKey.bin \
  -keyform DER \
  -pubin \
  -out EncryptedKeyMaterial.bin
```

```bash:RSAES_OAEP_SHA_1
# 公開鍵でキーマテリアルの暗号化（RSAES_OAEP_SHA_1）
openssl rsautl -encrypt \
  -in PlaintextKeyMaterial.bin \
  -oaep \
  -inkey PublicKey.bin \
  -keyform DER \
  -pubin \
  -out EncryptedKeyMaterial.bin
```

```bash:RSAES_OAEP_SHA_256
# 公開鍵でキーマテリアルの暗号化（RSAES_OAEP_SHA_256）
openssl pkeyutl -encrypt \
  -in PlaintextKeyMaterial.bin \
  -pkeyopt rsa_padding_mode:oaep \
  -pkeyopt rsa_oaep_md:sha256 \
  -inkey PublicKey.bin \
  -keyform DER \
  -pubin \
  -out EncryptedKeyMaterial.bin
```

## 6. キーマテリアルのインポート
```bash:
# 暗号化後のキーマテリアルのインポート
aws kms import-key-material \
  --key-id 12345678-abcd-1234-abcd-123456789012 \
  --encrypted-key-material fileb://EncryptedKeyMaterial.bin \
  --import-token fileb://ImportToken.bin \
  --expiration-model KEY_MATERIAL_EXPIRES \
  --valid-to "2020-12-31T12:00:00-08:00"
```

## 7. キーマテリアルの削除
```bash:キーマテリアルの削除
aws kms delete-imported-key-material --key-id 12345678-abcd-1234-abcd-123456789012
```