Vault

Vault を使う CI/CD パターン: ビルド/デプロイ時のシークレット取得

2026-04-19
NicheeLab編集部

リポジトリやランナーにシークレットを残さず、短寿命トークンと動的シークレットで使い切るのが基本です。Vault は CI/CD と相性がよく、認証・取得・監査まで一貫して扱えます。

本稿は、公式ドキュメントの動作に基づく安定パターンだけを扱います。プロバイダやバージョン差異に左右されにくい設計と、運用/試験で問われやすい論点を優先します。

パイプライン全体像と責務分離

CI ランナーは Vault に短寿命で認証し、必要最小限のシークレットだけをその場で取得して消費します。リポジトリ・アーティファクト・ログにはシークレットを保存しません。ステージ間の受け渡しが必要な場合はレスポンスラッピングを使い、ラップトークンの TTL を短くします。

ビルド(依存取得、コンテナビルド)とデプロイ(Kubernetes/Helm 等)で取得経路を分け、権限を分離します。ビルドは読み取り中心、デプロイは環境への投入を担い、両者のポリシーを分けて最小権限を徹底します。

  • シークレットは pull 型(ランナー/Pod 側から都度取得)で扱い、push 配布を避ける
  • 短寿命トークン+上限 TTL(max_ttl)を設定し、更新可能性を必要最小限に
  • 監査ログ(audit device)を必ず有効化し、パイプラインの request_id と紐づける

CI→Vault→Secret Engine→実行環境のデータフロー

JWT/OIDC/AppRolesecretsauto-auth/sidecar/CSICI RunnerBuild / DeployVaultAuth + PolicyBuild Stagee.g. image buildKV v2DynamicDB / CloudDeploy StageHelm / ArgoK8s Workload (Pod)Vault Agent / InjectorCI Runner から Vault で認証し、KV/動的シークレットを Build/Deploy に供給

レスポンスラッピングでステージ間受け渡し(例: kv データを 5 分ラップ)

vault write -field=wrapping_token -wrap-ttl=5m sys/wrapping/wrap \
  secret=@<(vault kv get -format=json kv/build/npmrc | jq -c '.data.data')

# 受け取り側ステージ(ラップ解除は 1 回のみ有効)
vault write sys/wrapping/unwrap wrapping_token=$WRAPPING_TOKEN > unwrapped.json
cat unwrapped.json | jq '.'

認証パターンの選定(AppRole / OIDC(JWT) / Kubernetes)

CI から Vault への入口は運用性と信頼境界で選びます。SaaS CI(GitHub Actions 等)では OIDC(JWT) が第一候補。自己管理ランナーでは AppRole、Kubernetes 内の Pod からは Kubernetes 認証が自然です。

いずれもポリシーで最小権限を定義し、トークンの TTL と max_ttl を短く保ちます。OIDC はフェデレーションで長期共有秘密を不要にでき、監査面でもメリットがあります。

  • OIDC: 外部 IdP からの署名付き JWT を Vault が検証(ロールでクレーム制約)
  • AppRole: ロール ID とシークレット ID を用いたサーバ間向け。レスポンスラッピング併用が前提
  • Kubernetes: ServiceAccount JWT を Vault が検証。Namespace/SA 名でロール制約
パターン主な適用先強み注意点
OIDC (JWT)SaaS CI(GitHub Actions、GitLab)長期共有鍵不要・監査しやすいIdP クレーム設計とロール制約が肝
AppRole自己管理ランナー/オンプレシンプル・依存少ないSecretID の保護と配布、ラッピング必須
KubernetesPod(Injector/CSI/Agent)Pod 単位で最小権限・自動ローテSA/JWT のスコープ管理

GitHub Actions OIDC で Vault にログインして KV を取得

jobs:
  build:
    permissions:
      id-token: write   # OIDC 発行に必要
      contents: read
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Get OIDC token
        id: oidc
        run: echo "token=$(curl -H 'Authorization: bearer $ACTIONS_ID_TOKEN' 2>/dev/null)" >> $GITHUB_OUTPUT
        env:
          ACTIONS_ID_TOKEN: ${{ steps.generate_token.outputs.token }}
      - name: Vault Login (JWT)
        env:
          VAULT_ADDR: https://vault.example.com
          JWT: ${{ steps.oidc.outputs.token }}
        run: |
          vault write -format=json auth/jwt/login role=gha-build jwt="$JWT" > login.json
          export VAULT_TOKEN=$(jq -r .auth.client_token login.json)
          vault kv get -format=json kv/build/npmrc | jq -r .data.data.authToken >> $GITHUB_ENV

ビルド段階のシークレット取得(依存取得・コンテナビルド)

npm/pip/maven の資格情報はファイルに一時的に出力し、ジョブ終了時に削除します。コンテナビルドでは Docker BuildKit の secrets 機能を使い、Dockerfile に平文で残さないのが安全です。

CI トークンは非更新・短 TTL が基本。リトライを考慮しつつも max_ttl を短く設定して、ビルドキャッシュや再実行で漏れにくい状態を保ちます。

  • Dockerfile への ARG 埋め込みは避け、--secret を使う
  • npmrc/pypirc はワークスペース外に書かない、ログに出さない
  • 必要なら動的シークレット(例: 一時 DB ユーザ)をテストのたびに払い出し・廃棄

BuildKit で Vault 取得シークレットを安全に渡す例

# 1) CI で Vault から取得しファイル化(短命)
vault kv get -format=json kv/build/npmrc | jq -r .data.data.npmrc > .npmrc.tmp

# 2) BuildKit 経由で Dockerfile に渡す(イメージには残らない)
DOCKER_BUILDKIT=1 docker build \
  --secret id=npmrc,src=.npmrc.tmp \
  -t app:build .

# Dockerfile (抜粋)
# syntax=docker/dockerfile:1.6
RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc \
    npm ci && rm -f /root/.npmrc

# 3) 後始末
shred -u .npmrc.tmp

デプロイ段階:Kubernetes への安全な供給

Kubernetes では Vault Agent Injector(サイドカー)や CSI Driver を使い、Pod 内のファイルとしてシークレットを供給します。etcd に平文を置かないため、Kubernetes Secret 単体より安全です。

Kubernetes 認証メソッドで ServiceAccount をロールにひも付け、Pod 単位の最小権限を実現します。ローテーションは Agent が自動更新し、アプリはファイル監視で再読込する設計が実務的です。

  • Injector: 手軽に導入、テンプレートでファイル生成、Sidecar で自動更新
  • CSI: volume としてマウント、Secret の種類が多い環境で管理しやすい
  • Helm の values にシークレットを直接入れない(テンプレート or 外部参照)

Vault Agent Injector を用いた Deployment 例(テンプレート生成)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  annotations:
    vault.hashicorp.com/agent-inject: "true"
    vault.hashicorp.com/role: "k8s-web"
    vault.hashicorp.com/agent-inject-secret-config.yaml: "kv/app/config"
    vault.hashicorp.com/agent-inject-template-config.yaml: |
      {{- with secret "kv/app/config" -}}
      DB_URL={{ .Data.data.DB_URL }}
      API_KEY={{ .Data.data.API_KEY }}
      {{- end -}}
spec:
  replicas: 2
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      serviceAccountName: web-sa
      containers:
        - name: app
          image: ghcr.io/acme/web:1.0
          envFrom:
            - secretRef: { name: dummy } # 実際の値はファイルから読み込む
          volumeMounts:
            - name: config
              mountPath: /run/secrets
      volumes:
        - name: config
          emptyDir: {}

セキュリティ強化と監査(TTL・トークン種別・ラップ・リース)

Vault にはサービストークン(更新可能)とバッチトークン(軽量・非更新)があり、CI の使い切りにはバッチトークンが適します。TTL と max_ttl を短く設定し、必要なら periodic で計画更新します。

動的シークレットはリースで管理され、ジョブ終了時に明示的に revoke するか、TTL で自動失効させます。監査デバイスは必ず有効化して、誰がどのポリシーでどのパスにアクセスしたかを記録します。

  • audit enable file file_path=/var/log/vault_audit.log を最低限有効化
  • sys/wrapping を用いた一回限りの受け渡しで漏えい面積を縮小
  • lease revoke -prefix でテスト用動的ユーザを確実に廃棄

代表的な運用コマンド(監査・トークン・リース)

# 監査ログを有効化(ファイル例)
vault audit enable file file_path=/var/log/vault_audit.log

# バッチトークン(軽量・非更新)を短 TTL で発行
vault token create -type=batch -policy=ci-readonly -ttl=15m -explicit-max-ttl=30m

# 動的シークレットの強制失効(接頭辞でまとめて)
vault lease revoke -prefix database/creds/ci-test

# レスポンスラッピング(5 分)で安全に受け渡し
vault write -wrap-ttl=5m sys/wrapping/wrap [email protected]

運用の落とし穴と SLO 設計

CI の同時実行が多いと Vault にスパイクがかかります。レート制御とコネクション再利用、Agent キャッシュを活用します。可用性要件に応じて HA(ストレージは公式推奨のバックエンド)と自動アンシールを設計します。

Vault 障害時の挙動も定義します。Injector/Agent ではキャッシュが効く範囲がありますが、強い一貫性が必要なケースではフェイルクローズ(デプロイ停止)を選ぶほうが安全です。

  • CI 側で指数バックオフと全体タイムアウトを設定
  • Agent の cache 機能と template の min_refresh 割当で負荷平準化
  • シークレット TTL とリリース時間(デプロイ窓)を整合させる

Vault Agent(auto_auth + cache)の最小構成例

auto_auth {
  method {
    type = "kubernetes"
    config = {
      role = "k8s-web"
    }
  }
  sink {
    type = "file"
    config = {
      path = "/home/vault/.token"
    }
  }
}
cache {
  use_auto_auth_token = true
}
template {
  source      = "/vault/templates/config.tpl"
  destination = "/run/secrets/config.env"
  # 更新間隔の下限を指定して過剰な再読込を抑制
  min_refresh_interval = "15s"
}

問題で確認

Ops

問題 1

CI ビルド中にユニットテスト用のデータベース資格情報が必要です。長期共有鍵は使わず、ジョブ終了後は自動的に無効化されること、ステージ間の受け渡しも安全であることが要件です。最も適切なアプローチはどれですか?

  1. 動的データベースシークレットを短 TTL で発行し、必要ならレスポンスラッピングでステージ間受け渡しを行う
  2. Git リポジトリの暗号化ファイルに資格情報を保存し、ビルドで復号する
  3. 1 か月の periodic トークンを使い回し、テストごとに再利用する
  4. Docker イメージに環境変数として埋め込み、ビルド後に削除する

正解: A

Vault の動的シークレットは短 TTL と自動失効が特長で、CI の使い切りに最適です。ステージ間は sys/wrapping を用いたレスポンスラッピングで安全に受け渡しできます。他の選択肢は長期鍵やイメージ埋め込みなど、露出リスクと監査性の面で不適切です.

よくある質問

GitHub Actions では OIDC と AppRole のどちらを使うべきですか?

原則 OIDC を推奨します。IdP からの署名付き JWT を Vault が検証するため、長期共有秘密が不要で監査もしやすいからです。自己管理ランナーや OIDC 非対応環境では AppRole を用い、SecretID はレスポンスラッピングで配布してください。

シークレットを環境変数とファイルのどちらで渡すべきですか?

ビルド・実行時ともにファイル渡しが望ましいです。環境変数はプロセスツリーやクラッシュダンプ、ログに残る可能性があります。Vault Agent/Injector のテンプレートでファイル化し、アプリは再読込可能な設計にします。

Vault 障害時にデプロイをどう扱えばよいですか?

機密性重視ならフェイルクローズ(Vault から取得できなければデプロイ中止)を選びます。可用性重視で、かつ短時間の断を許容できる場合は Agent/Injector のキャッシュを利用し、後で正規のローテに追従する方針を定めます。いずれも監査ログで痕跡を残してください。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Vault

Vault のコア概念を最短距離で理解する:Secret / Auth / Policy / Token

HashiCorp Vault Associate レベルで押さえるべきコア概念(Secret Engine、Auth ...

Vault

Vault Operations Professional: 上位資格としての範囲を実務目線で押さえる

HashiCorp Vault Operations Professional(Ops Pro)の出題範囲を、Assoc...

Vault

Vaultにおけるパスベースのルーティング: マウントとAPI構造を読み解く

HashiCorp Vaultのパスベースのルーティングを、マウント設計とAPIパスの観点から整理。Associateレ...

Vault

Vault Tokens の基礎: 認証の起点となる概念

HashiCorp Vault におけるトークンの役割、種類、ライフサイクル、ポリシー連携、設計パターンをAssocia...

Vault

Vault のトークン種類を正しく使い分ける: service / batch 実践

HashiCorp Vault Associate 向けの試験対策と実務運用を両立させた、service トークンと b...

Vaultの記事一覧 (100件)
© 2026 NicheeLab All rights reserved.