HashiCorp Vault
データベースのパスワードといった、ソフトウェアシステムで扱う秘密情報の管理を行うためのソフトウェア。 秘密情報を暗号化された状態で保管したり、システムを構成する他のソフトウェアと連携して、各ソフトウェアにアクセスするための秘密情報を作成、提供、破棄したりすることができる。
Vaultの概念
「ソフトウェアシステムのコンポーネントが、auth methodを使ってVaultにログインし、secret engineを使って秘密情報を作成、取得などする」というのが基本的なユースケースである。
秘密情報の作成、保管、提供、破棄を担う。
ソフトウェアシステムのコンポーネントが使用する秘密情報の管理も担う。例えば、アプリケーションがDBMSの認証情報の作成と提供をVaultに要求したとき、Vaultは認証情報を作成、提供するとともに、DBMSでSQLを実行してアプリケーションがその認証情報を使えるように準備する、といったことができる。
Vaultへのアクセスを認証する。端的に言えばVaultへのログイン方法を提供するコンポーネント。
ソフトウェアシステムのコンポーネントがVaultで秘密情報を作成したり、Vaultで保管されている秘密情報を欲しかったりするとき、Vaultにログインして取得することになる。
入門や導入に役立つ記事
公式ドキュメントのクイックスタート
運用用途:
Vaultの設定をシェルスクリプトやTerraformで自動化する
Vaultの秘密情報はマスターキーで暗号化されている。
unseal keyというキーを渡して、マスターキーを解いてVault内の秘密情報を使えるようにすることをunseal、その逆をsealという。
Vaultを停止すると自動的にsealされる。
Vaultを起動する際に秘密情報を使えるようにするためには、unsealをしなければならない。
unsealの方法はいくつかある。
手動Unseal:VaultのCLIなりAPIでunsealオペレーションを呼び出して、unseal keyを渡す。
Transit auto unseal:
別のVaultインスタンスのTransit secret engineにunseal keyを保管させて、auto unsealされる側のVaultインスタンスは、保管されているunseal keyを取得してunsealする。
unseal keyを保管しているインスタンスのunsealをどうするか?という問題が残るが、auto unsealされる側のVaultインスタンスが多数ある場合は、手動unsealを1回に減らせるので便利。mgn901.icon
参考にした資料
参考にした資料
ソフトウェアシステムのコンポーネントがVaultから秘密情報を取得するときには、App Roleというauth methodを使うことが多い。
1. ソフトウェアシステムのコンポーネント毎にroleを作成する。
2. 作成したroleからrole-idとsecret-idを払い出す。
3. ソフトウェアシステムのコンポーネントはそれらの認証情報を使ってVaultにログインし、秘密情報を取得する。
App Roleの有効化
APIでapprole以下を叩いたときにApp Roleの機能を使えるようにする。
code:sh
# CLIで行う場合
vault auth enable -path approle approle
code:tf
# Terraformで行う場合
resource "vault_auth_backend" "approle" {
type = "approle"
path = "approle"
}
Vaultを使いたいコンポーネント毎にroleを作成する。
このroleから払い出されるsecret-idの有効期間は5分
ログイン後のコンポーネントがVaultから秘密情報を取得する際に使用するクライアントトークンの有効期間は10分(延長すると最大15分)
token_ttlなどの代わりにtoken_periodでトークンの有効期間を指定すると、token_periodが過ぎる前に延長すれば無期限で使えるが、延長をサボると無効になるトークン(Periodic Token)が払い出される。 code:sh
vault write auth/approle/role/webapp-role \
policies=webapp-policy
secret_id_ttl=5m \
token_ttl=10m \
token_max_ttl=15m
code:tf
resource "vault_approle_auth_backend_role" "webapp-role" {
backend = "approle"
role_name = "webapp-role"
secret_id_ttl = "5m"
token_ttl = "10m"
token_max_ttl = "15m"
# 同じファイルでApp Roleの有効化を行う場合は、roleの作成をApp Role有効化後に行わせる。
}
ソフトウェアシステムのコンポーネントからVaultにログインする。
作成したroleからrole-idとsecret-idを払い出し、ソフトウェアシステムのコンポーネントはそれらの認証情報を使ってVaultにログインする。
方法1: secret_idをVault管理者から渡してもらう
1. Vault管理者はrole-idとsecret-idを生成する
code:sh
vault read -field=role_id auth/approle/role/webapp-role/role-id
vault write -field=secret_id -f auth/approle/role/webapp-role/secret-id
2. ソフトウェアシステムのコンポーネントでは、管理者からrole_idとsecret_idを受け取り、Vaultにログインする。
code:sh
# Vault CLI使用の場合
vault write -field=token auth/approle/login \
role_id=$VAULT_ROLE_ID \
secret_id=$VAULT_SECRET_ID
方法2: secret_idを取得できるようなtokenをVault管理者から渡してもらう
参考にした資料
Vaultユーザが取得可能な秘密情報の種類を制限する。
例えばsecret/data/webapp以下の秘密情報に対してwriteコマンドを実行するためには、secret/data/webapp/*に対してcreate、updateが必要。
ポリシーの作成
code:sh
cat > ./webapp-policy.hcl <<EOF
path "secret/data/webapp/*" {
}
path "database/creds/webapp-dbrole" {
}
EOF
vault policy write webapp-policy webapp-policy.hcl
参考にした資料
秘密情報の読み書きができる。
KVの有効化
code:sh
vault secrets enable -path secret -version 2 kv
code:tf
resource "vault_mount" "secret" {
type = "kv"
path = "secret"
options = {
version = "2"
}
}
KVにデータを保存する
<mount_path>/data/<name>にwriteすると保存できる。
code:sh
vault write secret/data/webapp/initial-user username=root password=72779673
code:tf
resource "vault_kv_secret_v2" "webapp-initial-user" {
mount = "secret"
name = "webapp/initial-user"
data_json = <<EOT
{
"username": "root",
"password": "72779673"
}
EOT
}
password policyを使ってKVでランダムなシークレットを生成することもできる。
参考にした資料
Databaseの有効化
code:sh
vault secrets enable -path database database
code:tf
resource "vault_mount" "database" {
path = "database"
type = "database"
}
Vaultからデータベースへ接続できるように設定する(この例ではPostgreSQLに接続する設定をwebapp-dbという名前で作成する) code:sh
vault write database/config/webapp-db \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@postgres.example.com:5432/db?sslmode=disable" \
allowed_roles=webapp-dbrole \
username="root" \
password="root72779673"
database roleを作成する
Vaultがデータベース上に作成するユーザの種類を定義できる。
db_nameには接続設定の名前を指定する。(この例ではwebapp-dbという名前で作成してある)
code:sh
cat > webapp-dbrole-creation-statements.sql <<EOF
CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}' INHERIT;
GRANT ALL PRIVILEGES ON DATABASE db TO "{{name}}";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";
EOF
vault write database/roles/webapp-dbrole \
db_name=webapp-db \
creation_statements=@webapp-dbrole-creation-statements.sql \
defualt_ttl=1h \
max_ttl=24h
Vaultにデータベース上のユーザを作成させる
code:sh
vault read database/creds/webapp-dbrole
code:txt
Key Value
--- -----
lease_id database/creds/webapp-dbrole/nNzFGjZxZoZpvpHIWcmLFtV6
lease_duration 24h
lease_renewable true
password 1kryMOYJWS-pxNr9jdvh
username v-root-webapp-d-pc12bPcJhOWS3V2LRJ5y-1761465062
初回起動時にやること
管理側
root tokenを無効化する
vault-admin roleを作成する
再起動時にやること
管理側
Vaultの手動unseal
コンポーネント側
Vaultにログインしてアプリケーションを起動する。
Dynamic Secretsを取得し続ける必要がある場合は、Vaultのクライアントトークンを定期的にrenewする。
障害復帰時にやること
管理側
Vaultの手動unseal
vault-admin roleから各コンポーネントにrole-idとsecret-idを払い出す
新しい認証情報を使ってコンポーネントを起動
コンポーネント側
Vaultにログインしてアプリケーションを起動する。
Dynamic Secretsを取得し続ける必要がある場合は、Vaultのクライアントトークンを定期的にrenewする。