HashiCorp Vaultとの連携
HashiCorp Vaultとの連携
このページで学べること
- HashiCorp Vaultとは何か
- TerraformでVaultを使用する理由
- Vaultプロバイダーの基本設定
- 認証方法とベストプラクティス
- 実践的な使用例
HashiCorp Vaultとは
概要
HashiCorp Vaultは、シークレット(機密情報)を安全に管理するための専用ツールです。
主な機能:
- シークレット管理: APIキー、パスワード、証明書などの安全な保管
- 動的シークレット: 必要な時に一時的な認証情報を生成
- 暗号化サービス: データの暗号化・復号化
- アクセス制御: きめ細かい権限管理
- 監査ログ: すべてのアクセスを記録
Terraformで使用する理由
- セキュリティの向上
- 認証情報をコードに含めない
- 集中管理されたシークレット
- アクセスログの記録
- 動的シークレット
- 必要な時に生成
- 自動的に失効
- 最小権限の原則
- コンプライアンス
- 監査ログ
- アクセス制御ポリシー
- シークレットのローテーション
- チーム協業
- 認証情報の共有が不要
- 環境ごとの権限管理
- 一元的なシークレット管理
前提条件
必要な環境
- Terraform 1.0以上
- HashiCorp Vault(クラウド版またはセルフホスト版)
- 基本的なTerraformの知識(プロバイダーの設定を参照)
Vaultのセットアップ
Vaultを使用するには、以下のいずれかの方法でVaultサーバーを用意する必要があります:
- HCP Vault(推奨): HashiCorp Cloud Platformのマネージドサービス
- セルフホスト: 自社環境でVaultサーバーを構築
Vaultプロバイダーの設定
基本設定
まず、Terraformの設定ファイルでVaultプロバイダーを宣言します。
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
version = "~> 4.0"
}
}
}
provider "vault" {
address = "https://vault.example.com:8200"
}
設定項目の説明:
address: VaultサーバーのURLversion: Vaultプロバイダーのバージョン制約
認証方法
Vaultには複数の認証方法があります。環境に応じて適切な方法を選択してください。
1. トークン認証(開発環境)
開発環境では、環境変数を使用したトークン認証が簡単です。
export VAULT_TOKEN="hvs.CAESIJ..."
export VAULT_ADDR="https://vault.example.com:8200"
provider "vault" {
address = var.vault_addr
# VAULT_TOKEN環境変数が自動的に使用されます
}
2. AppRole認証(本番環境推奨)
本番環境では、AppRole認証を使用することを推奨します。
provider "vault" {
address = "https://vault.example.com:8200"
auth_login {
path = "auth/approle/login"
parameters = {
role_id = var.vault_role_id
secret_id = var.vault_secret_id
}
}
}
AppRoleの設定例:
# AppRoleの有効化
vault auth enable approle
# ロールの作成
vault write auth/approle/role/terraform \
token_policies="terraform-policy" \
token_ttl=1h \
token_max_ttl=4h
# Role IDの取得
vault read auth/approle/role/terraform/role-id
# Secret IDの生成
vault write -f auth/approle/role/terraform/secret-id
3. Kubernetes認証(Kubernetes環境)
Kubernetes環境で実行する場合は、Kubernetes認証を使用できます。
provider "vault" {
address = "https://vault.example.com:8200"
auth_login_jwt {
role = "terraform"
path = "auth/kubernetes/login"
}
}
Vaultからシークレットを取得
KV v2エンジンの使用
Vault KV(Key-Value)v2エンジンは、最も一般的なシークレット保管方法です。
# Vaultからシークレットを読み取る
data "vault_kv_secret_v2" "aws_creds" {
mount = "secret"
name = "aws/credentials"
}
# AWSプロバイダーで使用
provider "aws" {
region = "ap-northeast-1"
access_key = data.vault_kv_secret_v2.aws_creds.data["access_key"]
secret_key = data.vault_kv_secret_v2.aws_creds.data["secret_key"]
}
Vaultにシークレットを保存:
vault kv put secret/aws/credentials \
access_key="AKIAIOSFODNN7EXAMPLE" \
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
汎用シークレットの使用(KV v1)
KV v1エンジンを使用する場合は、vault_generic_secretを使用します。
data "vault_generic_secret" "aws_credentials" {
path = "secret/aws/credentials"
}
provider "aws" {
region = "ap-northeast-1"
access_key = data.vault_generic_secret.aws_credentials.data["access_key"]
secret_key = data.vault_generic_secret.aws_credentials.data["secret_key"]
}
動的シークレットの使用
動的シークレットは、必要な時に一時的な認証情報を生成する機能です。
AWS動的シークレット
# Vaultから動的なAWS認証情報を取得
data "vault_aws_access_credentials" "creds" {
backend = "aws"
role = "terraform-role"
}
provider "aws" {
region = "ap-northeast-1"
access_key = data.vault_aws_access_credentials.creds.access_key
secret_key = data.vault_aws_access_credentials.creds.secret_key
}
動的シークレットのメリット:
- 一時的な認証情報(自動的に失効)
- 最小権限の付与
- 使用後の自動クリーンアップ
- 監査ログによる追跡
Vaultでの設定例:
# AWSシークレットエンジンの有効化
vault secrets enable aws
# AWS認証情報の設定
vault write aws/config/root \
access_key="AKIAIOSFODNN7EXAMPLE" \
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
region="ap-northeast-1"
# ロールの作成
vault write aws/roles/terraform-role \
credential_type=iam_user \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*"
}
]
}
EOF
実践例:複数クラウドの統合管理
複数のクラウドプロバイダーの認証情報をVaultで一元管理する例です。
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
version = "~> 4.0"
}
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
# Vaultプロバイダー
provider "vault" {
address = var.vault_addr
}
# AWS認証情報をVaultから取得
data "vault_kv_secret_v2" "aws" {
mount = "secret"
name = "aws/credentials"
}
provider "aws" {
region = "ap-northeast-1"
access_key = data.vault_kv_secret_v2.aws.data["access_key"]
secret_key = data.vault_kv_secret_v2.aws.data["secret_key"]
}
# Azure認証情報をVaultから取得
data "vault_kv_secret_v2" "azure" {
mount = "secret"
name = "azure/credentials"
}
provider "azurerm" {
features {}
client_id = data.vault_kv_secret_v2.azure.data["client_id"]
client_secret = data.vault_kv_secret_v2.azure.data["client_secret"]
subscription_id = data.vault_kv_secret_v2.azure.data["subscription_id"]
tenant_id = data.vault_kv_secret_v2.azure.data["tenant_id"]
}
# リソースの作成
resource "aws_instance" "example" {
ami = "ami-0c3fd0f5d33134a76"
instance_type = "t2.micro"
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "Japan East"
}
ベストプラクティス
1. 環境ごとの設定分離
環境(開発、ステージング、本番)ごとにシークレットを分離します。
# variables.tf
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
}
# main.tf
data "vault_kv_secret_v2" "credentials" {
mount = "secret"
name = "${var.environment}/aws/credentials"
}
Vaultでの構造例:
secret/
├── dev/
│ └── aws/credentials
├── staging/
│ └── aws/credentials
└── prod/
└── aws/credentials
2. ポリシーの最小権限化
Vaultポリシーで最小限の権限のみを付与します。
# terraform-dev-policy.hcl
path "secret/data/dev/*" {
capabilities = ["read", "list"]
}
# terraform-prod-policy.hcl
path "secret/data/prod/*" {
capabilities = ["read"]
}
ポリシーの適用:
vault policy write terraform-dev terraform-dev-policy.hcl
vault policy write terraform-prod terraform-prod-policy.hcl
3. 変数の使用
Vault関連の設定は変数化して、柔軟性を持たせます。
# variables.tf
variable "vault_addr" {
description = "Vault server address"
type = string
default = "https://vault.example.com:8200"
}
variable "vault_role_id" {
description = "Vault AppRole Role ID"
type = string
sensitive = true
}
variable "vault_secret_id" {
description = "Vault AppRole Secret ID"
type = string
sensitive = true
}
# main.tf
provider "vault" {
address = var.vault_addr
auth_login {
path = "auth/approle/login"
parameters = {
role_id = var.vault_role_id
secret_id = var.vault_secret_id
}
}
}
4. エラーハンドリング
Vaultが利用できない場合のフォールバック処理を実装します。
variable "use_vault" {
description = "Whether to use Vault for secrets"
type = bool
default = true
}
variable "aws_access_key" {
description = "AWS Access Key (fallback when Vault is not used)"
type = string
default = ""
sensitive = true
}
variable "aws_secret_key" {
description = "AWS Secret Key (fallback when Vault is not used)"
type = string
default = ""
sensitive = true
}
data "vault_kv_secret_v2" "aws" {
count = var.use_vault ? 1 : 0
mount = "secret"
name = "aws/credentials"
}
locals {
aws_access_key = var.use_vault ? data.vault_kv_secret_v2.aws[0].data["access_key"] : var.aws_access_key
aws_secret_key = var.use_vault ? data.vault_kv_secret_v2.aws[0].data["secret_key"] : var.aws_secret_key
}
provider "aws" {
region = "ap-northeast-1"
access_key = local.aws_access_key
secret_key = local.aws_secret_key
}
トラブルシューティング
よくある問題と解決方法
1. 認証エラー
エラーメッセージ:
Error: error reading from Vault: Error making API request
原因と解決方法:
- トークンの有効期限切れ
# トークンの確認
vault token lookup
# トークンの更新
vault login
- 環境変数の未設定
# 環境変数の確認
echo $VAULT_TOKEN
echo $VAULT_ADDR
# 環境変数の設定
export VAULT_TOKEN="hvs.CAESIJ..."
export VAULT_ADDR="https://vault.example.com:8200"
2. パーミッションエラー
エラーメッセージ:
Error: permission denied
原因と解決方法:
Vaultポリシーで必要な権限が付与されていない可能性があります。
# ポリシーの確認
vault policy read terraform-policy
# ポリシーの更新
vault policy write terraform-policy policy.hcl
必要な権限の例:
# 読み取り権限
path "secret/data/aws/*" {
capabilities = ["read"]
}
# リスト権限(ディレクトリ一覧)
path "secret/metadata/aws/*" {
capabilities = ["list"]
}
3. シークレットが見つからない
エラーメッセージ:
Error: secret not found
原因と解決方法:
- シークレットの存在確認
# シークレットの確認
vault kv get secret/aws/credentials
# シークレットの一覧表示
vault kv list secret/aws
- シークレットの作成
vault kv put secret/aws/credentials \
access_key="AKIAIOSFODNN7EXAMPLE" \
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
4. 接続エラー
エラーメッセージ:
Error: error checking seal status: Get "https://vault.example.com:8200/v1/sys/seal-status": dial tcp: lookup vault.example.com: no such host
原因と解決方法:
- Vaultサーバーのアドレス確認
# 接続テスト
curl https://vault.example.com:8200/v1/sys/health
- ネットワーク設定の確認
- ファイアウォール設定
- DNS設定
- プロキシ設定
セキュリティ上の注意事項
やるべきこと ✅
- 環境変数でVaultトークンを管理: コードにトークンを含めない
- 最小権限の原則を適用: 必要最小限の権限のみを付与
- 定期的なシークレットローテーション: 定期的に認証情報を更新
- 監査ログの有効化: すべてのアクセスを記録
- TLS/HTTPSの使用: 通信を暗号化
- トークンのTTL設定: トークンに有効期限を設定
- 動的シークレットの活用: 可能な限り動的シークレットを使用
やってはいけないこと ❌
- Vaultトークンをコードにハードコーディング: 絶対に避ける
- 過度に広い権限の付与: 必要以上の権限を与えない
- 本番環境でrootトークンを使用: 開発環境のみで使用
- シークレットをログに出力: ログにシークレットを含めない
- 平文での通信: 必ずHTTPSを使用
- トークンの共有: 個人ごとにトークンを発行
- 長期間有効なトークン: 適切なTTLを設定
次のステップ
Vaultとの連携を理解したら、以下のトピックも確認してください:
今後追加予定のトピック
- Terraform Cloud/Enterpriseとの連携
- CI/CDパイプラインでの使用
- モジュール開発のベストプラクティス