AWS KMSの暗号化は、S3のデフォルト暗号化などで使われることが多いと思います。
オブジェクトをPutすると自動で暗号化されるため、**「実際にどんな処理が裏で動いているのか」**を意識していない方もいるのではないでしょうか?この記事ではS3を題材にしつつ、KMS暗号化の仕組みに焦点を当てて解説します。
「KMSで暗号化するから、Encryptの権限が必要です。」
これはありがちな誤解ですが、大体の場合は間違った理解です。なぜそうなのか?その理由を紐解いていきます。
CMKはどこにいる?
まずは鍵を作成しなければ始まりません。ここではカスタマーマスターキー(以下CMK)を対象鍵で作成するものとします。
キー作成はKMSのAPIである”kms:CreateKey” が発行され、AWS管理下のどこかに対象鍵(以下CMK)が作成されます。
ここでまず頭に入れておくべきことがあります。
作成されたCMKはKMSから出てくることはありません。
このことはKMSの動きを理解する上で重要です。
作成したCMKで何らかのデータを暗号化・復号化する際は、CMKをKMSから取り出すのではなく、対象データをKMSに送って暗号化・復号化を依頼し、結果を送り返してもらう、という流れになります。
ここで次の疑問が沸いた人は鋭いです。
「でかいデータだと全部KMSに送らないといけないのでわ・・・・RDSとかEBSとかどうするの? ^^;」
実際は暗号化したいデータをKMSに送ったりはしていません。「データを暗号化する鍵」をCMKで暗号化してやりとりすることでこの問題を回避しています。
GenerateDataKey
唐突ですが、KMSには”kms:GenerateDataKey“いうActionがあります。(この話題での最重要アクションです。)
CMKを引数として実行し、以下の2つの文字列を返してきます。以下はAWS CLIで実行してみたものです。
$ aws kms generate-data-key --key-id arn:aws:kms:ap-northeast-1:999999999999:key/99999999-9999-9999-9999-999999999999 --key-spec AES_256 { "CiphertextBlob": "AQIDAHiF7qVe(略)", "Plaintext": "eS7mjjJQby2(略)", "KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/99999999-9999-9999-9999-999999999999" }
- “Plaintext” 単なるバイト列
- “CiphertextBlob” Plaintext を指定したCMKで暗号化したバイト列 + メタデータ
KMSはGenerateDataKeyを受けると、内部でランダムな文字列を生成し(Plaintext)、それを指定されたCMKで暗号化し(CiphertextBlob)、その2つを返してくれます。
この”Plaintext” のことをデータキーと言い、実際のデータの暗号化の鍵として使われます。(ファイルやらEBSやらRDSやら。。)
ここでは重要な点が2つあります。
まず、データキーはKMSの外側に出てきているということ。
次にデータキーを用いた暗号化(Encrypt)は、kmsのアクションではない、ということ。(一般的な暗号化なのかな。AES?)
また、CiphertextBlob のメタデータにはCMKの情報を含んでいます。つまり
暗号化されたデータキーは、自分がどのCMKで暗号化されているのかを知っています。このことはデータ復号化の時に大変重要になってきますので覚えておいてください。(また今度書くかも)
データ暗号化の流れ
以上の内容をまとめまして、データ暗号化の流れは以下のようになります。例としてS3にPutする場合を示していますが、例えばEBSの暗号化の流れも同じようなものになります。
ユーザはKMSに対して、作成済みのCMKを指定してkms:GenerateDataKey を発行する。
CMKはデータキーとデータキーを暗号化したものを返す。
ここでCMKの役割は終わっています。
ユーザはデータキーを使ってデータを暗号化し、そのデータキーを廃棄
この暗号化はKMSの外側で行われています。
暗号化されたデータに暗号化されたデータキーを添えて、S3に保存
(エンベロープ暗号化、とか言ったりします。)
最後でデータに暗号化されたデータキーを一緒にして保存していることは覚えておきましょう。
「鍵とデータ一緒にして大丈夫なの?家のドアに鍵を貼り付けてるようなものでは?」とは思わないように。この場合、鍵自体が暗号化された状態ですので、このままでは使えません。CMKに復号化を依頼できる人だけがこのデータを復号できます。
以上のフローを見てわかるように、KMSに対してはkms:GenerateDataKeyだけしか実行していません。なのでデータ暗号化の際に必要な権限としてはkms:GenerateDataKeyがあればよい、ということになります。(kms:Encryptではなく!)
以上。データ暗号化の時の基本的な流れを説明してみました。
若干フローなどは単純化している個所もありますが、理解の助けになれば幸いです。