AWSのKMSで非対称キーペア（公開鍵 / 秘密鍵）を使って暗号化と復号をしてみる

この記事は、[AWS初心者 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/aws_beginner)の10日目のものになります。

先日、AWSまわりの情報をあさっていたら、KMS（Key Management Service）で非対称キーペアがサポートされたというニュースを見かけました。

AWS Key Management Service は非対称キーをサポートします（2019/11/25）
https://aws.amazon.com/jp/about-aws/whats-new/2019/11/aws-key-management-service-supports-asymmetric-keys/

そういえば今までKMSってまともに使ったことないなー、ということで、KMSの勉強がてらに平文の暗号化と復号でも試してみるかと思って色々やってみたところ、ちょっとした気づき（罠？）がありましたので、記事にしてみました。どうせならということで、KMSの使い方的な内容も含めてみたいと思います。

なお、デジタル署名については先に記事にされている方がいまして、私もここを見ながら色々試してみた次第です。

KMS で非対称キーペア（公開鍵暗号方式）が利用できるようになったのでデジタル署名を試してみました！
https://dev.classmethod.jp/cloud/aws/key-management-service-supports-asymmetric-keys/

「公開鍵暗号方式」そのものの詳しい内容については語れるほどの知識は持ち合わせておりませんので、あくまでも実務的な内容のみとなっておりますが、その旨ご了承ください。また、記事内容の正確性も安全性も担保できませんので、実務等でお使い頂く場合は各自の責任の下でお願いいたします。

# （1）何はともあれ、KMSで非対称キーペアを作ってみる

KMSから「キーの作成」を押して、以下のように設定してみます。
<img width="818" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/2c846c80-835e-5a3a-1949-96912896f7cc.png">
キーの名前（エイリアス）を決めます。タグは任意で。
<img width="806" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/f4f07876-d1f7-185e-1f13-dfb93bdf7a20.png">
続いてこのキーの管理者を決める画面が出ると思いますが、これはAWSに現在ログインしているアカウントを入れるなり、状況に応じて決めてください。根源に関わる部分ですので、下手にキーを削除されたりしないように気をつける必要があるかと思います。

さらに続けると、キーの使用アクセス許可（使用アカウント）を決める画面が出てきます。こちらも適宜選択してください。ただし、EC2インスタンス上やLambda上で直接使用する場合は、KMSにアクセスできるポリシーを持ったIAMロールを直接割り当てる方（後に説明します）がアクセスキーなどを管理しない分安全かと思います。その場合はここで指定しておく必要はありません。

最後にキーポリシーの確認画面が出ますので、念のため内容を確認の後に作成を完了させます。
<img width="987" alt="kms.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/c94b0b25-8cda-74ce-2e41-b532d9edeed5.png">
こんな感じで非対称キーペアが作成されました。マスクしてある部分がキーIDです。

作成されたキーにはパブリックキー（公開鍵情報）が表示できるようになっています。ここがおそらく既存のと大きく違うところでしょう。

# （2）IAMでポリシーとロールを作成してみる

公開鍵や秘密鍵を扱うので、まずはその鍵を扱う権限の管理が必要となります。IAM（Identity and Access Management）で、必要最低限のポリシーとロールを作ります。今回はEC2インスタンスに直接ロールを割り当てるパターンでやってみます。

### まずはポリシーの作成から

暗号化だけのポリシー
<img width="1197" alt="kms2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/13339a74-c80e-bc03-5abc-09a08dc61e83.png">
復号だけのポリシー
<img width="1192" alt="kms3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/e1aea46e-7b33-8bea-e81b-7aa25248e36c.png">
右側のマスクの部分は先ほど作ったキーのキーIDを入れます。あとはそれぞれにわかりやすい名前をつけて保存します。

### 次にロールを作る

こちらも暗号化と複合の2つのロールを作ることにします。上で作ったポリシーと1対1で対応させます。
<img width="993" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/4bd91c3a-6402-d487-8f07-140fca815334.png">

今回はEC2インスタンス上で試してみたいので「このロールを使用するサービスを選択」で「EC2」を選択します。「Attach アクセス権限ポリシー」で、先ほど作成したポリシー名で検索してアタッチしてください。あとはロールの名前をつけて作成を完了させます。

「暗号化だけのポリシー」が一つアタッチされている「暗号化ロール」、「復号だけのポリシー」が一つアタッチされている「複合ロール」の2つを作ります。ロール一覧の「信頼されたエンティティ」に「AWS サービス: ec2」となっている新しい2つのロールが表示されていれば完了です。

# （3）それぞれのIAMロールが割り当てられているEC2インスタンスを別々に立てる

今回は検証作業をシンプルにするため、それぞれのIAMロールが割り当てられているEC2インスタンスを別々に立てることにします。EC2インスタンスの立て方の細かい説明についてはここでは書きません。他のドキュメントなどを参照してください。
<img width="731" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104477/cb534657-ab8c-7bff-62f7-aac94ceb5ffa.png">
IAMロールの指定部分のみ触れます。今回作成したロールが選択できるようになっています。こちらを選択するのを忘れないようにして、「暗号化ロール」「復号ロール」が割り当てられているEC2インスタンスをそれぞれ立てます。

### Amazon Linux 2 にあらかじめ入っているaws-cliのバージョンに注意

あとはawsコマンドで暗号化や復号の処理を試してみるだけなのですが、aws-cliは最新のものを使う必要があるようです。これから新規にインストールする場合は問題ないのですが、Amazon Linux2にあらかじめ入っているのはバージョンがちょっと古く（2019年12月9日現在 1.16.102）、この非対称キーペアには対応していませんでした（ここでかなり嵌まった…）。

```bash
$ aws --version
aws-cli/1.16.298 Python/3.7.4 Linux/4.14.154-128.181.amzn2.x86_64 botocore/1.13.34
```

2019年12月9日現在でaws-cliの最新は上記のバージョンになっているようです。以下を参照にして最新にしてください（バージョン1で問題ありません）。

AWS CLI のインストール
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv1.html

pip3コマンドを使うためにPython3をインストールする必要があったりパスを通したりする必要があるかもしれません。Amazon Linux2の場合は正しくパスを通してないと、最新バージョンをインストールしても既存の古いaws-cliをたたいてたりするので注意が必要です。

### aws configure で region だけは設定する必要がある

IAMロールを紐付けているのでaws configureは必要ないのかな？と思ったのですが、設定せずにやると以下のように怒られることになります。

```You must specify a region. You can also configure your region by running "aws configure".```

暗号化や復号のたびに都度```--region ap-northeast-1```と指定してもいいのですが、なんかそれも面倒なので```aws configure```は一度やっておくと良さそうです。```AWS Access Key ID```と```AWS Secret Access Key```は設定しておく必要はありません（EC2インスタンスにIAMロールを紐付けてない場合は必要になりますが）。

# （4）やっと暗号化と復号だ！

ここまで来てようやく暗号化と復号ですね。まずは暗号化からやってみます。暗号化ロールを紐付けた方のEC2インスタンスにログインして、以下のようにたたいてみます。

```bash
$ aws kms encrypt --key-id [キーID] --encryption-algorithm RSAES_OAEP_SHA_256 --plaintext "暗号化したい文字" --query CiphertextBlob --output text
```

```ぐにゅぐにゅとくそ長い文字列（base64エンコードされてます）``` が出てきたと思います。```--encryption-algorithm RSAES_OAEP_SHA_256```の指定は非対称キーペアを使う場合は必須かと思います（```RSAES_OAEP_SHA_1```も指定可能）。[キーID]は```alias/[キーの名前]```という風に書くこともできます。暗号化する平文の長さはたしか制限があるはずです（~~4096byteだったかな？~~ 実はもっと短いようで、鍵長やアルゴリズムにもよりますが約190〜470バイトとのことです。対称キーペアは4096byteなのでかなり短いですね…）。

それではそのまま調子に乗って復号の処理もしてみましょう。

```bash
$ aws kms decrypt --key-id [キーID] --encryption-algorithm RSAES_OAEP_SHA_256 --ciphertext-blob fileb://<(echo "ぐにゅぐにゅとくそ長い文字列" | base64 -d) --output text --query Plaintext | base64 -d
```

```ぐにゅぐにゅとくそ長い文字列``` の部分は暗号化したときに出力された文字を入れてくださいね。

おそらく

```An error occurred (AccessDeniedException) when calling the Decrypt operation```

という感じで怒られるかと思います。そうです、このEC2インスタンスには復号できるポリシーがアタッチされていません。これぞ公開鍵っぽい感じの挙動ですが、実際はポリシーで実現できているだけことです。

ということで、さきほど別に立てた復号ポリシーがアタッチされているロールが割り当てた方のEC2インスタンスにログインし、上のコマンドをたたいてみてください。

``` 暗号化したい文字 ```

と表示されれば成功です。復号の場合は```--encryption-algorithm```の指定が必要ないとおもっていたのですが、どうやら非対称キーペアの場合では必要みたいです（当然ですが、暗号化したときの指定に合わせる必要があります）。

# 最後に

今まで非対称キーペアが使えなかったということは「実際のところ、使いどころってどこなの？」って感じなんですかねぇ？　公開鍵を外に出せるので、オンプレサーバとAWSとの連携とかで使えるのではないか？という気もしますが、そんな要件あるのかしら？

とにかく、（ほぼ初めて）KMSをまともに使ってみて楽しかったので記事としてまとめてみた次第です。この年末になっても情報漏洩のニュースが絶えませんし、そういったことへの防御としてKMSを上手く活用できればいいのかな？と思います。

見てる人の参考になれば幸いです。突っ込みなどありましたらコメントください。読んで頂きありがとうございました。