Manage your Kubernetes secrets with Hashicorp Vault.

The power of Kubernetes plus the security of Hashicorp Vault

Ariel Viñas
Craftech
8 min readApr 13, 2020

--

Once your Kubernetes clusters starts to grow, managing secrets can be a challenge. Yaml definitions of secrets are base64 encoded, so finding errors could be quite difficult. And yes, you could use a tool to convert these secrets from an env file, to a Kubernetes secret yaml definition using a simple python script for example. Maybe even have these stored in a S3 Bucket, but where’s the security in that?. If you’re serious about security in Kubernetes, you need a secret management tool that provides a single source of secrets, credentials, attaching security policies, etc. In other words, you need Hashicorp Vault.

This post outlines a process to use vault within Kubernetes to make the secret management more secure and robust with GoDaddys external secrets project. It was based on the talk that Seth Vargo gave at Cloud Next ‘18.

Prerequisites:

  • A Kubernetes cluster (or more)

Tools used:

I’ll divide this into 4different sections:

  1. Run Vault on Kubernetes
  2. Deploying and Configuring External Secrets in Kubernetes.
  3. Connect to Vault from Kubernetes.
  4. Creating a secret from an external secret.

1. Run Vault on Kubernetes

The goal of this first section is to answer two questions:

  1. Why would I run this on Kubernetes? Is it a good idea? Should I?
  2. And how do I do it?

The first answer is YES… So I’ll just move on to the second question.

Vault as a service

Since we’re using Vault to manage our secrets, we’ll first need to install it in our Cluster.

I want to make it clear, and it is really important to understand that we want to think of Vault as a service. This means:

Vault is available at an IP/DNS address for consumers. Kubernetes is simply an implementation detail.

So yes, I’m running Vault under Kubernetes and I’m leveraging a lot of the functionality that Kubernetes provides. But ultimately, I’m delivering secrets management as a service. So there’s Vault, and an API and an IP/DNS address. And users ultimately shouldn’t care whether Vault is running on a VM or a container or bare metal. It doesn’t really matter. So we really want to think about this as Kubernetes is providing the building blocks that let us run Vault as a highly-available service.

For the deployment of the Vault cluster, I recommend using official Vault helm chart maintained by Hashicorp.

For the deployment of mine cluster, I’ll be using an ingress based access to my service, but you could use a Load Balancer, obtaining its IP address and just that as your vault service endpoint. In my case, my endpoint will be https://vault.craftech.io

It is worth noticing that Hashicorps chart already implements some great features for the cluster deployment, such as HA using pod anti affinity settings, making Vault deploy its replicas into different nodes of the cluster providing real high availability.

After you finish customizing the values.yaml, you can install Vault:

Once finished, you can initialize your Vault cluster running:

This will return the initial root token and unseal keys. For more information, go to Initializing the Vault.

And that’s pretty much it. We have a highly available Vault cluster running under Kubernetes accessible by an IP/DNS address.

We can use vaults CLI to check status, just by exporting some environment variables:

Now we can check status running vault status:

2. Deploying and Configuring External Secrets in Kubernetes.

System architecture

Kubernetes External Secrets allows you to use external secret management systems, like AWS Secrets Manager or HashiCorp Vault, to securely add secrets in Kubernetes.

This is achieved by extending the Kubernetes API by adding a ExternalSecrets object using Custom Resource Definition and a controller to implement the behavior of the object itself.

We need to edit the values.yaml file found in the repo. There are several configurations to set up, depending if your using AWS Secrets Manager, Azure Key Vault, etc. We are focusing on Vault, so the important parts in the values.yaml are the VAULT_ADDR and allow creation of a serviceaccount for the service itself (we are then going to use that serviceaccount to authenticate against Vault).

Deploying is again done by the use of helm, but this time you add a helm repo to your helm source lists:

Now let’s move on to the most anticipated part, creating and managing Kubernetes secrets with Vault.

3. Connect to Vault from Kubernetes

Authentication in Vault is the process which users or machines supply information to Vault. Vault verifies that information either with internal data or some external third party, and then, assuming that is valid, converts that into a token with policy authorization attach to it.

Mental Reset

You have to forget everything. Forget everything you’ve just read, because the next section is: Now that I have Vault running, how do I connect to it from Kubernetes?

But I want you to forget that Vault is running in Kubernetes, instead Vault is just a thing running, available at an IP/DNS address. Everything described in the next section will work with any Kubernetes cluster, deployed on any cloud or on-prem infrastructure.

Vault Auth with Kubernetes

In a more graphical way:

  1. We can see the Vault server in the middle which would receive a request from a user, machine or application (in this case, the ExternalSecrets’ serviceaccount).
  2. Then, Vault verifies that information with the Kubernetes Token Reviewer, verifying the serviceaccounts JWT token validity, timestamp, etc. Assuming that’s successful, it goes back to Vault saying “Yup, this looks great”
  3. After that, Vault goes back to its own internal policy engine saying, well, the things in this particular namespace, get this particular policies attach to it… “here’s a vault token with that policy attach to it”.
  4. Finally, Vault returns the token to ExternalSecrets’ serviceaccount, which would then be used for all future requests.

NOTE: The pattern Vault uses to authenticate Pods depends on sharing the JWT token over the network. Given the security model of Vault, this is allowable because Vault is part of the trusted compute base. In general, Kubernetes applications should not share this JWT with other applications, as it allows API calls to be made on behalf of the Pod and can result in unintended access being granted to 3rd parties.

But as the great Linus Torvald once

“Talk is cheap. Show me the code.” — Linus Torvalds

So, how do we actually connect multiple Kubernetes clusters to my Vault SaaS?

Well, I reduced the connection based on a couple of commands:

  1. Export in environment variables the name of your cluster and Vault connection details:

As an example, I’ll be using an EKS cluster, so my cluster name is:

2. Apply a clusterrolebinding for the ExternalSecrets’ serviceaccount with the role auth-delegator.

3. Create a policy for the serviceaccounts token to be attached.

4. Saved in environment variables cluster configuration and ExternalSecrets serviceaccounts JWT token.

5. Enable the Kubernetes auth method for this particular cluster using path

6. Configure the clusters auth method in Vault.

7. Finally, create a role in the Kubernetes auth method to be used by the ExternalSecrets’ serviceaccount:

And that’s it! We have our Kubernetes cluster configured to create secrets based on externalsecrets definitions.

4. Creating a secret from an external secret.

Finally, we reach the part that would become the most anticipated: actually creating a secret in Kubernetes obtained from a Vault’s secret.

In order to do that, we’ll have to create an ExternalSecret definition. This can be achieved from a yaml definition like this one:

And we get:

According to GoDaddy’s Github documentation, if you use Vault:

Vault values are matched individually. If you have several keys in your Vault secret, you will need to add them all separately

I opened up an issue to them, explaining that Vault actually admins just referencing the secret location to pull every key-value stored in it. At the time of writing this post, I haven’t got an answer, yet.

We can obtain the external secrets created with:

This shows 404 Not Found, because the secret doesn’t exist in Vault… yet.

So now we’ll move on to Vault’s Web UI, and create the secret:

Creating a KV v2 secret in Vault’s Web UI.

We save it, and check again:

Bingo! It appears to be working. Let’s check the Kubernetes secret created:

Secret named test created from an external secret definition viewed from the Kubernetes Dashbord.

Conclusion

We have provisioned a Kubernetes cluster with secrets obtained form a Vault cluster running as a service, avoiding the need to encrypt our secrets ourself or stored them in different places.

We also benefit from being able to visualize the changes of secrets in plain text from a web ui, so troubleshooting on secrets become an easy task.

Questions?

Please feel free to join us on Craftech’s community Slack and ask any questions.

What is Craftech?

Craftech is a reliable, nimble and experienced infrastructure development group. Our team only consists of top level engineers, designers and managers. Craftech relies in the use of the latest accelerated development methodologies, tools, technologies and processes to deliver excellence in our solutions, communication and client experiences.

Learn more: https://craftech.io

--

--

Ariel Viñas
Craftech

Co-founder of Craftech & infrastructure enthusiast!