CLIでKMSを使った暗号化を試す

お勉強のためにCLIでKMSを使った暗号化を試してみたメモ。

処理の流れ

データの暗号化は以下の流れで実施する。

  1. KMSでマスターキーを作成する(CreateKey)
  2. データキー作成APIを叩く(GenerateDataKey)
  3. 平文データキーとマスターキーで暗号化されたデータキーが返ってくる
  4. 平文データキーで暗号化したいデータを暗号化する
  5. 平文データキーを削除する
  6. 暗号化されたデータ暗号化されたデータキーを同じ場所で保存する

データの復号は以下の流れで実施する。

  1. 復号APIを叩く
  2. 平文データキーが返ってくる
  3. 平文データキーで暗号化されたデータを復号する
  4. 平文データキーを削除する

CLIで実施

CLIでデータの暗号化操作を試す。

カスタマーキーの作成

マスターキーを作成し、エイリアスをつけておく。

master_key_arn=$(aws kms create-key --query KeyMetadata.Arn --output text)
master_key_id=${master_key_arn##*/}
aws kms create-alias \
    --alias-name alias/sample-master-key \
    --target-key-id ${master_key_id}

キーとキーポリシーを確認する。

$ aws kms describe-key --key-id ${master_key_id}
{
    "KeyMetadata": {
        "AWSAccountId": "XXXXXXXXXXXX",
        "KeyId": "e6e603eb-e463-432b-806e-aa64a8f191cc",
        "Arn": "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/e6e603eb-e463-432b-806e-aa64a8f191cc",
        "CreationDate": "2020-05-01T13:00:28.388000+09:00",
        "Enabled": true,
        "Description": "",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "Origin": "AWS_KMS",
        "KeyManager": "CUSTOMER",
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ]
    }
}
$ aws kms get-key-policy --key-id ${master_key_id} --policy-name default
{
    "Policy": "{\n  \"Version\" : \"2012-10-17\",\n  \"Id\" : \"key-default-1\",\n  \"Statement\" : [ {\n    \"Sid\" : \"Enable IAM User Permissions\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : {\n      \"AWS\" : \"arn:aws:iam::XXXXXXXXXXXX:root\"\n    },\n    \"Action\" : \"kms:*\",\n    \"Resource\" : \"*\"\n  } ]\n}"
}
$ aws kms get-key-policy --key-id ${master_key_id} --policy-name default | jq -r '.Policy' | jq .
{
  "Version": "2012-10-17",
  "Id": "key-default-1",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::XXXXXXXXXXXX:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    }
  ]
}

キーポリシーではIAMユーザー全体が許可されているので、IAMユーザーに権限があればキーにアクセスできる。今回は管理者権限のあるユーザーで操作しているのでアクセスできる。

データの暗号化

暗号化したいデータを用意する。

cat <<EOF > plaintext-data.txt
Hello World!
EOF

マスターキーを指定し、データキーを作成する。

aws kms generate-data-key \
  --key-id ${master_key_id} \
  --key-spec AES_256 > generate-data-key-response.json

レスポンスの内容を確認する。Plaintextが平文データキーで、CiphertextBlobがマスターキーで暗号化されたデータキー。

$ cat generate-data-key-response.json
{
    "CiphertextBlob": "AQIDAHgX8Ezyy+LslKPEZFBMzquXkfEIBf5KiG30hr6DrYByPAF1OOxZnAQCsaf7Ke1fWe7EAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMldmNdV+smKOHHupHAgEQgDvUJVao4FbT7ewFcHgGaCnisntNYMsDpCrony+xs1qVmwQphiiazFZvi1L0WqHMPmyYW1RopFT/HMHOkQ==",
    "Plaintext": "sbK7LuWiBjV8LR76MDNLMQIpFfh6xITEG6GOcaYdQEU=",
    "KeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/e6e603eb-e463-432b-806e-aa64a8f191cc"
}

PlaintextとCiphertextBlobをBase64でデコードしてファイルに保存しておく。

cat generate-data-key-response.json | jq -r '.Plaintext' | base64 > plaintext-data-key
cat generate-data-key-response.json | jq -r '.CiphertextBlob' | base64 --decode > encrypted-data-key

平文データキーを使ってデータを暗号化する。

openssl aes-256-cbc -e -in plaintext-data.txt -out encrypted-data.txt -pass file:plaintext-data-key

暗号化したら、平文データキーは削除する。暗号化前のデータ(plaintext-data.txt)やCLIの戻り値を格納したファイル(generate-data-key-response.json)も削除する。

データの復号

暗号化されたデータキーを復号する。CiphertextBlobにはメタデータが含まれているため、マスターキーを指定する必要はない。

aws kms decrypt \
  --ciphertext-blob fileb://encrypted-data-key > decrypt-response.json

平文データキーが返ってくるのでファイルに保存する。

cat decrypt-response.json | jq -r '.Plaintext' | base64 > decrypted-data-key

この平文データキーを使ってデータを復号する。

$ openssl aes-256-cbc -d -in encrypted-data.txt -pass file:decrypted-data-key
Hello World!

復号されることが確認できた。復号できたら平文データキーは削除する。