鍵の管理するためのAWSのサービスにKMSがある。これを使用すると、鍵自体を自分で保持する事なく、必要な情報を暗号化/復号化できる。AWS KMSを使用した際に調べた事を記録しておく。
boto3で暗号化する
boto3でKMSの暗号化を使うためには以下のようにする。
import boto3
import base64
plain_text: str = "yay"
boto3_session = boto3.Session()
kms_client = boto3_session.client('kms')
resp = kms_client.encrypt(
KeyId="11111111-2222-3333-4444-555555555555",
Plaintext=plain_text,
)
cipher_blob: bytes = resp["CiphertextBlob"]
cipher_b64: bytes = base64.b64encode(cipher_blob)
cipher_text: str = cipher_b64.decode()
return cipher_text
気を付ける点としては、返されるデータはバイト列になっているため、文字列として取り扱うためにはbase64でエンコードしたり、decode()して文字列化したりする必要がある。
local開発用のAWS KMS local-kmsを使う
local-kmsはAmazon KMSのダミーサーバーで、local-kmsへ問い合わせるようにすることでAmazon KMSに問い合わせることなく開発が進められる。KMS自体の料金は高くないからあまり使う事はないかもしれないが、CIでのテストなどでは使用してもよいかもしれない。以下では、local-kmsの使い方をまとめる。
local-kmsのDocker Imageをダウンロードする。
docker pull nsmithuk/local-kms
dockerを用いてlocal-kmsを起動する。
docker run -p 8080:8080 -e REGION=ap-northeast-1 nsmithuk/local-kms
KeyIdを発行する。
POST http://localhost:8080/
X-Amz-Target: TrentService.CreateKey
Content-Type: application/json; charset=utf-8
{}
{
"KeyMetadata": {
"AWSAccountId": "111122223333",
"Arn": "arn:aws:kms:ap-northeast-1:111122223333:key/834140e8-e12f-4047-a723-8261bd21c171",
"CreationDate": 1557292212,
"Enabled": true,
"KeyId": "834140e8-e12f-4047-a723-8261bd21c171",
"KeyManager": "CUSTOMER",
"KeyState": "Enabled",
"KeyUsage": "ENCRYPT_DECRYPT",
"Origin": "AWS_KMS"
}
}
// POST http://localhost:8080/
// HTTP/1.1 200 OK
// Content-Type: application/x-amz-json-1.1
// Date: Wed, 08 May 2019 05:10:12 GMT
// Content-Length: 317
// Request duration: 0.021481s
利用するkeyを登録する。Plaintextにはbase64でエンコードした値を設定する。
POST http://localhost:8080/
Content-Type: application/json
X-Amz-Target: TrentService.Encrypt
{
"KeyId": "834140e8-e12f-4047-a723-8261bd21c171",
"Plaintext": "dGVzdA=="
}
{
"KeyId": "arn:aws:kms:ap-northeast-1:111122223333:key/834140e8-e12f-4047-a723-8261bd21c171",
"CiphertextBlob": "UGFybjphd3M6a21zOmFwLW5vcnRoZWFzdC0xOjExMTEyMjIyMzMzMzprZXkvODM0MTQwZTgtZTEyZi00MDQ3LWE3MjMtODI2MWJkMjFjMTcxAAAAAEb30YwGZIgUXvTlNpB3LLXl544WZucO+LzvlE3jgDCT"
}
// POST http://localhost:8080/
// HTTP/1.1 200 OK
// Content-Type: application/x-amz-json-1.1
// Date: Wed, 08 May 2019 05:31:03 GMT
// Content-Length: 268
// Request duration: 0.015830s
ここで取得したCiphertextBlobを使って実際にboto3.clientから鍵を取り出してみる。
環境変数にリージョンを設定する。この環境変数はboto3が参照する。
(setenv "AWS_DEFAULT_REGION" "ap-northeast-1")
boto3.clientを使って鍵を取り出す。endpoint_urlにはlocal-kmsのURLを指定する。CiphertextBlobは先程鍵を保存したときのレスポンスのCiphertextBlobの値です。この値はbase64でエンコードされているので、その値をデコードしてclient.decryptメソッドに渡す。
import base64
import boto3
client = boto3.client('kms', endpoint_url='http://127.0.0.1:8080')
res = client.decrypt(CiphertextBlob=base64.b64decode(
b"UGFybjphd3M6a21zOmFwLW5vcnRoZWFzdC0xOjExMTEyMjIyMzMzMzprZXkvODM0MTQwZTgtZTEyZi00MDQ3LWE3MjMtODI2MWJkMjFjMTcxAAAAAEb30YwGZIgUXvTlNpB3LLXl544WZucO+LzvlE3jgDCT"
))
return res # for org-babel results
{'KeyId': 'arn:aws:kms:ap-northeast-1:111122223333:key/834140e8-e12f-4047-a723-8261bd21c171', 'Plaintext': b'test', 'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Wed, 08 May 2019 05:31:32 GMT', 'content-length': '115'}, 'RetryAttempts': 0}}
Plaintextに test
というバイト列が返される事が確認できた。