Manage RDS access with AWS Secrets Manager
I had the same problem, the code that is present on AWS page doesn't work out of the box. The class you are looking for is GetSecretValueResult
Here are the latest java docs
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/secretsmanager/model/GetSecretValueResult.html
Here is a piece that shall work:
public void printRdsSecret() throws IOException {
String secretName = "mySecretName";
System.out.println("Requesting secret...");
AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().build();
GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest().withSecretId(secretName);
GetSecretValueResult getSecretValueResult = client.getSecretValue(getSecretValueRequest);
System.out.println("secret retrieved ");
final String secretBinaryString = getSecretValueResult.getSecretString();
final ObjectMapper objectMapper = new ObjectMapper();
final HashMap<String, String> secretMap = objectMapper.readValue(secretBinaryString, HashMap.class);
String url = String.format("jdbc:postgresql://%s:%s/dbName", secretMap.get("host"), secretMap.get("port"));
System.out.println("Secret url = "+url);
System.out.println("Secret username = "+secretMap.get("username"));
System.out.println("Secret password = "+secretMap.get("password"));
}
This was tested with aws-java-sdk-secretsmanager
of version 1.11.337
I think the main problem was in lack of dependencies to AWS SDK v2.
Adding a code snippet here that utilizes AWS SDK v2. Just in case anybody is looking for this.
package com.may.util;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.DecryptionFailureException;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
import software.amazon.awssdk.services.secretsmanager.model.InternalServiceErrorException;
import software.amazon.awssdk.services.secretsmanager.model.InvalidParameterException;
import software.amazon.awssdk.services.secretsmanager.model.InvalidRequestException;
import software.amazon.awssdk.services.secretsmanager.model.ResourceNotFoundException;
public class SecretsManagerUtil {
public static String obtainSecret() {
String secretName = "db_secret_name";
String region = "us-east-1";
SecretsManagerClient client = SecretsManagerClient.builder().region(Region.of(region)).build();
GetSecretValueResponse response = null;
try {
response = client.getSecretValue(GetSecretValueRequest.builder().secretId(secretName).build());
} catch (DecryptionFailureException e) {
// Secrets Manager can't decrypt the protected secret text using the provided KMS key.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InternalServiceErrorException e) {
// An error occurred on the server side.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidParameterException e) {
// You provided an invalid value for a parameter.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidRequestException e) {
// You provided a parameter value that is not valid for the current state of the resource.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (ResourceNotFoundException e) {
// We can't find the resource that you asked for.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
}
return response.secretString();
}
}
Deserialize and print secret:
public class SecretPrinter {
private static final Logger logger = LoggerFactory.getLogger(SecretPrinter.class);
public void printSecret() {
String json = SecretsManagerUtil.obtainSecret(); // secret in json format
RdsSecret secret;
try {
secret = new ObjectMapper().disable(FAIL_ON_UNKNOWN_PROPERTIES).readValue(json, RdsSecret.class);
} catch (IOException e) {
logger.error("Couldn't parse secret obtained from AWS Secrets Manager!");
throw new RuntimeException(e);
}
System.out.println("username: " + secret.getUsername());
System.out.println("password: " + secret.getPassword());
}
static class RdsSecret {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
Maven:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>secretsmanager</artifactId>
</dependency>
Gradle:
implementation platform('software.amazon.awssdk:bom:2.6.3')
implementation 'software.amazon.awssdk:secretsmanager'
aws-secretsmanager-jdbc can be used to access AWS RDS via AWS secrete manager. https://github.com/aws/aws-secretsmanager-jdbc
Below is the content of my application.properties
spring.datasource.url=jdbc-secretsmanager:mysql://dev-xxxx-database.cluster-xxxxxxxxx.ap-southeast-1.rds.amazonaws.com:3306/dev_xxxxxx
spring.datasource.username=/secret/application
spring.datasource.driver-class-name=com.amazonaws.secretsmanager.sql.AWSSecretsManagerMySQLDriver
spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
Below is the secret in AWS secret manager.
By using this method, you don't need to obtain username and password manually and create data sources.