概要
HashiCorp Vault(OSS版)にて、HA Clusterを構成します
前提条件
- HashiCorp Vault 1.13.2 を使って確認した内容です。
- AWS にて、AmazonLinux 2023 3台を使用します。
- Vaultは、Auto-Unseal を利用できるものとします。(未設定の場合は利用できる状態まで済ませてください)
- AWSやEC2、ALB、DNSまわりの細かな設定は省略しますので、ご利用の環境にあわせて設定を行ってください。
上記以外の環境でも利用可能ですので、必要に応じて読み替えてください。
まだauto-unsealを利用していない場合は、こちらで切り替え方法のメモやリンクを載せてます
unseal - auto-unseal 切り替え
PC上で検証環境を作る場合でも、Transit Keyを使ったAuto-Unsealが利用可能です。 ※追加でvaultがもう1台必要
seal Stanza
Auto Unseal(Tutorial)
はじめに
全体の構成
大雑把にですが、下図のような構成を作ります。
- Vault 3台 を 3つのAZに分散して配置し、1つのClusterを構成します(IPは説明の都合上、連番にしています)
- vault-01 192.168.11.101
- vault-02 192.168.11.102
- vault-03 192.168.11.103
- 外部からは、ALB経由でvault cluster にアクセスします
- clusterの各node間通信、およびALBから各node宛ての通信はhttpsに対応します
ストレージタイプについて
Vault ver 1.13 においては、ストレージにRaftを利用することで、シンプルにCluster構成を組むことができます。
RaftはVaultに統合されているため、Vaultのインストールのみで利用でき、追加機能のインストールは不要です。
Raftを利用して初期構成を行うことで、あとはメンバー追加するのみで、容易にClusterを構成できます。
HA Cluster構成は、ストレージタイプ Fileでは利用できません。
Fileですでに稼働中の場合は、データの変換をする必要があります。
※本記事にて、FileからRaftへの移行手段も紹介しています。
Raftの利用時の注意点
- Raftでは、最低3台での構成が必要です。(1台の障害まで許容)
※2台構成では、1台の障害のみでRaftストレージのRead/Writeが一切できなくなります。 - Raft利用時は、バースト可能なCPUの利用は避けることを推奨されています。
本記事ではt2.micro を利用しますが、負荷のかかる環境で利用する場合は、適切なインスタンスタイプを選択してください。
Vault with Integrated Storage Reference Architecture
For predictable performance on cloud providers, it's recommended to avoid "burstable" CPU and storage options (such as AWS
t2
andt3
instance types) whose performance may degrade rapidly under continuous load.
OSS版でのクラスタ構成の動作制限
- OSS版のVaultでは、Clusterの台数を増やしても、性能の向上はありません。
(Standby Node 宛ての処理は、すべてActive Node に転送される)
※HCP Vault や、Enterprise版では、Standby NodeでもRead処理を行う機能があるようです。 - その他、機能の違いについては、下記をご参照ください。
- What is HCP Vault Self Managed と HCP Vaultの比較あり
- Vault pricing HCP Vaultや、Enterprise版のコスト、機能比較
事前準備
EC2の用意
EC2 を3台作成し、vaultをインストールします。
(本例では、AmazonLinux 2023、 InstanceType t2.micro を使用します)
sudo hostnamectl set-hostname vault-01
sudo timedatectl set-timezone Asia/Tokyo
# vault インストール ※この時点ではまだ起動しない
sudo dnf install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo dnf -y install vault
sudo systemctl enable vault
# vault auto complete と、必要環境変数追加
cat <<EOF | sudo tee /etc/profile.d/vault.sh
complete -C /usr/bin/vault vault
export VAULT_SKIP_VERIFY=true
EOF
source /etc/profile
# rsyslog が入ってないので追加
sudo dnf -y install rsyslog
sudo systemctl enable rsyslog
sudo systemctl start rsyslog
SecurityGroup
下記のようなSecurityGroupを定義し、EC2に割り当ててください。
- 同一SecurityGroup内の通信を許可 (Cluster node間の通信用)
- ALBからの tcp 8200 の通信を許可
- その他管理に必要な任意の通信を許可
証明書の用意(https対応時のみ)
node間の通信をhttpsに対応させるために、SSL証明書を用意します。
本例では、証明書作成を簡単にするために、自己署名証明書を利用します。
証明書作成処理 ※要openssl 1.1.1 または 3.0
# 自己署名でSANに vault-cluster を含めた証明書を生成
openssl req -x509 -days 7300 -nodes -newkey rsa:2048 -out vault-cluster.crt -keyout vault-cluster.key -config - <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = vault-cluster
[v3_req]
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = vault-cluster
EOF
説明の都合上、CA証明書も同一ファイルをコピーして使用します。
※ファイル名が同じだとサーバー証明書とCA証明書の設定を混同しそうなので・・・
(みなさんは同じファイル名のままでも構いません)
cp vault-cluster.crt ca.crt
用意した証明書、秘密鍵、CA証明書を、vault の設定に合わせて配置します
※証明書ファイルは、3台ともに同一ファイルを使用してください。
# 証明書の配置
sudo cp vault-cluster.crt vault-cluster.key ca.crt /opt/vault/tls/
sudo chown -R vault: /opt/vault/tls
もし、ご自身でCA証明を利用している場合は、そちらを使って作成してください。
ただし、SANの登録は必須ですので、適切な値(本例では vault-cluster )を登録してください。
Tagの割り当て(auto-join に対応する場合のみ)
3台のEC2に、Vault-Clusterのメンバーであることを示すタグを設定します。
本記事では、 Tag名 Project
値 vault-dev-cluster
とします。
※タグ名、値は任意です
IAM Roleの設定(auto-join に対応する場合のみ)
IAM Roleを作成し、必要なPolicyを追加します。(auto-join に対応する場合のみ)
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "ec2:DescribeInstances",
"Effect": "Allow",
"Resource": "*"
}
]
}
このIAM Roleを、上記で作成した3台のEC2に割り当ててください。
【参考】Vault関連のPolicy
aws 上でvaultを稼働させる場合、ほとんどの場合、aws auth や、aws secret は利用するかと思います。
その場合に必要となるPolicyの一例です。※必要に応じて修正してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:ListRoles",
"iam:GetUser",
"iam:GetRole",
"iam:GetInstanceProfile",
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:RemoveUserFromGroup",
"iam:PutUserPolicy",
"iam:ListUserPolicies",
"iam:ListGroupsForUser",
"iam:ListAttachedUserPolicies",
"iam:ListAccessKeys",
"iam:GetUser",
"iam:DetachUserPolicy",
"iam:DeleteUserPolicy",
"iam:DeleteUser",
"iam:DeleteAccessKey",
"iam:CreateUser",
"iam:CreateAccessKey",
"iam:AttachUserPolicy",
"iam:AddUserToGroup"
],
"Effect": "Allow",
"Resource": [
"arn:aws:iam::*:user/*",
"arn:aws:iam::*:group/*"
]
},
{
"Action": "iam:ListUsers",
"Effect": "Allow",
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Resource": "arn:aws:iam::*:role/*"
}
]
}
構成ファイル指定によるCluster構成
おおよそ下記の順番で進めます
- vault-01 にて、Raft構成、Auto-Unseal の設定を行う。
- vault-01 で、vault サービスを起動。
vault operator init
で初期化を行う - vault-02, 03 も、Raft構成を行ったうえでサービス起動
- 3台ともRaftのメンバーとなったことを確認
vaultの設定 (設定項目の説明)
vault-01, 02, 03 それぞれで、構成ファイル /etc/vault.d/vault.hcl
に設定を追加します。
※設定が終わっても、この時点ではまだ起動しないでください。
ui = true
api_addr = "https://192.168.11.101:8200"
cluster_addr = "https://192.168.11.101:8201"
disable_mlock = true
enable_response_header_hostname = true
enable_response_header_raft_node_id = true
storage "raft" {
path = "/opt/vault/raft"
node_id = "vault-01"
retry_join {
leader_tls_servername = "vault-cluster"
leader_api_addr = "https://192.168.11.101:8200"
leader_ca_cert_file = "/opt/vault/tls/ca.crt"
leader_client_cert_file = "/opt/vault/tls/vault-cluster.crt"
leader_client_key_file = "/opt/vault/tls/vault-cluster.key"
}
retry_join {
leader_tls_servername = "vault-cluster"
leader_api_addr = "https://192.168.11.102:8200"
leader_ca_cert_file = "/opt/vault/tls/ca.crt"
leader_client_cert_file = "/opt/vault/tls/vault-cluster.crt"
leader_client_key_file = "/opt/vault/tls/vault-cluster.key"
}
retry_join {
leader_tls_servername = "vault-cluster"
leader_api_addr = "https://192.168.11.103:8200"
leader_ca_cert_file = "/opt/vault/tls/ca.crt"
leader_client_cert_file = "/opt/vault/tls/vault-cluster.crt"
leader_client_key_file = "/opt/vault/tls/vault-cluster.key"
}
}
# HTTP listener
#listener "tcp" {
# address = "0.0.0.0:8200"
# cluster_address = "0.0.0.0:8201"
# tls_disable = 1
#}
# HTTPS listener
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "0.0.0.0:8201"
tls_cert_file = "/opt/vault/tls/vault-cluster.crt"
tls_key_file = "/opt/vault/tls/vault-cluster.key"
tls_client_ca_file = "/opt/vault/tls/ca.crt"
}
# AWS KMS auto unseal
seal "awskms" {
region = "ap-northeast-1"
kms_key_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
項目 | 説明 |
---|---|
api_addr | Clusterのメンバーに対して、自身のアドレスとして通知する値 Private IPや、内部DNSの登録がある場合はDNS名で指定 |
cluster_addr | Clusterのメンバーに対して、自身のアドレスとして通知する値 Private IPや、内部DNSの登録がある場合はDNS名で指定 |
disable_mlock | Raft利用時は mlock 無効を推奨 |
enable_response_header_hostname | httpヘッダーにhost名を出力(任意) |
enable_response_header_raft_node_id | httpヘッダーにnode_idを出力(任意) |
※api_addr, cluster_addr は、サーバーごとに適切な値を指定
raft 設定項目 | 説明 |
---|---|
path | raft データを配置する場所 |
node_id | node_id をわかりやすい名前で指定 省略時はUUIDとなる |
※ node_id は、サーバーごとに適切な値を指定(省略でも可)
raft retry_join 設定項目 | 説明 |
---|---|
leader_tls_servername | 接続先ノードの証明書中のSANに登録されている値を指定 接続先が適切であるかチェックに使用 ※この値は名前解決できる必要はありません |
leader_api_addr | 接続先 api_addr を指定 |
leader_ca_cert_file | 接続先のサーバー証明書チェックに使うCA証明書 |
leader_client_cert_file | 自身のクライアント証明書 |
leader_client_key_file | クライアント証明書のキー |
※retry_join 部分の設定は、3台とも共通設定で問題ありません
Integrated Storage (Raft) Backend
listener の設定
lister 設定項目 | 説明 |
---|---|
address | vault のAPIを受けるアドレス指定 |
cluster_address | vault のCluste関連通信を受けるアドレス指定 (省略時は address のポートに1足した値) |
tls_cert_file | 自身のサーバー証明書 |
tls_key_file | サーバー証明書のキー |
tls_client_ca_file | クライアント証明書のチェックに使うCA証明書 |
vault-01 起動、raft 、HA の状態チェック
まず1台のホストで、Raftを使った構成で、vaultを起動し、初期化します
# Raftデータ用のディレクトリを作成
[ ! -d /opt/vault/raft ] && sudo mkdir /opt/vault/raft
sudo chown -R vault: /opt/vault/raft
# vault が raft ストレージで正常に起動することを確認
sudo systemctl start vault
vault status
Key Value
--- -----
Recovery Seal Type awskms
Initialized false
Sealed true
(省略)
Storage Type raft
HA Enabled true
# 初期化を行う(発行された 情報は大切に保管)
vault operator init
vault login ******
# raft に、単一ノードで追加されていることを確認
vault operator raft list-peers
Node Address State Voter
---- ------- ----- -----
vault-01 192.168.11.101:8201 leader true
vault operator members
Host Name API Address Cluster Address Active Node Version Upgrade Version Redundancy Zone Last Echo
--------- ----------- --------------- ----------- ------- --------------- --------------- ---------
vault-01 https://192.168.11.101:8200 https://192.168.11.101:8201 true 1.13.2 1.13.2 n/a n/a
# auto unseal で起動できることを確認
sudo systemctl restart vault
vault status
vault-02 起動、raft 、HA の状態チェック
2台目以降は、vaultを起動すれば、自動でClusterに参加できます。
# Raftデータ用のディレクトリを作成
[ ! -d /opt/vault/raft ] && sudo mkdir /opt/vault/raft
sudo chown -R vault: /opt/vault/raft
# vault を起動すると、自動的にRaftに追加され、すでに初期化済みとなる ※反映に数秒かかる
sudo systemctl start vault
vault status
Key Value
--- -----
Recovery Seal Type shamir
Initialized true
Sealed false
(省略)
HA Enabled true
HA Cluster https://192.168.11.101:8201
HA Mode standby
Active Node Address https://192.168.11.101:8200
# vault-01 で取得した root token でログイン
vault login ******
# raft 追加されていることを確認
vault operator raft list-peers
Node Address State Voter
---- ------- ----- -----
vault-01 192.168.11.101:8201 leader true
vault-02 192.168.11.102:8201 follower false
vault operator members
Host Name API Address Cluster Address Active Node Version Upgrade Version Redundancy Zone Last Echo
--------- ----------- --------------- ----------- ------- --------------- --------------- ---------
vault-01 https://192.168.11.101:8200 https://192.168.11.101:8201 true 1.13.2 1.13.2 n/a n/a
vault-02 https://192.168.11.102:8200 https://192.168.11.102:8201 false 1.13.2 1.13.2 n/a 2023-05-18T03:15:24+09:00
vault-03 起動、raft 、HA の状態チェック
# Raftデータ用のディレクトリを作成
[ ! -d /opt/vault/raft ] && sudo mkdir /opt/vault/raft
sudo chown -R vault: /opt/vault/raft
# vault を起動すると、自動的にRaftに追加される
sudo systemctl start vault
vault status
# vault-01 で取得した root token でログイン
vault login ******
# raft 追加されていることを確認
vault operator raft list-peers
Node Address State Voter
---- ------- ----- -----
vault-01 192.168.11.101:8201 leader true
vault-02 192.168.11.102:8201 follower true
vault-03 192.168.11.103:8201 follower false
vault operator members
Host Name API Address Cluster Address Active Node Version Upgrade Version Redundancy Zone Last Echo
--------- ----------- --------------- ----------- ------- --------------- --------------- ---------
vault-01 https://192.168.11.101:8200 https://192.168.11.101:8201 true 1.13.2 1.13.2 n/a n/a
vault-02 https://192.168.11.102:8200 https://192.168.11.102:8201 false 1.13.2 1.13.2 n/a 2023-05-18T03:15:24+09:00
vault-03 https://192.168.11.103:8200 https://192.168.11.103:8201 false 1.13.2 1.13.2 n/a 2023-05-18T03:15:24+09:00
auto-joinを利用したCluster構成
上記の手段では、各メンバーホストのIPアドレス情報をあらかじめ入手する必要がありました。
別の手段として、auto-join 機能を用いることで、特定のタグの付いたメンバーホスト検出し、Raftに自動追加することも可能です。
例えば下記の設定ならば、各ホストとも完全に共通の設定とすることが可能です。
ui = true
api_addr = "https://{{ GetPrivateIP }}:8200"
cluster_addr = "https://{{ GetPrivateIP }}:8201"
disable_mlock = true
enable_response_header_hostname = true
enable_response_header_raft_node_id = true
storage "raft" {
path = "/opt/vault/raft"
retry_join {
auto_join = "provider=aws addr_type=private_v4 tag_key=Project tag_value=vault-dev_cluster region=ap-northeast-1"
auto_join_scheme = "https"
auto_join_port = 8200
leader_ca_cert_file = "/opt/vault/tls/ca.crt"
leader_client_cert_file = "/opt/vault/tls/vault-cluster.crt"
leader_client_key_file = "/opt/vault/tls/vault-cluster.key"
}
}
# HTTP listener
#listener "tcp" {
# address = "0.0.0.0:8200"
# cluster_address = "0.0.0.0:8201"
# tls_disable = 1
#}
# HTTPS listener
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "0.0.0.0:8201"
tls_cert_file = "/opt/vault/tls/vault-cluster.crt"
tls_key_file = "/opt/vault/tls/vault-cluster.key"
tls_client_ca_file = "/opt/vault/tls/ca.crt"
}
# AWS KMS auto unseal
seal "awskms" {
region = "ap-northeast-1"
kms_key_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
項目 | 説明 |
---|---|
api_addr cluster_addr |
{{ GetPrivateIP }} で、自身のPrivateIPを割り当てます |
auto_join | AWS利用時の設定例 EC2に割り当てたTagやregion を指定することで、該当EC2のPrivateIPを検出します |
auto_join_scheme auto_join_port |
https, port 8200 での接続を試みます |
Vault HA Cluster with Integrated Storage on AWS
go-sockaddr template
Integrated Storage (Raft) Backend
hashicorp/go-discover
auto-join を利用する場合も、マニュアル設定時と同様に、初回は1台のnodeのみ起動し、初期化を行った後、順次メンバーを追加してください。
ALBからのヘルスチェック
target group は下記のように設定してください。
- Protocol: HTTPS
- Port 8200
- Health Check Path:
/v1/sys/health
※ヘルスチェックは、Active Node の場合、200を返します。
【参考】FileからRaftへの移行
冒頭で説明したとおり、HA Cluster構成は、File ストレージでは利用できません。
既にFileストレージで利用中の場合は、File → Rafrへのデータ変換が必要です。
あらかじめ、上記マニュアル構成もしくはauto-join構成などを利用して、Raftの設定が追加済みであることを前提とします。
また、root token を使っての操作を前提とします。もしRoot Tokenを削除している場合は、RecoveryKeyから再生成してください。
OS側の操作は、rootユーザー で行います。(パーミッションがややこしいため)
# サービスは停止しておく
systemctl stop vault.service
# もしRaft path が存在しない場合はディレクトリ作成
[ ! -d /opt/vault/raft ] && mkdir /opt/vault/raft
chown -R vault: /opt/vault/raft
# もし既存のRaftデータが存在する場合は、削除しておく
rm -rf /opt/vault/raft/*
現在のディレクトリに、データ変換用ファイルmigrate.hcl
を作成します。
既存のFileストレージのデータが/opt/vault/data
、Raft のデータが /opt/vault/raft
の場合、下記のようになります。
(もし他サーバーで稼働していた場合は、Fileデータを、Clusterを構成するサーバーにコピーしてください)
# 変換元のFileデータのpath指定
storage_source "file" {
path = "/opt/vault/data"
}
# 変換先のRaftデータのpath指定
storage_destination "raft" {
path = "/opt/vault/raft"
node_id = "vault-01"
}
# 自ホストのcluster_addr
cluster_addr = "https://192.168.11.101:8201"
vaultコマンドで、上記ファイルを指定し、データ変換処理を行います。
※vault のサービスは停止状態のままにしてください。
vault operator migrate -config migrate.hcl
(省略)
Success! All of the keys have been migrated.
vaultのサービスではなく、コマンド実行ユーザー(本例ではrootユーザー)によるデータ変換操作です。
したがって、サービス停止状態で問題ありません
ファイルのownerが、root(変換コマンドを実行したユーザー)となっているため、ownerをvault(サービス起動ユーザー)に修正
# 変換されたデータを確認
ls -l /opt/vault/raft
# owner ユーザー/グループを vault に修正
chown -R vault: /opt/vault/raft
サービス起動、Raft で起動したことを確認
systemctl start vault.service
# 起動状態を確認
# データが格納されているため、Initialized true , Auto-unseal 設定により Sealed false となっていることを確認
vault status
Key Value
--- -----
Recovery Seal Type shamir
Initialized true
Sealed false
(省略)
Storage Type raft
HA Enabled true
HA Cluster https://192.168.11.101:8201
HA Mode active
(省略)
もとのFileストレージのデータが移行されたことを確認
# もとのFileストレージで使用していた認証でログイン
vault login *****
# Raftが単一ノードで起動していることを確認
vault operator raft list-peers
# データ移行ができたことを確認
vault auth list
vault secrets list
あとは、Raft初期構成時と同様に、他のメンバーを追加してください。
# 他のノードも起動し、複数 node 構成となったことを確認
vault operator raft list-peers
Node Address State Voter
---- ------- ----- -----
vault-01 192.168.11.101:8201 leader true
vault-02 192.168.11.102:8201 follower true
vault-03 192.168.11.103:8201 follower true
root token や、recovery key も含め、まるごと移行できます
最後に
vault のclusterは、最初から必要機能がすべて備わっているため、設定のみで簡単に構築できます。
耐障害性を確保するためにも、Cluster構成を検討されてはいかがでしょうか?