はじめに
昨年まで参画していたクラウド移行PoC検証案件にて、PKCS#11アプリケーションで使用していたHSMをAWS CloudHSMへ変更した際に発生したトラブルとその対処について備忘として記載します。
前提
PKCS#11アプリケーション
- PKCS#11を利用してレスポンスに電子署名を付与するアプリケーション
- リクエスト/レスポンスの処理をApacheで制御しており、Apacheの子プロセスが1つ起動するたび、HSMにログインしセッションを1つ確立する(Apacheの子プロセス数=HSMとのセッション数という関係)
- HSMを介した署名処理は不定期に発生するため、パフォーマンスと安定性を確保する目的で、常時16本のセッションを確立し待機させている
- オンプレミスで動いているシステムと同じ要件
StartServers 16 # Apacheの子プロセス数の初期値
MaxSpareServers 16 #子プロセスの希望最大個数
MinSpareServers 16 #子プロセスの希望最少個数
環境
- OS: Red Hat Enterprise Linux8.6
- HSM: AWS CloudHSM v2(PKCS#11)
- HSMクライアントSDK: cloudhsm-pkcs11 5.16.0-1.el8
- Web/App: Apache 2.4 (MPM: prefork)
発生した問題
PKCS#11アプリケーションの起動失敗。
HSMクライアントに出力されたログを確認したところ、
「HSMクラスター内に十分な数のHSMが作成されていない」、「HSMがBusy状態」などと出力されていました。
いったん字面通りに受け取りHSMクラスター内のHSMの数を増やしたりしてみましたが、同じ個所で同じエラーが発生したためAWSサポートへ調査を依頼しました。
サポート回答
上記の問題をサポートに聞いてみたところ以下のような回答を得ました。
"AWS CloudHSMの既知の問題に関連する事象と見受けられる。
この問題はHSMへのログインをシリアルに実行するようにアプリケーション改修。もしくは同時ログインが実行される回数を減らせば回避可能"
影響: hsm2m.medium は、最新の FIPS 140-3 Level 3 要件に準拠しています。こ> のため、hsm2m.medium へのログインでは、強化されたセキュリティおよびコンプラ> イアンス要件に従う必要があり、その結果として遅延が増加します。
回避策: 可能であれば、ログイン中にレイテンシーが長くなるのを避けるため、同じ> アプリケーションにおいてログインリクエストをシリアル化します。複数のログイン> リクエストが並行に実行されると、レイテンシーが増加します。
アプリの開発元に聞いてみた
現行システムに近い設定が望ましいという顧客要望があり、アプリケーション改修の方向で調整するため、開発者との打ち合わせを設定しました。
発生した事象とサポートから提案された対応策について説明し、改修を依頼しましたが、ほかの優先度が高い改修で立て込んでおり年度内のアプリケーション改修は不可能とのことでした。
思いついた解決策
なんとなくApacheのドキュメントを眺めていたところ以下の文言が目に留まりました。
MinSpareServers よりも少ない数がアイドルであれば、 親プロセスは最高で 1 秒につき 1 個の割合で新しい子プロセスを生成します。
上記から アプリ改修が難しい場合の回避策として、StartServers(サービス起動時のApacheの子プロセス数)を MinSpareServers(Apacheの子プロセスの希望最少個数)より小さい値にすれば、サービス起動後に不足しているプロセスを段階的に起動できる=HSMへのログインが分散して行われるようになるのではないかと考えました。
設定変更内容
具体的には以下のように設定を変更しました。
StartServers 16
MaxSpareServers 16
MinSpareServers 16
StartServers 4 #この値を16から4へ変更
MaxSpareServers 16
MinSpareServers 16
この設定のポイントは、「Apache起動時に最初の4プロセスは即座に作り、残りの12本はApacheがインターバルを置いて作る」点にあります。
Apacheを起動すると prefork のプロセス生成のルールに則り、
- 起動直後は StartServers 分だけプロセスを作る
- MinSpareServers で設定した値を満たさない場合、不足分のプロセスを補充する
補充の際「1秒間に1つ、次は2個、その次は4個……」のように指数関数的、かつ秒単位のインターバルを置いて生成する
この仕様のおかげで、HSMへのログインリクエストが以下のように分散されるようになりました。
……
0秒目: サービス起動 4セッションログイン
1秒目: 1セッションログイン
2秒目: 2セッションログイン
3秒目: 4セッションログイン
……
結果として、HSMへの同時ログインによる負荷を抑えつつ、最終的に目標とする16プロセスの待機状態を作り出すことに成功しました。
最後に
稀なケースかと思いますが誰かの参考になれば幸いです。
ご覧いただきありがとうございました。