AWS KMSに利用者が作成した共通鍵をインポートする手順

2016.09.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、虎塚です。

先月のAWSアップデートで、利用者が作成した共通鍵をAWS KMSにインポートできるようになったので、概要と手順をご紹介します。

概要

これまでのAWS KMSでは、AWS側で生成された鍵(カスタマーデータキー)を元に作成したデータキーで、AWSリソースやユーザデータを暗号化/復号してきました。今回のアップデートで、カスタマーデータキーとして、ユーザがローカルで独自に作成した鍵も、カスタマーデータキーの1つとして利用できるようになりました。

カスタマーマスターキーは、Key Materialと呼ばれるデータと関係づけられることで有効化されます。これまで、Key Materialは、AWSが内部的に生成していました。これからは、Key MaterialとしてAWS外のデータを使うことができます。ユーザが作成したKey Materialが、「利用者が作成した共通鍵」です。

どんなケースで鍵をインポートすると便利か

鍵に特定の要件が求められるケース

鍵にシステム独自の基準が求められるような場合に、ユーザが制御できるようになりました。たとえば、鍵の生成に使用するシードのランダム性について、なんらかの基準を満たす必要があるとき、必要な設定に基づいてKey Materialを作成することで、基準をクリアできるでしょう。

これまでは、カスタマーマスターキーの生成をAWS KMSが内部的におこなっていたため、Key Materialの生成プロセスにユーザは関与できませんでした。

鍵の利用可能期間をあらかじめ設定したいケース

インポートした鍵から生成したカスタマーマスターキーには、ユーザが任意の有効期限を設定できます。また、カスタマーマスターキーと関連づけられたKey Materialを手動で削除することもできます。Key Materialを削除すると、カスタマーマスターキーは利用できない状態になります。もし再びカスタマーマスターキーが必要になったら、Key Materialを再アップロードすることで、復活させることができます。

これまでは、カスタマーデータキーを無効化するか、猶予期限を与えた上で削除することしかできませんでした。そして、カスタマーマスターキーを削除すると、二度と復活させることはできませんでした。

インポート機能の安全性

鍵の生成から破棄までがAWS側で完結するこれまでの機能と違い、本機能ではユーザが作成した鍵をインターネット経由でアップロードするので、セキュリティが気になる方もいらっしゃるかと思います。

鍵のインポートでは、AWSが発行する有効期限付きの公開鍵とインポートトークンを使います。インポートする共通鍵 (Key Material) を、公開鍵で暗号化してから、インポートトークンとともにアップロードすることで、AWS KMS側ではアップロードされた鍵の真正性を確認できます。言い換えると、途中の経路で改ざんされた鍵が有効化されることはありません。

また、カスタマーマスターキーにインポートされたKey Materialは、そのカスタマーマスターキーと永続的に関連づけられます。もし誰かがKey Materialを不正に入手して、自分のカスタマーマスターキーにインポートしても、その鍵では本来のカスタマーマスターキーで暗号化したデータを復号することはできません。

鍵のインポート手順

それでは、鍵のインポート手順を説明します。動作確認は次の環境でおこないました。

  • Mac OS X 10.5.5 Yosemite
  • AWS CLI 1.10.64 (botocore 1.4.54)

1. カスタマーマスターキーの作成

まず、カスタマーマスターキーをAWS KMSに作成します。この時、originに「EXTERNAL」を指定します。デフォルト値はAWS_KMSで、この場合は従来のインポートしない鍵が生成されます。

aws kms create-key --origin EXTERNAL --description imported_key

実行結果は、次のようになります。

{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "12345678-abcd-abcd-abcd-123456789012",
        "Description": "imported_key",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1473967382.465,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/12345678-abcd-abcd-abcd-123456789012",
        "AWSAccountId": "123456789012"
    }
}

Originが「EXTERNAL」になっていることと、KeyStateが「PendingImport」になっていることが重要です。生成されたカスタマーマスターキーのKey IDを控えておきましょう。

念のため、describeコマンドを使用して、生成コマンドの実行時と同じ情報が出力されることを確認します。

aws kms describe-key --key-id 12345678-abcd-abcd-abcd-123456789012

実行結果は、次のようになります。

{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "12345678-abcd-abcd-abcd-123456789012",
        "Description": "imported_key",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1473967382.465,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/12345678-abcd-abcd-abcd-123456789012",
        "AWSAccountId": "123456789012"
    }
}

2. 公開鍵とインポートトークンをダウンロード

ステップ1で生成したカスタマーマスターキーを指定して、ユーザが独自に生成する鍵をアップロードする時に必要な公開鍵インポートトークンをダウンロードします。

ダウンロードする前に、アップロードする鍵の暗号化に利用する公開鍵暗号化方式で、どのpadding方式を使うかを選びます。ここで選んだ方式を、ダウンロード時にオプションとして指定する必要があるためです。次の3種類から選びます。

  • RSAES_OAEP_SHA_256
  • RSAES_OAEP_SHA_1
  • RSAES_PKCS1_V1_5
aws kms get-parameters-for-import \
--key-id 12345678-abcd-abcd-abcd-123456789012 \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048

今回は、RSAES_PKCS1_V1_5にします。wrapping-key-specオプションに指定できる値は、「RSA_2048」固定です。

実行結果は、次のようになります。

{
    "ParametersValidTo": 1474058793.704,
    "PublicKey": "MIIBIjANBgkqhki...",
    "KeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/12345678-abcd-abcd-abcd-123456789012",
    "ImportToken": "AQECAHhykjoG..."
}

実行結果から得られた公開鍵 (PublicKey) とインポートトークン (ImportToken) をテキストファイルに保存します。ここでは、ファイル名をそれぞれPublicKey.b64、ImportToken.b64とします。

「ParametersValidTo」は、公開鍵とインポートトークンの有効期限を表わすタイムスタンプです。公開鍵とインポートトークンは、ダウンロードから24時間有効です。

date -r 1474058793
Sat Sep 17 05:46:33 JST 2016

3. 公開鍵とインポートトークンのデコード

公開鍵とインポートトークンをそれぞれbase64デコードして、新しいファイルに保存します。

$ openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
$ openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin

4. インポートする鍵の生成と暗号化

AWS KMSにインポートする鍵を作成します(これがKey Materialです)。ここでは、32bitのランダムビットを生成しました。

openssl rand -out PlaintextKeyMaterial.bin 32

生成した鍵を、ステップ3でデコードした公開鍵を使って暗号化します。

openssl rsautl -encrypt \
-in PlaintextKeyMaterial.bin \
-pkcs \
-inkey PublicKey.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial.bin

5. 暗号化した鍵のインポート

ステップ4で暗号化した鍵を、AWS KMSにインポートします。

今回は、インポートするKey Materialの期限を2016年12月10日に指定しました。暗号化した鍵 (Key Material) とインポートするトークンは、いずれもblobファイルとして「fileb://」で読み込みます。

aws kms import-key-material --key-id 12345678-abcd-abcd-abcd-123456789012 \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://ImportToken.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2016-12-10T12:00:00-08:00

実行後、describeコマンドを使って鍵のメタデータを確認します。実行結果は、次のようになります。

 aws kms describe-key --key-id 12345678-abcd-abcd-abcd-123456789012
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "12345678-abcd-abcd-abcd-123456789012",
        "Description": "imported_key",
        "ExpirationModel": "KEY_MATERIAL_EXPIRES",
        "ValidTo": 1481400000.0,
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1473967382.465,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/12345678-abcd-abcd-abcd-123456789012",
        "AWSAccountId": "123456789012"
    }
}

KeyStateが「Enabled」に変更されたことを確認します。

おわりに

ユーザが独自に作成した鍵をインポートできるようになったことで、AWS KMSを利用できる場面がさらに広がったと思います。

それでは、また。