Vault
HashiCorp Vault 完全ガイド:シークレット管理の最前線
目次
イントロダクション
Vault とは
HashiCorp Vault は、シークレット管理、暗号化、アクセス制御を統一的に提供するオープンソースのセキュリティプラットフォームです。データベース認証情報、API キー、TLS/SSL 証明書、パスワード、暗号化キーなど、あらゆるシークレット情報を安全に保管・管理・利用できます。
重要性
現代のクラウドネイティブアーキテクチャでは、マイクロサービス、コンテナ、サーバーレス環境など、数多くのアプリケーションやシステムがシークレット情報を必要とします。これらを以下の課題と直面します:
- スケーラビリティ: 数千のアプリケーション、サービスが独立したシークレットを必要
- セキュリティ: シークレットの漏洩防止とアクセス制御
- 回転管理: 定期的なシークレット変更の自動化
- 監査: すべてのアクセス、操作の記録
- 複雑性: 複数のシークレット形式、バックエンドの統一管理
Vault はこれらすべての課題に対処する統合ソリューションです。
主要な利点
| 利点 | 説明 |
|---|---|
| 集中管理 | すべてのシークレットを単一の信頼できるソースから管理 |
| 動的シークレット | 必要に応じてオンデマンドでシークレット生成 |
| 自動回転 | バックエンド連携によるシークレット自動更新 |
| 監査ログ | すべてのアクセスと変更の詳細記録 |
| 暗号化 | Transit エンジンによるデータ暗号化 |
| 複数認証 | LDAP、OIDC、AWS IAM など多数の認証方法対応 |
Vault の基本概念
1. シークレット(Secret)
シークレットは、保護が必要なデータの最小単位です。
種類:
- スタティックシークレット: データベース認証情報、API キーなど変わらないもの
- ダイナミックシークレット: Vault が生成し、TTL 後に失効するもの
- 暗号化データ: Transit エンジンで暗号化されたデータ
# 例:スタティックシークレット
{
"username": "app_user",
"password": "super_secret_password_123",
"host": "db.example.com"
}
# 例:ダイナミックシークレット(生成)
{
"username": "vault_generated_user_a7f8d9e2",
"password": "temporary_password_valid_1_hour",
"ttl": "1h",
"lease_id": "database/creds/app_role/8e8c3a2b"
}
2. Path(パス)
Vault 内のシークレットは、ファイルシステムのようなパス構造で組織されます。
secret/data/database/prod # 本番環境のDB認証情報
secret/data/api/stripe # Stripe API キー
aws/creds/deploy # AWS の一時認証情報
pki/issue/web-cert # 証明書生成
transit/encrypt/payments # 支払いデータ暗号化
3. Mount Point(マウントポイント)
Vault のシークレットエンジンは、マウントポイント経由でアクセスされます。
secret/ → KV シークレットエンジン
aws/ → AWS シークレットエンジン
database/ → データベースシークレットエンジン
pki/ → PKI(公開鍵基盤)エンジン
transit/ → Transit 暗号化エンジン
4. Token(トークン)
Vault へのアクセスは、必ずトークンで認証されます。トークンはポリシーをattachされ、アクセス権限を定義します。
s.qlBr8Z3jPgLXemCN6p9WNY4a # トークン例
├─ TTL: 1 hour
├─ Renewable: true
├─ Policies: ["app-policy", "read-secrets"]
└─ Entity ID: 123e4567-e89b-12d3-a456-426614174000
5. Lease(リース)
Vault から発行されるシークレットやトークンは、有効期限を持ちます(リース期間)。
# リースの例
Lease ID: aws/creds/deploy/abc123def456
Lease Duration: 3600s (1 hour)
Lease Renewable: true
# 自動更新(Renew)
- クライアントが事前にリースを更新可能
- 管理者がリース時間をカスタマイズ可能
- TTL 終了後は自動的にシークレット失効
# リース管理
vault lease renew <lease_id> # リース更新
vault lease revoke <lease_id> # リース失効
6. Auth Method(認証方式)
Vault へアクセスするために、様々な認証方式が利用可能です。
┌─────────────────────────────────────┐
│ Vault 認証方式 │
├──────────────┬──────────────────────┤
│ 認証タイプ │ 例 │
├──────────────┼──────────────────────┤
│ 基本認証 │ Username/Password │
│ クラウド │ AWS IAM, Azure, GCP │
│ SSO/OIDC │ Okta, Auth0, Google │
│ ディレクトリ │ LDAP, Active Dir. │
│ Kubernetes │ ServiceAccount Token │
│ AppRole │ Role ID + Secret ID │
│ JWT │ OIDC Token │
│ TLS Cert │ Client Certificate │
└──────────────┴──────────────────────┘
アーキテクチャ概要
1. 全体構成図
┌─────────────────────────────────────────────────────────┐
│ Client Applications │
│ (Web Apps, Microservices, Scripts, CI/CD Pipeline) │
└──────────────┬──────────────────────────────────────────┘
│ HTTP/HTTPS
┌──────────────▼──────────────────────────────────────────┐
│ Vault API / CLI │
│ (RESTful HTTP Endpoint) │
└──────────────┬──────────────────────────────────────────┘
│
┌──────────────▼──────────────────────────────────────────┐
│ Authentication Layer │
│ (Auth Methods & Access Control Policies) │
├──────────────────────────────────────────────────────────┤
│ AppRole │ OIDC │ LDAP │ AWS IAM │ Kubernetes │ RADIUS │
└──────────────┬──────────────────────────────────────────┘
│
┌──────────────▼──────────────────────────────────────────┐
│ Policy Engine │
│ (Token Generation & Validation) │
└──────────────┬──────────────────────────────────────────┘
│
┌──────────────▼──────────────────────────────────────────┐
│ Secret Engines Layer │
├──────────────────────────────────────────────────────────┤
│ KV │ Database │ AWS │ PKI │ Transit │ SSH │ LDAP Dir │
└──────────────┬──────────────────────────────────────────┘
│
┌──────────────▼──────────────────────────────────────────┐
│ Storage Backend │
│ (Encrypted Data Persisted Here) │
├──────────────────────────────────────────────────────────┤
│ File System │ Consul │ S3 │ DynamoDB │ PostgreSQL │
│ Integrated Storage (Raft) │ etcd │ Azure │ GCS │
└──────────────────────────────────────────────────────────┘
│
┌──────────────▼──────────────────────────────────────────┐
│ Encryption & Key Management │
│ (Barrier Key & Master Key Hierarchy) │
└──────────────────────────────────────────────────────────┘
2. コアコンポーネント
2.1 Vault Core(コア)
Vault サーバーの中心。すべての要求を処理します。
┌─────────────────────────────────────┐
│ Vault Core │
├─────────────────────────────────────┤
│ • HTTP API Handler │
│ • Request Routing │
│ • Token Management │
│ • Policy Enforcement │
│ • Lease Management │
│ • Audit Logging │
└─────────────────────────────────────┘
2.2 Auth Methods(認証)
クライアントが Vault に対してアイデンティティを証明する方法。
例:AppRole 認証フロー
┌─────────────┐
│ Application │
└──────┬──────┘
│ Send RoleID + SecretID
▼
┌──────────────────────────────────────┐
│ AppRole Auth Method │
│ ├─ RoleID (Public ID) │
│ ├─ SecretID (Private Secret) │
│ └─ Policies attached to role │
└──────┬───────────────────────────────┘
│ Validate credentials
▼
┌──────────────────────────────────────┐
│ Token Policy Engine │
└──────┬───────────────────────────────┘
│ Return token with policies
▼
┌──────────────────────────────────────┐
│ Token = s.abc123... (with policy) │
└──────────────────────────────────────┘
2.3 Secret Engines(シークレットエンジン)
実際のシークレットデータを管理・生成する機構。
KV Engine (Key-Value)
├─ Version 1: Simple key-value storage
└─ Version 2: Versioning + metadata
Database Engine
├─ PostgreSQL
├─ MySQL
├─ MongoDB
├─ MSSQL
└─ Oracle (with TTL-based credentials)
AWS Engine
├─ Access key generation
├─ STS temporary credentials
└─ EC2 instance authentication
PKI Engine
├─ CA management
├─ Certificate issuance
└─ CRL management
Transit Engine
├─ Data encryption/decryption
└─ Keyring management
2.4 Storage Backend(ストレージバックエンド)
Vault データを暗号化して保存する層。
Integrated Storage (推奨, Enterprise のみ)
├─ 内蔵 Raft コンセンサス
└─ マルチノード HA
External Storage
├─ Consul: 分散型キーバリューストア
├─ etcd: 分散トランザクションログ
├─ S3: AWS S3 バケット
├─ PostgreSQL: リレーショナルDB
├─ DynamoDB: AWS 管理型 NoSQL
├─ Azure Blob: Azure クラウドストレージ
└─ GCS: Google Cloud Storage
2.5 Audit Devices(監査)
すべての API リクエストと応答をログに記録します。
監査ログ形式
{
"type": "request",
"auth": {
"display_name": "approle",
"token_ttl": 3600,
"policies": ["app-policy"]
},
"request": {
"id": "req-123",
"operation": "read",
"path": "secret/data/database/prod",
"data": "<redacted>"
},
"response": {
"data": "<redacted>",
"warnings": null
},
"time": "2026-04-07T10:30:45.123456789Z"
}
3. High Availability(HA)構成
┌────────────────────────────────────────────────────────┐
│ Load Balancer │
│ (Layer 7 HA Proxy) │
└─────────────┬────────────────┬───────────────────────┘
│ │
┌─────────▼────┐ ┌────────▼─────────┐
│ Vault Server │ │ Vault Server │
│ (Active) │ │ (Standby) │
└─────────┬────┘ └────────┬─────────┘
│ │
└────────┬───────┘
│ Raft Consensus / etcd / Consul
┌────────▼──────────┐
│ Storage Backend │
│ (Replicated) │
└───────────────────┘
認証メカニズム
1. AppRole 認証(最も一般的)
用途: アプリケーション、CI/CD パイプライン、自動化ツール
# Step 1: AppRole の定義(管理者が実施)
path "secret/data/app/*" {
capabilities = ["read", "list"]
}
resource "vault_approle_auth_backend_role" "example" {
backend = "approle"
role_name = "my-app"
token_ttl = "1h"
token_max_ttl = "24h"
secret_id_ttl = "0h" # 無制限
secret_id_num_uses = "0" # 無制限
}
# Step 2: Role ID と Secret ID 取得
resource "vault_approle_auth_backend_role_secret_id" "example" {
backend = "approle"
role_name = vault_approle_auth_backend_role.example.role_name
}
output "role_id" {
value = vault_approle_auth_backend_role.example.role_id
}
output "secret_id" {
value = vault_approle_auth_backend_role_secret_id.example.secret_id
}
# Step 3: アプリケーションから認証
vault write auth/approle/login \
role_id=<ROLE_ID> \
secret_id=<SECRET_ID>
# 応答:
# Key Value
# token s.abc123...
# token_duration 1h
# token_policies ["my-app"]
セキュリティ上の配置:
- Role ID: 設定に埋め込むか、環境変数で配布
- Secret ID: オペレーター管理、回転可能(可選)
- 分離: Role ID と Secret ID を分けて管理
2. OIDC / JWT 認証
用途: Kubernetes, CI/CD(GitHub Actions など), クラウド環境
# Step 1: OIDC Auth Method 有効化
vault auth enable oidc
# Step 2: OIDC 設定
vault write auth/oidc/config \
oidc_discovery_url="https://accounts.google.com" \
oidc_client_id="<CLIENT_ID>" \
oidc_client_secret="<CLIENT_SECRET>"
# Step 3: Role 定義(Kubernetes ServiceAccount)
vault write auth/oidc/role/my-app \
bound_audiences="my-app" \
user_claim="sub" \
policies="app-policy"
# Step 4: ポッドから認証(Kubernetes)
KUBE_SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
vault write -method=post auth/oidc/login \
role=my-app \
jwt="$KUBE_SA_TOKEN"
3. AWS IAM 認証
用途: EC2、Lambda、その他 AWS リソース
# Step 1: AWS Auth Method 有効化
vault auth enable aws
# Step 2: AWS IAM セットアップ
vault write auth/aws/config/client \
access_key=<AWS_ACCESS_KEY> \
secret_key=<AWS_SECRET_KEY>
# Step 3: Role 定義
vault write auth/aws/role/ec2-role \
auth_type=ec2 \
bound_account_id="123456789012" \
bound_vpc_id="vpc-12345678" \
policies="app-policy" \
ttl=1h
# Step 4: EC2 インスタンスから認証
TOKEN=$(curl http://169.254.169.254/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
IDENTITY=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document -H "X-aws-ec2-metadata-token: $TOKEN")
SIGNATURE=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/signature -H "X-aws-ec2-metadata-token: $TOKEN")
vault write -method=post auth/aws/login \
iam_http_request_method=POST \
iam_request_body="$IDENTITY" \
iam_request_signature="$SIGNATURE"
4. Kubernetes ServiceAccount 認証
用途: Kubernetes ポッド
# Step 1: Kubernetes Auth Method 有効化
vault auth enable kubernetes
# Step 2: Kubernetes クラスタ設定
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc.cluster.local:443" \
kubernetes_ca_cert="@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
# Step 3: Role 定義
vault write auth/kubernetes/role/my-app \
bound_service_account_names=my-app \
bound_service_account_namespaces=default \
policies="app-policy" \
ttl=1h
# Step 4: ポッドから認証
vault write auth/kubernetes/login \
role=my-app \
jwt="@/var/run/secrets/kubernetes.io/serviceaccount/token"
シークレット管理
1. KV Secret Engine
用途: スタティックシークレット(パスワード、API キーなど)
# KV v2(推奨、バージョン管理対応)有効化
vault secrets enable -version=2 kv
# シークレット書き込み
vault kv put secret/database/prod \
username="admin" \
password="super_secret_123" \
host="db.production.internal"
# シークレット読み取り
vault kv get secret/database/prod
# 出力:
# ======== Secret Path ========
# secret/data/database/prod
#
# ======== Data ========
# Key Value
# host db.production.internal
# password super_secret_123
# username admin
# バージョン管理
vault kv list secret/database/prod # すべてのバージョン
vault kv get -version=1 secret/database/prod # 特定バージョン取得
# メタデータ
vault kv metadata get secret/database/prod
vault kv metadata delete secret/database/prod
# JSON 形式で全データ取得
vault kv get -format=json secret/database/prod | jq '.data.data'
2. Database Secret Engine
用途: ダイナミックなデータベース認証情報
# Database Engine 有効化
vault secrets enable database
# PostgreSQL 接続設定
vault write database/config/my-postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="readonly","readwrite" \
connection_url="postgresql://{{username}}:{{password}}@postgres.prod.internal:5432/mydb" \
username="vault" \
password="vault_password_123"
# Role 定義(Read-only)
vault write database/roles/readonly \
db_name=my-postgres \
creation_statements="CREATE USER \"{{name}}\" WITH PASSWORD '{{password}}' IN ROLE readonly; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"
# シークレット要求
vault read database/creds/readonly
# 出力:
# Key Value
# lease_id database/creds/readonly/abc123...
# lease_duration 1h
# lease_renewable true
# password xxxxx
# username v_readonly_a1b2c3d4_xyz
# 自動回転設定
vault write -f database/rotate-root/my-postgres
マルチデータベース対応:
# MySQL
vault write database/config/my-mysql \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(mysql.prod.internal:3306)/" \
username="vault" \
password="vault_pass"
# MongoDB
vault write database/config/my-mongo \
plugin_name=mongodb-database-plugin \
connection_url="mongodb://{{username}}:{{password}}@mongo.prod.internal:27017" \
username="vault" \
password="vault_pass"
# MSSQL
vault write database/config/my-mssql \
plugin_name=mssql-database-plugin \
connection_url="server={{username}}:{{password}}@mssql.prod.internal;port=1433;" \
username="vault" \
password="vault_pass"
3. AWS Secret Engine
用途: AWS アクセスキー、STS 認証情報の動的生成
# AWS Engine 有効化
vault secrets enable aws
# AWS 認証情報設定
vault write aws/config/root \
access_key=<AWS_ACCESS_KEY> \
secret_key=<AWS_SECRET_KEY> \
region=us-east-1
# IAM Policy 定義
vault write aws/roles/s3-readonly \
credential_type=iam_user \
policy_document=@policy.json \
ttl=1h \
max_ttl=24h
# ポリシー内容(policy.json)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
]
}
# シークレット要求
vault read aws/creds/s3-readonly
# 出力:
# Key Value
# lease_id aws/creds/s3-readonly/abc123
# access_key AKIAJXYZ123...
# secret_key xyz123abc...
# ttl 1h
# STS 一時認証(外部アカウント向け)
vault write aws/roles/external-sts \
credential_type=assumed_role \
role_arn=arn:aws:iam::ACCOUNT_ID:role/VaultRole \
ttl=1h \
max_ttl=12h
vault read aws/creds/external-sts
4. PKI Secret Engine
用途: TLS/SSL 証明書の動的生成
# PKI Engine 有効化
vault secrets enable pki
# キーペアサイズと期間設定
vault secrets tune -max-lease-ttl=87600h pki
# Root CA 生成
vault write -field=certificate pki/root/generate/internal \
common_name="example.com" \
ttl=87600h > ca.crt
# 中間 CA 生成
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int
vault write -format=json pki_int/intermediate/generate/internal \
common_name="example.com Intermediate Authority" \
| jq -r '.data.csr' > pki_intermediate.csr
# Root CA で署名
vault write -format=json pki/root/sign-intermediate \
csr=@pki_intermediate.csr \
format=pem_bundle \
ttl=43800h | jq -r '.data.certificate' > intermediate.cert.pem
# 中間 CA を設定
vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem
# ロール定義(サーバー証明書)
vault write pki_int/roles/example-dot-com \
allowed_domains="example.com" \
allow_subdomains=true \
max_ttl="720h" \
generate_lease=true
# 証明書発行
vault write pki_int/issue/example-dot-com \
common_name="api.example.com" \
ttl="168h"
# 出力:
# Key Value
# certificate -----BEGIN CERTIFICATE-----
# issuing_ca -----BEGIN CERTIFICATE-----
# private_key -----BEGIN RSA PRIVATE KEY-----
# serial_number ab:cd:ef:01:23:45:...
5. Transit Secret Engine
用途: アプリケーションレベルのデータ暗号化・復号化
# Transit Engine 有効化
vault secrets enable transit
# 暗号化キー作成
vault write -f transit/keys/payments
# データ暗号化
vault write transit/encrypt/payments \
plaintext=$(base64 <<< "4111111111111111")
# 出力:
# Key Value
# ciphertext vault:v1:abc123def456...
# データ復号化
vault write transit/decrypt/payments \
ciphertext="vault:v1:abc123def456..."
# 出力:
# Key Value
# plaintext NDExMTExMTExMTExMTExMTE= (base64)
# キー回転(既存データに透過的)
vault write -f transit/keys/payments/rotate
# バッチ処理(複数データ一度に暗号化)
vault write transit/encrypt/payments \
batch_input='[
{"plaintext": "NDExMTEx..."},
{"plaintext": "NDIyMjIy..."}
]'
# HMAC 署名生成
vault write transit/hmac/payments \
input="sensitive_data"
# 署名検証
vault write transit/verify/payments \
input="sensitive_data" \
hmac="vault:v1:xxx..."
暗号化機能
1. Encryption at Rest
Vault が保存するすべてのデータは、デフォルトで暗号化されます。
暗号化ハイアラルキー:
┌─────────────────────────────────────┐
│ Master Key (外部管理) │
│ (HSM, Seal Key, KMS など) │
└────────────────┬────────────────────┘
│
▼ (復号化)
┌──────────────┐
│ Barrier Key │
│ (メモリ保持) │
└──────┬───────┘
│ (暗号化)
▼
┌──────────────┐
│ Stored Data │
│ (ディスク) │
└──────────────┘
暗号化方式:
- AES-256-GCM: データ暗号化(デフォルト)
- HMAC-SHA256: 整合性検証
- SHA1: キー導出(Argon2 推奨)
2. Seal Mechanism(シール機構)
Vault は起動時に Unseal が必要です。これは Master Key を使用してシステムを復号化するプロセスです。
# Shamir Secret Sharing(デフォルト)
# Master Key を複数のシェア(キー分割)に分割
vault operator init \
--key-shares=5 \
--key-threshold=3
# 出力:
# Unseal Key 1: KqD...
# Unseal Key 2: NmA...
# Unseal Key 3: PlB...
# Unseal Key 4: QmC...
# Unseal Key 5: RnD...
# Root Token: s.xxxxxx
# Unseal(3つのキーが必要)
vault operator unseal <KEY_1>
vault operator unseal <KEY_2>
vault operator unseal <KEY_3>
# ステータス確認
vault status
# 出力:
# Key Value
# Sealed false
# Total Shares 5
# Threshold 3
# Unseal Progress 3/3
Auto Unseal 設定:
# AWS KMS を使用した自動 Unseal
seal "awskms" {
region = "us-east-1"
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/abc123"
}
# Google Cloud KMS
seal "gcpkms" {
project = "my-project"
region = "us"
key_ring = "vault"
crypto_key = "vault-seal"
}
# Azure Key Vault
seal "azurekeyvault" {
client_id = "xxxx"
client_secret = "xxxx"
tenant_id = "xxxx"
vault_name = "vault-kms"
key_name = "vault-seal"
}
# HSM(Hardware Security Module)
seal "pkcs11" {
lib = "/usr/lib/softhsm/libsofthsm2.so"
slot = 0
pin = "1234"
key_label = "vault-seal-key"
}
3. Transit によるアプリケーション暗号化
┌─────────────────────────────────────────────────────┐
│ Application Layer │
│ (暗号化されていないシークレット データ) │
└────────────┬────────────────────────────────────────┘
│ 1. plaintext + keyname
▼
┌──────────────────────────────────────────────────────┐
│ Vault Transit Engine │
│ ├─ Request: encrypt/payments?plaintext=... │
│ ├─ Key Management: payments key v3 │
│ ├─ Cipher: AES-256-GCM │
│ └─ Response: ciphertext=vault:v1:abc... │
└────────────┬──────────────────────────────────────────┘
│ 2. ciphertext のみ保存
▼
┌──────────────────────────────────────────────────────┐
│ Application Data Store │
│ (暗号化されたデータのみ格納) │
│ { │
│ "user_id": 123, │
│ "ssn": "vault:v1:abc123def456", │
│ "phone": "vault:v1:xyz789..." │
│ } │
└──────────────────────────────────────────────────────┘
ポリシーとアクセス制御
1. Policy 基礎
Policy は HCL(HashiCorp Configuration Language)で記述された ACL ルールです。
# 基本的なポリシー構文
path "<path>" {
capabilities = ["<capability>"]
# オプション制約
parameters = {
"key" = ["value"]
}
}
# 利用可能な Capability
read # 読み取り
create # 作成
update # 更新
delete # 削除
list # リスト
sudo # 管理者操作
deny # 明示的な拒否
2. 実践的なポリシー例
# 例1: アプリケーション用ポリシー
path "secret/data/app/myapp/*" {
capabilities = ["read", "list"]
}
path "database/creds/app-role" {
capabilities = ["read"]
}
# 例2: データベース管理者用ポリシー
path "database/config/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "database/roles/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "database/rotate-root/*" {
capabilities = ["update"]
}
# 例3: Kubernetes ポッド用ポリシー
path "secret/data/k8s/*" {
capabilities = ["read"]
}
path "pki_int/issue/web-cert" {
capabilities = ["create", "update"]
}
# 例4: 監査ログアクセス
path "sys/audit" {
capabilities = ["read", "list"]
}
path "sys/audit-hash" {
capabilities = ["update"]
}
# ワイルドカード使用例
path "secret/data/prod/*" {
capabilities = ["read"]
}
path "secret/data/+/database" {
capabilities = ["read"] # secret/data/app/database, secret/data/web/database
}
path "secret/data/*/database/**" {
capabilities = ["read"] # secret/data/app/database/mysql 等
}
3. ポリシーの作成と適用
# ポリシーファイル作成(app-policy.hcl)
path "secret/data/app/*" {
capabilities = ["read", "list"]
}
path "database/creds/readonly" {
capabilities = ["read"]
}
# ポリシー登録
vault policy write app-policy app-policy.hcl
# ポリシー確認
vault policy read app-policy
vault policy list
# トークンにポリシー付与
vault token create -policy=app-policy -ttl=1h
# AppRole にポリシー付与
vault write auth/approle/role/myapp \
token_policies="app-policy" \
secret_id_ttl=0 \
token_ttl=1h \
token_max_ttl=24h
4. Entity と Identity Group
OIDC、JWT などで認証されるユーザーを管理します。
# Entity 作成
vault write identity/entity \
name="john.doe" \
metadata="role=admin,department=engineering"
# Entity Alias 追加(外部 ID マッピング)
vault write identity/entity-alias \
name="john.doe@example.com" \
canonical_mount_accessor=<OIDC_ACCESSOR> \
mount_accessor=<OIDC_ACCESSOR>
# Entity に Policy 割り当て
vault write identity/entity \
name="john.doe" \
policies="admin-policy,read-all-policy"
# Identity Group 作成
vault write identity/group \
name="engineers" \
policies="read-all-policy,deploy-policy"
# Entity をグループに追加
vault write identity/group \
name="engineers" \
member_entity_ids="<ENTITY_ID>"
# ID Group Policy 適用
vault write identity/group-policies \
name="engineers" \
policies="engineering-policy"
実装パターン
1. マイクロサービス向け実装
# docker-compose.yml
version: '3.8'
services:
vault:
image: vault:latest
ports:
- "8200:8200"
environment:
VAULT_DEV_ROOT_TOKEN_ID: "root-token"
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200"
volumes:
- vault-storage:/vault/file
app-service-1:
build: ./app-service-1
ports:
- "3001:3000"
environment:
VAULT_ADDR: "http://vault:8200"
VAULT_ROLE_ID: "${SERVICE_1_ROLE_ID}"
VAULT_SECRET_ID: "${SERVICE_1_SECRET_ID}"
depends_on:
- vault
app-service-2:
build: ./app-service-2
ports:
- "3002:3000"
environment:
VAULT_ADDR: "http://vault:8200"
VAULT_ROLE_ID: "${SERVICE_2_ROLE_ID}"
VAULT_SECRET_ID: "${SERVICE_2_SECRET_ID}"
depends_on:
- vault
volumes:
vault-storage:
Python クライアント実装:
import hvac
import os
import logging
class VaultClient:
def __init__(self):
self.vault_addr = os.getenv('VAULT_ADDR', 'http://localhost:8200')
self.role_id = os.getenv('VAULT_ROLE_ID')
self.secret_id = os.getenv('VAULT_SECRET_ID')
self.client = hvac.Client(url=self.vault_addr)
self.logger = logging.getLogger(__name__)
def authenticate(self):
"""AppRole 認証"""
try:
response = self.client.auth.approle.login(
role_id=self.role_id,
secret_id=self.secret_id
)
self.client.token = response['auth']['client_token']
self.logger.info(f"✓ Vault 認証成功 (TTL: {response['auth']['token_ttl']})")
except Exception as e:
self.logger.error(f"✗ Vault 認証失敗: {e}")
raise
def get_database_credentials(self, role):
"""データベース認証情報取得"""
try:
secret = self.client.secrets.database.generate_database_credentials(
name=role
)
return {
'username': secret['data']['username'],
'password': secret['data']['password'],
'lease_id': secret['lease_id'],
'ttl': secret['lease_duration']
}
except Exception as e:
self.logger.error(f"✗ DB認証情報取得失敗: {e}")
raise
def get_secret(self, path):
"""シークレット取得"""
try:
secret = self.client.secrets.kv.read_secret_version(path=path)
return secret['data']['data']
except Exception as e:
self.logger.error(f"✗ シークレット取得失敗 ({path}): {e}")
raise
def encrypt_data(self, transit_key, plaintext):
"""データ暗号化"""
try:
response = self.client.secrets.transit.encrypt_data(
name=transit_key,
plaintext=plaintext
)
return response['data']['ciphertext']
except Exception as e:
self.logger.error(f"✗ 暗号化失敗: {e}")
raise
def decrypt_data(self, transit_key, ciphertext):
"""データ復号化"""
try:
response = self.client.secrets.transit.decrypt_data(
name=transit_key,
ciphertext=ciphertext
)
return response['data']['plaintext']
except Exception as e:
self.logger.error(f"✗ 復号化失敗: {e}")
raise
# 使用例
if __name__ == "__main__":
vault = VaultClient()
# 認証
vault.authenticate()
# DB 認証情報取得
db_creds = vault.get_database_credentials('readonly')
print(f"DB User: {db_creds['username']} (TTL: {db_creds['ttl']})")
# API キー取得
api_key = vault.get_secret('secret/api/stripe')
print(f"API Key: {api_key['key'][:20]}...")
# データ暗号化
encrypted = vault.encrypt_data('payments', '4111111111111111')
print(f"Encrypted: {encrypted}")
2. Kubernetes 統合実装
# vault-setup.yaml - Kubernetes 認証設定
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-auth
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: vault-auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault-auth
namespace: default
---
apiVersion: v1
kind: Pod
metadata:
name: vault-auth-setup
namespace: default
spec:
serviceAccountName: vault-auth
containers:
- name: vault-setup
image: vault:latest
command:
- /bin/sh
- -c
- |
# Vault に接続
export VAULT_ADDR=http://vault:8200
# Kubernetes 認証有効化
vault auth enable kubernetes || true
# API 設定
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# アプリケーション用ロール
vault write auth/kubernetes/role/myapp \
bound_service_account_names=default \
bound_service_account_namespaces=default \
policies="kv-reader" \
ttl=24h
echo "✓ Kubernetes 認証セットアップ完了"
---
# アプリケーション Pod
apiVersion: v1
kind: Pod
metadata:
name: app-pod
namespace: default
spec:
serviceAccountName: default
containers:
- name: app
image: myapp:latest
env:
- name: VAULT_ADDR
value: "http://vault:8200"
- name: VAULT_K8S_MOUNT_PATH
value: "kubernetes"
- name: VAULT_ROLE
value: "myapp"
volumeMounts:
- name: k8s-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
volumes:
- name: k8s-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
Go クライアント実装:
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"github.com/hashicorp/vault/api"
)
func main() {
// Vault クライアント初期化
config := api.DefaultConfig()
config.Address = os.Getenv("VAULT_ADDR")
client, err := api.NewClient(config)
if err != nil {
log.Fatalf("Failed to create Vault client: %v", err)
}
// Kubernetes トークン読み込み
token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
log.Fatalf("Failed to read token: %v", err)
}
// Kubernetes 認証
auth := client.Auth().Kubernetes()
secret, err := auth.Login(nil, map[string]interface{}{
"role": os.Getenv("VAULT_ROLE"),
"jwt": string(token),
})
if err != nil {
log.Fatalf("Kubernetes auth failed: %v", err)
}
// トークン設定
client.SetToken(secret.Auth.ClientToken)
fmt.Println("✓ Kubernetes 認証成功")
// シークレット取得
secret, err = client.Logical().Read("secret/data/database/prod")
if err != nil {
log.Fatalf("Failed to read secret: %v", err)
}
data := secret.Data["data"].(map[string]interface{})
fmt.Printf("Database User: %s\n", data["username"])
}
3. CI/CD パイプライン統合
# .gitlab-ci.yml または .github/workflows/deploy.yml
deploy:
image: alpine:latest
before_script:
- apk add curl jq
- |
# Vault へのログイン(CI/CD トークン)
export VAULT_ADDR="https://vault.company.com"
export VAULT_NAMESPACE="ci-cd"
# AppRole 認証
AUTH_RESPONSE=$(curl -s -X POST \
$VAULT_ADDR/v1/auth/approle/login \
-d "{
\"role_id\": \"$CI_APPROLE_ROLE_ID\",
\"secret_id\": \"$CI_APPROLE_SECRET_ID\"
}")
export VAULT_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.auth.client_token')
echo "✓ Vault 認証成功"
script:
# AWS 認証情報取得
- |
AWS_CREDS=$(curl -s -X GET \
"$VAULT_ADDR/v1/aws/creds/deploy" \
-H "X-Vault-Token: $VAULT_TOKEN")
export AWS_ACCESS_KEY_ID=$(echo $AWS_CREDS | jq -r '.data.access_key')
export AWS_SECRET_ACCESS_KEY=$(echo $AWS_CREDS | jq -r '.data.secret_key')
# デプロイ実行
- aws s3 sync ./build s3://my-app-bucket --delete
- echo "✓ デプロイ完了"
運用とベストプラクティス
1. HA 構成(Consul バックエンド)
# vault.hcl 設定ファイル
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/etc/vault/certs/vault.crt"
tls_key_file = "/etc/vault/certs/vault.key"
}
storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
scheme = "http"
# レプリケーション設定
consistency_mode = "strong"
disable_registration = false
}
seal "awskms" {
region = "us-east-1"
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/xxx"
}
ui = true
log_level = "info"
# API アドレス設定(HA クラスタ向け)
api_addr = "https://vault.example.com"
cluster_addr = "https://vault-node.example.internal"
Terraform による HA 構成:
# terraform/main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# ロードバランサー
resource "aws_lb" "vault" {
name = "vault-lb"
internal = false
load_balancer_type = "network"
subnets = var.subnet_ids
enable_deletion_protection = true
tags = {
Name = "vault-lb"
}
}
# Auto Scaling Group
resource "aws_autoscaling_group" "vault" {
name = "vault-asg"
vpc_zone_identifier = var.subnet_ids
min_size = 3
max_size = 5
desired_capacity = 3
launch_template {
id = aws_launch_template.vault.id
version = "$Latest"
}
tag {
key = "Name"
value = "vault-server"
propagate_at_launch = true
}
}
# Launch Template
resource "aws_launch_template" "vault" {
name_prefix = "vault-"
image_id = data.aws_ami.ubuntu.id
instance_type = "t3.large"
user_data = base64encode(templatefile("${path.module}/user_data.sh", {
vault_version = "1.15.0"
}))
tag_specifications {
resource_type = "instance"
tags = {
Name = "vault-instance"
}
}
}
# Consul クラスタ(ストレージバックエンド)
resource "aws_autoscaling_group" "consul" {
name = "consul-asg"
vpc_zone_identifier = var.subnet_ids
min_size = 3
max_size = 5
desired_capacity = 3
launch_template {
id = aws_launch_template.consul.id
version = "$Latest"
}
}
2. バックアップとディザスタリカバリー
#!/bin/bash
# backup_vault.sh - Vault バックアップスクリプト
set -e
VAULT_ADDR="https://vault.example.com"
BACKUP_DIR="/backups/vault"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/vault_backup_$DATE.snap"
echo "📦 Vault バックアップ開始..."
# バックアップ作成
curl -X PUT \
"$VAULT_ADDR/v1/sys/leases/lookup/database/creds/readonly" \
-H "X-Vault-Token: $VAULT_TOKEN" \
> "$BACKUP_FILE.tmp"
# ストレージバックエンドからの raft スナップショット
vault write -f sys/storage/raft/snapshot \
> "$BACKUP_FILE"
# 圧縮
gzip "$BACKUP_FILE"
# S3 にアップロード
aws s3 cp "$BACKUP_FILE.gz" \
"s3://vault-backups/vault_backup_$DATE.snap.gz"
# 古いバックアップ削除(30日以上前)
find "$BACKUP_DIR" -name "vault_backup_*.snap.gz" -mtime +30 -delete
echo "✅ バックアップ完了: $BACKUP_FILE.gz"
ディザスタリカバリー:
#!/bin/bash
# restore_vault.sh - Vault リストア スクリプト
set -e
BACKUP_FILE="$1" # vault_backup_20260407_120000.snap.gz
if [ -z "$BACKUP_FILE" ]; then
echo "使用方法: $0 <backup_file>"
exit 1
fi
echo "🔄 Vault リストア開始..."
# Vault を Raft リーダーから削除
vault write -f sys/storage/raft/remove-peer node_id=<node_id>
# スナップショット復元
gunzip -c "$BACKUP_FILE" | vault write sys/storage/raft/restore-
# 再起動
systemctl restart vault
# ステータス確認
sleep 5
vault status
echo "✅ リストア完了"
3. 監査ログ管理
# 監査ログの有効化
# ファイルベースの監査ログ
vault audit enable file file_path=/var/log/vault/audit.log
# Syslog
vault audit enable syslog tag="vault"
# CloudWatch(AWS)
vault audit enable cloudwatch log_group_name="/vault/audit" log_stream_name="vault-audit"
# 監査ログのフォーマット確認
vault audit list
# JSON 形式の監査ログ解析
cat /var/log/vault/audit.log | jq '.request.path' | sort | uniq -c
# 特定ユーザーのアクション追跡
cat /var/log/vault/audit.log | jq 'select(.auth.display_name=="john.doe") | {time, request_path: .request.path, operation: .request.operation}'
4. ベストプラクティス
| カテゴリ | ベストプラクティス |
|---|---|
| セキュリティ | TLS を必須にする、Auto Unseal を使用、定期的な監査ログ確認 |
| HA 構成 | 最小3ノード、ロードバランサー経由、複数 AZ 配置 |
| 認証 | 本番環境では AppRole、Kubernetes、OIDC を使用 |
| シークレット回転 | 30-90 日ごと、Database Engine の自動回転を活用 |
| ポリシー | 最小権限原則、定期的なレビュー |
| バックアップ | 日次バックアップ、リストアテスト実施 |
| 監査 | すべての監査ログを外部ストレージに送信、1年以上保持 |
| パフォーマンス | キャッシング、接続プーリング、レート制限設定 |
まとめ
主要ポイント
- 統合管理: Vault はスタティック/ダイナミック シークレット、認証、暗号化を統一的に管理
- スケーラビリティ: マイクロサービス環境で数千のシークレットを安全に運用可能
- 自動化: Database Engine、PKI による自動生成・回転
- 監査: すべてのアクセスと操作を記録し、コンプライアンス対応
- 柔軟性: 複数の認証方式、ストレージバックエンド、暗号化オプション
次のステップ
- ローカル開発:
vault server -devで試してみる - Docker 環境: 公式イメージで HA 構成を構築
- クラウド統合: AWS、Azure、GCP のネイティブ認証を設定
- 自動化: Terraform、Helm で IaC 化
- 監視: Prometheus メトリクスの収集とアラート設定
HashiCorp Vault は、シークレット管理の複雑さを軽減し、セキュアで スケーラブルなインフラストラクチャを構築するための不可欠なツールです。