Secret management is always a serious issue in any kind of application. Although, Kubernetes has its own Secret feature could help to manage secret, but after some reading I realized that it basically encode the secret with Base64.
So, I looked into HashiCorp Vault.
HashiCorp Vault
It is an open source secret management tool that used to manage access to sensitive credential.
Refer here for more information.
Vault Setup
HashiCorp have provided a ready Helm Chart that we can use.
- Create the following files in our demo helm chart directory :
-
Chart.yaml
1 2 3 4 5
apiVersion: v1 name: helm-vault version: 0.1.0 appVersion: 1.0 description: Helm Vault
-
requirements.yaml
1 2 3 4 5 6
dependencies: - name: vault version: 0.8.0 repository: "https://helm.releases.hashicorp.com" condition: vault.enabled alias: vault
-
values.yaml
** We will come back to the value later.
-
Dev Mode
Vault provide an option to start Vault server in dev
mode which does not require any further setup.
Note: Never, ever, ever run a “dev” mode server in production
In this section we will setup Vault in dev mode and validate it by running a simple KV store and read action via API.
- Edit
values.yaml
with the following value.1 2 3 4 5 6
vault: server: dev: enabled: true readinessProbe: enabled: false
- Set the dev.enabled to
true
. - Set the readinessProbe.enabled to
false
as the probe check will query the status with https which the Vault server currently does not support HTTPS scheme
- Set the dev.enabled to
-
Helm install the Vault.
helm install helm-vault
-
Once the pod is ready, we will need to port forward the vault service to localhost to play around with Vault.
kubectl port-forward helm-vault 8200:8200
-
Execute following command to store a KV into vault.
1 2 3 4 5 6 7 8 9 10 11
curl --location --request POST 'http://localhost:8200/v1/secret/data/my-secret' \ --header 'X-Vault-Token:root' \ --header 'Content-Type: application/json' \ --data '{ "options": { "cas": 0 }, "data": { "secretKey": "secretValue" } }'
- We will store the KV at
my-secret
. - A token
root
(Dev Mode default token) is set at the header.
- We will store the KV at
-
Execute the following command to read the KV from the path we set in step4.
1 2
curl --location --request GET http://localhost:8200/v1/secret/data/my-secret?version=1 \ --header "X-Vault-Token: root"
Sample KV Read response:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
{ "request_id": "c7305d4f-29b3-e097-a837-1149cf95e3c5", "lease_id": "", "renewable": false, "lease_duration": 0, "data": { "data": { "foo": "bar", "zip": "zap" }, "metadata": { "created_time": "2020-11-29T04:19:17.5690113Z", "deletion_time": "", "destroyed": false, "version": 1 } }, "wrap_info": null, "warnings": null, "auth": null }
Standard mode
In this section, we will setup the vault with TSL.
SSL Certificate and Key
We will use cfssl to generate SSL certificate and key for our vault to use.
-
Create a directory named
ssl
, and download the required software.1 2 3 4 5 6 7 8 9
mkdir ssl cd ssl curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl_1.4.1_linux_amd64 -o cfssl chmod +x cfssl curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssljson_1.4.1_linux_amd64 -o cfssljson chmod +x cfssljson curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl-certinfo_1.4.1_linux_amd64 -o cfssl-certinfo chmod +x cfssl-certinfo
-
Create CA CSR, Configuration, Vualt Certificate CSR.
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
echo ''' { "hosts": [ "cluster.local" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "MY", "L": "KualaLumpur", "O": "Example", "OU": "CA", "ST": "Example" } ] } '''> ca-csr.json echo ''' { "signing": { "default": { "expiry": "8760h" }, "profiles": { "default": { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "8760h" } } } } '''> ca-config.json echo ''' { "CN": "helm-vault", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "MY", "L": "KualaLumpur", "O": "Kubernetes", "OU": "Vault", "ST": "" } ] } '''> vault-csr.json
-
Create CA cert and key.
1
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
-
Generate cert and private key for Vault.
1 2 3 4 5 6 7
cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -hostname="helm-vault,helm-vault.playground.svc.cluster.local,helm-vault.playground.svc,localhost,127.0.0.1" \ -profile=default \ vault-csr.json | cfssljson -bare helm-vault
Note:
-hostname
need to follow according the kubernetes service name and namespace.
In my case,- kubernetes service name =
helm-vault
- kubernetes namespace =
playground
- kubernetes service name =
- At this point, you should have the below 6 files created :
ca.pem
ca-key.pem
ca.csr
helm-vault.pem
helm-vault-key.pem
helm-vault.csr
-
Remove cfssl software.
1
rm cfssl cfssl-certinfo cfssljson
Configure Helm
-
Create a directory named
templates
. -
In directory
templates
, create a kubernetes secret,vault-secret.yaml
:1 2 3 4 5 6 7 8 9 10 11 12 13
apiVersion: v1 kind: Secret metadata: name: vault-secret data: helm-vault.pem: |- {{ .Files.Get "ssl/helm-vault.pem" | b64enc }} helm-vault-key.pem: |- {{ .Files.Get "ssl/helm-vault-key.pem" | b64enc }} ca.pem: |- {{ .Files.Get "ssl/ca.pem" | b64enc }}
-
Configure
values.yaml
as below: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
vault: global: tlsDisable: false server: dev: enabled: false standalone: config: | ui = true listener "tcp" { tls_disable = 0 address = "[::]:8200" cluster_address = "[::]:8201" tls_cert_file = "/vault/userconfig/vault-secret/helm-vault.pem" tls_key_file = "/vault/userconfig/vault-secret/helm-vault-key.pem" } storage "file" { path = "/vault/data" } extraEnvironmentVars: VAULT_CACERT: /vault/userconfig/vault-secret/ca.pem extraVolumes: - type: secret name: vault-secret
Run Vault
-
Helm install the Vault.
helm install helm-vault .
- Unseal vault with following command
kubectl exec pod/helm-vault-0 -- vault operator init -key-shares=1 -key-threshold=1
You will be getting an unseal key and token by executing the command.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Unseal Key 1: 1+Pwsc6ZonA3nK51UVrB4rDqkMtTqtxyPbHT4StGkPA= Initial Root Token: s.0WGR21db8KpPuBL69zowkLjl Vault initialized with 1 key shares and a key threshold of 1. Please securely distribute the key shares printed above. When the Vault is re-sealed, restarted, or stopped, you must supply at least 1 of these keys to unseal it before it can start servicing requests. Vault does not store the generated master key. Without at least 1 key to reconstruct the master key, Vault will remain permanently sealed! 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.
- Unseal Key :
1+Pwsc6ZonA3nK51UVrB4rDqkMtTqtxyPbHT4StGkPA=
- Root Token :
s.0WGR21db8KpPuBL69zowkLjl
- Unseal Key :
- Unseal Vault with the key obtained.
1
kubectl exec pod/helm-vault-0 -- vault operator unseal 1+Pwsc6ZonA3nK51UVrB4rDqkMtTqtxyPbHT4StGkPA=
-
Execute the command below to enable KV store feature.
1
kubectl exec pod/helm-vault-0 -- sh -c 'export VAULT_TOKEN="s.0WGR21db8KpPuBL69zowkLjl" && vault secrets enable -version=1 -path secret kv'
-
Vault is ready now.
-
Execute following command to store a KV into vault.
1 2 3 4 5 6 7 8 9 10 11 12 13
curl --location --request POST 'https://localhost:8200/v1/secret/data/my-secret' \ --cacert helm-vault.pem \ --header 'X-Vault-Token:s.0WGR21db8KpPuBL69zowkLjl' \ --header 'Content-Type: application/json' \ --data '{ "options": { "cas": 0 }, "data": { "secretKey": "secretValue" } }'
- We will store the KV at
my-secret
. - A token
s.0WGR21db8KpPuBL69zowkLjl
is set at the header. helm-vault.pem
is used for TSL.
- We will store the KV at
-
Execute the following command to read the KV from the path we set in step6.
1 2 3
curl --location --request GET https://localhost:8200/v1/secret/data/my-secret?version=1 \ --cacert helm-vault.pem \ --header "X-Vault-Token: s.0WGR21db8KpPuBL69zowkLjl"
Sample KV Read response:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
{ "request_id": "c9af2608-ced3-492d-f1a8-e41b2d121709", "lease_id": "", "renewable": false, "lease_duration": 2764800, "data": { "data": { "secretKey": "secretValue" }, "options": { "cas": 0 } }, "wrap_info": null, "warnings": null, "auth": null }
Reference
Vault KV API : Documentation
SSL Certificate Generation: Ref1 | Ref2