In the articles mysql-quartz-email-scheduler and postgres-quartz-email-scheduler we have provided the database username and password in application.properties.
There, we let the spring boot auto configure the datasource for us.
However, we missed one thing. We are writing the database and password in plain text in properties file and this is prone to attacks and leaking sensitive information. We must store the sensitive information such as database username and passwords securely in a secret manager and when application starts, it should fetch the username and password and establish a connection with the database server.
In this way, our code doesn’t contain and expose any sensitive information. Here the sensitive information is database username and password.
In this article, we will use Hashicorp vault to store the secrets and fetch them from spring boot application.
Let’s get started.
Vault Installation
Refer the below link for the vault installation based on your OS.
https://learn.hashicorp.com/tutorials/vault/getting-started-install?in=vault/getting-started
Starting the vault server
We will start the vault server in dev mode for testing our code.
Vault is a client server application where vault server interacts with the data storage and backends. We will store the secrets in vault with the vault CLI over a TLS Connection.
To start the Vault dev server, run:
$ vault server -dev
You should see the output similar to above. Notice that Unseal Key and Root Token values are displayed
Note: The dev server listens on localhost without TLS and stores the data in-memory and shows you unseal key and root key.
Now open a new terminal and execute below commands.
export VAULT_ADDR='http://127.0.0.1:8200'
Provide root token as shown below.
export VAULT_TOKEN=“<vault root token>”
To interact with Vault, you must provide a valid token.
If the output looks different, restart the dev server and try again.
Storing the database secrets in vault
One of the core features of Vault is the ability to read and write arbitrary secrets securely. Secrets written to Vault are encrypted and then written to backend storage. Therefore, the backend storage mechanism never sees the unencrypted value and doesn't have the means necessary to decrypt it without Vault.
Let's write a secret to Key/Value v2 secrets engine when running a dev server. Use the vault kv put <path> <key>=<value> command.
Notice that the version is now 2. The vault kv put command creates a new version of the secrets and replaces any pre-existing data at the path if any.
Sending data as a part of the CLI command often end up in the shell history unencrypted. To avoid this, refer to the Static Secrets: Key/Value Secrets Engine tutorial to learn different approaches.
Verifying our secrets
To fetch secrets, use below command.
$ vault kv get secret/db
Vault returns the latest version (in this case version 2) of the secrets at secret/db.
To print only the value of a given field, use the -field=<key_name> flag.
vault kv get -field=username secret/db
Optional JSON output is very useful for scripts. For example, you can use the jq tool to extract the value of the excited secret.
$ vault kv get -format=json secret/db | jq -r .data.data.username
Deleting a Secret
Now that you've learned how to read and write a secret, let's go ahead and delete it. You can do so using the vault kv delete command.
$ vault kv delete secret/db
Spring boot Vault Config
Quartz-dependency
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
Since, we need to fetch the username and password from vault and then initialise the datasource we need to exclude the DataSourceAutoConfiguration.class and QuartzAutoConfiguration.class
After exclusion, our application file will look like below
We will choose, local-postures profile here. But you can select any profile you wish and add the two properties in the application-{profile}.properties file like this file<link>
vault.uri=http://localhost:8200
vault.token=s.npj4vbfvXd7MDmYHdimslXMO #your root token here - obtained from dev server
We will use EnvironmentVaultConfiguration.class to configure the vault in our application like below
Here, from my properties file, vault.uri and vault.token will be picked up and instantiated.
Now, I will create a Credentials POJO like below to cast secrets object fetched from vault to obtain username and password
Now, lets create a CredentialsService class to create a datasource bean by fetching the database credentials from vault like below
Now, we will use the same datasource for our quartz as well. Let’s create a bean for quartz scheduler as well like below
Now, we can run our application. Remember, postgres should be running for this. Refer this post to install postgres.
You should be able to see your application running like below
You can follow the same for mysql as well. For mysql docker installation and using with spring boot, refer this example.
You can find the GitHub code base here, Checkout to vault-configs branch.
Resources
- https://www.baeldung.com/spring-vault
- https://docs.spring.io/spring-vault/docs/current/reference/html/index.html#vault.core.environment-vault-configuration
Keep Experimenting 🔎
Keep Learning 🚀
Post a Comment