HCP Vault Dedicated を利用しているときに required index state not present というエラーメッセージが出たので、原因と対策をまとめます。

何が起きたか

HCP Vault Dedicated では KV シークレットエンジンなどのシークレット管理サービスや Transit シークレットエンジンを使った暗号化サービスを提供しています。

クライアントアプリケーションから HCP Vault Dedicated の暗号化サービスに対して復号リクエストしたときに、まれに required index state not present というエラーが返ってくることがありました。

原因

HCP Vault Dedicated のノード間のインデックス同期よりもクライアント側の Write リクエストと Read リクエストの間隔が短いことが原因でした。

少し踏み込んでみます。

HCP Vault Dedicated は内部的に Active ノードと Performance Standby ノードを持っていて、Vault クラスタに対する Write/Read リクエストは各ノードに振り分けられます。 リクエストが Active ノードに送られた場合は特に影響ないため割愛。

Write リクエストが Performance Standby ノードに送られると Active ノードに転送されます。 ドキュメントを読むと、厳密には認証や動的シークレットのリクエストのときには RPC を使って Active ノードにトークンなどの情報を書き込み、それ以外の Write リクエストは Active ノードに転送するようです。 Write リクエストが処理されると Vault の内部でインデックスが更新されます。

Write request

Read リクエストの場合はそのまま Performance Standby ノードで処理されます。 ただし、Active ノードで Write されたデータが Performance Standby ノードにレプリケーションされるまでにタイムラグがあるため、一貫性は担保されていません。

この一貫性については Vault のバージョンアップで色々対処されているようで、Vault v1.10 でサーバーサイドの一貫性担保の仕組みが導入されたようです。 Active ノードのインデックスが反映されていない Performance Standby ノードにリクエストが送られると、HTTP ステータスコード 412 とともに required index state not present というエラーが返されるようになっています。 これが今回のエラーメッセージの正体です。

Read request

「HCP Vault Dedicated はそんなにインデックスの同期が遅いの?」と思ったのですが、アプリケーションのログを見てみると、認証 (Write) と復号 (Read) のリクエストの間隔が 2ms 程度しか空いていませんでした。 世の中のシステムがどの程度の早さで同期しているかは分かりませんが、2ms でインデックスの同期が間に合っていない、しかもたまにしか起きないのなら「まぁ仕方ないよね」感もあります。

対策

Go の Vault ライブラリでは Vault から 412 エラーが返されるとリトライするようになっています。 一方、他の言語の場合は自前でリトライ処理を入れないといけない模様。

Vault Enterprise のドキュメントによると、クライアント側でリクエストヘッダーに X-Vault-Forward: active-nodeX-Vault-Inconsistent: forward-active-node をつけることで、リクエストを Active ノードに直接送ることができるようですが、HCP Vault Dedicated ではこの機能はサポートされていないようです。

そのため、HCP Vault Dedicated を使っている場合はクライアント側でリトライ処理を入れることが required index state not present エラーを回避する現実的な対策になります。

まとめ

HCP Vault Dedicated を利用する場合、クライアントの Write と Read のリクエストの間隔が短いと、Vault クラスタのインデックス同期のタイムラグによって required index state not present エラーが発生することがあります。

Vault Enterprise では Active ノードにリクエストを直接送って回避する方法があるようですが、HCP Vault Dedicated ではサポートされていないため、クライアント側でリトライ処理を入れるなどして対処しましょう。

参考情報