DEV Community

Robertino
Robertino

Posted on • Originally published at auth0.com

Secure Secrets With Spring Cloud Config and Vault

Original post written by Jimena Garbarino for Auth0 blog.

Storing secrets in your code is a bad idea. Learn how to use Spring Cloud Config and HashiCorp Vault to make your app more secure.


In 2013, GitHub released a search feature that allows users to scan code in all public repositories. A day after the release, however, they had to partially shut it down. It was speculated that the shutdown was because the feature allowed any user to search for all kinds of secrets stored in GitHub repositories. Later, in 2014, data on 50,000 Uber drivers were stolen. It seems someone got access to the company’s database using login credentials found in a GitHub public repository. Hashicorp Vault, a tool for managing secrets and encrypting data in transit, was first announced in 2015, and Spring Vault, the integration of Spring with Vault, was first released in 2017.

It seems like a long time ago, right? Secrets leakage seems to remain pervasive and constant, happening to all kinds of developers—as explained by this study from NC State University. Exposed secrets lead to cyber-attacks, data loss or corruption, sensitive data breaches, and crypto-jacking (cryptocurrency mining using a victim’s cloud computer power). With tools like Hashicorp’s Vault and Spring Cloud Vault, the risk can be reduced.

Nowadays, it is widely recommended never to store secret values in code. Therefore, this tutorial will demonstrate the following alternatives:

  • Using environment variables for Spring Boot secrets
  • Secrets encryption with Spring Cloud Config
  • Secrets management with HashiCorp’s Vault
  • Using Spring Cloud Vault

This tutorial was created with the following frameworks and tools:

Java OpenJDK 17

Okta CLI 0.10.0

Docker 20.10.12

HTTPie 3.2.1

Vault 1.12.0

Use Environment Variables for Secrets; A Precursor to Spring Vault

Spring Boot applications can bind property values from environment variables. To demonstrate, create a vault-demo-app with OpenID Connect (OIDC) authentication using the Spring Initializr. Then add web, okta, and cloud-config-client dependencies, some of which will be required later in the tutorial:

https start.spring.io/starter.zip \
  bootVersion==2.7.4 \
  dependencies==web,okta,cloud-config-client \
  groupId==com.okta.developer \
  artifactId==vault-demo-app  \
  name=="Spring Boot Application" \
  description=="Demo project of a Spring Boot application with Vault protected secrets" \
  packageName==com.okta.developer.vault > vault-demo-app.zip
Enter fullscreen mode Exit fullscreen mode

Unzip the file and open the project. Modify its src/main/java/.../Application.java class to add the / HTTP endpoint:

package com.okta.developer.vault;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/")
    String hello(@AuthenticationPrincipal OidcUser user) {
        return String.format("Welcome, %s", user.getFullName());
    }

}
Enter fullscreen mode Exit fullscreen mode

Disable the cloud configuration for the first run. Edit application.properties and add the following value:

spring.cloud.config.enabled=false
Enter fullscreen mode Exit fullscreen mode

OpenID Connect authentication with Okta

In a command line session, go to the vault-demo-app root folder.

Before you begin, you’ll need a free Okta developer account. Install the Okta CLI and run okta register to sign up for a new account. If you already have an account, run okta login. Then, run okta apps create. Select the default app name, or change it as you see fit. Choose Web and press Enter.

Select Okta Spring Boot Starter. Accept the default Redirect URI values provided for you. That is a Login Redirect of http://localhost:8080/login/oauth2/code/okta and a Logout Redirect of http://localhost:8080.

What does the Okta CLI do?

The Okta CLI will create an OIDC Web App in your Okta Org. It will add the redirect URIs you specified and grant access to the Everyone group. You will see output like the following when it’s finished:

Okta application configuration has been written to: 
  /path/to/app/src/main/resources/application.properties
Enter fullscreen mode Exit fullscreen mode

Open src/main/resources/application.properties to see the issuer and credentials for your app.

okta.oauth2.issuer=https://dev-133337.okta.com/oauth2/default
okta.oauth2.client-id=0oab8eb55Kb9jdMIr5d6
okta.oauth2.client-secret=NEVER-SHOW-SECRETS
Enter fullscreen mode Exit fullscreen mode

> NOTE: You can also use the Okta Admin Console to create your app. See Create a Spring Boot App for more information.

Instead of storing Okta credentials in application.properties as part of the project code, Spring Boot allows you to bind properties from environment variables. You can see this in action by starting your application with the Maven command below:

OKTA_OAUTH2_ISSUER={yourOktaIssuerURI} \
OKTA_OAUTH2_CLIENT_ID={yourOktaClientId} \
OKTA_OAUTH2_CLIENT_SECRET={yourOktaClientSecret} \
./mvnw spring-boot:run
Enter fullscreen mode Exit fullscreen mode

NOTE: Copy the values of yourOktaIssuerURI, yourOktaClientId, and yourOktaClientSecret as you will need them for configuration in the next sections. You can also just keep at hand yourOktaClientId and retrieve the configuration with okta apps config --app {yourOktaClientId}.

In an incognito window, go to http://localhost:8080. Here, you should see the Okta login page:

Okta login page

In the application logs, you’ll see the security filter chain initializes an OAuth 2.0 authentication flow on startup:

2022-09-07 08:50:09.460  INFO 20676 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with
[org.springframework.security.web.session.DisableEncodeUrlFilter@6b4a4e40,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46a8c2b4,
org.springframework.security.web.context.SecurityContextPersistenceFilter@640d604,
org.springframework.security.web.header.HeaderWriterFilter@7b96de8d,
org.springframework.security.web.csrf.CsrfFilter@2a0b901c,
org.springframework.security.web.authentication.logout.LogoutFilter@38ac8968,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@7739aac4,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@36c07c75,
org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@353c6da1,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@7e61e25c,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@4f664bee,
org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@21b51e59,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5438fa43,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@512abf25,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@76563ae7,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter@3e14d390,
org.springframework.security.web.session.SessionManagementFilter@4dc52559,
org.springframework.security.web.access.ExceptionTranslationFilter@51ac12ac,
org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2407a36c]
Enter fullscreen mode Exit fullscreen mode

Using environment variables for passing secrets to containerized applications is now considered bad practice because the environment can be inspected or logged in a number of cases. So, let’s move on to using Spring Cloud Config server for secrets storage.

Read more...

Top comments (0)