私の戦闘力は53万です

awsとgcpについて書きます

AWS KMS の概要とエンベロープ暗号化について説明してみる

最近AWS KMSについて聞かれることがあったので

ブログにまとめてみようと思います。 

KMSってなに?をざっくり

  • 対象鍵を安全に保管してくれるサービス
  • AWSサービスのデータ暗号化・複合化する機能として連携(S3、EBS等)
  • うるさいセキュリティのポイントをある程度抑えてくれる(キーローテーション、暗号化鍵の方式を決定)
 
記事執筆時点で非対称の鍵もサポートが開始されたようです。
まだ内容がわからないので今回は対象鍵の部分について書きます! 

前提知識:対称鍵とは

対称鍵というのは暗号化と復号化の時の鍵が同じことを指します。
身近な例では、ファイルをzip暗号化でパスワードを利用するケースです。
暗号化する時と、復号化する時で同じ鍵(パスワード)を指定しますね。
もっと身近な例だと家の鍵です。
鍵をしめる(暗号化)時と、鍵を開ける(複合化)するときで
同じ家の鍵を使いますね。
 

キーの種類

1つ目の混乱ポイントです。
KMSでは鍵の種類がたくさん出てきます。
私は初見に結構混乱しました。
鍵の全体像を整理すると下記のようになります。
kms/
├── cmk
│   ├── AWS所有
│   ├── AWS管理
│   └── カスタマー管理
│       ├── aws_make
│       └── origin_external
└── データキー

下記に簡単な説明を書きます。

AWS所有

  見ることすらできない鍵です。AWSが利用します。

  基本的に触れないので理解すべきこともないです。

AWS管理

 もっともよく使う鍵です。

 おおよそのケースで単純に暗号化したいだけならこの鍵を利用します。

    デフォルトの鍵です。aws/service-nameの形式で存在します

 ある程度AWSが用意した枠組みでしか管理ができないため

 細かい制御が必要な場合は後述のカスタマー管理のキーを利用します。

 例えば、クロスアカウントで共有が不可のため、

 複数アカウントが関連するときは利用できないケースが多いです

・カスタマー管理

 AWSで作れる鍵です。この鍵だとキーポリシー(アクセス制限)とか、
 手動のキーローテーションとか、有効無効の操作の自由度が高くなります。
 また、クロスアカウントでの利用にもこちらを用いることが多いです。
 カスタマー管理キーは2種類に分かれます。
 インポートされたキーマテリアル(origin external)と
 awsで作成する鍵(aws make)です。
 基本的にはawsで作成する鍵を利用しますが、
 暗号化方式まで厳密に管理したい、
 自分たちで自作した鍵を利用したいという場合には
 インポートされたキーマテリアル(origin external)を利用します。

・データキー

CMKを元に作成するキーのことです。
データキーがなぜ必要なのか?と思う人もいると思います。
これに対する答えとしてまず、
エンベロープ暗号化の概念を理解する必要があります。
 
AWS KMSで管理するキー(CMK)では暗号化の対象データ容量の上限が
32KB(記事執筆時点)とかなり小さいです。
例えばこの制限で、容量の小さいデータを暗号化するのであれば良いのですが、
基本的にはEBSやS3内のファイルも32KBを上回ることが想定されるため
管理ができません。
 
そこで、下記例に習いファイル容量に依存しない暗号化管理を実現します。
この考え方がエンベロープ暗号化です。
(1)CMK(MasterKey)からDataKeyを作成する。
(2)Datakeyを鍵として32KBよりも大きいデータ(EBS等)を暗号/複合化する
通常の運用では、このデータキーは利用時にはPlaintext(複合化された状態)で利用し、
利用が終わったら捨てます。そして暗号化されたDatakeyは取っておきます。

上記のように運用することで下記を実現できます

・容量大データも一律して同じ大きさのDatakeyを利用し暗号/複合管理

・外部に漏れるとマズイ情報(Plaintext data key)は必要な時のみ取出し利用 

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

KMSのAPIにも、キーを生成するAPIが2つあります。

kms:CreateKey
kms:GenerateDataKey
 
上記は考え方ですので、実際にCLIを使って動作させてみます。
一度実行してみると頭の中で理解しやすいのでおすすめです。

エンベロープ暗号化をCLIで一通りこなしてみる

まずはKMSを生成します

f:id:remmemento:20191127100736p:plain

create-key
aws kms create-key
{
   "KeyMetadata": {
       "AWSAccountId": "xxxxxxxxxxxx",
       "KeyId": "08e5af4f-ba9c-4f97-b6ec-xxxxxxxxx",
       "Arn": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-2425af102c37",
       "CreationDate": 1574814784.429,
       "Enabled": true,
       "Description": "",
       "KeyUsage": "ENCRYPT_DECRYPT",
       "KeyState": "Enabled",
       "Origin": "AWS_KMS",
       "KeyManager": "CUSTOMER"
   }
}
 
キーIDだと分かりにくいので、名前(エイリアス)をつけてあげます 
aws kms create-alias --alias-name alias/test-key-alias --target-key-id 08e5af4f-ba9c-4f97-b6ec-xxxxxxxxx
 
続いてCMKからデータキーを作成します。
 

f:id:remmemento:20191127100812p:plain

data-key
 
 
aws kms generate-data-key --key-id alias/test-key-alias  --key-spec AES_256
{
   "CiphertextBlob": "AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ==",
   "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc=",
   "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx"
}
 
「CiphertextBlob」は「Plaintext」を暗号化した情報のことです。「CiphertextBlob」を利用して複合化してみましょう。
 
aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ=='|base64 -D)
{
    "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx",
    "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc="
}
上記のPlaintext」と一致することがわかりますね。 さて、このデータキーの「Plaintext」を利用してさらにデータを暗号化します。

f:id:remmemento:20191127101005p:plain

データの暗号化
上記の例だとデータキーは「KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc=」です。
例えばzipとかの暗号化パスワードに利用するイメージです。
AWSサービスで利用した場合だとEBSやS3のデータの暗号化時に
上記の「Plaintext」部分が利用されます。
 データの暗号化が終わったら Plaintext(複合化された素の状態)の
キー情報は捨てます。Plaintextが外部に漏洩するとデータを
複合化される可能性があるためセキュリティ事故になってしまいます。

f:id:remmemento:20191127100716p:plain

データキーの管理
一方暗号化されたキーは(ローカルとかに)保存しておきます。
この暗号化されたキーは仮に外部に漏洩したとしても、CMKを利用できない限りは、データを複合化されることがないため実被害はありません。
(とはいえ漏洩しないに越したことはないです) 
その後は暗号化されたキー(CiphertextBlob)を保管しておき、
またデータの暗号化/複合化をしたい時には上記で実施したように
一時的にデータキーを複合化(Palintextを取出)して利用します。
aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ=='|base64 -D)
{
    "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx",
    "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc="
}
 
以上がデータの管理の流れとなります。
 
下記ポイントが抑えられていることが確認できたと思います。
・容量大データも一律して同じ大きさのDatakeyを利用し暗号/複合管理
・外部に漏れるとマズイ情報(Plaintext data key)は必要な時のみ取出し利用  

 

長くなってしまうので、残りの機能はまた次回以降で書きたいと思います。