Retrieving Credentials/Secrets from Secret Manager with Spring Boot

1. Overview

Secrets like passwords, API keys, are sensitive information should be stored in a secure, encrypted storage, access controlled, and auditable. Some systems opt to use Vault to store these secrets. On Google Cloud, you can use Secret Manager, a managed service, to securely store the secrets, and control access to individual secrets using IAM.

In Spring Boot, you can use Spring Cloud GCP to easily access these secrets by referring to them as any other Spring properties.

In this codelab, you will store a secret in Secret Manager, then build simple Spring Boot microservices and retrieve the secret.

What you'll learn

  • How to create a Spring Boot Java application and configure Secret Manager.

What you'll need

  • A Google Cloud Project
  • A Browser, such Chrome or Firefox
  • Familiarity with standard Linux text editors such as Vim, EMACs or Nano

How will you use use this tutorial?

Read it through only Read it and complete the exercises

How would you rate your experience with building HTML/CSS web apps?

Novice Intermediate Proficient

How would you rate your experience with using Google Cloud services?

Novice Intermediate Proficient

2. Setup and Requirements

Self-paced environment setup

  1. Sign in to Cloud Console and create a new project or reuse an existing one. (If you don't already have a Gmail or G Suite account, you must create one.)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Remember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in this codelab as PROJECT_ID.

  1. Next, you'll need to enable billing in Cloud Console in order to use Google Cloud resources.

Running through this codelab shouldn't cost much, if anything at all. Be sure to to follow any instructions in the "Cleaning up" section which advises you how to shut down resources so you don't incur billing beyond this tutorial. New users of Google Cloud are eligible for the $300USD Free Trial program.

Google Cloud Shell

While Google Cloud services can be operated remotely from your laptop, in this codelab we will be using Google Cloud Shell, a command line environment running in the Cloud.

Activate Cloud Shell

  1. From the Cloud Console, click Activate Cloud Shell H7JlbhKGHITmsxhQIcLwoe5HXZMhDlYue4K-SPszMxUxDjIeWfOHBfxDHYpmLQTzUmQ7Xx8o6OJUlANnQF0iBuUyfp1RzVad_4nCa0Zz5LtwBlUZFXFCWFrmrWZLqg1MkZz2LdgUDQ.

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

If you've never started Cloud Shell before, you'll be presented with an intermediate screen (below the fold) describing what it is. If that's the case, click Continue (and you won't ever see it again). Here's what that one-time screen looks like:

kEPbNAo_w5C_pi9QvhFwWwky1cX8hr_xEMGWySNIoMCdi-Djx9AQRqWn-__DmEpC7vKgUtl-feTcv-wBxJ8NwzzAp7mY65-fi2LJo4twUoewT1SUjd6Y3h81RG3rKIkqhoVlFR-G7w

It should only take a few moments to provision and connect to Cloud Shell.

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory and runs in Google Cloud, greatly enhancing network performance and authentication. Much, if not all, of your work in this codelab can be done with simply a browser or your Chromebook.

Once connected to Cloud Shell, you should see that you are already authenticated and that the project is already set to your project ID.

  1. Run the following command in Cloud Shell to confirm that you are authenticated:
gcloud auth list

Command output

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

Command output

[core]
project = <PROJECT_ID>

If it is not, you can set it with this command:

gcloud config set project <PROJECT_ID>

Command output

Updated property [core/project].

3. Configure a Secret

To use Secret Manager, first enable the API:

$ gcloud services enable secretmanager.googleapis.com

Then, create a secret named greeting, with value of Hello:

$ echo -n "Hello" | \
 gcloud secrets create greeting \
 --data-file=-

This command uses STDIN to provide the value to the command line. However, you can also simply put the secret value in a file, an specify the filename for the --data-file argument.

You can list all the secrets using the gcloud CLI:

$ gcloud secrets list

4. Create a new Spring Boot REST Service

After Cloud Shell launches, you can use the command line to generate a new Spring Boot application with Spring Initializr:

$ curl https://start.spring.io/starter.tgz -d packaging=jar \
  -d dependencies=web,cloud-gcp \
  -d bootVersion=3.0.6 \
  -d type=maven-project \
  -d baseDir=hello-secret-manager | tar -xzvf - \
  && cd hello-secret-manager

In the pom.xml, add the Spring Cloud GCP starter dependency:

pom.xml

<project>
  ...

  <dependencies>
    ...
    <!-- Add Secret Manager Starter -->
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>spring-cloud-gcp-starter-secretmanager</artifactId>
    </dependency>
  </dependencies>

  ...
</project>

In the src/main/resources/application.properties file, add the following configuration to enable the Spring Boot Config Data API.:

spring.config.import=sm://

This will configure a Spring Property Source, so that you can refer to secrets using a property value, with the prefix of sm://, for example, sm://greeting.

See Spring Cloud GCP Secret Manager documentation for more detail on the format of the property. Note that the application.properties requirement is new in Spring Cloud GCP 4.x. Read more details in the migration guide.

Create a new REST controller by adding a new class file:

src/main/java/com/example/demo/HelloSecretController.java

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloSecretController {
  String greeting = "Hi";

  @GetMapping("/")
  public String hello() {
    return greeting + " World!";
  }
}

You can start the Spring Boot application normally with the Spring Boot plugin.

Make sure JAVA_HOME is set to the correct JDK version:

$ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/

Let's skip tests for this lab, and start the application:

$ ./mvnw -DskipTests spring-boot:run

Once the application started, click on the Web Preview icon e18df08334f0d809.pngin the Cloud Shell toolbar and choose preview on port 8080.

After a short wait you should see the result:

1e9a7884ff113c14.png

5. Retrieve a Secret

You can use the @Value annotation to refer to the secret property using the sm:// prefix.

In the HelloSecretController class, inject the greeting value using the annotation:

src/main/java/com/example/demo/HelloSecretController.java

import org.springframework.beans.factory.annotation.Value;

...

@RestController
public class HelloSecretController {
  @Value("${sm://greeting}")
  String greeting;

  ...
}

You can start the Spring Boot application normally with the Spring Boot plugin. Let's skip tests for this lab:

$ ./mvnw -DskipTests spring-boot:run

Once the application started, click on the Web Preview icon e18df08334f0d809.pngin the Cloud Shell toolbar and choose preview on port 8080.

After a short wait you should see the result:

Screenshot of the running application, showing 'Hello World!'

You can also map the value to a property in application.properties:

src/main/resources/application.properties

greeting=${sm://greeting}

In HelloSecretController, you can reference to this more generic property name as opposed to a Secret Manager name:

src/main/java/com/example/demo/HelloSecretController.java

@RestController
public class HelloSecretController {
  @Value("${greeting}")
  String greeting;
  ...
}

You can start the Spring Boot application normally with the Spring Boot plugin. Let's skip tests for this lab:

$ ./mvnw -DskipTests spring-boot:run

Once the application started, click on the Web Preview icon Web Preview iconin the Cloud Shell toolbar and choose preview on port 8080.

Updating the secret value

Using the sm://greeting short syntax, you automatically use the latest version of the secret. By creating a new version of the secret, you can update your application without changing your code.

Update the value of the secret by adding a new version:

$ echo -n "Greetings" |
 gcloud secrets versions add greeting \
 --data-file=-

Restart the application, and see the new version of the secret is being returned.

Screenshot of the running application, showing 'Greeings World!'

Expanding this concept

This technique is useful especially if you use different Spring Boot application profiles. For example, you can create secrets such as greeting-dev, greeting-staging, greeting-prod. And in each of the profile, map to the right greetings.

Create a greeting-prod secret:

$ echo -n "Hola" | \
 gcloud secrets create greeting-prod \
 --data-file=- --replication-policy=automatic

Create an application-prod.properties file:

src/main/resources/application-prod.properties

greeting=${sm://greeting-prod}

You can start the Spring Boot application normally with the Spring Boot plugin, but with the prod profile. Let's skip tests for this lab:

$ ./mvnw -DskipTests spring-boot:run -Dspring-boot.run.profiles=prod

Once the application started, click on the Web Preview icon Web Preview Iconin the Cloud Shell toolbar and choose preview on port 8080.

After a short wait you should see the result:

Screenshot of the running application, showing 'Hola World!'

6. Summary

In this lab, you've created a service that can be configured using secrets stored in Secret Manager by using Spring's property names prefixed with sm:// and injecting the value from applications.properties file and @Value annotations..

7. Congratulations!

You learned how to use the Secret Manager API in Java.

Learn More

License

This work is licensed under a Creative Commons Attribution 2.0 Generic License.