# Hashicorp Vault

For integrating Hashicorp Vault with the K8s Vault Webhook, first we need to setup Hashicorp Vault inside or outside the Kubernetes cluster.

Here we will talk about the integration of Vault inside Kubernetes.

# Consul Setup

But before setting up Vault, we have to setup a key-value store for it. We are going to use Hashicorp Consul (opens new window) for our datastore.

Add the HashiCorp Helm Repository:

$ helm repo add hashicorp https://helm.releases.hashicorp.com
...
"hashicorp" has been added to your repositories

Ensure you have access to the consul chart:

$ helm search repo hashicorp/consul
...
NAME                CHART VERSION   APP VERSION DESCRIPTION
hashicorp/consul    0.20.1          1.7.2       Official HashiCorp Consul Chart

Now you’re ready to install Consul! To install Consul with the default configuration using Helm 3 run:

$ helm install consul hashicorp/consul \
    --set global.name=consul --namespace vault
...
LAST DEPLOYED: Mon May  3 20:57:16 2021
NAMESPACE: vault
STATUS: deployed
REVISION: 1
NOTES:
Thank you for installing HashiCorp Consul!

Now that you have deployed Consul, you should look over the docs on using 
Consul with Kubernetes available here: 

https://www.consul.io/docs/platform/k8s/index.html


Your release is named consul.

To learn more about the release, run:

  $ helm status consul
  $ helm get all consul

Let’s verify the consul pods.

$ kubectl get pods -n vault -l release=consul
...
NAME              READY   STATUS    RESTARTS   AGE
consul-server-2   1/1     Running   0          50s
consul-server-0   1/1     Running   0          50s
consul-server-1   1/1     Running   0          50s
consul-5crwc      1/1     Running   0          51s
consul-k4hn5      1/1     Running   0          51s
consul-jldb8      1/1     Running   0          51s

# Vault Setup

Once the consul cluster is ready, let’s try to install vault cluster with HA mode. Also we will change the datastore of vault to consul.

$ cat << EOF > ./override-values.yaml
server:
  ha:
    enabled: true
    replicas: 3
    config: |
      ui = true

      listener "tcp" {
          tls_disable = 1
          address = "[::]:8200"
          cluster_address = "[::]:8201"
      }

      storage "consul" {
          path = "vault"
          address = "consul-server:8500"
      }
EOF
$ helm install vault -f override-values.yaml \
    hashicorp/vault --namespace vault
...
NAME: vault
LAST DEPLOYED: Mon May  3 21:00:37 2021
NAMESPACE: vault
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
Thank you for installing HashiCorp Vault!

Now that you have deployed Vault, you should look over the docs on using
Vault with Kubernetes available here:

https://www.vaultproject.io/docs/


Your release is named vault. To learn more about the release, try:

  $ helm status vault
  $ helm get manifest vault
$ kubectl get pods -n vault -l app.kubernetes.io/instance=vault
...
NAME                                    READY   STATUS    RESTARTS   AGE
vault-agent-injector-77fbb4d4f8-mwngm   1/1     Running   0          30m
vault-2                                 0/1     Running   0          2m24s
vault-0                                 0/1     Running   0          2m24s
vault-1                                 0/1     Running   0          2m24s

Note:- You will see your vault pods are not in Ready state because vault is still sealed. We need to unseal it before using it.

$ kubectl exec -it vault-0 -n vault -- vault operator init
...
Unseal Key 1: mK1PeGrP+A+QidoKzsYIpaAhszwaMCGd0dUMGZ1JWWoQ
Unseal Key 2: q2bazJZReOhY2yfJmJ8puS2FLF4mpWqlE6umws4M2lwl
Unseal Key 3: fnpqx2xpAtI4iTU8iTA3uFM5xP/yDqnsPMsDzVTEyqPa
Unseal Key 4: I2D1KeIA3lIqdlodRL1AeFBmvBoy92mg8kno3QD0mKN0
Unseal Key 5: cNpXnigDnm/djUED5UE0nhAc3wXrfvIDKWQoVgzn5X5b

Initial Root Token: s.XP91VwITtMaMhiL1JMHzFpSR

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 does not store the generated master key. Without at least 3 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.

Note:- Save the output at a special secure place, because this will be required to login in Vault as root user. Use first three unseal tokens to unseal the vault.

$ kubectl exec -it vault-0 -n vault \
    -- vault operator unseal mK1PeGrP+A+QidoKzsYIpaAhszwaMCGd0dUMGZ1JWWoQ
$ kubectl exec -it vault-0 -n vault \
    -- vault operator unseal q2bazJZReOhY2yfJmJ8puS2FLF4mpWqlE6umws4M2lwl
$ kubectl exec -it vault-0 -n vault \
    -- vault operator unseal fnpqx2xpAtI4iTU8iTA3uFM5xP/yDqnsPMsDzVTEyqPa
...
Key                    Value
---                    -----
Seal Type              shamir
Initialized            true
Sealed                 false
Total Shares           5
Threshold              3
Version                1.7.0
Storage Type           consul
Cluster Name           vault-cluster-57a810a1
Cluster ID             2ec3fced-cf4c-d59c-74ba-78d57f4bb94e
HA Enabled             true
HA Cluster             n/a
HA Mode                standby
Active Node Address    <none>

Repeat the same unseal steps for vault-1 and vault-2 as well

The pods will become ready as soon as vault is unsealed.

$ kubectl get pods -n vault -l app.kubernetes.io/instance=vault
...
NAME                                    READY   STATUS    RESTARTS   AGE
vault-agent-injector-77fbb4d4f8-l4x45   1/1     Running   0          18m
vault-0                                 1/1     Running   0          18m
vault-1                                 1/1     Running   0          18m
vault-2                                 1/1     Running   0          18m

# Vault Configuration

For Vault configuration, we are going to use vault-cli and vault-ui both. Download and install vault-cli on your local system. It can be downloaded from here (opens new window).

First, forward the port of vault to your local system.

$ kubectl port-forward vault-0 8200:8200 -n vault
...
Forwarding from 127.0.0.1:8200 -> 8200
Forwarding from [::1]:8200 -> 8200

Login into the vault using the root token which we got using init command.

$ export VAULT_ADDR=http://127.0.0.1:8200
$ vault login
...
Token (will be hidden): 
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                s.XP91VwITtMaMhiL1JMHzFpSR
token_accessor       dK1rauoPrf0nNxMb8wRfwz1i
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

Enable the Kubernetes auth backend in the vault cluster

$ vault auth enable kubernetes
...
Success! Enabled kubernetes auth method at: kubernetes/

Create a file with name vault-reviewer.yaml which will have the service-account and cluster role access information.

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-reviewer
  namespace: vault
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: role-tokenreview-binding
  namespace: vault
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault-reviewer
  namespace: vault
$ kubectl apply -f vault-reviewer.yaml

Configure Vault with the vault-reviewer token and Kubernetes CA to fetch secrets.

$ VAULT_SA_TOKEN_NAME=$(kubectl get sa vault-reviewer -n vault -o jsonpath="{.secrets[*]['name']}")

$ SA_JWT_TOKEN=$(kubectl get secret -n vault "$VAULT_SA_TOKEN_NAME" -o jsonpath="{.data.token}" | base64 --decode; echo)

$ SA_CA_CRT=$(kubectl get secret -n vault "$VAULT_SA_TOKEN_NAME" -o jsonpath="{.data['ca\.crt']}" | base64 --decode; echo)
$ vault write auth/kubernetes/config token_reviewer_jwt="$SA_JWT_TOKEN" kubernetes_host=https://kubernetes.default kubernetes_ca_cert="$SA_CA_CRT"
...
Success! Data written to: auth/kubernetes/config

Create a policy in vault for Kubernetes to read the secrets.

path "secret/*" {
  capabilities = ["read", "list"]
}
$ vault policy write k8s_policy policy.hcl

Create a service-account which can be associated with the application pod to fetch the secrets.

$ kubectl create sa tester

Associate the role to service-account.

$ vault write auth/kubernetes/role/tester \
  bound_service_account_names=tester \
  bound_service_account_namespaces=default \
  policies=k8s_policy \
  ttl=1h

Let’s try to put some secret inside Vault.

$ vault kv put secret/mysql MYSQL_ROOT_PASSWORD=password