AWS Secret Manager Service as application properties with Spring boot

Secrets Manager enables us to supersede hardcoded credentials in our code, including passwords, with an API call to Secrets Manager to retrieve the secret programmatically. These avails ascertain the secret can't be compromised by someone examining our code, because the secret no longer subsists in the code. Withal, we can configure Secrets Manager to automatically rotate the secret for us according to a designated schedule. This enables us to supersede long-term secrets with short-term ones, significantly abbreviating the peril of compromise.

Overview


1. The admin creates a new secret in AWS Secrets Manager
2. A Spring Boot application uses the secret name to access the secrets stored in AWS Secrets Manager

Step 1: Create & Store secrets in AWS Secret Manager.

Use the AWS Console to create and store a new secret in AWS Secrets Manager. Link

Step 2: Add the below dependency to the pom.xml file.

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-secretsmanager</artifactId>
<version>1.11.942</version>
</dependency>

Programmatic approach

Step 3: Create an application listener class to retrieve secrets

package com.knf.aws.secretmanager.demo.listner;

import java.io.IOException;
import java.util.Properties;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.DecryptionFailureException;
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
import com.amazonaws.services.secretsmanager.model.InternalServiceErrorException;
import com.amazonaws.services.secretsmanager.model.InvalidParameterException;
import com.amazonaws.services.secretsmanager.model.InvalidRequestException;
import com.amazonaws.services.secretsmanager.model.ResourceNotFoundException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class PropertiesListener implements
ApplicationListener<ApplicationPreparedEvent> {

private ObjectMapper mapper = new ObjectMapper();
private static final String AWS_SECRET_NAME = "<AWS_SECRET_NAME>";
private static final String AWS_REGION = "<AWS_REGION>";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";

@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
// Get username and password from AWS Secret Manager using secret name
String secretJson = getSecret();
String database = getString(secretJson, USERNAME);
String uri = getString(secretJson, PASSWORD);
ConfigurableEnvironment environment = event.
getApplicationContext().getEnvironment();
Properties props = new Properties();
props.put(USERNAME, database);
props.put(PASSWORD, uri);
environment.getPropertySources().addFirst
(new PropertiesPropertySource("aws.secret.manager", props));
}

private String getSecret() {
// Create a Secrets Manager client
AWSSecretsManager client = AWSSecretsManagerClientBuilder.
standard().withRegion(AWS_REGION).build();
String secret = null;
GetSecretValueRequest getSecretValueRequest = new
GetSecretValueRequest().withSecretId(AWS_SECRET_NAME);
GetSecretValueResult getSecretValueResult = null;
try {
getSecretValueResult = client.getSecretValue(getSecretValueRequest);
if (getSecretValueResult != null && getSecretValueResult.
getSecretString() != null) {
secret = getSecretValueResult.getSecretString();
}
} catch (DecryptionFailureException | InternalServiceErrorException
| InvalidParameterException
| InvalidRequestException | ResourceNotFoundException e) {

return null;
}
return secret;
}

private String getString(String json, String path) {
try {
JsonNode root = mapper.readTree(json);
return root.path(path).asText();
} catch (IOException e) {

return null;
}
}
}


Step 4: Add the new application listener to the spring.factories

We will also need to add the new application listener to the spring.factories file in the folder src/main/resources/META-INF/spring.factories:
org.springframework.context.ApplicationListener=com.knf.aws.secretmanager.demo.listner.PropertiesListener

More...


Popular posts from this blog

Spring boot video streaming example-HTML5

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Spring Boot + Mockito simple application with 100% code coverage

Spring Boot + OpenCSV Export Data to CSV Example

Custom Exception Handling in Quarkus REST API

DataTable-Pagination example with Spring boot, jQuery and ajax

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Node JS mini projects with source code - free download

Spring boot web project free download:User Registration System

Spring Boot + Apache Commons Export Data to CSV Example