Managing sensitive configuration like database credentials, API keys, or OAuth secrets is a challenge in modern application development. Storing these secrets securely while making them accessible to the application at runtime is a critical requirement.

AWS Secrets Manager solves this by storing, rotating, and retrieving secrets securely. In this blog, we will walk through how to integrate AWS Secrets Manager into a Spring Boot application using Java 17.

Why AWS Secrets Manager?

  • Centralized secret management
  • Secret versioning and rotation
  • Fine-grained IAM-based access control
  • Audit trails via AWS CloudTrail

Prerequisites

  • Java 17 installed
  • Spring Boot 3.x (compatible with Java 17)
  • AWS CLI configured (aws configure)
  • Maven or Gradle
  • AWS account with Secrets Manager access
  • An existing secret created in AWS Secrets Manager

Step 1: Create a Secret in AWS Secrets Manager

Go to the AWS Console → Secrets Manager → Store a new secret.

  • Choose Other type of secrets
  • Key-value pairs:
{   
    "username": "admin",   
    "password": "My$ecretPass123" 
}
  • Name your secret (e.g., myapp/dev/dbcredentials)
  • Save and note the ARN or name

Step 2: Add Dependencies

In your pom.xml, add the following:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>secretsmanager</artifactId>
  </dependency>
  <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sts</artifactId>
  </dependency>
</dependencies>

For Gradle:

implementation 'software.amazon.awssdk:secretsmanager'
implementation 'software.amazon.awssdk:sts'

Step 3: Create a SecretsManager Service Class

package com.example.secrets;

import org.springframework.stereotype.Service;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.*;
import java.util.Base64;
@Service
public class AWSSecretsManagerService {
    private final SecretsManagerClient secretsClient;
    public AWSSecretsManagerService() {
        this.secretsClient = SecretsManagerClient.builder()
                .region(Region.AP_SOUTH_1) // Use your AWS region
                .build();
    }
    public String getSecret(String secretName) {
        try {
            GetSecretValueRequest request = GetSecretValueRequest.builder()
                    .secretId(secretName)
                    .build();
            GetSecretValueResponse response = secretsClient.getSecretValue(request);
            if (response.secretString() != null) {
                return response.secretString();
            } else {
                return new String(Base64.getDecoder().decode(response.secretBinary().asByteBuffer()).array());
            }
        } catch (SecretsManagerException e) {
            throw new RuntimeException("Error retrieving secret: " + e.awsErrorDetails().errorMessage(), e);
        }
    }
}

Step 4: Use the Secret in Your Application

Suppose you want to use DB credentials stored in Secrets Manager.

Define a model class:

package com.example.secrets.model;

public class DbCredentials {
    private String username;
    private String password;
    // Getters and Setters
}

Parse the secret:

package com.example.secrets;

import com.example.secrets.model.DbCredentials;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
@Component
public class SecretConfig {
    private final DbCredentials dbCredentials;
    public SecretConfig(AWSSecretsManagerService secretsService) {
        String secretJson = secretsService.getSecret("myapp/dev/dbcredentials");
        try {
            ObjectMapper mapper = new ObjectMapper();
            this.dbCredentials = mapper.readValue(secretJson, DbCredentials.class);
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse secret", e);
        }
    }
    public DbCredentials getDbCredentials() {
        return dbCredentials;
    }
}

Step 5: Use in a Controller

@RestController
@RequestMapping("/secrets")
public class SecretController {

private final SecretConfig secretConfig;
    public SecretController(SecretConfig secretConfig) {
        this.secretConfig = secretConfig;
    }
    @GetMapping("/db")
    public ResponseEntity<DbCredentials> getDbSecrets() {
        return ResponseEntity.ok(secretConfig.getDbCredentials());
    }
}

Step 6: IAM Role Configuration (for EC2, ECS, or Lambda)

  • If you're deploying this on AWS (EC2/ECS/Lambda), attach an IAM role with secretsmanager:GetSecretValue permission.

Example IAM Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "arn:aws:secretsmanager:ap-south-1:123456789012:secret:myapp/dev/dbcredentials-*"
    }
  ]
}

Optional: Use Secrets in application.properties

While not recommended for highly sensitive secrets, you can initialize secrets on startup and inject them into the environment dynamically (using Spring EnvironmentPostProcessor). Let me know if you'd like this advanced approach as a follow-up!

Best Practices

  • Enable automatic rotation for secrets in AWS.
  • Use IAM roles, not hardcoded credentials.
  • Limit access using least privilege.
  • Avoid logging secret content.
  • Cache secrets if they're retrieved frequently.

Conclusion

Integrating AWS Secrets Manager with Spring Boot and Java 17 is seamless using the AWS SDK v2. It enhances your application's security posture by avoiding hardcoded secrets or unsafe configuration storage.

With just a few steps, you've now learned how to:

  • Create and manage secrets on AWS
  • Access secrets securely via SDK
  • Parse and use secrets in your Spring Boot app

Further Reading