Manage credentials using AWS Secrets Manager - AWS Prescriptive Guidance

Manage credentials using AWS Secrets Manager

Created by Durga Prasad Cheepuri (AWS)

Created by: AWS

Environment: PoC or pilot

Technologies: Databases; Security, identity, compliance

AWS services: AWS Secrets Manager

Summary

This pattern walks you through using AWS Secrets Manager to dynamically fetch database credentials for a Java Spring application.

In the past, when you created a custom application that retrieves information from a database, you typically had to embed the credentials (the secret) for accessing the database directly in the application. When it was time to rotate the credentials, you had to invest time to update the application to use the new credentials, and then distribute the updated application. If you had multiple applications that shared credentials and you missed updating one of them, the application would fail. Because of this risk, many users chose not to regularly rotate their credentials, which effectively substituted one risk for another.

Secrets Manager enables you to replace hard-coded credentials in your code (including passwords) with an API call to retrieve the secret programmatically. This helps ensure that the secret can't be compromised by someone who is examining your code, because the secret simply isn't there. You can also configure Secrets Manager to automatically rotate the secret according to a schedule that you specify. This enables you to replace long-term secrets with short-term ones, which helps significantly reduce the risk of compromise. For more information, see the AWS Secrets Manager documentation.

Prerequisites and limitations

Prerequisites

  • An AWS account with access to Secrets Manager

  • A Java Spring application

Architecture

Source technology stack

  • A Java Spring application with code that accesses a database, with DB credentials managed from the application.properties file.

Target technology stack

  • A Java Spring application with code that accesses a database, with DB credentials managed in Secrets Manager. The application.properties file holds the secrets to Secrets Manager.

Secrets Manager integration with an application

Diagram showing AWS Secrets Manager interaction with admin, custom app, and personnel database.

Tools

  • Secrets ManagerAWS Secrets Manager is an AWS service that makes it easier for you to manage secrets. Secrets can be database credentials, passwords, third-party API keys, and even arbitrary text. You can store and control access to these secrets centrally by using the Secrets Manager console, the Secrets Manager command-line interface (CLI), or the Secrets Manager API and SDKs.

Epics

TaskDescriptionSkills required
Store the DB credentials as a secret in Secrets Manager.

Store Amazon Relational Database Service (Amazon RDS) or other DB credentials as a secret in Secrets Manager by following the steps in Creating a secret in the Secrets Manager documentation.

Sys Admin
Set permissions for the Spring application to access Secrets Manager.

Set the appropriate permissions based on how the Java Spring application uses Secrets Manager. To control access to the secret, create a policy based on the information provided in the Secrets Manager documentation, in the sections Using identity-based policies (IAM Policies) and ABAC for Secrets Manager and Using resource-based policies for Secrets Manager. Follow the steps in the section Retrieving the secret value in the Secrets Manager documentation.

Sys Admin
TaskDescriptionSkills required
Add JAR dependencies to use Secrets Manager.

See the Additional information section for details.

Java developer
Add the details of the secret to the Spring application.

Update the application.properties file with the secret name, endpoints, and AWS Region. For an example, see the Additional information section.

Java developer
Update the DB credentials retrieval code in Java.

In the application, update the Java code that fetches the DB credentials to fetch those details from Secrets Manager. For example code, see the Additional information section.

Java developer

Related resources

Additional information

Adding JAR dependencies for using Secrets Manager

Maven:

<groupId>com.amazonaws</groupId>     <artifactId>aws-java-sdk-secretsmanager</artifactId>     <version>1.11. 355 </version>

Gradle:

compile group: 'com.amazonaws', name: 'aws-java-sdk-secretsmanager', version: '1.11.355'

Updating the application.properties file with the details of the secret

spring.aws.secretsmanager.secretName=postgres-local spring.aws.secretsmanager.endpoint=secretsmanager.us-east-1.amazonaws.com spring.aws.secretsmanager.region=us-east-1

Updating the DB credentials retrieval code in Java

String  secretName  =  env.getProperty("spring.aws.secretsmanager.secretName"); String  endpoints  =  env.getProperty("spring.aws.secretsmanager.endpoint"); String  AWS Region  =  env.getProperty("spring.aws.secretsmanager.region"); AwsClientBuilder.EndpointConfiguration  config  =  new  AwsClientBuilder.EndpointConfiguration(endpoints, AWS Region); AWSSecretsManagerClientBuilder  clientBuilder  =  AWSSecretsManagerClientBuilder.standard(); clientBuilder.setEndpointConfiguration(config); AWSSecretsManager  client  =  clientBuilder.build();        ObjectMapper  objectMapper  =  new  ObjectMapper();   JsonNode  secretsJson  =  null;   ByteBuffer  binarySecretData;   GetSecretValueRequest  getSecretValueRequest  =  new  GetSecretValueRequest().withSecretId(secretName);    GetSecretValueResult  getSecretValueResponse  =  null;   try  {      getSecretValueResponse  =  client.getSecretValue(getSecretValueRequest);     }   catch  (ResourceNotFoundException  e)  {      log.error("The requested secret "  +  secretName  +  " was not found");     }      catch  (InvalidRequestException  e)  {          log.error("The request was invalid due to: "  +  e.getMessage());      }      catch  (InvalidParameterException  e)  {          log.error("The request had invalid params: "  +  e.getMessage());      } if  (getSecretValueResponse  ==  null)  {          return  null;      }  // Decrypted secret using the associated KMS key // Depending on whether the secret was a string or binary, one of these fields will be populated               String secret = getSecretValueResponse.getSecretString();     if (secret != null) {        try {                         secretsJson  =  objectMapper.readTree(secret);                }           catch  (IOException  e)  {                         log.error("Exception while retrieving secret values: "  +  e.getMessage());                } }      else  {          log.error("The Secret String returned is null");          return null;              }      String  host  =  secretsJson.get("host").textValue();      String  port  =  secretsJson.get("port").textValue();      String  dbname  =  secretsJson.get("dbname").textValue();      String  username  =  secretsJson.get("username").textValue();      String  password  =  secretsJson.get("password").textValue(); }