KMSについては優れた記事があるのですが、KMSの「対称キー」と「非対称キー」について理解していなかった点があるのでその話を書きます。
なお、以下でいう「対称キー」はKMSが生成したもの(外部からインポートしたものではなく)、「非対称キー」はRSA 4096ビットのもののみを考えます(ECCについては除外します)。
KMSの対称キーは非対称キーの上位互換である
KMSの対称キーは次のような用途に利用できます。
- S3のサーバーサイド暗号化
- EBSの暗号化
- RDSのストレージ暗号化
- SNSのメッセージ暗号化
- ……
- 非対称キーの生成
- キーの自動ローテーション
非対称鍵では公開鍵と秘密鍵が固定される
当たり前といえば当たり前ですが、一度KMSで非対称キー(すなわち秘密鍵と公開鍵のペア)を作成したら変更はできません。キーIDと秘密鍵・公開鍵は一意に固定されます。権限がなければキーを削除することもできません。
逆に言えば、このような用途に利用したい場合にのみ非対称鍵は有効です。
なんでこういうことになるのか
KMSの対称キーとは、つまるところ
- 何か(最大4096バイト1)を入れるとそれが暗号化されて出てくる
- 暗号化されたデータを入れると元に戻る
- キーそのものは決して外に出てくることはない
- キーにはIAM PolicyとKey Policyで保護がかけられている
というブラックボックスであるととらえることができます。
「4096バイト」というサイズ制限が厳しいので、なんでもかんでもKMSに突っ込むわけにはいきません(もちろんこれで十分なケースもあります。パスワードとか)。しかしKMSは十分にランダムな2乱数を生成するAPIも持っています。これと「ブラックボックス」を組み合わせると何ができるかを見ていきます。
例1: AES 256ビットの暗号化キーをもらう
キー生成
KMSで対称キーを作り、そのキーを使ってAWS CLI経由でGenerateDataKey APIを叩いてみます。
aws kms generate-data-key \
--key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
--key-spec AES_256
次のようなJSONが得られました。(これは実行するたびに変わります)
{
"CiphertextBlob": "AQIDAHgjnCLqIzJ0vSDVeFv0F6upPLnpikd00qPCK4mCNcl3tAFsloiSofee6YIoUd96AyU4AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMMvqesGTcFkW5VwCnAgEQgDu+0DtmeJ8UDH4F+RswNj1Tzb+kGSsDlN2n9u80b9vl2OKDUsBFfbbm4Q4oMQR8AstGqylw+b7aTL6uQg==",
"Plaintext": "dmd8Asv/3+fUQtVRWRZjTVyN56m8KuAwKV1W+/deeVE=",
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef"
}
BASE64エンコードされていますが、 Plaintext
は32バイト、つまり256ビットの乱数列ですので、これはAES 256ビットで手元のデータを暗号化するときのキーとして使えます3。
また、 CiphertextBlob
はこの乱数列をKMSの対称鍵で暗号化したものです。つまり CiphertextBlob
さえ持っていればDecrypt APIで元に戻せるはずです。試してみましょう。
復号
aws kms decrypt \
--key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
--ciphertext-blob "AQIDAHgjnCLqIzJ0vSDVeFv0F6upPLnpikd00qPCK4mCNcl3tAFsloiSofee6YIoUd96AyU4AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMMvqesGTcFkW5VwCnAgEQgDu+0DtmeJ8UDH4F+RswNj1Tzb+kGSsDlN2n9u80b9vl2OKDUsBFfbbm4Q4oMQR8AstGqylw+b7aTL6uQg=="
こうなりました。一致しています。
{
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef",
"Plaintext": "dmd8Asv/3+fUQtVRWRZjTVyN56m8KuAwKV1W+/deeVE=",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
で、どうするのか
こんな手順になります。
- KMSに「256ビットの乱数列をくれ」とお願いする
- 256ビットの乱数列(A)が降ってくる。ついでにそれをKMSで暗号化したデータ(B)ももらえる
- (A)を使って手元のデータを暗号化する(X)
- (A)は捨ててしまい、(X)と(B)だけをどこかに保存する
- KMSでキーへのアクセス権限があれば(B)→(A)が得られ、(X)から元のデータが得られる
簡単ですね!
KMSとS3との関係
SSE-KMSを有効にしたS3バケットにAWS SDK経由でファイルをアップロードすると、この暗号化処理がクライアントサイドで行われ、通信経路には平文のデータは一切流れません。そうでない場合は同等の処理をS3が実行します。したがって、「SSE-S3はサーバーサイド暗号化」と見るのは間違いである(ケースもある)ということになります。
例2: RSA 4096ビットの鍵をもらう
次はRSAの秘密鍵と公開鍵を作ってみます。
キー生成
GenerateDataKeyPair APIでRSAのキーを生成できます。
aws kms generate-data-key-pair \
--key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
--key-pair-spec RSA_4096
見慣れたRSAの秘密鍵、公開鍵、そして秘密鍵をKMSで暗号化したやつのセットが得られます。
{
"PrivateKeyCiphertextBlob": "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",
"PrivateKeyPlaintext": "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",
"PublicKey": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx2J5WuuQFq8jYTLNU9G4xhzxPMC4lMn2ZjMOBu37RyI+01kJ1E1Hf32wAjBprqdvxyz8VvEmp2XEUOZoMcrJpYY3SHyIJBW6UOdJXeSaIyWKhtelqxHUIpkLe5MnJrk8GIpNIvPMK9p91gLPA8euS8zHhPFLkjsiSNSVZZvMulzrVQNh0/rbCgRtcSvXRTB1y0GpoeSYao7UI10SQ4G2z+H4on2pR0c+JA4hGRdAVHEBLgApELNBRNlYViNHkhDRi6tPJkdG1KajOfIFJ5IE16L55Mi8x1YE3ezY9GWNG3fJqEbOTM8/ozh67sYMUmOcbPT1FJej0CSxViO5gu2EwllnCBZIJittLnoLOUnkRo5tCekpNXOHll2QCUs4vQbWq2egb4AZKBs9qqBv6WZGSW/e2uSCKvKt7/zlqasjS9j1msYS34xUiW1m7aCwQu8vvHeuoOCLu+GhehejqN+Z+ypzkc/K7T67xwadI30RH2mSUz4tzeZIXb39cmtSYjv9FhtLsnl9ZPiLk/g6gR8NKgJRx4P1+vkeM2LfHKMZq+8Rv3LspwpBJ6q2YKsMuRxvL4ZWIvKnqlqN79lfwew9H3pHcgZ3kRLKjTkmr/JSJSi4xtFmsLTpadOcYZbTHC9PICBlcyxIY1NkuwnsNSMlM1XQLiRAQR0lB8MmV8WicgsCAwEAAQ==",
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef",
"KeyPairSpec": "RSA_4096"
}
復号
念のため、こちらも PrivateKeyCiphertextBlob
を復号して PrivateKeyPlaintext
になるか試してみます。
aws kms decrypt \
> --key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
> --ciphertext-blob "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"
一致しました。つまり、こちらも PrivateKeyCiphertextBlob
さえあれば PrivateKeyPlaintext
は破棄してしまって構わないわけです。
{
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef",
"Plaintext": "MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC+djSO4prsMygNeSngi/1T+cmcSfzJodbtaQ8QBVVpuY6+9EdcWMrUPBcibmgsXIsiS7tNAPF9axtfYMc/iXe+329qwyAq4DoPu0+kulSTOo46O0vVJTMLvPNCFf1YFRDYL3dNqoj0QWFpRpqT1qWaiU7TlAWxHqqvxtzGpq3/hwB7UD5Nrx4i/5idHLa43i2UWa5u+3ZeSO9pcVr7/as/TDMIVeK7DDzNk7u2zVOUZ/c9Z4DKMhUgYzor8XG9b/uIgTNAPEhbm/KChduDD956sN6onIq6JcEK68uGlzZeMXQ6n9nr+wGV9wEBGH1WfIhbpyWQZsHehgTFoCfXK99RIC0Is7akDNvYtUSCIZ3Oc+BeTm+uPqy6T0LxCZTNCcSsSTU6De3wIqFgpt7fniZkr6EZ9Qy7sX9FvUDgjksgiQ0thwGmUlkVXcWpcXUNEBGtoDgJvOD4KQ/1Wg27/SQtYwmQUbj1+ebR/Ovkz+zE2ivAedk4iWw7dDNQ3rcyL3uRhgGBaoYV7bVTZyWl/YItRh3hGzB9USrdAYToA7Uzi1R+TznIcbm13BlS2zRlKSReBx1IciOr6UUgGf4OysviOWasyRxydyaMfPN0E8h6oF6fcnPpNrDfehAfejvdYfXMKsMsp9fW0B7D8n2osJq9Px6CfzfmQ5Xi/qzwAwbP1QIDAQABAoICACMZao8ocI91z/xHp3GDquBGaKKeOfE4m4Ct+0IjEX4F3aoQH3SDwoFBP6wvN5BxT4y28yH6Oga4bddyYNWzMjehOomswulT4C9VABTl578oK9zMX6m8jL8th5DWt5T7cNq+SJiuBEYrJFX/1m3HQUaM5lN0dGYTNjZlifsr7WXpTavr+kdbrcyaWNgfWgcQnsq3ij9WpRY0D7bZVoCY222zT7ZKCZoZ47yo7I+AIFZ5oGUXBXN9rkoFL0u415KnJ+4cjULZuSX0w8jM/UqWapQmsynUi3ZJjd1C3gOEK1dJetdw7Pqhi8XEutEmX7bIBWMKlxAY98JX5Vo8LQtowOMDQ8iMXadNxpwLl76TdCojkJBz2sP4FDmmkMLfx9BrqJSi2VUrjhGcDf58pnZ9ni+vnGTUkMzfW9Z6O629fEWrt2QYfaRx//7skHxdbwqEKLn9/BEfg4XBq9BxefwPKWoe+arfs/dtYoDnILgsGkIY7Cra/+CcVbBCC8oUyiqFB++r0rE0G1kLKpP7PF+iEEUXe28snHnFrV9Qbp5v+gHhhYEYlY7FfCWjnkkdCr8kr5oacUiFDf4yGEo/7CnMmFQXbSyRN+oOhhMm2yKbQQXWc5VAd8gp64TVZjQ4k2cgQfsf2ynhehnpRaivpwI/F960wcLzH6STeA2kkU3cRTQRAoIBAQDwMtD9PLX9SaW/dIpjWhKVNQl76F7DPtcnaxhe7z/LrEFmybYtLuA3yzjbnb8bMxfHRGjPTPB9RBLD6LprMTeYlUyzoDc/DA/gZNkZAJ9m1HZ4ZqGudYGL1bp6n8epz0HOugM4+UHCx7PMSW6L+P0nMNaP+c0PzCGu2AScGID/er3vzSkPlTczHKrUnxmjmGEbTBREfjSDJ1aYpcJf0kiWzA/GREasbEcbLLT52d89NobdQj4JM0zJtsXPA86+wpIUb9gRL58W7vRIqWK/8W6riGdoSwhhBjGqG3Mm/jpwms6l23zVEuqEvW2q9gSjz0T2+H1Ua4GINyOGq3IomWGtAoIBAQDK/cWhYa13VxCV/Nu07CXxSTkm8wjWdAeIfXy55L6hfv3PHwxwOFAbrnmOYRlNkvIQY838bz+krztdxQ6NdvV/m0UIzRpBPBu5Om24XuTSv0jBNGxg8e2Fp9Ap6lLhNezPoirgB9J0h3OI33ARupEPvaEBP1pCVADkVY/CNOTnE+uTW0Ap7EyMHtxRGxh+KUcPEqW4O+TnFgpRugDHDW4mY69tD61OqvAm+eQxSdEANXe8dpS4WeSK2k2HMs7lGz3Fs6YhhrIGSdn/3UyIELhj1Wi8yAdoapjEGHX2AW8wM1r/uMC8L09xiEaZGaeWbnFj6qJMf7CfluUZuaXWt3vJAoIBAF9X7Hj4xkx6FV6/xcbWFBZB7TfP7v2VThYJfq0ATtRr1bIVU0jwGHRNKI6UOS10xHWGhAv1QGiYwtIc6RJvgOACM2YBrKxL/2lU3o/8HUnWAAiexILZhciZ1+Gg1sJi0H5ce7b7ycylNItcgpLxDJun2SNhRrKElsIuYPYNC/ddI1Oynh/fXP/e2zh2xtiXPcR2GH1vkyyUSt1gvp0GfWXOLlzG8T6z5C23O0cJ4oELydC94J4KTOqssCwSGNjDpvSRyLRZsM6Ln0/QXLBQB1vzUwik7/iDWudo6faKZ2wXJvvS+eQiFBEImCWKbiEPvxJBZI5D9jC5olJsb24KJCkCggEAMM+rCS5itvKxo09lSXELgqS34HzKYD8QXKrIJi8yA8V0pKxzojx4Tt+6jRkeK4AtQvGs44mgxSn53Yd4A15alC+y/vXK3Wrlw7mgDpiK735dsU+4y+sA0YXT0XBuM4dzBU6afrqCydCUYJJR8YFqRl2z7IfeXVqzyDQm2G09qa8pk4p6uFoA4iS9l6crUZL9aktynAWS+lpbauGONE8vcH3B/jip1OPX0Zd/XrbAUguJWkEta9L52MW7pMn75C2Twgl75k3sWwTBLfx53bIflKoJgHOdDGetimHTY69enDmNJTa46cd6k/NP/pqjqNGv5HXURw7hWs6/EluI3EPMuQKCAQAyAOkARVHWzXuEsBzNkiesN4CSv1tmn4CnAvabnm1WytZDfbfPtCdCpSzKTiQV9cPHkaTQtC2vuuoprL1PANOWWyCbhM82H7yFlgplRv1LtnMp74QhQbl7S2dTzP9GxqA3Fn8+bfWNQhnntkqv6tlJcDBCEpVmUtxy6pQB0uwMgdfauxeYfcR2o0Qwan7m760xVZRhmWh+RvPCXL0RRZPoS9k3e1mFIt406ktpcYEoCK+Vrynr+LJx2Gny0cphODCY21mTV0q19o2F4DEtcA8xGuacG8WYqALPaispMPR099MdLW5+mscKNjQeW02/Nk+2y/y9kM5xyBX5BKv3gO/a",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
というわけで、RSAのキーが欲しいときもKMSの対称キーとKMS APIを使うことができます。
ただし、ここで作ったRSAのキーとKMS Key IDとの間には何の紐付きもありません。単に手元の ssh-keygen コマンドを叩いたのと同じです。「秘密鍵は1個でいい、直接参照できる必要もない、とにかくどこか安全な場所に保管しておきたい」という用途のときには対称キーではなく非対称キーを使えばいいわけです。
例3: 自分が作ったパスワードを直接KMSで暗号化する
KMSは小さなサイズのデータなら暗号化してくれるのでした。実際に MySpecialSecretPassword*&!
というパスワードをKMSのEncrypt APIで暗号化してみます。
password="MySpecialSecretPassword*&!"
base64=`echo $password | base64`
aws kms encrypt \
--key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
--plaintext $base64
暗号化した結果はこちらです。
{
"CiphertextBlob": "AQICAHgjnCLqIzJ0vSDVeFv0F6upPLnpikd00qPCK4mCNcl3tAHsstmbVra4ww+3aPQTOmEYAAAAeTB3BgkqhkiG9w0BBwagajBoAgEAMGMGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMvBlvazm0sh90G+zeAgEQgDZfDwTWk4cpKwGwtEneFzGdlFpe/aQY7utO56ocdfpMDvTwg5Efhdvk3+7+jEYBd2vIAMvTbrg=",
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
もちろんDecrypt APIを使えばちゃんと元に戻せます。
aws kms decrypt \
--key-id deadbeef-deaf-beef-deaf-beefbeadbeef \
--ciphertext-blob "AQICAHgjnCLqIzJ0vSDVeFv0F6upPLnpikd00qPCK4mCNcl3tAHsstmbVra4ww+3aPQTOmEYAAAAeTB3BgkqhkiG9w0BBwagajBoAgEAMGMGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMvBlvazm0sh90G+zeAgEQgDZfDwTWk4cpKwGwtEneFzGdlFpe/aQY7utO56ocdfpMDvTwg5Efhdvk3+7+jEYBd2vIAMvTbrg="
{
"KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/deadbeef-deaf-beef-deaf-beefbeadbeef",
"Plaintext": "TXlTcGVjaWFsU2VjcmV0UGFzc3dvcmQqJiEK",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
$ echo "TXlTcGVjaWFsU2VjcmV0UGFzc3dvcmQqJiEK" | base64 -d
MySpecialSecretPassword*&!
おわりに
「暗号化キーと……暗号化された暗号化キー??」と混乱していた頭がAWS CLIを叩くことですっきりしました。手を動かすのは大切ですねというありがちな結論で締めさせていただきます。
-
https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html より、Plaintextの長さは最大4096バイトであることから ↩
-
つまり暗号学的に安全なやつ ↩
-
もちろんそれ以外の用途に使っても構いません。32バイト以内のデータにXORをかけるとか、これ自体を何かのパスワードにするとか ↩