Vault Workshop 08: Vault in Docker and Initialization
如果你希望追蹤最新的草稿,請見鐵人賽2023
本 workshop 也接受網友的許願清單,如果有興趣的題目可於第一篇底下留言,筆者會盡力實現,但不做任何保證
整篇 Workshop 會使用的範例與原始碼,放在 Github Repository: vault-playground
Day 08: Vault in Docker and Initialization
Vault in container
前幾天我們使用 vault dev Server 來啟用測試用的 Vault server。
在 production 環境我們不會使用 dev Server。Vault 提供許多安裝方法
- 可以使用 binary 直接安裝在VM上
- 也可以透過 hashicorp/vault official docker image,在container 環境中執行
- 或是使用 hashicorp official helm chart,安裝在kuberntes上
使用範例 repository
你可以使用筆者準備的範例 repository https://github.com/chechiachang/vault-playground
git clone git@github.com:chechiachang/vault-playground.git
cd deploy/00-docker-dev/
你可以使用下列指令啟動 vault in docker
- 並使用 -v flag 來掛載 ./config/ volume 到 container 中的 /vault/config.d/
docker run --cap-add=IPC_LOCK \
--volume ./vault/config/:/vault/config.d \
--volume ./vault/file/:/vault/file \
--volume ./vault/logs/:/vault/logs \
-p 8200:8200 \
--name vault_1 \
-d \
hashicorp/vault:1.14.3 \
vault server -config=/vault/config.d/vault.hcl
然後使用 docker logs 指令檢視 vault server log
docker logs -f vault_1
output
==> Vault server configuration:
Administrative Namespace:
Api Address: https://0.0.0.0:8200
Cgo: disabled
Cluster Address: https://0.0.0.0:8201
Environment Variables: GODEBUG, GOTRACEBACK, HOME, HOSTNAME, NAME, PATH, PWD, SHLVL, VERSION
Go Version: go1.20.8
Listener 1: tcp (addr: "0.0.0.0:8200", cluster address: "0.0.0.0:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level:
Mlock: supported: true, enabled: false
Recovery Mode: false
Storage: file
Version: Vault v1.14.3, built 2023-09-11T21:23:55Z
Version Sha: 56debfa71653e72433345f23cd26276bc90629ce
==> Vault server started! Log data will stream in below:
2023-09-20T13:38:25.914Z [INFO] proxy environment: http_proxy="" https_proxy="" no_proxy=""
2023-09-20T13:38:25.920Z [INFO] core: Initializing version history cache for core
你會發現,vault server 不是以 dev server 的狀態啟動的,需要進行額外的初始化設定
export VAULT_ADDR='http://127.0.0.1:8200'
檢查 vault status
vault status
output,顯示一個上未初始化的 vault server 與其 storage backend “filesyste”
- 可以在 ./vault/config/vault.hcl 上看到我們使用新的 Storage Backend “file” 設定
- vault server 的 storage backend 目前是 sealed 狀態
- 不是 vault server sealed,而是沒有提供 vault server 初始化設定 / unseal keys,所以 vault server 無法解密 storage backend
Key Value
--- -----
Seal Type shamir
Initialized false
Sealed true
Total Shares 0
Threshold 0
Unseal Progress 0/0
Unseal Nonce n/a
Version 1.14.3
Build Date 2023-09-11T21:23:55Z
Storage Type file
HA Enabled false
Storage Backend: filesystem
https://developer.hashicorp.com/vault/docs/configuration/storage/filesystem
filesystem storage backend將 Vault 的資料存儲在文件系統上,使用標準的目錄結構。
它可以用於持久的Single Server情況,或者在本地開發時,耐久性不是關鍵問題的情況下使用。
filesystem storage backend 不支援高可用性 - 檔案系統後端不支援高可用性。
filesystem storage backend 由HashiCorp 官方支援 - 檔案系統後端是由 HashiCorp 官方支援維護的。
初始化 Vault
初始化是配置 Vault 的過程。僅對第一次使用在 Vault server 上的 Backend 上執行一次。在高可用(HA)模式下運行時,這僅在每個叢集(Vault Cluster)中執行一次,而不是每台Server。
在初始化期間,將生成加密金鑰、創建 unseal keys,並創建 init root token。
初始化不需身份驗證,僅適用於全新的 Vault,有資料存在的 Storage Backend 無法用初始化解鎖。
要初始化 Vault,使用以下命令
vault operator init
output
Unseal Key 1: 9AYJ...kNCn
Unseal Key 2: RqDx...odRU
Unseal Key 3: uHUv...lws4
Unseal Key 4: f+KD...aHgL
Unseal Key 5: AKyF...e6vd
Initial Root Token: hvs.8yU3...7esX
Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.
# Vault 使用了 5 個金鑰份額encryption key share和 3 的 key threshold 進行初始化。請安全地分發上面的金鑰份額。
# 當 Vault 被重新密封、重新啟動或停止時,你必須提供至少 3 個這些金鑰來對其進行解封,然後它才能開始處理請求。
Vault does not store the generated root key. Without at least 3 keys to
reconstruct the root key, Vault will remain permanently sealed!
# Vault 不存儲生成的根金鑰。如果沒有至少 3 個金鑰來重建根金鑰,Vault 將保持永久密封!
It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.
# 如果你有足夠的現有解封金鑰份額,則可以生成新的解封金鑰。有關更多信息,請參閱 "vault operator rekey"。
初始化過程輸出了兩個非常重要的信息:解封金鑰和 init root token。這是唯一一次 Vault 顯示這些資料。
為了這個入門課程,請將這些金鑰保存在某個地方,然後繼續進行操作。
- Vault backend storage 認 key 不認人,請收好這五隻 unseal key,放置在五個不同安全的地方
- 有 3/5 的 unseal key 就能重建 encryption key,也就是能夠解密 storage backend
- 可以用 3/5 unseal key 產生 root token
vault operator generate-root
- 換句話說,unseal key 是比 root 還大的超級管理員 key
- 在實際的部署情況下,你永遠不應該將這些金鑰保存在一起。
- 你可能會使用 Vault 的 PGP 和 Keybase.io 支援,使用使用者的 PGP 金鑰加密每個解封金鑰。
- 這可以防止單個人擁有所有的解封金鑰。
vault server log,可以看到 vault server 開始進行初始化流程
2023-09-20T13:47:05.113Z [INFO] core: security barrier not initialized
2023-09-20T13:47:05.117Z [INFO] core: seal configuration missing, not initialized
2023-09-20T14:03:28.506Z [INFO] core: security barrier not initialized
2023-09-20T14:03:28.512Z [INFO] core: seal configuration missing, not initialized
2023-09-20T14:03:28.521Z [INFO] core: security barrier not initialized
2023-09-20T14:03:28.557Z [INFO] core: security barrier initialized: stored=1 shares=5 threshold=3
2023-09-20T14:03:28.589Z [INFO] core: post-unseal setup starting
2023-09-20T14:03:28.609Z [INFO] core: loaded wrapping token key
2023-09-20T14:03:28.609Z [INFO] core: successfully setup plugin catalog: plugin-directory=""
2023-09-20T14:03:28.613Z [INFO] core: no mounts; adding default mount table
2023-09-20T14:03:28.629Z [INFO] core: successfully mounted: type=cubbyhole version="v1.14.3+builtin.vault" path=cubbyhole/ namespace="ID: root. Path: "
2023-09-20T14:03:28.631Z [INFO] core: successfully mounted: type=system version="v1.14.3+builtin.vault" path=sys/ namespace="ID: root. Path: "
2023-09-20T14:03:28.631Z [INFO] core: successfully mounted: type=identity version="v1.14.3+builtin.vault" path=identity/ namespace="ID: root. Path: "
2023-09-20T14:03:28.686Z [INFO] core: successfully mounted: type=token version="v1.14.3+builtin.vault" path=token/ namespace="ID: root. Path: "
2023-09-20T14:03:28.696Z [INFO] rollback: starting rollback manager
2023-09-20T14:03:28.697Z [INFO] core: restoring leases
2023-09-20T14:03:28.698Z [INFO] expiration: lease restore complete
2023-09-20T14:03:28.713Z [INFO] identity: entities restored
2023-09-20T14:03:28.714Z [INFO] identity: groups restored
2023-09-20T14:03:28.720Z [INFO] core: usage gauge collection is disabled
2023-09-20T14:03:28.733Z [INFO] core: Recorded vault version: vault version=1.14.3 upgrade time="2023-09-20 14:03:28.720230178 +0000 UTC" build date=2023-09-11T21:23:55Z
2023-09-20T14:03:29.120Z [INFO] core: post-unseal setup complete
2023-09-20T14:03:29.146Z [INFO] core: root token generated
2023-09-20T14:03:29.146Z [INFO] core: pre-seal teardown starting
2023-09-20T14:03:29.146Z [INFO] rollback: stopping rollback manager
2023-09-20T14:03:29.146Z [INFO] core: pre-seal teardown complete
你可以在這時檢視 ./vault/file 裡面的內容,./vault/file 在 vault operator init
前是空白的
ls -al ./vault/file
output,可以看到 ./vault/file 內已經初始化 filesystem storage backend 的內容
core
logical
sys
你可以檢視 ./vault/file/* 內的檔案內容,會發現內容都是 json 相容格式,而且都經過加密
- 在正常的條件下,沒有 unseal key 的人,是無法在有效時間內解鎖這些 filesystem 中的內容,內容還是受到保護
- 這並不代表你可以隨意放置 filesystem storage backend 的內容
- 例如將他 commit 到 repository 中(vault-playground 已經添加 .gitignore)
- 請選擇安全,經過 vault 資安團隊測試過的 backend,來保障資料安全與可用程度
Unseal
每個初始化的 Vault Server 都始於密封狀態。根據配置,Vault 可以訪問 storage backend,但它無法讀取其中的任何資料,因為它不知道如何解密它。教會 Vault 如何解密數據稱為解封(unseal) Vault。
每次 Vault 開始運行時都必須進行解封。可以通過 API 和命令行來執行解封操作。
要解封 Vault,你必須擁有解封金鑰的閾值數量(threshold)。在上面的輸出中,請注意 “key threshold” 是 3。這意味著要解封 Vault,你需要 5 個生成的金鑰中的 3 個。
注意
Vault 不存儲任何解封金鑰片段(key share)。Vault 使用一種稱為 Shamir’s Secret Sharing 的算法來將 root encryption key 分成片段(share)。只有擁有threshold數量的金鑰,才能將其重建,最終訪問你的資料。
開始解封 Vault:
vault operator unseal
output
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 1/3
Unseal Nonce 9d03a4e0-bb4f-cfd5-326b-5afb55fdce53
Version 1.14.3
Build Date 2023-09-11T21:23:55Z
Storage Type file
HA Enabled false
繼續操作,輸入3/5把 unseal key 就可順利解封 storage backend
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 3
Version 1.14.3
Build Date 2023-09-11T21:23:55Z
Storage Type file
Cluster Name vault-cluster-f90273e8
Cluster ID 5ecc63c9-11eb-c384-355d-dffea2dd6484
HA Enabled false
vault server log,成功解封後
2023-09-20T14:57:17.077Z [INFO] core.cluster-listener.tcp: starting listener: listener_address=0.0.0.0:8201
2023-09-20T14:57:17.078Z [INFO] core.cluster-listener: serving cluster requests: cluster_listen_address=[::]:8201
2023-09-20T14:57:17.089Z [INFO] core: post-unseal setup starting
2023-09-20T14:57:17.115Z [INFO] core: loaded wrapping token key
2023-09-20T14:57:17.115Z [INFO] core: successfully setup plugin catalog: plugin-directory=""
2023-09-20T14:57:17.127Z [INFO] core: successfully mounted: type=system version="v1.14.3+builtin.vault" path=sys/ namespace="ID: root. Path: "
2023-09-20T14:57:17.128Z [INFO] core: successfully mounted: type=identity version="v1.14.3+builtin.vault" path=identity/ namespace="ID: root. Path: "
2023-09-20T14:57:17.128Z [INFO] core: successfully mounted: type=cubbyhole version="v1.14.3+builtin.vault" path=cubbyhole/ namespace="ID: root. Path: "
2023-09-20T14:57:17.148Z [INFO] core: successfully mounted: type=token version="v1.14.3+builtin.vault" path=token/ namespace="ID: root. Path: "
2023-09-20T14:57:17.154Z [INFO] rollback: starting rollback manager
2023-09-20T14:57:17.154Z [INFO] core: restoring leases
2023-09-20T14:57:17.156Z [INFO] expiration: lease restore complete
2023-09-20T14:57:17.158Z [INFO] identity: entities restored
2023-09-20T14:57:17.159Z [INFO] identity: groups restored
2023-09-20T14:57:17.166Z [INFO] core: usage gauge collection is disabled
2023-09-20T14:57:17.178Z [INFO] core: post-unseal setup complete
2023-09-20T14:57:17.178Z [INFO] core: vault is unsealed
Hashicorp Vault docker
使用容器(container) 前需要查閱 image 的官方說明 https://hub.docker.com/r/hashicorp/vault,幾件事情要注意
Base Image 是選擇使用 Alpine,比起其他 linux distributions 具有相對較小的安全風險,但功能足夠用於開發和測試。
Vault 始終在 dumb-init 下運行,將 process 與 SIG 傳遞給容器中運行的所有process。
使用的 Binary 由 HashiCorp 構建,並使用 GPG 金鑰簽名,因此你可以驗證Binary。
在不帶任何參數的情況下運行 Vault,容器將為你提供一個處於dev mode的 Vault Server。
容器公開了兩個可選的volume:
/vault/logs,用於寫入 audit log。預設情況下,這裡不會寫入任何內容;必須在Vault config 中啟用文件audit backend。
/vault/file,用於在使用資料storage plugin時,將資料寫入persistency。預設情況下,這裡不寫入任何內容(dev mode使用 in-memory storage);在啟動容器之前,必須在 Vault 的配置中啟用文件 data storagebackend。
容器在 /vault/config 設置了一個 Vault 配置目錄,Server 將通過volume,載入這裡放置的任何 hcl 或 json config file。或者,也可以通過通過環境變數 VAULT_LOCAL_CONFIG
傳遞配置 json 來添加config。
Vault configuration
如同前面說明,透過 --volume ./config/:/vault/config.d
flag 將 ./config/vault.hcl 設定檔案掛載進容器中
你可以檢視目前的 vault server configuration,是以 vault.hcl 格式表示
cat ./config/vault.hcl
output,在這裡可以設置 vault server 的啟動參數
- 配置一個 listener “tcp”,監聽容器內 0.0.0.0:8200 進來的 request
- 由於
docker run
也設定-p 8200:8200
將主機網路的 8200 port bind 到容器的 8200 port,讓我們可以在主機網路中存取 vault。
ui = true
disable_mlock = true
api_addr = "https://0.0.0.0:8200"
default_lease_ttl = "168h"
max_lease_ttl = "720h"
storage "file" {
path = "/vault/file"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = "true"
}
操作 Vault
Vault in Docker 使用起來與透過 binary 執行的 dev server 一樣。
你可以參照前幾天文章的內容,對 vault server 進行操做,也算是做個練習
vault login
vault secrets list
vault secrets enable -version=2 -path=chechia-net kv
在後面的內容,我們會用更有效率的方式管理,設定 vault
關閉 vault container
你可以使用以下指令關閉 vault容器
docker stop vault_1
output,server 接受到後會進行 docker 封鎖
==> Vault shutdown triggered
2023-09-20T13:06:28.627Z [INFO] core: marked as sealed
2023-09-20T13:06:28.627Z [INFO] core: pre-seal teardown starting
2023-09-20T13:06:28.627Z [INFO] rollback: stopping rollback manager
2023-09-20T13:06:28.628Z [INFO] core: pre-seal teardown complete
2023-09-20T13:06:28.628Z [INFO] core: stopping cluster listeners
2023-09-20T13:06:28.628Z [INFO] core.cluster-listener: forwarding rpc listeners stopped
2023-09-20T13:06:28.641Z [INFO] core.cluster-listener: rpc listeners successfully shut down
2023-09-20T13:06:28.641Z [INFO] core: cluster listeners successfully shut down
2023-09-20T13:06:28.641Z [INFO] core: vault is sealed
如果有啟用 storage backend 的話,vault 資料或留存在 storage “file” 上,重啟不會如 dev server in-memory storage 一樣,被清空
vault operator
你可以使用 vault operator 指令來做更多 vault cluster 相關的操作
vault operator -h
你可以使用下列指令產生新的 root token
vault operator generate-root -generate-otp
output
A One-Time-Password has been generated for you and is shown in the OTP field.
You will need this value to decode the resulting root token, so keep it safe.
Nonce 13ed8986-7b01-323c-0d06-2c32536fb8c1
Started true
Progress 0/3
Complete false
OTP eYr...cMqx
OTP Length 28
vault server log 顯示開始產生 root
2023-09-20T15:12:08.633Z [INFO] core: root generation initialized: nonce=13ed8986-7b01-323c-0d06-2c32536fb8c1
使用 -otp flag,並輸入 unseal key
vault operator generate-root -otp="..."
output
Operation nonce: 13ed8986-7b01-323c-0d06-2c32536fb8c1
Unseal Key (will be hidden):
Nonce 13ed8986-7b01-323c-0d06-2c32536fb8c1
Started true
Progress 1/3
Complete false
持續輸入 3/5 unseal keys,直到取得 encoded token
Operation nonce: 13ed8986-7b01-323c-0d06-2c32536fb8c1
Unseal Key (will be hidden):
Nonce 13ed8986-7b01-323c-0d06-2c32536fb8c1
Started true
Progress 3/3
Complete true
Encoded Token DS8B...MdGw
使用 otp + encoded token 來進行 decode
vault operator generate-root \
-decode="DS8B...MdGw" \
-otp="eYr1...cMqx"
output
hvs.bDKG...Pnlc
vault server log 顯示逞生 root 完成
2023-09-20T15:15:40.541Z [INFO] core: root generation finished: nonce=13ed8986-7b01-323c-0d06-2c32536fb8c1
NOTE: 第一把 init root token 還是有效,加上後來生成的第二把,現在有兩把常效期的 root token
清空
你可以刪除 ./vault/file/,完全清除 vault server 使用的 filesystem storage backend
rm -rf ./vault/file/*
vault server 本身幾乎是無狀態,清除 storage backend 後就什麼也不剩了
chatGPT
本段部分內容使用 chatGPT-3.5 翻譯 https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-deploy https://hub.docker.com/r/hashicorp/vault 內容,並由筆者人工校驗
base context
我希望你能充當一名繁體中文翻譯,拼寫修正者和改進者。我將用英文與程式語言與你對話,你將翻譯它,並以已糾正且改進的版本回答,以繁體中文表達。我希望你能用更美麗和優雅、高級的繁體中文詞語和句子替換我簡化的詞語和句子。保持意義不變。我只希望你回答糾正和改進,不要寫解釋。
很重要:不要使用敬語,翻譯結果中若出現"您",請用"你"取代"您"。
result correction
部分英文內容為專有名詞,產生的繁體中文翻譯結果中,這些名詞維持英文,不需要翻譯成中文:key,value,certificate,token,policy,policy rule,path,path-based,key rolling,audit,audit trail,plain text,key value,Consul,S3 bucket,Leasing,Renewal,binary,prefix,instance,metadata。
修正下列翻譯:將 "數據" 改為 "資料",將 "數據庫" 改為 "資料庫",將 "數據" 改為 "資料",將 "訪問" 改為 "存取",將 "源代碼" 改為 "原始碼",將 "信息" 改為 "資訊",將 "命令" 改為 "指令",將 "禁用" 改為 "停用",將 "默認" 改為 "預設"。