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 作業が必要だったので、それと同じ役割なのでしょう。
[Enable] を押すと警告文が表示されるので、チェックをいれて [Confirm] を選択。
するとエラーになってしまいました。
Vault の画面にも表示されていますが、HCP Vault Dedicated で Secrets Sync を使うには Plus tier
のクラスタが必要です。
既に用意していたクラスタは検証用としてコストが最も低い Development tier
、かつクラスタサイズも最も小さい Extra-small
で作っていました。
Plus tier のクラスタを作成
というわけで、Plus tier
のクラスタを作り直します。
Vault tier のうち Plus tier
は機能の制限がない最上位、コストも割高です。
Plus tier
の場合、選べるクラスタサイズは Small
からとなっていて、その点もコスト高の要因に。
Plus tier
で作り直したクラスタで再度 Secrets Sync を有効化すると無事に成功。
[Create first destination] ボタンが出てくるので、このボタンから同期先を設定していきます。
v1.18.1 で同期先に設定できるのは以下。
- AWS Secrets Manager
- Azure Key Vault
- Google Secret Manager
- GitHub Actions
- Vercel Project
今回は Azure Key Vault と GitHub Actions を同期先として設定してみます。
Azure Key Vault への同期
Azure Key Vault への同期設定には Azure Key Vault にアクセスするための URI と、HCP Vault Dedicated が Azure リソースへアクセスする際に利用する認証情報となるサービスプリンシパルが必要です。
まずは Azure Key Vault を作成します。 作成時の設定はデフォルトから変えていません。
アクセス構成もデフォルトのまま。
パブリックアクセスは有効化しておきます。
次に Microsoft Entra ID の「アプリの登録」からサービスプリンシパルを作成します。
現在はフェデレーション資格情報に対応していないので、サービスプリンシパルにシークレットを作成します。
作ったサービスプリンシパルが Azure Key Vault のシークレットを管理できるようにロールを付与します。 今回は「キーコンテナー管理者」を割り当てました。
Secrets Sync の Destination 設定に戻って、Azure Key Vault の URI とサービスプリンシパルの情報を入力していきます。
Granularity: Secret path
追加設定の Secret sync granularity では Vault に格納したシークレットをどの粒度で同期するかを [Secret path] と [Secret key] の 2 種類から選びます。
[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] を選びます。
同期先の設定が終わったら、同期したい Vault シークレットを指定します。
クラスタ内で有効になっている KV シークレットエンジンのマウントパス (secret/
) とシークレット (sample-secret
) を選びます。
同期設定のシークレット一覧を見ると、さきほど指定したシークレット secret/sample-secret
が Synced になっています。
Azure Key Vault のシークレットを見てみると vault-kv-0b11dae9-sample-secret
というシークレットが登録されていました。
シークレット値を見てみると Vault シークレットのバリューと一致していました。 ちゃんと同期されてそうです。
Granularity: Secret key
今度は Secret sync granularity に [Secret key] を設定した同期設定を作ってみます。
さきほどと同じく Secret name template は未入力でしたが、-{{ .SecretPath }}-{{ .SecretKey }}
が追加されている点が異なります。
Azure Key Vault を見ると新しくシークレットが追加されていました。 1 つの Azure Key Vault に対して複数の Vault シークレットを同期できるようです。
シークレット値は Vault Is The Way
となっていて、Vault シークレットの値がそのまま入っています。
アプリ側で参照した値をそのまま使えそうなので、個人的にはシークレットの同期方法は [Secret key] のほうが好みです。
シークレットの更新
Vault シークレットの値を更新して Azure Key Vault に反映されるかも試してみました。 Vault の UI からシークレット値を更新します。
すぐに Azure Key Vault のシークレットに新しいバージョンが追加されていました。
シークレット値も更新したものと一致しています。
シークレットの更新も問題ないようです。 履歴も Vault と Azure Key Vault の両方で残るようです。
カスタムタグ
追加設定にカスタムタグもあったため試してみました。
同期設定に hoge: fuga
というタグを追加します。
Azure Key Vault のシークレット内にカスタムタグが設定されていました。
hashicorp:vault
というタグ名もあります。
こちらは組み込みタグのようですが、タグ値がタグ名に含まれてしまっているようで不具合な気がします。
GitHub Actions への同期
GitHub Actions 宛の同期も設定してみました。 同期先のリポジトリ情報やアクセストークンを設定します。 追加設定の Secret sync granularity は [Secret key]、Secret name template は未設定、カスタムタグは設定項目がありませんでした。
同期先のリポジトリを作成します。 プライベートリポジトリでも大丈夫です。
Vault クラスタが使うアクセストークンを作成します。 さきほど作成したリポジトリのみ対象にしています。
権限は Secrets への Read and write
が必須です。
Metadata は勝手に付与されます。
同期設定ができました。
同期したいシークレットを選択します。
すると GitHub リポジトリ内の [Actions secrets] に VAULT_KV_0B11DAE9_SAMPLE-SECRET_FIRST_SECRET
というシークレットが追加されました。
GitHub Actions のワークフローでどうにかこうにかするとシークレット値も確認できますが、今回はそこまでしませんでした(会社ブログのほうでは確認してます)。
GitHub Actions のほうにも問題なく同期できています。
気になるポイント
HCP Vault Dedicated でも使えるようになった Secrets Sync ですが、気になるポイントがいくつかあります。
プライベートエンドポイント
まずは「プライベートエンドポイント経由で Azure Key Vault にアクセスできるのか」という点。 HCP Vault Dedicated では Azure に対してプライベートアクセスでの動的シークレットができない、という既知の問題があります。
結論を言うと、Secrets Sync はプライベートエンドポイント経由で Azure Key Vault にシークレットを同期できません。
Azure にプライベートエンドポイントを作成した際にプライベート DNS ゾーンにレコードを追加できます。 仮想ネットワークリンクを HVN (HashiCorp Virtual Netowrk) に対して設定できれば Vault クラスタからプライベートアクセスできそうですが、現状は仮想ネットワークリンクを設定できません。
プライベート IP アドレスを直接設定してみても Vault クラスタ側で弾かれました。 こちらは登録できたとしても繋がらないとは思いますが。
プライベート 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 の項目がカウントされていました。
Secrets Sync の設定は 3 つありますが、このうち 2 つは同じ Vault シークレットに対する設定なのでクライアント数としてカウントされるものは 2 つです。
このスクショでは [Total secrets] が None になっていますが、本来はここにクライアント数としてカウントされるシークレットの数が表示されます。 スクショ撮り損ねましたが設定後にしばらく時間が経てばちゃんと表示されていました。
HCP の課金を確認するページでは Plus tier にクライアント数課金が発生しているのを確認できます。 クラスタ立ち上げて 2 時間も使ってなかったですが Development tier (Extra-Small) と比べると Plus tier (Small) は高いですね。
Secrets Sync はとても便利な機能ですが、HCP Vault Dedicated で使う場合はクライアント数課金も想定して設定が必要ですね。