🔑

[aws] KMSを使ったことがなかったのでKMSを使ってファイルを暗号化してみた

2021/06/19に公開

こんにちは!
今回はタイトルにある通り、awsのkmsを利用してファイルを暗号化してみました。

では早速始めていきます。

まずはawsコンソールにログインし、IAMユーザーを作成

aws cliで使えるようにしたいので画像赤枠の「プログラムによるアクセス」にチェックを入れます。
ユーザー名は「kms-test」にしました。

作成後、AdministratorAccessの権限を与えました。

kmsキーを作成

kmsを選択すると上記画像のような画面が表示されるので「キーの作成」をクリック。
キータイプは「対称」を選択、aliasは「kms-test」とし、キー管理者とキー使用者には先ほど作成したIAMユーザー「kms-test」を指定しました。キーポリシーは何も変更を加えずデフォルトのものを使用しました。

キーポリシー
{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::[アカウントID]:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::[アカウントID]:user/kms-test"
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::[アカウントID]:user/kms-test"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::[アカウントID]:user/kms-test"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}

デフォルトのキーポリシーでは、以下のようなことを許可しているようです。

  • rootユーザーにkmsに関する全てのアクションを許可 rootユーザーだけでなくアカウント内のIAMユーザー・ロール全てにkmsに関する全てのアクションを許可
  • キー管理者「kms-test」にキーを作成したり削除したりするのを許可
  • キー使用者「kms-test」にデータキーを作成したり暗号化、復号するのを許可

ここで作成したのはデータキーを暗号化するためのキー、CMKです。
CMK: Customer Master Key

iTerm等のターミナルを開き、aws cliの設定をする

aws configure

上記コマンドを実行し、先ほど作成したIAMユーザー「kms-test」のアクセスキーとシークレットアクセスキーを設定。

kmsに関するaws cliのコマンドを実行してみる

  • KMSのキー一覧を取得
aws kms list-keys

上記コマンドでKMS上のキー一覧を取得してみました。
想定では先ほど作成したキーが1つだけ返却されると思っていたのですが、3つも返ってきました。

他の2つは何なのか調べてみると、S3とlightsailのAWSマネージド型キーでした。S3では暗号化のオブションを選択できるので、それをしたときにこのキーが使われているのだと思います。

lightsailは知らないサービスでした。またいつか調べてみたいと思います。

  • キーポリシーを取得
aws kms get-key-policy --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

上記コマンドを実行し、キーポリシーを取得してみます。key-idは「aws kms list-keys」を実行すれば取得できます。awsコンソールにも表示されていますのでそちらからでも取得できます。

「the following arguments are required: --policy-name」というエラーがでました。ポリシーネームが必要みたいなことだと思いますが、ポリシーネームなんて付けた覚えはないですね。。

  • ポリシーネームを取得

ポリシーネームが取得できるらしいので下記コマンドを実行してみました。

aws kms list-key-policies --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

以下のようなのが返ってきました

{
    "PolicyNames": [
        "default"
    ]
}

ポリシーネームは「default」のようです。

  • もう一度キーポリシーを取得

policy-nameを指定して下記を実行

aws kms get-key-policy --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f --policy-name default

エラーは出ませんでしたが、非常に見づらいキーポリシーが返ってきました。見づらいので記載しないでおきます。

暗号化するファイルを作成

password.txtというファイルを作成しました。中身は以下です。

aws password: 12345678

password.txtの中身はなんでも良いので好きに変更してください。

データキーを作成

下記コマンドを実行してデータキーを作成します。データキーがCDKと呼ばれているものですね。
CDK: Customer Data Key

aws kms generate-data-key --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

失敗しました。。以下のようなエラーがでました。

An error occurred (ValidationException) when calling the GenerateDataKey operation: Please specify either number of bytes or key spec.

number of bytes か key specのどっちかを指定しろという感じですね。key specを指定することにしました。

aws kms generate-data-key --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f --key-spec AES_256

今度は成功しました。下記のようなのが返ってきました

{
    "CiphertextBlob": "AQIDAHhbXK8vC6ueIBOD6mT2+VGf7SEiHZyxTqwFXRq+VzBFkQElU/bKe8/eJiA9P2bu1oy5AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMr/a3bNv8bx4rQ0qvAgEQgDsuKKGZ/F6aaDldHR0Gl1eyfkLRXj54AMGAWstwiMvT4S17eIGTzKj9irkKFcvFg2HcimiWVgWW1//LvA==",
    "Plaintext": "yrqwcz2sM37hWE8TKh5hguQiAo8OYega+gbeDZS24uc=",
    "KeyId": "arn:aws:kms:ap-northeast-1:[アカウントID]:key/9487f504-67dc-4cc7-be51-eabe94ced81f"
}

CiphertextBlobは暗号化されたデータキー、
Plaintextはデータキー、
KeyIdはデータキーを暗号化するときに使用したCMKのARN
です。

データキーと暗号化済みデータキーを保存するファイルを作成

datakey.txtというファイルを作成し、Plaintextの値をコピーして貼り付けました。
次にencrypted-datakey.txtというファイルを作成し、CiphertextBlobの値をコピーして貼り付けました。
※ ファイル名は何でも良いです

データキーを使って先ほど作成したpassword.txtを暗号化

下記コマンドを実行します。

openssl aes-256-cbc -e -in password.txt -out encrypted-password.txt -pass file:./datakey.txt

このコマンドを大まかに説明するとdatakey.txtというファイルを使ってpassword.txtを暗号化し、encrypted-password.txtというファイルに出力するというものです。コマンド実行前にencrypted-password.txtというファイルを作成する必要はありません。

暗号化されたファイルを見てみましょう。

encrypted-password.txt
Salted__e^?í±*} _     È7¡5!<98><84>8M):?^]¤^$Ͻ^]õ^Cù^YÉ|W

元のファイルと比べると全然違うことが分かりますね。これは人間には解読できないでしょう。ちなみに元のファイルはこちらです。

password.txt
aws password: 12345678

データキーを復号

ファイルの暗号化に成功したので今度は復号してみました。
まずはデータキーを復号する必要があります。

下記コマンドを実行し、データキーを復号します

aws kms decrypt --ciphertext-blob fileb://encrypted-datakey.txt --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

またエラー出ました。。

An error occurred (InvalidCiphertextException) when calling the Decrypt operation:

オプションciphertext-blobで指定しているファイルが正しくないみたいです。

他の記事では暗号化済みのデータキーのファイル名に、拡張子「.txt」がないのが多かったので、下記コマンドを実行しencrypted-datakey.txtをencrypted-datakeyに変更してみました。

mv encrypted-datakey.txt encrypted-datakey

そして以下を実行

aws kms decrypt --ciphertext-blob fileb://encrypted-datakey --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

全く同じエラーがでました。。

以下のコマンドを実行すれば良いみたいな記事が見つかったので実行してみました。

aws kms decrypt --ciphertext-blob fileb://<(echo 'encrypted-datakey' | base64 -d) --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

同じ。。

generate-data-keyを実行したときに返却されたCiphertextBlobの文字列をbase64デコードする必要がありそうだったので、base64してからencrypted-datakey2というファイルに保存する下記コマンドを実行

echo generate-data-keyを実行したときに返却されたCiphertextBlobの文字列 | base64 --decode > encrypted-datakey2

encrypted-datakey2が作成されました。

そしてこのencrypted-datakey2を使用して復号コマンドを実行

aws kms decrypt --ciphertext-blob fileb://encrypted-datakey2 --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

成功しました。以下のようなのが返ってきました。

{
    "KeyId": "arn:aws:kms:ap-northeast-1:[アカウントID]:key/9487f504-67dc-4cc7-be51-eabe94ced81f",
    "Plaintext": "yrqwcz2sM37hWE8TKh5hguQiAo8OYega+gbeDZS24uc=",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

generate-data-keyを実行したときに返却されたPlaintextと同じPlaintextが返却されていることが分かるかと思います。つまりデータキーの復号に成功していますね。

encrypted-datakey2をencrypted-datakey2.txtにしても成功するか確認

拡張子「.txt」の有無は関係あるのか再度確かめてみました。

mv encrypted-datakey2 encrypted-datakey2.txt

そして

aws kms decrypt --ciphertext-blob fileb://encrypted-datakey2.txt --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f

成功しました。拡張子「.txt」の有無は関係ないようです。

decrypted-datakey.txtというファイルを作成し、復号して得られたPlaintextの値をコピーして貼り付け

復号されたデータキーのプレーンテキストをdecrypted-datakey.txtというファイルに保存しました。

datakey.txtとdecrypted-datakey.txtが同じであることを確認

暗号化前のデータキーと復号後のデータキーが同じであることを下記コマンドを実行し確認

diff datakey.txt decrypted-datakey.txt

実行後何も表示されなければ同じだということです。

encrypted-password.txtを復号

続いてpassword.txtを暗号化したencrypted-password.txtを復号するため下記コマンドを実行

openssl aes-256-cbc -d -in encrypted-password.txt -out decrypted-password.txt -pass file:./decrypted-datakey.txt

decrypted-datakey.txtを使ってencrypted-password.txtを復号してdecrypted-password.txtに出力します。

decrypted-password.txtの中身を確認

下記コマンドを実行

view decrypted-password.txt

以下が表示されました。

aws password: 12345678

暗号化前のpassword.txtと同じですね。一応diffをとってみましょう

diff password.txt decrypted-password.txt

何も表示されません。つまり差がないということです。復号に成功していますね。

キーの無効化

awsコンソールにアクセスし、「無効」をクリックします。画像赤枠の箇所です。

無効化後、データキーを作成しようとすると、

aws kms generate-data-key --key-id 9487f504-67dc-4cc7-be51-eabe94ced81f --key-spec AES_256

ちゃんとエラーになりますね

An error occurred (DisabledException) when calling the GenerateDataKey operation: arn:aws:kms:ap-northeast-1:[アカウントID]:key/9487f504-67dc-4cc7-be51-eabe94ced81f is disabled.

キーの削除

KMSではキーの削除に7〜30日の待機期間が設けられているためすぐには削除されません。

awsコンソールにアクセスし、画像赤枠の「キーの削除をスケジュール」をクリックすると待機期間を指定できます。今回は7日を指定しました。

画像のようにステータスが削除保留中になっており、スケジュールされた削除日が7日後になっていればOKです。

後片付け

IAMユーザー「kms-test」には結構強い権限を与えているのでアクセスキー等が流出すると危険です。このテスト用に作ったユーザーで今後は必要ないので削除します。

削除後、aws cliが実行できなくなったことを確認します。適当に「aws s3 ls」とかを実行し、InvalidAccessKeyIdのエラーがでればOKです。

終わりに

今回初めてKMSを使ってみました。AWS認定セキュリティ試験のためにKMSについて勉強していて理解が曖昧だったのですが、今回実際に使用してみたことで理解が深まった気がします。ハマったことはデータキーを作成したときに取得できる暗号化されたデータキーは、base64デコードしないといけないということですね。これは実際にやってみるまで知りませんでした。

最後に今回で理解したKMSの大まかな使用の流れを書いて終わりにしたいと思います。
1, CMKを作成
2, CMKを使ってデータキーを作成。データキーと暗号化されたデータキーを取得
3, データキーを使って暗号化したいファイルを暗号化
4, 暗号化されていないファイルとデータキーを削除
5, CMKを使って暗号化されたデータキーを復号
6, データキーを使って暗号化されたファイルを復号

Discussion