PKCS11とAWS CloudHSMとAzure KeyVault入門

#HSMとは

　この記事は、**HSM**(Hardware Security Module)とは何かと、それがクラウド環境ではどう実装されているかの概略を説明したものです。

　いきなりですが、HSMの特徴をまとめると以下４点になります。

 - **機密情報を守る**仕組みである 
 - 機密情報は**専用のハードウェアデバイス**に格納される（最近ではUSB接続かNFCカードが普通）
 - 機密情報のサイズは小さい（せいぜい数KB)
 - 機密情報そのものにアクセスすることは避け、機密情報を使った**「操作」をデバイスに依頼し、その結果を受け取る**のを基本とする

　機密情報とは**悪意ある人物に知られるとマズい情報**です。皆さんのPCにもSSH秘密鍵の２つや３つは保管されていると思いますが、それは紛れもなく機密情報です。それ以外の機密情報というと、今の時代では**ビットコイン等仮想通貨の秘密鍵が機密情報の代表**です。取引所の秘密鍵が奪取されて億円単位の損害が出る事件はたくさんありますからね。逆にいえば攻撃側からすると、そういう秘密鍵であるならば、奪取のコストが億円単位であっても実行する価値があるわけです。10億円入ってるウォレットの秘密鍵奪取に7億円かかっても、成功すれば差し引き3億円の利益ですからね！
  ぶっちゃけ、ショボい個人情報とかは、流出しても金銭的価値はいくらもありませんが（流出させた側の社会的責任は過剰なくらいに問われますが、不正入手した個人情報を現金化するのは難しいです）、仮想通貨は一旦流出すれば取引所を通してほぼ匿名で法定通貨に換金できるのでシビアな時代になりました。

　３番目の特徴はもうちょっと説明が必要です。HSMに格納するデータサイズはごく小さいため、企業の購買履歴丸ごと、みたいなやつは機密データではあってもHSMに入れるような性質ではありません。機密データそのものではなく、データを操作するための「鍵」をHSMに入れるというのが普通です。

　４番目の特徴は**最重要**です。これは、たとえ一時的であっても、**機密情報をメモリに置かない**ということです。
　もし機密情報がメモリにあるならば、対象コンピュータをマルウェアに感染させるとかroot権限を奪取するとかの手段で、機密情報を見ることができてしまいます。これでは専用ハードウェアを使っていてもあまり意味がなくなってしまいます。
　例えばDB接続のパスワードは、機密情報には違いありませんが、使用時にはどうしてもメモリ上にパスワードを置く必要があるので、HSMで保護する必要があるかというとちょっと疑問です。もちろんファイルに平文で書いてある、とかよりはマシですが。

　必要なデータをメモリにも置かないで必要な操作ができるのか、と思うかもしれませんが、暗号の世界では必要な操作はごく限られているので十分可能です。それが**PKCS11**という仕様です。
　
#PKCS11

　HSMを使うための標準APIが**PKCS11**です。典型的には、**USBやNFCカードで接続する小型のコンピュータ**に秘密鍵を置いておいて、秘密鍵が必要な操作

 * 所定のデータを送って秘密鍵による署名を受け取る
 * 公開鍵で暗号化済みのデータを秘密鍵で復号する

　といったことをAPIで行うわけです。

　HSMのハードウェアメーカーがPKCS11に準拠したAPIを実装し、クライアントアプリもPKCS11を呼び出す実装になっていれば、 **両者がどういう組み合わせであってもちゃんと動く** 、というのがこの仕様の目標です。

　ただこの仕様の問題点は**古い**ことです。初版は1995年と実に古い。これまでに何度か改訂はされていますが基本的には当時のままです。
　1995年がどれくらい古いかというと、クラウドやDockerのような技術が存在しなかったのは言うまでもなく、USBすらなかった（少なくとも普及はしていない）ですし、JavaやPythonですら登場したばかりのフレッシュな技術で新参者扱いでした。今はPythonはともかくJavaはレガシーな感じがするので時間の経過を感じます。これの設計当時は、シリアルポート・パラレルポート、あるいはPS/2ポートでHSM用ハードウェアが提供される前提だったと推定しますが、最近のPCはそもそもそんなの持ってないですね。

　そういう具合にPKCS11は古いので、PKCS11の機能のうち、現代でも必要なものはそのうちごく一部です。例えば、DESやAESなど共通鍵暗号の鍵をHSMに入れて暗号化・復号化をするような用途もPKCS11はカバーしてますが、そんなのはもう今は使わないでしょう。またハッシュアルゴリズムについても、MD5はもうノーサポートで問題ないでしょうし、SHA1も無視でいいかもしれないという情勢になっています。
　そのため、PKCS11のうち今でも本当に必要な機能はそのうちほんの一部なのですが、PKCS11準拠を名乗るためにはそういう古いヤツもサポートする必要があり、結構重い話になってきているわけです。

　また**APIはC言語を前提としている**ため、APIデザインも非常に古臭く使いづらいです。Java, Go, C#などCとの接続ができる他言語でも、このデザインには引きづられてしまいます。実際、この公式の仕様書を見れば、**ゲゲっと思うのも無理ありません**。

  http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html

#時代はクラウドとコンテナ
　
　このようにHSMとPKCS11は**機密情報をメモリにすら置かない**という特徴のためとても有用な技術なのですが、今や時代はクラウドとコンテナであります。
　EC2インスタンスやKubernetes上のコンテナにUSB接続のハードウェアを持ち込むようなわけにはいかないのですが、さすがAWS、現代的環境でもHSMを扱えるようにしてくれているのです！　それが**AWS CloudHSM**です。

　一見すごいのですが、アクセスするAPIは古いPKCS11なので実際にはしびれも憧れもしません　_(┐「ε:)_ｽﾞｺｰ

#AWS CloudHSM

　AWSは、主要なLinuxディストリビューションとWindows向けにCloudHSMにアクセスするためのライブラリとコマンドラインツール群を用意してくれています。

　https://docs.aws.amazon.com/ja_jp/cloudhsm/latest/userguide/install-and-configure-client-linux.html

これを使うと、クライアントアプリはPKCS11によってClouｄHSMの機能が使えるようになり、EC2インスタンスやDockerコンテナから、USB接続のHSMが接続されているかのような感覚でいけます。

　これまでの説明をまとめると以下のようになります。

![cloudhsm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59073/2d4a1496-d0f2-c34f-c9f5-8c8e0d84bb52.png)


　PKCS11を使ったクライアントアプリが多数ある世界においてクラウド化を進めるならこういう設計になるのは当然でしょうが、そもそもそういうのは多くなさそうなのでこの方針の正しさは疑問があります。
　
　AWSは、多数の独立したユーザの機密情報をまとめてCloudHSMで管理する必要があるため、たぶんその実態は、USB接続のハードウェアがたくさんつながったサーバ群でしょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59073/ce21f75b-b878-2a0d-f333-1f4dd02d5892.jpeg" width="640"><br>(想像図です)

　もう一つCloudHSMの重要なメリットは、**ハードウェアは遅かれ早かれ故障する**という問題から解放されることです。

　HSMの正体はたいていUSB接続のさほど頑丈でないチープなハードウェアなので、ちょっとした弾みに故障したり壊れます。それで大事な秘密鍵が失われたりすると困るのでバックアップのHSMを用意したりするわけですが、セキュリティを確保しつつ適切にバックアップするのは結構面倒です。CloudHSMの場合、他のAWSの技術の御多分にもれず、複数のAZで複数のHSMが自動的に同期されるようになっていて、論理上は一つのHSMとして扱えるようになっているので、ハードウェアトラブルの心配からは解放されます。

　一方、CloudHSMのちょっと嫌な点は、PKCS11ライブラリが**全ての環境向けに用意されているわけではない**ことと、用意されていてもインストールやセットアップに一手間かかることです。
　とりわけ、Alpine Linux用がないというのはコンテナ環境向けにはちょっと不便です。ソースコードが公開されていればAlpineへの移植はそう難しくはないと思いますが、下手にそのソースの脆弱性が見つかったりしても事件になるので悩ましいところです。まあこの辺は今後状況が変化する可能性はありまし、何か別の理由でソースコード非公開なのかもしれません。

#Azure KeyVault 

　最後になりましたが、Azure KeyVaultは、実現する機能はCloudHSMとだいたい一緒なんですが、**PKCS11は完全無視で、REST APIで機能が提供されている**のが特徴です。もちろん、それを呼び出すための主要な言語ごとのライブラリも整備されています。

　このほうがOSや言語を選ばないしセットアップも簡単なのでスマートといえると思います。個人的にはAzureのこの割り切りの方が好みです。今更PKCS11にこだわっても、昔からPKCS11のアプリを運用していた人にしかメリットはありませんからね。


#まとめ

- HSMは、数KB程度の機密情報を、実態をメモリ上に置くことなく利用するための機構である
- 鍵ペアの保管が利用目的の大本命である
- 機密情報本体が別のハードウェアにあるため、セキュリティ上有利である
- PKCS11は別ハードウェア上の機密情報を利用するための歴史ある汎用APIだが、いかんせん古く使いづらい
- AWS CloudHSMやAzure KeyVaultは、HSMの機能をクラウド環境から使うために、AWSとAzureが用意したものである
- AWS CloudHSMはPKCS11 APIをベースにしており、Azure KeyVaultは独自のREST APIをベースにしている、というアプローチの違いがある
- 個人的にはAzureの方針が好き