Chuyển đến nội dung chính

レッスン 10: AWS、Azure、GCP、およびクラウド シークレット エンジン

AWS Secrets Engine (IAM, STS AssumeRole, Federation Token), Azure Secrets Engine (Service Principal, Static roles 1.21), GCP Secrets Engine (SA keys, OAuth2), multi-cloud best practices.

🔒 D​​evSecOps — レッスン 10 レッスン 10: AWS、Azure、GCP、クラウドの秘密 Engines

HashiCorp Vault の基本から上級まで

パート 2: シークレット エンジン - シークレットの管理

xdev.asia

## 導入

Cloud Secrets Engine を使用すると、Vault でクラウド プロバイダー (AWS、Azure、GCP) の 動的認証情報 を作成できます。 Vault は、有効期間の長いクラウド認証情報 (IAM アクセス キー、サービス プリンシパル シークレット、サービス アカウント キー) を管理する代わりに、オンデマンドで有効期間の短い認証情報を作成し、TTL の有効期限が切れると自動的に取り消します。

主な利点

  • 長期間有効な認証情報は不要: 認証情報が漏洩した場合のリスクを軽減します
  • 最小権限: 各リクエストは必要な権限を正確に受け取ります。
  • 監査証跡: 誰がいつクラウド認証情報を要求したかを正確に把握します。
  • 集中アクセス: 単一の場所からマルチクラウド アクセスを管理
  • 自動ローテーション: 手動でキーをローテーションする必要はありません

PHẦN 1: AWS Secrets Engine

###1.1. AWS Secrets Engine のアーキテクチャ

┌──────────────┐   Request AWS creds    ┌───────────┐
│  Application │ ─────────────────────▶ │   Vault   │
│              │ ◀───────────────────── │   AWS     │
│              │   Dynamic IAM creds    │  Engine   │
└──────────────┘                        └─────┬─────┘
                                              │
                                              │ AWS API calls
                                              ▼
                                        ┌───────────┐
                                        │    AWS     │
                                        │  IAM/STS  │
                                        └───────────┘

Vault は 3 種類の認証情報をサポートしています。

タイプ説明TTL
IAM ユーザーIAM ユーザー + アクセスキーを作成ロング (キーローテーションあり)
STS の役割を引き受けるAssumeRole → 一時的な認証情報15分~12時間
STS フェデレーション トークン取得フェデレーショントークン15分~36時間

###1.2.有効化と構成

# Enable AWS secrets engine
vault secrets enable aws

# Configure root credentials cho Vault
vault write aws/config/root \
  access_key="AKIAIOSFODNN7EXAMPLE" \
  secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  region="ap-southeast-1"

# Rotate root credentials ngay (khuyến nghị!)
vault write -f aws/config/rotate-root

# Cấu hình lease
vault write aws/config/lease \
  lease="30m" \
  lease_max="1h"

セキュリティ: ルート認証情報をローテーションした後は、Vault のみが新しいアクセス キーを認識します。回転する前に構成がテストされていることを確認してください。

1.3. IAM User Credentials

アプリケーションがアクセス キーを要求すると、Vault はアクセス キーを持つ IAM ユーザーを作成します。

# Tạo role cho IAM user
vault write aws/roles/s3-readonly \
  credential_type=iam_user \
  policy_document=-<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-app-bucket",
        "arn:aws:s3:::my-app-bucket/*"
      ]
    }
  ]
}
EOF

# Hoặc sử dụng existing IAM policy ARN
vault write aws/roles/ec2-admin \
  credential_type=iam_user \
  policy_arns="arn:aws:iam::aws:policy/AmazonEC2FullAccess"

# Request credentials
vault read aws/creds/s3-readonly

# Output:
# Key                Value
# ---                -----
# lease_id           aws/creds/s3-readonly/abcd1234...
# lease_duration     30m
# lease_renewable    true
# access_key         AKIAI44QH8DHBEXAMPLE
# secret_key         je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
# security_token     <nil>

1.4. STS AssumeRole

STS AssumeRole は、IAM ロールを引き受けることによって一時的な認証情報を作成します。IAM ユーザーを作成する必要はありません。

# Tạo IAM role trên AWS trước (Trust policy cho phép Vault assume)
# Trust policy cho Vault's IAM user:
# {
#   "Version": "2012-10-17",
#   "Statement": [{
#     "Effect": "Allow",
#     "Principal": {"AWS": "arn:aws:iam::123456789012:user/vault-user"},
#     "Action": "sts:AssumeRole"
#   }]
# }

# Tạo Vault role cho STS AssumeRole
vault write aws/roles/deploy-role \
  credential_type=assumed_role \
  role_arns="arn:aws:iam::123456789012:role/DeployRole" \
  default_sts_ttl="1h" \
  max_sts_ttl="4h"

# Request credentials
vault read aws/creds/deploy-role

# Output:
# Key                Value
# ---                -----
# lease_id           aws/creds/deploy-role/xyz789...
# lease_duration     1h
# lease_renewable    false
# access_key         ASIAJEXAMPLEXEG2JICEA
# secret_key         9drTJvcXLB89EXAMPLEKEY
# security_token     AQoDYXdzEBY...  ← STS session token

# STS credentials có security_token — phải sử dụng cả 3 values
export AWS_ACCESS_KEY_ID="ASIAJEXAMPLEXEG2JICEA"
export AWS_SECRET_ACCESS_KEY="9drTJvcXLB89EXAMPLEKEY"
export AWS_SESSION_TOKEN="AQoDYXdzEBY..."

aws s3 ls

1.5. STS Federation Token

# Tạo role Federation Token
vault write aws/roles/ci-deploy \
  credential_type=federation_token \
  policy_document=-<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload",
        "ecs:UpdateService",
        "ecs:DescribeServices"
      ],
      "Resource": "*"
    }
  ]
}
EOF

# Request credentials
vault read aws/creds/ci-deploy

###1.6.スクリプトは AWS 動的認証情報を使用します

#!/bin/bash
# aws-deploy.sh — Deploy sử dụng Vault dynamic credentials

set -euo pipefail

ROLE="${1:-deploy-role}"

# Lấy credentials từ Vault
echo "Requesting AWS credentials from Vault..."
CREDS=$(vault read -format=json "aws/creds/${ROLE}")

export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r '.data.access_key')
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r '.data.secret_key')

# STS credentials có security_token
TOKEN=$(echo "$CREDS" | jq -r '.data.security_token // empty')
if [ -n "$TOKEN" ]; then
  export AWS_SESSION_TOKEN="$TOKEN"
fi

LEASE_ID=$(echo "$CREDS" | jq -r '.lease_id')
echo "Got credentials. Lease: $LEASE_ID"

# Cleanup khi exit
cleanup() {
  echo "Revoking AWS credentials..."
  vault lease revoke "$LEASE_ID" 2>/dev/null || true
}
trap cleanup EXIT

# Thực hiện deploy
echo "Deploying..."
aws ecs update-service \
  --cluster production \
  --service my-app \
  --force-new-deployment

echo "Deploy complete!"

PHẦN 2: Azure Secrets Engine

###2.1.有効化と構成

# Enable Azure secrets engine
vault secrets enable azure

# Configure Azure credentials
vault write azure/config \
  subscription_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" \
  tenant_id="11111111-2222-3333-4444-555555555555" \
  client_id="66666666-7777-8888-9999-000000000000" \
  client_secret="AzureClientSecretValue"

# Rotate root credentials
vault write -f azure/config/rotate-root

2.2. Dynamic Service Principal

Vault は、指定されたロール割り当てを持つ一時的な Azure サービス プリンシパル (SP) を作成します。

# Tạo role — Dynamic SP với Contributor trên Resource Group
vault write azure/roles/contributor-rg \
  ttl=1h \
  max_ttl=4h \
  azure_roles=-<<EOF
[
  {
    "role_name": "Contributor",
    "scope": "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/my-app-rg"
  }
]
EOF

# Tạo role với nhiều role assignments
vault write azure/roles/devops-role \
  ttl=2h \
  max_ttl=8h \
  azure_roles=-<<EOF
[
  {
    "role_name": "Contributor",
    "scope": "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/my-app-rg"
  },
  {
    "role_name": "AcrPush",
    "scope": "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/my-app-rg/providers/Microsoft.ContainerRegistry/registries/myappacr"
  }
]
EOF

# Request credentials
vault read azure/creds/contributor-rg

# Output:
# Key                Value
# ---                -----
# client_id          zzzzzzzz-yyyy-xxxx-wwww-vvvvvvvvvvvv
# client_secret      DynamicGeneratedSecret123!
# lease_duration     1h
# lease_id           azure/creds/contributor-rg/abc...
# lease_renewable    true

###2.3. Azure の動的資格情報を使用する

# Lấy credentials từ Vault
CREDS=$(vault read -format=json azure/creds/contributor-rg)

CLIENT_ID=$(echo "$CREDS" | jq -r '.data.client_id')
CLIENT_SECRET=$(echo "$CREDS" | jq -r '.data.client_secret')

# Login Azure CLI
az login --service-principal \
  --username "$CLIENT_ID" \
  --password "$CLIENT_SECRET" \
  --tenant "11111111-2222-3333-4444-555555555555"

# Thực hiện operations
az vm list --resource-group my-app-rg

# Cleanup
LEASE_ID=$(echo "$CREDS" | jq -r '.lease_id')
vault lease revoke "$LEASE_ID"
az logout

2.4. Azure Static Roles (Vault 1.21+)

静的ロールを使用すると、Vault で 既存のサービス プリンシパルのパスワード ローテーションを管理できるようになります。

# Tạo static role cho existing SP
vault write azure/static-roles/my-static-sp \
  application_object_id="app-object-id-here" \
  rotation_period="86400"

# Đọc current credentials
vault read azure/static-creds/my-static-sp

# Output:
# Key                    Value
# ---                    -----
# client_id              existing-sp-client-id
# client_secret          AutoRotatedPassword!
# last_vault_rotation    2024-01-15T12:00:00Z
# rotation_period        24h
# ttl                    23h45m

# Force rotation
vault write -f azure/rotate-role/my-static-sp

###2.5。 MS Graph 権限を持つ Azure ロール

# Role với Azure AD permissions (MS Graph)
vault write azure/roles/graph-reader \
  ttl=1h \
  max_ttl=4h \
  azure_groups=-<<EOF
[
  {
    "group_name": "App-Developers",
    "object_id": "group-object-id-here"
  }
]
EOF

PHẦN 3: GCP Secrets Engine

###3.1.有効化と構成

# Enable GCP secrets engine
vault secrets enable gcp

# Configure với Service Account key
vault write gcp/config \
  credentials=@/path/to/vault-sa-key.json \
  ttl=3600 \
  max_ttl=86400

3.2. Service Account Key (Roleset)

Vault は一時的なサービス アカウント キーを作成します。

# Tạo roleset cho GCS access
vault write gcp/roleset/gcs-reader \
  project="my-gcp-project" \
  secret_type="service_account_key" \
  bindings=-<<EOF
resource "//cloudresourcemanager.googleapis.com/projects/my-gcp-project" {
  roles = [
    "roles/storage.objectViewer"
  ]
}
EOF

# Request Service Account key
vault read gcp/roleset/gcs-reader/key

# Output:
# Key                 Value
# ---                 -----
# lease_duration      1h
# lease_id            gcp/roleset/gcs-reader/key/abc...
# lease_renewable     true
# key_algorithm       KEY_ALG_RSA_2048
# key_type            TYPE_GOOGLE_CREDENTIALS_FILE
# private_key_data    ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsC...  ← base64 encoded JSON key

3.3. OAuth2 Access Token (Roleset)

Vault はキーを生成する代わりに、有効期間の短い OAuth2 アクセス トークンを返すことができます。

# Tạo roleset cho OAuth2 tokens
vault write gcp/roleset/compute-viewer \
  project="my-gcp-project" \
  secret_type="access_token" \
  token_scopes="https://www.googleapis.com/auth/compute.readonly" \
  bindings=-<<EOF
resource "//cloudresourcemanager.googleapis.com/projects/my-gcp-project" {
  roles = [
    "roles/compute.viewer"
  ]
}
EOF

# Request OAuth2 token
vault read gcp/roleset/compute-viewer/token

# Output:
# Key                Value
# ---                -----
# expires_at_seconds 1705315800
# token              ya29.a0AfB_byBq...
# token_ttl          3599

# Sử dụng token
curl -H "Authorization: Bearer ya29.a0AfB_byBq..." \
  "https://compute.googleapis.com/compute/v1/projects/my-gcp-project/zones/asia-southeast1-a/instances"

3.4. Static Account

既存のサービス アカウントのキーのローテーションを管理します。

# Tạo static account
vault write gcp/static-account/my-app-sa \
  service_account_email="[email protected]" \
  secret_type="service_account_key" \
  bindings=-<<EOF
resource "//cloudresourcemanager.googleapis.com/projects/my-gcp-project" {
  roles = [
    "roles/cloudsql.client"
  ]
}
EOF

# Đọc key
vault read gcp/static-account/my-app-sa/key

# OAuth2 token cho static account
vault write gcp/static-account/my-app-sa \
  service_account_email="[email protected]" \
  secret_type="access_token" \
  token_scopes="https://www.googleapis.com/auth/cloud-platform"

vault read gcp/static-account/my-app-sa/token

# Rotate key
vault write -f gcp/static-account/my-app-sa/rotate-key

###3.5。 GCP 認証情報を使用する

#!/bin/bash
# gcp-deploy.sh — Deploy sử dụng Vault GCP credentials

set -euo pipefail

# Lấy Service Account key từ Vault
KEY_DATA=$(vault read -format=json gcp/roleset/gcs-reader/key | \
  jq -r '.data.private_key_data' | base64 -d)

# Ghi ra temp file
KEYFILE=$(mktemp /tmp/gcp-key-XXXXXX.json)
echo "$KEY_DATA" > "$KEYFILE"

# Cleanup khi exit
cleanup() {
  rm -f "$KEYFILE"
  LEASE_ID=$(vault read -format=json gcp/roleset/gcs-reader/key | jq -r '.lease_id')
  vault lease revoke "$LEASE_ID" 2>/dev/null || true
}
trap cleanup EXIT

# Activate Service Account
gcloud auth activate-service-account --key-file="$KEYFILE"

# Thực hiện operations
gsutil ls gs://my-app-bucket/

echo "Done!"

PHẦN 4: Multi-Cloud Best Practices

###4.1.政策組織

# === AWS Policies ===

# Policy cho CI/CD pipeline
path "aws/creds/ci-deploy" {
  capabilities = ["read"]
}

# Policy cho developer (read-only)
path "aws/creds/s3-readonly" {
  capabilities = ["read"]
}

# === Azure Policies ===

path "azure/creds/contributor-rg" {
  capabilities = ["read"]
}

path "azure/static-creds/my-static-sp" {
  capabilities = ["read"]
}

# === GCP Policies ===

path "gcp/roleset/gcs-reader/key" {
  capabilities = ["read"]
}

path "gcp/roleset/compute-viewer/token" {
  capabilities = ["read"]
}

# === Lease Management ===

path "sys/leases/renew" {
  capabilities = ["update"]
}

path "sys/leases/revoke" {
  capabilities = ["update"]
}

4.2. Multi-Cloud Helper Script

#!/bin/bash
# cloud-creds.sh — Unified script cho multi-cloud credentials

set -euo pipefail

PROVIDER="$1"
ROLE="$2"
shift 2

case "$PROVIDER" in
  aws)
    echo "Getting AWS credentials..."
    CREDS=$(vault read -format=json "aws/creds/${ROLE}")
    
    export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r '.data.access_key')
    export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r '.data.secret_key')
    
    TOKEN=$(echo "$CREDS" | jq -r '.data.security_token // empty')
    [ -n "$TOKEN" ] && export AWS_SESSION_TOKEN="$TOKEN"
    ;;
    
  azure)
    echo "Getting Azure credentials..."
    CREDS=$(vault read -format=json "azure/creds/${ROLE}")
    
    export AZURE_CLIENT_ID=$(echo "$CREDS" | jq -r '.data.client_id')
    export AZURE_CLIENT_SECRET=$(echo "$CREDS" | jq -r '.data.client_secret')
    export AZURE_TENANT_ID="your-tenant-id"
    ;;
    
  gcp)
    echo "Getting GCP credentials..."
    KEYFILE=$(mktemp /tmp/gcp-key-XXXXXX.json)
    
    vault read -format=json "gcp/roleset/${ROLE}/key" | \
      jq -r '.data.private_key_data' | base64 -d > "$KEYFILE"
    
    export GOOGLE_APPLICATION_CREDENTIALS="$KEYFILE"
    ;;
    
  *)
    echo "Unknown provider: $PROVIDER"
    echo "Usage: $0 <aws|azure|gcp> <role> -- <command>"
    exit 1
    ;;
esac

# Lưu lease ID cho cleanup
LEASE_ID=$(echo "$CREDS" 2>/dev/null | jq -r '.lease_id // empty')

cleanup() {
  [ -n "${LEASE_ID:-}" ] && vault lease revoke "$LEASE_ID" 2>/dev/null || true
  [ -n "${KEYFILE:-}" ] && rm -f "$KEYFILE" 2>/dev/null || true
}
trap cleanup EXIT

echo "Credentials ready. Executing command..."
exec "$@"

使用:

# AWS
./cloud-creds.sh aws deploy-role -- aws s3 ls

# Azure
./cloud-creds.sh azure contributor-rg -- az vm list -g my-app-rg

# GCP
./cloud-creds.sh gcp gcs-reader -- gsutil ls gs://my-bucket/

4.3. TTL Guidelines cho Cloud Credentials

Use CaseAWSAzureGCP
CI/CD PipelineSTS AssumeRole, 30mDynamic SP, 1hOAuth2 Token, 1h
Developer AccessSTS AssumeRole, 1hDynamic SP, 2hOAuth2 Token, 1h
Application RuntimeIAM User + RotationStatic SP, 24h rotateStatic SA, key rotate
Emergency AccessSTS AssumeRole, 15mDynamic SP, 30mOAuth2 Token, 30m

4.4. Monitoring Cloud Credentials

# Kiểm tra active leases cho từng provider
echo "=== AWS Active Leases ==="
vault list sys/leases/lookup/aws/creds/ 2>/dev/null || echo "None"

echo "=== Azure Active Leases ==="
vault list sys/leases/lookup/azure/creds/ 2>/dev/null || echo "None"

echo "=== GCP Active Leases ==="
vault list sys/leases/lookup/gcp/roleset/ 2>/dev/null || echo "None"

# Force revoke tất cả credentials của một provider
# ⚠️ CẨN THẬN — sẽ ảnh hưởng đến applications đang chạy
vault lease revoke -prefix aws/creds

4.5. Security Checklist cho Cloud Engines

AWS:

  • ✅ Rotate root credentials ngay sau khi configure
  • ✅ IAM ユーザーではなく STS AssumeRole を優先します
  • ✅ IAM ポリシーで条件キーを使用する
  • ✅ CloudTrail で API 呼び出しを監査できるようにする
  • ✅ Least privilege IAM policies cho Vault

Azure:

  • ✅ Rotate root credentials ngay sau khi configure
  • ✅ スコープのロール割り当ては最小限 (リソース グループ、サブスクリプションなし)
  • ✅ 固定 SP を必要とするアプリケーションには Azure 静的ロールを使用します
  • ✅ Monitor SP creation trong Azure AD audit logs

GCP:

  • ✅ サービス アカウント キーの代わりに OAuth2 アクセス トークンを優先します。
  • ✅ Vault SA には iam.serviceAccountKeyAdmin と iam.serviceAccountAdmin のみが必要です
  • ✅ 可能な場合は Workload Identity Federation を使用します
  • ✅ Monitor SA key creation trong Cloud Audit Logs

5. Troubleshooting

5.1. AWS Common Issues

# Error: "error assuming role"
# → Kiểm tra trust policy của IAM role
aws iam get-role --role-name DeployRole | jq '.Role.AssumeRolePolicyDocument'

# Error: "AccessDenied"
# → Vault IAM user thiếu permissions
# → Kiểm tra: sts:AssumeRole, iam:CreateUser, iam:CreateAccessKey, etc.

# Error: "cannot use STS token to call IAM"
# → STS credentials không thể tạo IAM users
# → Sử dụng credential_type=assumed_role thay vì iam_user

5.2. Azure Common Issues

# Error: "insufficient privileges"
# → Vault SP cần: Application.ReadWrite.OwnedBy hoặc Application.ReadWrite.All
# → Plus: Role Based Access Control Administrator trên target scope

# Error: "SP not ready"
# → Azure AD replication delay (vài giây đến vài phút)
# → Thêm wait/retry logic trong application

5.3. GCP Common Issues

# Error: "permission denied"
# → Vault SA cần:
#    - iam.serviceAccountAdmin
#    - iam.serviceAccountKeyAdmin
#    - resourcemanager.projectIamAdmin (cho bindings)

# Error: "quota exceeded"
# → GCP giới hạn 10 keys per SA
# → Revoke leases cũ hoặc dùng OAuth2 tokens

## まとめ

このレッスンでは、Cloud Secrets Engine の使用方法をマスターしました。

  1. AWS Secrets Engine — IAM Users, STS AssumeRole, Federation Tokens
  2. Azure Secrets Engine — Dynamic Service Principals, Static Roles (1.21+)
  3. GCP Secrets Engine — Service Account Keys, OAuth2 Tokens, Static Accounts
  4. Multi-cloud best practices — unified tooling, policies, monitoring
  5. TTL ガイドライン — ユースケースごとに適切な認証情報の種類と TTL を選択します
  6. トラブルシューティング — 一般的な問題の処理

これは パート 2: シークレット エンジンの最後の記事です。 KV 静的シークレット、データベースの動的認証情報、PKI 証明書、トランジット暗号化からクラウド認証情報に至るまで、Vault のすべての最も重要なシークレット エンジンの強固な基盤がすでに構築されています。次のセクションでは、認証方法、つまり Vault で ID を認証および管理する方法について詳しく説明します。