How do we manage the large amount of Secret information in our work? (For example, my project involves the storage of secret keys and passwords for OpenSSH, as well as the regular rotation and external invocation of this)
- Solidified in a configuration file, stored in a server file or Database
- stored as code on a
git
private repository, with strict access rights to the repository - Hosted on a public cloud service as a KMS (Key Management Service, mostly cloud services)
- Challenges from the cloud:
Unlocking the Cloud Operating Model
(https://www.hashicorp.com/cloud-operating-model)
The generic cryptographic repository we need to implement needs to satisfy the following characteristics.
- Cryptographic storage (taking into account complexity)
- Generic, reducing the workload of manual Secret modification, i.e. providing RestfulAPI
- Permission control
In this article, we would like to introduce Vault, an open source Secret management tool (password, token, private key and certificate, etc.), which is an excellent application practice for managing passwords and secret keys in code (to prevent plaintext leakage). In addition, KMS (Key Management Service, cloud services mostly) is also a better Secret management practice. vault project source code here (https://github.com/hashicorp/vault)
For such products, the following points need to be focused on.
- the way the Secret is stored, the supported storage backend
- the encryption method and algorithm of the Secret
- the system’s permission control, permission allocation (which people / clients can access which machine Secret)
- the system’s authentication method, the client uses what way to access RestfulAPI
- the system’s Secret storage method and expiration mechanism
- how to ensure the high availability of the system
- the QPS and concurrency performance of the system’s external interface
0x01 Vault Fundamentals
This subsection refers to the official documentation
(https://www.vaultproject.io/docs/internals/architecture). The basic application scenario of vault is as follows.
Vault is generally used in the following scenarios:
- system users (such as operations and maintenance colleagues) write Secret data to Vault via
HTTP-Vault-API
, Vault command line tools, etc. - Vault then stores the encrypted data to the backend
- external users (e.g. developers, scripts or applications) use
HTTP-Vault-API
, Vault command-line tools, etc. to get the Secret data associated with their own accounts only, which involves the fine-grained permissions management of Valut
The vault architecture is as follows.
As you can see from the architecture diagram, Vault is divided into three parts: Storage Backend, Barrier and HTTP API. The Barrier ensures that only encrypted data is written to the Storage Backend, and that encrypted data is verified and decrypted as it is read out through the Barrier.
The functions of the other major components are as follows.
HTTP(s) API
:Storage backend
.Token Store
.Auth Method
.Core
: responsible for processing requests and response logs from the Audit brok, sending requests to all configured Audit devicesPolicy store
: responsible for managing and storing ACL Policies, withCore
performing the ACL Policy checks
Vault’s data flow
0x02 The main operation flow of Vault
Step1: Data Storage and Encryption/Decryption
Understand a few terms.
-
Storage Backend: Vault does not store data itself, it needs to be configured with a Storage Backend. Storage Backend is not trusted and is only used to store encrypted data.
-
Initialaztion: Vault needs to be initialized when it is first started, this step generates an Encryption key to encrypt the data, and the encrypted data can only be saved to Storage Backend.
-
Unseal: After the Vault starts, it will enter the Sealed state because the Encryption Key is not known, and no operation can be performed until it is unsealed; the Encryption Key is protected by the Master key, and the Master key must be provided to complete the Unseal operation
The relationship between Master key and Encryption Key is shown in the following figure.
Step2: Authentication && Permissions Management
After the Unseal operation is completed, the Vault can process client requests. The first time a client connects to the Vault, they need to complete authentication. Client authentication methods are as follows
- Suitable for users: User name/password, LDAP authentication, etc. The user must be granted appropriate permissions to access the Vault.
- Suitable for applications: Public/Private keys, Tokens or Jwt Token, etc.
This general flow is as follows.
- The client initiates an authentication request, which flows through the
Core
module and intoAuth methods
, which determines whether the request is valid and returns a list of associated policies (Policies). After the authentication is completed withAuth methods
and the checked association policies match the authorization, theToken Store
generates and manages a new Token, which is returned to the client for subsequent requests. Note that this token also has a Lease term (expiration date), and the Token is associated with a Policy that will be used to verify the request’s authority. - After the request is validated, it is routed to the
Secret engine
module. If theSecret engine
returns a Secret (automatically generated by Vault),Core
registers it with theExpiration manager
and appends alease ID
to it. If the client allows the lease to expire, theExpiration manager
will automatically revoke the Secret Token.
Step3: Secret Engine (important)
The Secret Engine
is the component of the Vault system that saves, generates or encrypts data. The Secret Engine
is like a virtual file system, all read
/write
/delete
/list
operations are performed under it, and then the Secret Engine
can decide for itself how to respond to requests. From the code design point of view, Secret Engine
is an abstraction that provides a unified interface to the upper layer (caller), such as physical file system, database, etc., which can be used to add, delete, change and check these operations. Commonly used Engines are as follows.
kv
: key-value storage. Can be seen as an encrypted Redis, simply store / read some static configuration / dataTransit Secrets Engine
: Provides encryption-as-a-service function, only responsible for encryption and decryption, not storage. The main application scenario is to provide App encrypted and decrypted data, but the data is still stored in MySQL and other databases- Certificate Management: The most common scenario is to store the root certificate (root) in Vault, and the business certificate is issued through this Engine
You can see which Secret Engine
s are currently enabled in the Vault with the command vault secrets list
.
|
|
The output of the command shows that there are 4
engines of type kv
(key-value pair encrypted storage), loaded on the kv/
, secret/
, secret_bifrost/
and vault/
paths; the other engines are supported internally by Vault. You can read and write to the specified paths because they are supported by the Secret Engine
; unloaded paths cannot be accessed (an error will be reported), and you cannot open the same paths at the same time.
In addition, the same Secret Engine
can be loaded under different paths (multiple instances of a single Secret Engine
class), and the data under each path is independent of each other.
0x03 Vault Details
This section describes some details of the Vault implementation.
Shamir key sharing algorithm (shamir secret sharing)
The implementation of Shamir algorithm is given in Vault. The basic idea of this key sharing algorithm is that the distributor decomposes the secret Secret into n
secret holders by a secret polynomial, where any secret at least k
can be recovered, i.e., a secret cannot be kept by a single holder, but must be kept by multiple holders and can be recovered only when multiple holders are present at the same time. the secret can be recovered.
Vault Authentication Methods
Vault supports the following authentication mechanisms.
-
Token method Token is a built-in authentication method in Vault, which is loaded at startup and cannot be disabled. For example,
Root Token
is output when the server is initialized, and the user who logs in withRoot Token
has the highest access rights to the system. In Vault, Token is an inheritable tree structure, and this<inheritance>
has two meanings.- The user holding the Token creates a new Token (
Child Token
), and by default theChild Token
has the same permissions as the parent Token (if specific permissions are required) - When a Token is revoked, the
Child Token
it created, and theChild Token
of theChild Token
(etc.) are deleted together, which is easy to understand from a tree perspective
- The user holding the Token creates a new Token (
-
AppRole method AppRole is a more secure authentication method provided by Vault for App applications, and is recommended. The general process of using AppRole is as follows (From official website).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
#1. Create a read-only policy file template 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. Load policy [root@VM_120_245_centos /vault]# vault policy write readonly readonly<br> Success! Uploaded policy: readonly #3. Create a token with TTL [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. View readonly's authentication information [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. Check 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. Check 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. Exchange token according to role-id and secret-id [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. Apply the new token to access the cluster [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. ultra-authorized access failure (unable to write) [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. Access failure after Token expiration [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
From an implementation perspective,
role-id
andsecret-id
are equivalent to the application’s username and password, but in reality they are not.Vault wants to use this design to solve the
Secret Zero
problem. -
The Token method is easy to use, but it is designed to support its own operation and is not very secure. For real user/machine authentication scenarios, Vault officially recommends using other more mature mechanisms such as LDAP, Github, AppRole authentication methods.
Storage
Vault supports a variety of storage backends: https://github.com/hashicorp/vault/tree/master/plugins/database
, production architecture backends are deployed using the HA
method, such as consul/etcd/mysql clusters, etc.
0x04 Basic functions of Vault
-
Configure Mysql as the storage backend and start Vault
1 2 3 4 5 6 7 8 9 10 11 12 13 14
[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
-
initialize vault, get
5
sub-secret keys androot Token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
[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=1 shares=5 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
-
Unblock vault, view unblock status
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[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
-
Login with
root Token
(first time)1 2 3 4 5 6 7 8 9 10 11 12 13
[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"]
-
Open vault component to test write / read / token generation etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
[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
-
Create token based on policy template Create read-only policy
test-read-policy
underkv/test
pathsCreate token based on policy.
1 2 3 4 5 6 7 8 9
[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"]
Test the operation of the token, read-only, write error, in accordance with the established policy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[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
-
View and close Secret engine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
[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
-
Turn on V2’s Secret Engine
1 2 3 4 5 6 7 8 9 10 11 12 13 14
[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
More use can be found in the official documentation: https://learn.hashicorp.com to learn more.