Storing Secrets in HashiCorp Vault in Kubernetes - An Overview

Storing Secrets in HashiCorp Vault in Kubernetes - An Overview

What is HashiCorp Vault?

HashiCorp Vault is an identity-based secret management system. Secrets like database credentials or certificates can be managed using Vault. For securing secrets, authentication and authorization methods are used as well as secrets are also encrypted. To store secrets, Vault provides many secret engines where secrets can be stored, generated or encrypted.

How HashiCorp Vault Work?

Initialize & Unseal Vault

After installing Vault in the Kubernetes cluster, the first step is to initialize the Vault server using a command operator init , this process prepares Vault's Storage backend to receive secrets. This command provides us with the root key, which is used to read the decryption key to decrypt the secret.

operator init command has two important parameters -key-shares & -key-threshold . -key-shares is the number of keys in which the root key will be split while -key-threshold is the minimum number of keys, which will be required to reconstruct the root key.

Confused .....?

Let's break it down, suppose there is a team of 5 engineers, working on Vault for an organization, 2 of them are full-time software engineers and the other 3 are interns. They'll provide -key-shares a value of 5 and they pick one key for each one of them to keep with themselves and -key-threshold a value of 2, so that even if the interns left the organization the 2 engineers can still construct the root key, basically it is the minimum number of keys required to reconstruct the root key.

I hope the confusion is cleared.... : ), the above process adds security to the system.

Initially, the Vault pods will be sealed and will not be ready. Therefore Unsealing is required to even start the pods.

kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY

Above command will be used to unseal a Vault running on the vault-0 pod. $VAULT_UNSEAL_KEY is the root key.

Wooooh.....Vault is up and ready to store secrets.

Setting a Secret

Firstly to create a secret, we need to log in with the root token(generated above) inside the vault pod and then enable a secret engine and store the secrets at a particular path(depending on the user).

First, start an interactive shell session on the vault-0 pod. kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh . Vault is now ready to log in with the initial root token. Vault requires clients to authenticate first before it allows any further actions. An unsealed Vault starts with the Token Auth Method enabled and generates an initial root token. $ vault login will successfully authenticate the root user.

To store secrets in Vault we need a secret engine to be enabled. Secret Engine is a component under Vault that is used to store, generate or encrypt the secret. This Secret Engine will be enabled at a path where the secret needs to be stored. Vault provides various secret engines like Kubernetes, AWS, Key-Value, Consul and many more, user can pick any one of them based on their use case.

Here we are further going to discuss Key-value secret engine :

Key-Value(kv) Secret engine is used to store secrets within the configured physical storage for Vault. Key names must always be strings. We can enable kv version 2 by : vault secrets enable kv-v2 . Now we'll try to create a secret at the path secret/webapp/config with a username and password using the command :

vault kv put <path> <key>=<value> , for example :

vault kv put secret/webapp/config username="static-user" password="static-password" , where secret/webapp/config is the path in Vault where we want to store the secret username & password .

To read a secret stored at a path, we'll use the command vault kv get <path> . Output:

We've successfully created secrets on the path secret/webapp/config .

Auth Methods

Auth methods are the components in the vault that perform authentication for the clients and provide an identity to the user by attaching them with a token(which can be thought of as a cookie on websites) and a set of policies. Vault supports multiple auth methods to use for authentication like AWS, Github, Kubernetes, etc. Before any client or a process can access Vault, it requires first authenticating against an auth method. After authentication, a token will be generated for the client.

To enable auth method we have to exec into the vault pod and execute respective commands for it.

kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh , this will exec into the vault-0 pod.

vault auth enable kubernetes , this will enable the kubernetes auth method. Vault accepts this service token from any client within the Kubernetes cluster. During authentication, Vault verifies that the service account token is valid by querying a configured Kubernetes endpoint.

Use the /config endpoint to configure Vault to talk to Kubernetes. This will help the vault to get the service account token from the kubernetes cluster and will verify it based on kubernetes_host information.

vault write auth/kubernetes/config \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"

Policy

Policies provide a declarative way to provide capabilities(access) to certain paths and operations in Vault.

Earlier in this blog, we stored the secret at the path secret/webapp/config . Now we will create a policy with the name webapp, to provide the capability of reading at the path secret/webapp/config , where our secret is stored. The policy :

vault policy write webapp - <<EOF
path "secret/data/webapp/config" {
  capabilities = ["read"]
}
EOF

Applying this policy requires the authentication engine to define a role. A role binds policies and environment parameters together. The below role binds policy webapp with kubernetes service account named vault under namespace default.

vault write auth/kubernetes/role/webapp \
        bound_service_account_names=vault \
        bound_service_account_namespaces=default \
        policies=webapp \
        ttl=24h

Policy - Authentication Workflow

The system admin must enable an authentication method for their clients. Authentication will allow the client to get access capabilities based on the policy which will be mapped to the authentication.

Work for system admin:

  1. Connect Authentication with the backend

  2. Create and upload a Vault Policy

  3. Map authentication data to Policy

From the client's perspective, after authentication, the vault token will be attached to the policy and then the token will be given to the client.

Now the Vault setup is ready and can be used to check whether an authorized and authenticated client can read the secrets or not.

Here, the Blog comes to end, this Blog is only an overview of Vault. But Vault is vast and full of different components depending on the user's use cases. I would recommend taking a look at the documentation of HashiCorp Vault, it is one of the best documentation I have seen. It covers everything needed, also easy to understand.

They also provide some tutorials. If you want to do the above process by yourself please go through this tutorial.

I also have implemented a demo of Vault, check it out here.

Singing Off,

Prateek Nandle.