Hashcorp Vault 基礎使用教程

我們在工作中是如何管理大量的 Secret 信息的?(比如筆者的項目中會涉及到對 OpenSSH 的祕鑰及口令存儲、以及對此的定時輪轉及外部調用)

我們需要實現的通用密碼倉庫需要滿足如下特性:

本文要介紹 Vault 這款開源的 Secret 管理工具(口令、token、私鑰及證書等等),是管理代碼中口令、祕鑰(防止明文泄漏)極佳的應用實踐。此外,KMS(Key Management Service,雲服務居多)也是較好的 Secret 管理實踐。vault 項目源碼 在此(https://github.com/hashicorp/vault)

針對此類產品,需要着重關注以下幾點:

  1. Secret 的存儲方式,支持的存儲後端

  2. Secret 的加密方式及算法

  3. 系統的權限控制、權限分配(哪些人 / 客戶端能訪問哪些機器的 Secret)

  4. 系統的認證方式,客戶端使用什麼方式訪問 RestfulAPI

  5. 系統的 Secret 存儲方式及過期機制

  6. 系統的高可用性如何保證

  7. 系統對外接口的 QPS 及併發性能

0x01 Vault 基本原理

本小節參考官方文檔(https://www.vaultproject.io/docs/internals/architecture)。vault 的基礎應用場景如下:

Vault 的使用場景一般爲:

  1. 系統用戶(如運維同事)通過 HTTP-Vault-API、Vault 命令行工具等將 Secret data 寫入 Vault

  2. Vault 再將加密的數據存儲到後端

  3. 外部用戶(如開發人員,各類腳本或者應用程序)通過 HTTP-Vault-API、Vault 命令行工具等方式來獲取到僅僅與自己賬號相關聯的 Secret data,這裏就涉及到 Valut 的權限細粒度管理

vault 的架構如下:

從架構圖可以看出,Vault 分爲 Storage Backend、安全屏障(Barrier) 和 HTTP API 三個部分,Storage Backend 和 Vault 之間的所有數據流動都需要經過 Barrier,Barrier 確保只有加密數據會被寫入 Storage Backend,加密數據在經過 Barrier 被讀出的過程中被驗證與解密。

其他主要組件的功能如下:

Vault 的數據流

0x02 Vault 的主要運行流程

Step1:數據存儲及加密解密

瞭解幾個名詞:1、Storage Backend(後端存儲): Vault 自身不存儲數據,需要爲其配置 Storage Backend。注意!!Storage Backend 是不受信任的,只用於存儲加密數據

2、Initialaztion: Vault 在首次啓動時需要初始化,這一步生成一個加密密鑰(Encryption key)用於加密數據,加密完成的數據才能被保存到 Storage Backend

3、Unseal(解封): Vault 啓動後,因爲不知道加密密鑰(Encryption Key),它會進入封印(Sealed)狀態,在被解封前無法進行任何操作。Encryption Key 被 Master key 保護,必須提供 Master key 才能完成 Unseal 操作

Master key 和 Encryption Key 的關係如下圖所示:

Step2:認證 && 權限管理

在 Unseal(解封) 操作完成後,Vault 纔可以處理客戶端請求,客戶端首次連接 Vault 時,需要先完成身份認證。客戶端的身份認證方式有:

此一般流程如下:

  1. 客戶端發起身份驗證請求,該請求流經 Core 模塊並進入 Auth methodsAuth methods 確定請求是否有效並返回關聯策略(Policies)的列表。在通過 Auth methods 完成了身份認證,並且檢查的關聯策略也符合授權之後,Token Store 將會生成並管理一個新的 Token, 這個 Token 會被返回給客戶端,用於進行後續請求。需要注意的是,此 token 也都存在一個 Lease 租期(有效期),同時 Token 關聯了相關的策略 Policies,這些策略將被用於驗證請求的權限。

  2. 請求經過驗證後,將被路由到 Secret engine 模塊。如果 Secret engine 返回了一個 Secret(由 Vault 自動生成的 Secret), Core 會將其註冊到 Expiration manager,並給它附加一個 lease IDlease ID 被客戶端用於更新(Renew)或吊銷(Revoke)它得到的 Secret。如果客戶端允許租約(Lease)到期,Expiration manager 將自動吊銷這個 Secret Token

Step3:Secret Engine(重要)

Secret Engine 是 Vault 系統保存、生成或者加密數據的組件。Secret Engine 類似一個虛擬文件系統,所有的 read/write/delete/list 操作等都在它下面進行的,然後 Secret Engine 可以自己決定如何來響應請求。從代碼設計角度而言,Secret Engine 一種抽象,它對上層(調用方)提供統一的接口,如物理文件系統、數據庫等等,都可以統一使用增刪改查這些操作接口。常用的 Engine 有如下幾種:

可以通過指令 vault secrets list 查看 Vault 中當前開啓了哪些 Secret Engine

[root@VM_120_245_centos ~/vault]# vault secrets enable -path=secret_bifrost kv
Success! Enabled the kv secrets engine at: secret_bifrost/
[root@VM_120_245_centos ~/vault]# vault secrets list
Path               Type         Accessor              Description
----               ----         --------              -----------
cubbyhole/         cubbyhole    cubbyhole_e86bac2b    per-token private secret storage
identity/          identity     identity_19b16864     identity store
kv/                kv           kv_988a3c7e           n/a
secret/            kv           kv_4a27cb62           n/a
secret_bifrost/    kv           kv_0b5b6ac3           n/a
sys/               system       system_8d02021f       system endpoints used for control, policy and debugging
vault/             kv           kv_e26a68a4           n/a

從指令輸出可知:有 4 個類型爲 kv(鍵值對加密存儲) 的引擎,分別加載到了 kv/secret/secret_bifrost/vault/ 路徑上;其他幾個 Engine 是 Vault 內部支撐。之所以能夠向指定的路徑進行讀寫,是因爲有 Secret Engine 的支持,未加載的路徑是不能訪問的(會報錯),不能同時開啓相同的路徑。

此外,同一個 Secret Engine 可以被加載到不同的路徑下(一個 Secret Engine 類的多個實例),每個路徑下的數據都是彼此獨立的。

0x03 Vault Details

本小節介紹 Vault 實現上的一些細節。

Shamir 密鑰分享算法(shamir secret sharing)

Vault 中給出了 Shamir 算法的 實現,該密鑰分享算法的基本思想是分發者通過祕密多項式,將祕密 Secret 分解爲 n 個祕密持有者,其中任意至少於 k 個祕密均能恢復密文,即某一個祕密通常不能由單個持有者保存,必須將祕密分由多人保管並且只有當多人同時在場時祕密才能得以恢復。

Vault 認證方法

Vault 支持 如下 的身份認證機制:1、Token 方式 Token 是 Vault 內置的驗證方法,啓動時即被加載,且不能禁用。例如,服務器初始化時會輸出 Root Token,使用 Root Token 登錄的用戶具有系統最高的訪問權限。在 Vault 中,Token 是可繼承的樹型結構,此 <繼承> 包括兩方面的含義:

2、AppRole 方式 AppRole 是 Vault 爲 App 應用提供的一種較爲安全的認證方式,推薦使用。使用 AppRole 的一般流程爲(From 官網):

#1、創建只讀 policy 文件模板 readonly
[root@VM_120_245_centos /vault]# cat readonly
# Read-only permission on secrets stored at 'secret/data/mysql/webapp'
path "secret/data/mysql/webapp" {
  capabilities = ["read"]
}
#2、加載 policy
[root@VM_120_245_centos /vault]# vault policy write readonly readonly<br>
Success! Uploaded policy: readonly
#3、創建帶 TTL 的 token
[root@VM_120_245_centos /vault]# vault write auth/approle/role/readonly token_policies="readonly" token_ttl=1h token_max_ttl=4h
Success! Data written to: auth/approle/role/readonly

#4、查看 readonly 的認證信息
[root@VM_120_245_centos /vault]#  vault read auth/approle/role/readonly
Key                        Value
---                        -----
bind_secret_id             true local_secret_ids           false secret_id_bound_cidrs      <nil>
secret_id_num_uses         0
secret_id_ttl              0s
token_bound_cidrs          []
token_explicit_max_ttl     0s
token_max_ttl              4h
token_no_default_policy    false token_num_uses             0
token_period               0s
token_policies             [readonly]
token_ttl                  1h
token_type                 default

#5、查看 rold-id,vault read auth/approle/role/readonly/role-id
[root@VM_120_245_centos /vault]# vault read auth/approle/role/readonly/role-id
Key        Value
---        -----
role_id    12afcbf7-33c9-d86f-e678-dc2beeb3fabd

#6、查看 secret-id
[root@VM_120_245_centos /vault]# vault write -force auth/approle/role/readonly/secret-id
Key                   Value
---                   -----
secret_id             7c9e58d5-8af2-176b-8fbc-572db2f8c872
secret_id_accessor    ff5c6dca-7b5c-587d-41e2-adaae932a669
secret_id_ttl         0s

#7、根據 role-id 和 secret-id 換取 token
[root@VM_120_245_centos /vault]#  vault write auth/approle/login role_id="12afcbf7-33c9-d86f-e678-dc2beeb3fabd"   secret_id="7c9e58d5-8af2-176b-8fbc-572db2f8c872"
Key                     Value
---                     -----
token                   s.qIcsK6N6lm4TffWWcRIRfRSQ
token_accessor          hDt3u9o9hjfHZwQ7Zisun7Vw
token_duration          1h
token_renewable         true token_policies          ["default" "readonly"]
identity_policies       []
policies                ["default" "readonly"]
token_meta_role_name    readonly

#8、應用新 token 訪問集羣
[root@VM_120_245_centos /vault]# export VAULT_TOKEN=s.qIcsK6N6lm4TffWWcRIRfRSQ
[root@VM_120_245_centos ~/vault]# vault kv get secret/data/mysql/webapp
== Data ==
Key    Value
---    -----
a      1

#9、越權訪問失敗(無法寫入)
[root@VM_120_245_centos /vault]#  vault kv put secret/data/mysql/webapp key=abcd
Error making API request.

URL: GET http://127.0.0.1:8200/v1/sys/internal/ui/mounts/secret/data/mysql/webapp
Code: 403. Errors:

* permission denied

#9、Token 過期後訪問失敗
[root@VM_120_245_centos /vault]# vault kv get secret/data/mysql/webapp
Error making API request.

URL: GET http://127.0.0.1:8200/v1/sys/internal/ui/mounts/secret/data/mysql/webapp
Code: 403. Errors:

* permission denied

從實現上看,role-idsecret-id 相當於應用程序的用戶名和密碼,但是實際上不是如此。Vault 希望用此設計來解決 Secret Zero 問題。

3、各類認證方式比較 Token 方法比較簡便易用,但其目的是爲了支持自身的運行,安全性並不高。對於真正的用戶 / 機器認證場景,Vault 官方推薦使用其他更加成熟的機制,例如 LDAP,Github,AppRole 認證方式。

Vault 授權機制

存儲

Vault 支持多種存儲後端:https://github.com/hashicorp/vault/tree/master/plugins/database,生產架構的後端存儲使用 HA 方式進行部署,比如 consul/etcd/mysql 集羣等。

0x04 Vault 基本功能使用

1、配置 Mysql 作爲存儲後端,啓動 Vault

[root@VM_120_245_centos ~/vault]# cat vault.hcl
disable_mlock  = true ui=true storage "mysql" {
    address = "127.0.0.1:3306"
    username = "root"
    password = "xxxxxx"
    database = "vault"
    table = "vault"
}
listener "tcp" {
 address     = "127.0.0.1:8200"
 tls_disable = 1
}

[root@VM_120_245_centos ~/vault]# vault server -config=vault.hcl

2、初始化 vault,得到 5 個子祕鑰及 root Token

[root@VM_120_245_centos ~/vault]# vault operator init
2021-08-20T21:34:41.973+0800 [INFO]  core: security barrier not initialized
2021-08-20T21:34:42.002+0800 [INFO]  core: security barrier initialized: stored=shares=threshold=3
2021-08-20T21:34:42.031+0800 [INFO]  core: post-unseal setup starting
2021-08-20T21:34:42.060+0800 [INFO]  core: loaded wrapping token key
2021-08-20T21:34:42.060+0800 [INFO]  core: successfully setup plugin catalog: plugin-directory=""
2021-08-20T21:34:42.060+0800 [INFO]  core: no mounts; adding default mount table
2021-08-20T21:34:42.080+0800 [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
2021-08-20T21:34:42.081+0800 [INFO]  core: successfully mounted backend: type=system path=sys/
2021-08-20T21:34:42.081+0800 [INFO]  core: successfully mounted backend: type=identity path=identity/
2021-08-20T21:34:42.136+0800 [INFO]  core: successfully enabled credential backend: type=token path=token/
2021-08-20T21:34:42.137+0800 [INFO]  rollback: starting rollback manager
2021-08-20T21:34:42.137+0800 [INFO]  core: restoring leases
2021-08-20T21:34:42.138+0800 [INFO]  expiration: lease restore complete 2021-08-20T21:34:42.163+0800 [INFO]  identity: entities restored
2021-08-20T21:34:42.164+0800 [INFO]  identity: groups restored
2021-08-20T21:34:42.165+0800 [INFO]  core: usage gauge collection is disabled
2021-08-20T21:34:42.174+0800 [INFO]  core: post-unseal setup complete 2021-08-20T21:34:42.200+0800 [INFO]  core: root token generated
2021-08-20T21:34:42.200+0800 [INFO]  core: pre-seal teardown starting
2021-08-20T21:34:42.200+0800 [INFO]  rollback: stopping rollback manager
2021-08-20T21:34:42.200+0800 [INFO]  core: pre-seal teardown complete Unseal Key 1: xxx1
Unseal Key 2: xxx2
Unseal Key 3: xxx3
Unseal Key 4: xxx4
Unseal Key 5: xxx5

Initial Root Token: xxx-root-token

3、解封 vault,查看解封狀態

[root@VM_120_245_centos ~/vault]# vault operator unseal xxx1
[root@VM_120_245_centos ~/vault]# vault operator unseal xxx2
[root@VM_120_245_centos ~/vault]# vault operator unseal xxx3

[root@VM_120_245_centos ~/vault]# vault status
Key                Value
---                -----
Seal Type          shamir
Initialized        true Sealed             true Total Shares       5
Threshold          3
Unseal Progress    2/3
Unseal Nonce       95ba53e7-63e2-c998-e1b8-4df4bba20ea3
Version            1.8.1
Storage Type       mysql
HA Enabled         false

4、使用 root Token 登錄(首次)

[root@VM_120_245_centos ~/vault]# vault login root-token
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                xxx
token_accessor       xxx
token_duration       ∞
token_renewable      false token_policies       ["root"]
identity_policies    []
policies             ["root"]

5、開啓 vault 組件,測試寫 / 讀 / token 生成等操作

[root@VM_120_245_centos ~/vault]# vault secrets enable kv
2021-08-20T21:44:37.837+0800 [INFO]  core: successful mount: namespace="" path=kv/ type=kv
[root@VM_120_245_centos ~/vault]# vault kv put kv/test api_key=abc1234 api_secret=1a2b3c4d^C
[root@VM_120_245_centos ~/vault]# vault kv get kv/test
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d
[root@VM_120_245_centos ~/vault]# vault token create -ttl 1h
Key                  Value
---                  -----
token                s.6sfhKw2J2dFfNSMdIyWQGqiS
token_accessor       o8MjM5SuLewdJk0WSZ0oPPrF
token_duration       1h
token_renewable      true token_policies       ["root"]
identity_policies    []
policies             ["root"]

[root@VM_120_245_centos ~/vault]# export VAULT_TOKEN=s.6sfhKw2J2dFfNSMdIyWQGqiS
[root@VM_120_245_centos ~/vault]# vault kv get kv/test
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d

6、根據策略模板創建 token 創建 kv/test 路徑下只讀的策略 test-read-policy

[root@VM_120_245_centos ~/vault]# cat limit-token.hcl
path "kv/test"{
capabilities = ["read"]
}
[root@VM_120_245_centos ~/vault]# vault policy write test-read-policy ./limit-token.hcl
Success! Uploaded policy: test-read-policy

根據策略創建 token:

[root@VM_120_245_centos ~/vault]# vault token create -policy=test-read-policy
Key                  Value
---                  -----
token                s.NMD47aWmzSUWC1bAqalQCWYw
token_accessor       gi6WVfxwJnGqMXhDVoJXI5AU
token_duration       768h
token_renewable      true token_policies       ["default" "test-read-policy"]
identity_policies    []
policies             ["default" "test-read-policy"]

測試 token 的操作情況,只讀,寫報錯,符合既定策略:

[root@VM_120_245_centos ~/vault]# export VAULT_TOKEN=s.NMD47aWmzSUWC1bAqalQCWYw
[root@VM_120_245_centos ~/vault]# vault kv get kv/test
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d5e6f
[root@VM_120_245_centos ~/vault]# vault kv put  kv/test api_key=foo api_secret=bar
Error writing data to kv/test: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/kv/test
Code: 403. Errors:

* 1 error occurred:
        * permission denied

7、查看和關閉 Secret engine

[root@VM_120_245_centos ~/vault]# vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_e86bac2b    per-token private secret storage
identity/     identity     identity_19b16864     identity store
kv/           kv           kv_988a3c7e           n/a
secret/       kv           kv_a1c65202           n/a
sys/          system       system_8d02021f       system endpoints used for control, policy and debugging

[root@VM_120_245_centos ~/vault]# vault secrets disable secret/ #關閉 secret/
Success! Disabled the secrets engine (if it existed) at: secret/


[root@VM_120_245_centos ~/vault]# vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_e86bac2b    per-token private secret storage
identity/     identity     identity_19b16864     identity store
kv/           kv           kv_988a3c7e           n/a
sys/          system       system_8d02021f       system endpoints used for control, policy and debugging

8、開啓 V2 的 Secret Engine

[root@VM_120_245_centos ~]# vault secrets enable -path=secretv2 -version=2 kv
Success! Enabled the kv secrets engine at: secretv2/
[root@VM_120_245_centos ~]# vault secrets list
Path               Type         Accessor              Description
----               ----         --------              -----------
bifrost_vault/     kv           kv_962069cd           n/a
cubbyhole/         cubbyhole    cubbyhole_e86bac2b    per-token private secret storage
identity/          identity     identity_19b16864     identity store
kv/                kv           kv_988a3c7e           n/a
secret/            kv           kv_4a27cb62           n/a
secret_bifrost/    kv           kv_0b5b6ac3           n/a
secretv2/          kv           kv_6e9e3b5b           n/a
sys/               system       system_8d02021f       system endpoints used for control, policy and debugging
vault/             kv           kv_e26a68a4           n/a

更多的使用可以參考官方文檔:https://learn.hashicorp.com 瞭解更多。

原文鏈接:https://pandaychen.github.io/2020/01/03/A-HASHCORP-VAULT-INTRO/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ijrkjUVLfN8SPdFVI-frFg