🔑

Vault Secrets sync を利用して、Vault に登録したシークレットをGitHub Actions のシークレットに同期する

2023/12/07に公開

HashiCorp プロダクトに関する記事を書いていこうと思っております。最初はタイトルにある Vault Secrets sync に関する内容を記載していきたいと思います。

What's Vault Secrets sync

Vault Secrets sync とは Vault Enterprise v1.15 から利用出来る様になった新機能です。

https://developer.hashicorp.com/vault/docs/sync

Notes: 2023年12月5日現在においては、Beta 版になりますので、本番環境でのご利用はお控え下さい。

この機能を利用することで、アプリ側はアプリが稼働しているクラウドや SaaS ネイティブのシークレットマネージャーを利用し、Vault で管理されているシークレットを利用することが可能になります。
また、シークレット管理に関しては、Vault で一元的にしっかりと管理する事で、シークレットのバージョン管理等従来通り出来るため、アプリケーション開発者、シークレット管理者、双方にメリットのある機能になっています。

現在サポートされている Secrets sync のターゲット先としては、以下になります。

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

ここではこちらのイベントのライトニングトークで利用するデモを作成した際の手順を記載していきます。
https://www.event-info.com/githubuniverserecap/

設定自体は非常に簡単ですので、Vault Secrets sync をお使いになる際の参考にしてみてください。

Prepare for Vault Secrets sync with GitHub Actions

Vault v1.15 以降、かつ Vault Enterprise の環境が必要になります。今回は、HCP Vault を利用し、Vault Secrets sync の環境を準備しました。
https://developer.hashicorp.com/hcp/docs/vault

HCP Vault は Vault クラスタを HashiCorp マネージドで提供している SaaS 版 Vault になります。HCP Vault で利用されている Vault Edition は下記のドキュメントの通り、Vault Enterprise になります。
https://developer.hashicorp.com/hcp/docs/vault#self-managed-vs-hcp-vault-cluster

現在、HCP Vault では v1.15.2 が利用出来る様になっているため、HCP Vault の環境を用いて、Vault Secrets sync の環境をセットアップしました。

Setup

設定手順は公式ドキュメントに記載のある通り、実施していけば問題なくいくと思います。
https://developer.hashicorp.com/vault/docs/sync/github

KV-v2 secrets engine

今回は、KV-v2 シークレットエンジンを用いて作成した github-actions というマウントポイント配下に作成した dockerhub というシークレットを GitHub の Secrets と同期させます。

mount point for vault secrets sync
$ vault secrets list
Path               Type            Accessor                 Description
----               ----            --------                 -----------
github-actions/    kv              kv_bba94bfa              secrets sync for github actions
secret_name for vault secrets sync
$ vault kv list github-actions/
Keys
----
dockerhub

dockerhub の中には以下の様なキー(.data.data.accesstoken, .data.data.username)を持ったシークレット情報を保存しています。

vault kv get -format=json github-actions/dockerhub
{
  "request_id": "d50330bf-08bb-5427-d461-bc94680d27fe",
  "lease_id": "",
  "lease_duration": 0,
  "renewable": false,
  "data": {
    "data": {
      "accesstoken": "xxxx",
      "username": "xxxx"
    },
    "metadata": {
      "created_time": "2023-11-29T03:20:24.20127561Z",
      "custom_metadata": null,
      "deletion_time": "",
      "destroyed": false,
      "version": 5
    }
  }
}

Destination setting

このシークレット情報を GitHub と同期させるために、先ず Destination を設定します。Destination はサポートされている同期先のターゲットを意味します。Destination と Vault がやり取りを行うための設定をしていきます。

GitHub 側のアクセストークンが access_token パラメータとして必要になりますが、ドキュメントに記載がある通り、ターゲット先の GitHub のリポジトリに対して以下の権限を付与し、生成します。

you will need an access token which has access to the repository you want to manage secrets for and write permissions on the repository's actions secrets. In the list of GitHub permissions, this is simply called "Secrets". Choosing this will automatically include read-only Metadata.

必要な情報が揃ったら以下の様に Destination 設定を行います。

vault write sys/sync/destinations/gh/demo-dest\
  access_token="$FINE_GRAINED_TOKEN" \
  repository_owner="$OWNER" \
  repository_name="$REPO_NAME"

Association setting

続いて、Association を設定していきます。
Association は設定された Destination に対して、Vault の KV-v2 シークレットを紐付ける事で設定を行います。
一つの Destination に対して、任意の数の Association を持たせる事が可能です。

今回は、KV-v2 シークレットエンジンを用いて作成した github-actions というマウントポイント配下に作成した dockerhub というシークレットを Association として定義します。

以下のコマンドで Association を設定します。

vault write sys/sync/destinations/gh/demo-dest/associations/set \
  mount=github-actions secret_name=dockerhub

Association が完了すると同期設定されたシークレットのステータス (.data.associated_secrets.kv_bba94bfa/dockerhub.sync_status) が SYNCED になります。

vault read sys/sync/destinations/gh/demo-dest/associations/ -format=json
{
  "request_id": "fa8df6e4-809d-fc7b-3d66-06cc296af775",
  "lease_id": "",
  "lease_duration": 0,
  "renewable": false,
  "data": {
    "associated_secrets": {
      "kv_bba94bfa/dockerhub": {
        "accessor": "kv_bba94bfa",
        "secret_name": "dockerhub",
        "sync_status": "SYNCED",
        "updated_at": "2023-11-29T03:20:24.584927939Z"
      }
    },
    "store_name": "demo-dest",
    "store_type": "gh"
  }
}

Association として定義した Vault 側のシークレットを更新した場合、Destination 側にも更新が反映されたかどうかは、sync_statusupdated_at から判断する事が可能です。

GitHub の方はと言うと、Vault Secrets sync の Destination 設定で指定したリポジトリの Settings -> Secrets and variables -> Actions の Repository secrets に登録されます。

GitHub へ登録されるシークレットの名前ですが、VAULT_ の後に、Association 設定時に mount で指定した KV-v2 シークレットエンジンのアクセサ (kv_bba94bfa)、secret_name に指定したシークレット名が続いた形で生成されます。

Use in GitHub Actions

GitHub Actions から利用していきますが、以下が GitHub 側の制約としてあります。
https://developer.hashicorp.com/vault/docs/sync/github#security

GitHub only supports single value secrets, so KVv2 secrets from Vault will be stored as a JSON string. In the example above, the value for secret "my-secret" will be synced to GitHub as the JSON string {"foo":"bar"}.

そのため、GitHub Actions のワークフローから Vault Secrets sync で同期されたシークレットを利用するためには、JSON 形式で値が登録されている事を前提に利用する必要があります。

ライトニングトークのデモ環境においては、以下の様に指定していました。

actions-workflow.yaml
name: Build and Push Docker Image

on: [ workflow_dispatch ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          registry: docker.io
          username: ${{ fromJSON(secrets.VAULT_KV_BBA94BFA_DOCKERHUB).username }}
          password: ${{ fromJSON(secrets.VAULT_KV_BBA94BFA_DOCKERHUB).accesstoken }}

      - name: Build and Push Image
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: ${{ fromJSON(secrets.VAULT_KV_BBA94BFA_DOCKERHUB).username }}/demo-logo-gallery:latest
          platforms: linux/amd64, linux/arm64

Summary

Vault にシークレットを一元的に管理し、シークレットのバージョン管理を行いつつ、Vault に登録したシークレットをクラウドや SaaS 側のネイティブなシークレットマネージャーに One-way で同期出来る機能、Vault Secrets sync をリリースしました。

シークレットは Vault でしっかりと管理しつつ、アプリからはネイティブなシークレットマネージャーをそのまま利用でき、アプリの改修が少なく、シークレット運用者、アプリ開発者それぞれに嬉しい機能です。

ご興味ございましたら、是非お試し下さい!

References

Discussion