HashiCorp Vault に Secrets Sync という機能があります。 これは Vault で管理しているシークレットを Azure Key Vault などのクラウドプロバイダが持つシークレットマネージャーや GitHub Actions などの開発ツールに同期できるものです。

Secrets Sync は Vault Enterprise で使えるようになり、マネージドサービスの HCP Vault Dedicated にもベータ機能として公開されていたんですが、不具合があったのかしばらくして利用できなくなっていました。

その後、2024年11月11日にリリースされた v1.18.1 で HCP Vault Dedicated の Secrets Sync が復活、正式に利用できるようになったので試してみました。

Secrets Sync を有効化

検証用の HCP Vault Dedicated クラスタを立てていたので、まずはそのクラスタで Secrets Sync を試しました。 HCP Vault Dedicated にログインすると Secrets Sync のメニューが追加されています。

Secrets Sync を使うには事前に有効化が必要なようです。 Vault Enterprise では自前で Secrets Sync の activate 作業が必要だったので、それと同じ役割なのでしょう。

alt text

[Enable] を押すと警告文が表示されるので、チェックをいれて [Confirm] を選択。

alt text

するとエラーになってしまいました。

alt text

Vault の画面にも表示されていますが、HCP Vault Dedicated で Secrets Sync を使うには Plus tier のクラスタが必要です。 既に用意していたクラスタは検証用としてコストが最も低い Development tier、かつクラスタサイズも最も小さい Extra-small で作っていました。

Plus tier のクラスタを作成

というわけで、Plus tier のクラスタを作り直します。 Vault tier のうち Plus tier は機能の制限がない最上位、コストも割高です。

alt text

Plus tier の場合、選べるクラスタサイズは Small からとなっていて、その点もコスト高の要因に。

alt text

Plus tier で作り直したクラスタで再度 Secrets Sync を有効化すると無事に成功。 [Create first destination] ボタンが出てくるので、このボタンから同期先を設定していきます。

alt text

v1.18.1 で同期先に設定できるのは以下。

  • AWS Secrets Manager
  • Azure Key Vault
  • Google Secret Manager
  • GitHub Actions
  • Vercel Project

alt text

今回は Azure Key Vault と GitHub Actions を同期先として設定してみます。

Azure Key Vault への同期

Azure Key Vault への同期設定には Azure Key Vault にアクセスするための URI と、HCP Vault Dedicated が Azure リソースへアクセスする際に利用する認証情報となるサービスプリンシパルが必要です。

まずは Azure Key Vault を作成します。 作成時の設定はデフォルトから変えていません。

alt text

アクセス構成もデフォルトのまま。

alt text

パブリックアクセスは有効化しておきます。

alt text

次に Microsoft Entra ID の「アプリの登録」からサービスプリンシパルを作成します。

alt text

現在はフェデレーション資格情報に対応していないので、サービスプリンシパルにシークレットを作成します。

alt text

作ったサービスプリンシパルが Azure Key Vault のシークレットを管理できるようにロールを付与します。 今回は「キーコンテナー管理者」を割り当てました。

alt text

Secrets Sync の Destination 設定に戻って、Azure Key Vault の URI とサービスプリンシパルの情報を入力していきます。

alt text

Granularity: Secret path

追加設定の Secret sync granularity では Vault に格納したシークレットをどの粒度で同期するかを [Secret path] と [Secret key] の 2 種類から選びます。

alt text

[Secret path] は指定した Vault シークレットのキーバリューすべてを Azure Key Vault の 1 つのシークレットに同期する設定です。 例えば、secret/sample-secret というパスのシークレットにキー first-secret、バリュー Vault Is The Way が含まれている場合、Azure Key Vault にはシークレット値が {"first-secret":"Vault Is The Way"} となるシークレットが登録されます。 シークレット値に Vault シークレットのキーバリューが含まれる形です。

一方、[Secret key] のほうは Vault シークレットのキーが Azure Key Vault の 1 つのシークレットに対応します。 さきほどの例でいうと、Azure Key Vault にキーの first-secret に対応したシークレットが作成されて、そのシークレット値は Vault Is The Way になります。

両方とも Azure Key Vault に作成されるシークレットの名前は Secret name template という設定に依存するようで、未設定の場合は自動的に一意となるシークレット名が使われます。

今回は [Secret path] を選びます。

alt text

同期先の設定が終わったら、同期したい Vault シークレットを指定します。 クラスタ内で有効になっている KV シークレットエンジンのマウントパス (secret/) とシークレット (sample-secret) を選びます。

alt text

同期設定のシークレット一覧を見ると、さきほど指定したシークレット secret/sample-secret が Synced になっています。

alt text

Azure Key Vault のシークレットを見てみると vault-kv-0b11dae9-sample-secret というシークレットが登録されていました。

alt text

シークレット値を見てみると Vault シークレットのバリューと一致していました。 ちゃんと同期されてそうです。

alt text

Granularity: Secret key

今度は Secret sync granularity に [Secret key] を設定した同期設定を作ってみます。

alt text

さきほどと同じく Secret name template は未入力でしたが、-{{ .SecretPath }}-{{ .SecretKey }} が追加されている点が異なります。

alt text

Azure Key Vault を見ると新しくシークレットが追加されていました。 1 つの Azure Key Vault に対して複数の Vault シークレットを同期できるようです。

alt text

シークレット値は Vault Is The Way となっていて、Vault シークレットの値がそのまま入っています。

alt text

アプリ側で参照した値をそのまま使えそうなので、個人的にはシークレットの同期方法は [Secret key] のほうが好みです。

シークレットの更新

Vault シークレットの値を更新して Azure Key Vault に反映されるかも試してみました。 Vault の UI からシークレット値を更新します。

alt text

すぐに Azure Key Vault のシークレットに新しいバージョンが追加されていました。

alt text

シークレット値も更新したものと一致しています。

alt text

シークレットの更新も問題ないようです。 履歴も Vault と Azure Key Vault の両方で残るようです。

カスタムタグ

追加設定にカスタムタグもあったため試してみました。 同期設定に hoge: fuga というタグを追加します。

alt text

Azure Key Vault のシークレット内にカスタムタグが設定されていました。

alt text

hashicorp:vault というタグ名もあります。 こちらは組み込みタグのようですが、タグ値がタグ名に含まれてしまっているようで不具合な気がします。

GitHub Actions への同期

GitHub Actions 宛の同期も設定してみました。 同期先のリポジトリ情報やアクセストークンを設定します。 追加設定の Secret sync granularity は [Secret key]、Secret name template は未設定、カスタムタグは設定項目がありませんでした。

alt text

同期先のリポジトリを作成します。 プライベートリポジトリでも大丈夫です。

alt text

Vault クラスタが使うアクセストークンを作成します。 さきほど作成したリポジトリのみ対象にしています。

alt text

権限は Secrets への Read and write が必須です。 Metadata は勝手に付与されます。

alt text

同期設定ができました。

alt text

同期したいシークレットを選択します。

alt text

すると GitHub リポジトリ内の [Actions secrets] に VAULT_KV_0B11DAE9_SAMPLE-SECRET_FIRST_SECRET というシークレットが追加されました。 GitHub Actions のワークフローでどうにかこうにかするとシークレット値も確認できますが、今回はそこまでしませんでした(会社ブログのほうでは確認してます)。

alt text

GitHub Actions のほうにも問題なく同期できています。

気になるポイント

HCP Vault Dedicated でも使えるようになった Secrets Sync ですが、気になるポイントがいくつかあります。

プライベートエンドポイント

まずは「プライベートエンドポイント経由で Azure Key Vault にアクセスできるのか」という点。 HCP Vault Dedicated では Azure に対してプライベートアクセスでの動的シークレットができない、という既知の問題があります。

結論を言うと、Secrets Sync はプライベートエンドポイント経由で Azure Key Vault にシークレットを同期できません。 alt text

Azure にプライベートエンドポイントを作成した際にプライベート DNS ゾーンにレコードを追加できます。 仮想ネットワークリンクを HVN (HashiCorp Virtual Netowrk) に対して設定できれば Vault クラスタからプライベートアクセスできそうですが、現状は仮想ネットワークリンクを設定できません。

alt text

プライベート IP アドレスを直接設定してみても Vault クラスタ側で弾かれました。 こちらは登録できたとしても繋がらないとは思いますが。

alt text

プライベート DNS ゾーンに登録されたレコードを HCP でも登録できれば繋がると思いますが、現状そのような機能は追加される気配がありません。

Azure Key Vault に対して Secrets Sync を使う場合は Azure Key Vault のパブリックアクセスを許可する必要があります。

クライアント数

HCP Vault Dedicated は Tier によってはクライアント数による課金も発生します。 クラスタ構築直後の admin トークンだけであればクライアント数は 1 になります。 Vault クラスタにエンティティを追加するとクライアント数もカウントされていきます。

Secrets Sync のドキュメントによると、Secrets Sync を設定したシークレットはクライアント数としてカウントされてしまうようです。

Secrets Sync 設定後に [Client Count] 画面を見てみると、確かに Secret Sync の項目がカウントされていました。

alt text

Secrets Sync の設定は 3 つありますが、このうち 2 つは同じ Vault シークレットに対する設定なのでクライアント数としてカウントされるものは 2 つです。

このスクショでは [Total secrets] が None になっていますが、本来はここにクライアント数としてカウントされるシークレットの数が表示されます。 スクショ撮り損ねましたが設定後にしばらく時間が経てばちゃんと表示されていました。

alt text

HCP の課金を確認するページでは Plus tier にクライアント数課金が発生しているのを確認できます。 クラスタ立ち上げて 2 時間も使ってなかったですが Development tier (Extra-Small) と比べると Plus tier (Small) は高いですね。

alt text

Secrets Sync はとても便利な機能ですが、HCP Vault Dedicated で使う場合はクライアント数課金も想定して設定が必要ですね。