メインコンテンツまでスキップ

GitOps によるシークレット配信(ArgoCD + Vault)

シークレットマネージャー統合 では一般的なパターン、すなわち External Secrets Operator (ESO) を通じて、すでに運用しているシークレットマネージャーから DuoKey がシークレットを取得する方法を説明しています。このページは、多くのエンタープライズの プラットフォームチームがすでに標準採用している特定の組み合わせ、すなわち GitOps コントローラー としての ArgoCD と、シークレットストアとしての HashiCorp Vault(または OpenBao。 後述の OpenBao と Vault を参照)について、そのパターンを詳細な手順として 示したものです。

中核となる原則

Git が保持するのはポインターであり、値ではありません。 ArgoCD の役割は、Git リポジトリ内の 宣言的なマニフェスト をクラスターへ反映させることです。これらのマニフェストが記述するのは、 シークレットが どこ にあり、誰 が読み取れるかということだけです。実際のシークレットの バイト列(データベースのパスワード、署名鍵)は、Git、CI パイプライン、ArgoCD の差分を通過する ことは決してありません。それらは実行時に ESO を仲介として、Vault から Pod へ直接流れます。

何がどこに置かれるか​

Git に置かれるもの(ArgoCD 管理)Vault にのみ置かれるもの
ESO のリーダー ID のための ServiceAccount実際のシークレットの値(DB のパスワード、署名/暗号化鍵、クライアントシークレット)
SecretStore / ClusterSecretStore(Vault のアドレスと認証ロールを指し示します)—
ExternalSecret(どの Vault のパス/キーを どの Kubernetes Secret のキーにマッピングするかを宣言します)—
上記をスコープする RBAC / NetworkPolicy—

マニフェストにはシークレットのマテリアルが含まれないため、通常の Git プルリクエストの プロセスを通じて、他の GitOps 管理ワークロードとまったく同じように、安全にレビュー、差分確認、 監査ができます。

配信フロー​

GitOps によるシークレット配信
Git リポジトリSecretStore · ExternalSecret のマニフェスト — シークレットの値は含まない
同期(リコンサイル)
ArgoCDGitOps コントローラー
マニフェストを適用
OpenShift クラスター
External Secrets OperatorServiceAccount 認証 · サイドカー不要
Kubernetes 認証 · refreshInterval ごとに取得
HashiCorp Vault / OpenBao信頼できる情報源
実体化
K8s Secrettmpfs · メモリ内
envFrom
DuoKey Pod
GitOps(Git + ArgoCD)シークレットの仲介ランタイム(クラスター内)

ArgoCD は SecretStore / ExternalSecret のマニフェスト(および ESO コントローラー自体)を Git から OpenShift へ同期します。次に ESO は Kubernetes の ServiceAccount トークンを用いて Vault に直接認証し、ExternalSecret が宣言した値だけを取得して、ネイティブでメモリ上の Kubernetes Secret として実体化します。DuoKey の Pod はその Secret を他と同じように利用するだけで、Vault、ArgoCD、Git のいずれとも通信しません。

  1. プラットフォームチームが SecretStore/ExternalSecret のマニフェスト(同じ方法で管理する 場合は ESO の Helm リリース自体も)を GitOps リポジトリにコミットします。
  2. ArgoCD が変更を検知し、クラスターに適用します。他のすべてのワークロードで既に使用して いるのと同じリコンサイルループです。
  3. ESO は専用の名前空間内でコントローラーとして稼働し、Kubernetes 認証方式を用いて Vault に認証します。すなわち、SecretStore に指定された投影済み ServiceAccount トークンを提示し、Vault がそれを OpenShift API に対して検証したうえで、構成済みのポリシーに スコープされた短命の Vault トークンを発行します。
  4. ExternalSecret の refreshInterval に従って、ESO は宣言されたパスを読み取り、ネイティブな Kubernetes Secret を書き込み(または更新)します。
  5. DuoKey の Pod は通常の envFrom を通じてその Secret を利用します。Vault、ArgoCD、Git の 存在を Pod が意識することはありません。
なぜ Vault Agent Injector のサイドカーを使わないのか

サイドカーパターン(変更用 Webhook がアプリケーション Pod に init コンテナとサイドカーを 注入する方式)は、シークレットをファイルとして出力し、それを環境変数として読み込むために イメージ内のシェルを前提とします。DuoKey のコンテナイメージは、シェルもパッケージ マネージャーも持たない 固定の非 root ユーザーで動作するため、その橋渡しは存在しません。 さらに、OpenShift の restricted SCC は注入されたコンテナに追加の制約を課します(任意の UID、 特権モードは既定で無効)。上記のコントローラー/プル型のパターンは DuoKey の Pod 内に何も 必要としないため、これらの最小構成イメージ上でもそのまま機能します。

Vault 側のセットアップ​

Vault の管理者は、クラスターごとに一度 Kubernetes 認証方式を有効化し、DuoKey が必要とする パスのみに、それ以上広げることなくポリシーをスコープします。

vault auth enable kubernetes

vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc:443"

vault policy write duokey-read - <<'EOF'
path "secret/data/duokey/*" {
capabilities = ["read"]
}
EOF

vault write auth/kubernetes/role/duokey \
bound_service_account_names=duokey \
bound_service_account_namespaces=duokey \
policies=duokey-read \
ttl=1h

ESO 自体のために、Vault のトークンや root 資格情報が Kubernetes Secret として保存される ことは一切ありません。信頼の基点は ServiceAccount の投影済みトークンであり、これは OpenShift がすでに自動的にローテーションしています。

OpenShift のマニフェスト(ArgoCD 管理)​

これらは GitOps リポジトリが保持するオブジェクトです。ArgoCD は他の Application と まったく同じようにこれらを適用します。

ClusterSecretStore​

apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.corp.example.local:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "duokey"
serviceAccountRef:
name: duokey
namespace: duokey

ExternalSecret​

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: duokey-bootstrap-secrets
namespace: duokey
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: duokey-bootstrap-secrets
data:
- secretKey: DATABASE_URL
remoteRef:
key: duokey/database
property: url
- secretKey: JWT_SECRET
remoteRef:
key: duokey/signing
property: jwt_secret
- secretKey: ENCRYPTION_KEY
remoteRef:
key: duokey/signing
property: encryption_key
- secretKey: HMAC_KEY
remoteRef:
key: duokey/signing
property: hmac_key

続いて DuoKey の Deployment が envFrom を介して duokey-bootstrap-secrets を参照します。 そこに含められる変数の一覧については Cockpit の構成 を参照してください。

2 つの異なるシークレットのスコープ — 混同しないでください

このページで扱うのは、DuoKey 自身の プラットフォームのブートストラップシークレット (データベース DSN、署名/暗号化鍵)であり、Pod の起動時に一度だけ配信される、小さく厳密に スコープされた Vault のパスです。これは テナントが構成するシークレットマネージャー (テナント自身の Vault/HSM 資格情報。KMS 統合のために DuoKey Cockpit コンソール内から入力 します)とは別の関心事です。後者のデータ経路は シークレットマネージャー統合 で一般論として説明されており、 この ArgoCD 管理のフローを通過することは決してありません。

Cockpit から Vault へ直接接続する方式をご希望ですか

上記の ESO パターンの代わりに、DuoKey がプロセス起動時にブートストラップ用の AppRole 資格情報を 使って自ら Vault/OpenBao に接続するように構成することもできます。どちらのパターンも フェイルクローズであり、完全にサポートされています。両者を比較してプラットフォームチームの 方針に合う方を選択するには、 Cockpit の構成 → シークレットの取得元 を参照してください。

OpenShift 固有の注意事項​

  • SCC — ESO 自身の Pod は、デフォルトの restricted/restricted-v2 SCC の下で問題なく 動作します(特権モードもホストアクセスも不要です)。その ServiceAccount がクラスターの デフォルト SCC を使用できるようにする以上のことは必要ありません。
  • Webhook の証明書 — ESO のアドミッション Webhook には TLS 証明書が必要です。ESO 組み込みの cert-controller に管理させる(デフォルト)か、クラスターですでに cert-manager を稼働させて いる場合はそちらに接続してください。
  • etcd への露出 — 実体化された Secret はネイティブな Kubernetes オブジェクトであり、他の Secret と同様に etcd に保存されます。クラスターで etcd 暗号化をすでに有効にしていれば、 それで対応できます。「決して etcd に触れさせない」といったより厳格なポリシーの場合は、 代わりに HashiCorp Vault CSI プロバイダーとともに Secrets Store CSI Driver を使用して ください。これは値を Pod の tmpfs にのみマウントし、ネイティブな Secret オブジェクトを 完全に省略します。この構成の適用範囲については DuoKey 担当者にご相談ください。
  • ネットワーク — Vault は、ESO が稼働する名前空間から到達可能である必要があります (ClusterIP Service と NetworkPolicy の許可ルール、あるいは Vault がクラスター外にある 場合は Route)。サイドカーが存在しないため localhost による近道もありません。コントローラーは Vault に直接接続するため、この経路には他のクラスター内 HTTP クライアントと同じ TLS および ネットワークのハードニングが必要です。 ネットワークセキュリティ を参照してください。

OpenBao と Vault​

セットアップは同一です。OpenBao は Vault の API と互換性があるため、ESO の Vault プロバイダーは OpenBao に対してもそのまま機能します。変更が必要なのは、OpenBao のアドレスを指す spec.provider.vault.server だけです。ESO に OpenBao 専用のプロバイダーは存在せず、同じ vault プロバイダーブロックを OpenBao のエンドポイントに向けることが、標準的でサポートされた 利用方法です。

ローテーションと監査​

  • Vault の duokey ロールの TTL と、その基となるポリシーは、通常のシークレットローテーションの 周期でローテーションしてください。ESO は取得のたびに再認証するため、絞り込んだポリシーは次の refreshInterval で有効になり、認可 の変更のために Pod を再起動する必要はありません (ローテーションされたシークレットの 値 を反映するには、環境変数の変更をアプリケーションが どう扱うかに依存します。DuoKey 自身の挙動については Cockpit の構成 を参照してください)。
  • Vault からの読み取りはすべて Vault 自身の監査デバイスによって記録されます。まだ有効にして いない場合は有効にしてください。これは、ESO が何をいつ取得したかを示す信頼できる記録であり、 DuoKey 自身の 監査証跡 とは独立しています。
  • duokey-read ポリシーは、secret/data/duokey/*(または相当するパス)だけにスコープしたまま にしてください。ここでの最小権限とは、ESO の ServiceAccount トークンが侵害されても、Vault 内の 他のものではなく DuoKey 自身のシークレットしか読み取れないということを意味します。

ID、SSO、アクセス制御 に進むか、このパターンの一般的な (あらゆるシークレットマネージャーに対応する)バージョンについては シークレットマネージャー統合 に戻ってください。