Securing Passwords Using HashiCorp Vault and Spring-Cloud

Rajeev Shukla
The Startup
Published in
6 min readJul 26, 2020

Introduction

An application should not be only secured from outsiders in this world, it should be secured from insiders as well. Recall those days when you hesitate to check-in secrete DB password into version control or email Id password which might be used for sending emails to end-user.

In my earlier post, I have written how to secure database properties using java simplified encryption.

In this post, we are going to learn how to secure properties using HashiCorp Value and spring which is the most secure way you can think of securing properties.

HashiCorp Vault setup on local

1. Installation

I am installing the HashiCorp vault on Ubuntu 20.20. Just in case if you are using different OS please follow this link to install and feel free to skip the installation section.

After installing vault when you run $vault you should see below output.

Note: Knowledge of Vault internals is not required to use Vault. This installation usually done by system administrator in the orgnization. Though as a developer you can learn if you interested much about internals here. We will only see basic things needed to get going.

2. Starting vault server on localhost

To start the vault server you need to pass config information on the startup. For that copy below config and save it into a file say vaultConfig.hcl.

Note: Don’t use above configuration in production. Also, during installation vault.hcl config file created on the path /etc/vault.d/vault.hcl (on ubuntu) but it has TL S/SSL configs automatically written in it to access Vault server over https which is out of the scope of this post. Also change path in above configuration according to your file system(Window/Mac).

$ sudo vault server -config /etc/vault.d/vault.hcl

Now once the server is started one a new terminal and set an environment variable for the vault address so that the vault client could use it. (On windows set it using environment variable)

# export VAULT_ADDR=http://127.0.0.1:8200

3. Initialize Vault

Once the vault server is started, for the very first time we need to initialize the vault and generate two different types of tokens one for login and one for Seal/Unseal the Vault. We have two ways to generate these tokens.

  • Using the command line
  • Using UI (By accessing http://127.0.0.1:8200)

3.1 Command line approach

when you write vault operator init it creates two different tokens.

  1. The master key portion
  2. Root Token(For authentication)

Key share and Key threshold

When a Vault server is started, it starts in a sealed state and it does not know how to decrypt data. Before any operation can be performed on the Vault, it must be unsealed. Unsealing is the process of constructing the master key necessary to decrypt the data encryption key.

Once a Vault node is unsealed, it remains unsealed until —

  • Server is restarted
  • any exception occurred
  • or manually resealed

Key shares: HashiCorp vault uses the master key to unseal vault and that master key can be split into any number of separate tokens. Key shares parameter ask you to enter a number and the master key will split into that many numbers of the token.

Key threshold: Number of key shares required to construct the master key to unseal the vault.

We can pass these params during initialization though we didn’t as it uses default key shares 5 and threshold as 3. Below is how we can pass during initialization.

# vault operator init -key-shares=5 -key-threshold=2

it generates 5 shared keys(-key-shares=5) out of which at least any of the two key combinations(-key-threshold=2) will be used to unseal the vault.

3.2 UI approach

We can also initialize vault through UI if it is enabled while starting up the vault server. (Check ui=true in vaultConfig.hcl)

You can access http://localhost:8200 below is the page you would see for the first time for the token generation.

Vault UI for the first time

In UI, it asks for you to enter key shares and key threshold parameters. As these are mandatory (but not in the command line) once you enter key shares and key threshold it will generate all the needed token and will ask you to download it.

Unseal vault

Vault will decrypt the key and serve the request only when it is unsealed. So before using it we need to unseal it.

  1. Command-line approach

# vault operator unseal <token 1>
# vault operator unseal <token 2>
# vault operator unseal <token 3>

Vault unsealing after entering all keys

2. UI approach

Access http://localhost:8200 in your browser

  1. You have to sign in to the vault server first by using to initial root token which was generated earlier.

2. Then Unseal your vault by using key shares -

Now it is time to add a secret in the vault which we will access later in the spring application.

To do that we need to perform the below steps.

  1. Login to vault

# vault login <Initial Root Token>

2. Enabling key-value secrets

We will have to do this the very first time because by default vault’s secret engine won’t be enabled.

# vault secrets enable -path=secret/ kv

  • where the -path is where we are going to put all our key-value pair secrets.
  • kv is internal to the vault by which we are telling the vault server that this path will store key-value pairs.

3. Add your secrets to the vault

Well, this is what we wanted to do, to put our secured key in the vault and access it directly from the spring application.

#vault kv put secret/spring-cloud-vault appSecurityKey=mysecretkey

#vault kv put secret/spring-cloud-vault/dev appSecurityKey=mysecretkey1

#vault kv put secret/spring-cloud-vault/prod appSecurityKey=mysecretkey2

where spring-cloud-vault is my spring boot application name and dev/prod is active profile

So the general syntax for multiple key-value pairs —

#vault kv put secret/<application-name>/<profile> key1=value1 key2=value2

Spring Cloud Integration with Vault Server

Now it is time to configure out spring boot application to fetch the secured key from the vault. For that, we need to add client jar dependency to connect to the vault

Maven Dependency

Adding spring cloud maven dependency into the project.

Creating bootstrap.yml to connect with vault server

Why bootstrap.yml not application.yml?

A Spring Cloud application operates by creating a “bootstrap” context, which is a parent context for the main application. Out of the box it is responsible for loading configuration properties from the external sources, and also decrypting properties in the local external configuration files. — From the documentation.

And hence we need to create bootstrap.yml to fetch external properties from vault server —

Spring Cloud Vault accesses different resources. By default, the secret backend is enabled which accesses secret config settings via JSON endpoints.

The HTTP service has resources in the form:

/secret/{application-name}/{profile}
/secret/{application-name}
/secret/{default-context}/{profile}
/secret/{default-context}

Now you can give it a try for adding more keys into vault serve with a different profile and access it in your spring cloud application by changing profile bypassing program argument like spring.profiles.active=dev/prod/test1 and see if value changes

Conclusion

We saw, how easy it is when it comes to access secrets from the vault server. The overall effort actually goes in the vault server setup which is actually a system administrator job done in your organization. You would only need your vault server IP and a token to authenticate with the vault server, and you would ask the admin to add key-value pairs in the vault server and access it directly in your spring application. There are various ways vault authentication can happen. Please see here for more details.

Git hub code present here

--

--

Rajeev Shukla
The Startup

Full-stack developer, Spring enthusiast , Java geek with a strong focus on code efficiency and simplicity.