Java client library for AWS Secrets Manager enabling secure storage, management, and retrieval of secrets.
—
Multi-region secret replication for high availability, disaster recovery, and global application deployment. AWS Secrets Manager supports cross-region replication to ensure secrets are available where your applications need them.
class ReplicateSecretToRegionsRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
List<ReplicaRegionType> addReplicaRegions; // Required: Regions to replicate to
Boolean forceOverwriteReplicaSecret; // Overwrite existing replica secrets
}class ReplicateSecretToRegionsResult {
String arn; // Primary secret ARN
List<ReplicationStatusType> replicationStatus; // Replication status per region
}class ReplicaRegionType {
String region; // Required: AWS region code
String kmsKeyId; // KMS key ID for encryption in this region
}class ReplicationStatusType {
String region; // AWS region
String kmsKeyId; // KMS key ID used
String status; // Replication status (InSync, Failed, InProgress)
String statusMessage; // Detailed status message
Date lastAccessedDate; // Last access date in this region
}// Replicate secret to multiple regions
List<ReplicaRegionType> replicaRegions = new ArrayList<>();
// Replicate to us-east-1 with default KMS key
replicaRegions.add(new ReplicaRegionType()
.withRegion("us-east-1"));
// Replicate to eu-west-1 with specific KMS key
replicaRegions.add(new ReplicaRegionType()
.withRegion("eu-west-1")
.withKmsKeyId("arn:aws:kms:eu-west-1:123456789012:key/12345678-1234-1234-1234-123456789012"));
ReplicateSecretToRegionsRequest replicateRequest = new ReplicateSecretToRegionsRequest()
.withSecretId("prod/database/credentials")
.withAddReplicaRegions(replicaRegions)
.withForceOverwriteReplicaSecret(false);
ReplicateSecretToRegionsResult replicateResult = client.replicateSecretToRegions(replicateRequest);
// Check replication status
for (ReplicationStatusType status : replicateResult.getReplicationStatus()) {
System.out.println("Region: " + status.getRegion() +
" Status: " + status.getStatus());
}// Create secret with immediate replication
List<ReplicaRegionType> initialReplicas = new ArrayList<>();
initialReplicas.add(new ReplicaRegionType().withRegion("us-east-1"));
initialReplicas.add(new ReplicaRegionType().withRegion("ap-southeast-1"));
CreateSecretRequest createWithReplication = new CreateSecretRequest()
.withName("global/api/key")
.withSecretString("api-key-value")
.withDescription("Global API key with multi-region replication")
.withAddReplicaRegions(initialReplicas);
CreateSecretResult createResult = client.createSecret(createWithReplication);
// Check initial replication status
for (ReplicationStatusType status : createResult.getReplicationStatus()) {
System.out.println("Initial replication to " + status.getRegion() +
": " + status.getStatus());
}// Add additional regions to existing replication
List<ReplicaRegionType> newRegions = new ArrayList<>();
newRegions.add(new ReplicaRegionType()
.withRegion("ap-northeast-1")
.withKmsKeyId("arn:aws:kms:ap-northeast-1:123456789012:key/asia-key-id"));
ReplicateSecretToRegionsRequest addRegionsRequest = new ReplicateSecretToRegionsRequest()
.withSecretId("global/api/key")
.withAddReplicaRegions(newRegions);
ReplicateSecretToRegionsResult addResult = client.replicateSecretToRegions(addRegionsRequest);
System.out.println("Added replication to new regions");class RemoveRegionsFromReplicationRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
List<String> removeReplicaRegions; // Required: Region codes to remove
}class RemoveRegionsFromReplicationResult {
String arn; // Primary secret ARN
List<ReplicationStatusType> replicationStatus; // Updated replication status
}// Remove replication from specific regions
List<String> regionsToRemove = Arrays.asList("us-east-1", "ap-southeast-1");
RemoveRegionsFromReplicationRequest removeRequest = new RemoveRegionsFromReplicationRequest()
.withSecretId("global/api/key")
.withRemoveReplicaRegions(regionsToRemove);
RemoveRegionsFromReplicationResult removeResult = client.removeRegionsFromReplication(removeRequest);
// Check remaining replications
for (ReplicationStatusType status : removeResult.getReplicationStatus()) {
System.out.println("Remaining replica in: " + status.getRegion());
}class StopReplicationToReplicaRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier (from replica region)
}class StopReplicationToReplicaResult {
String arn; // Replica secret ARN
}// Stop replication when called from the replica region
// This promotes the replica to a standalone secret
StopReplicationToReplicaRequest stopRequest = new StopReplicationToReplicaRequest()
.withSecretId("global/api/key");
// This call must be made from the replica region you want to stop
StopReplicationToReplicaResult stopResult = replicaRegionClient.stopReplicationToReplica(stopRequest);
System.out.println("Stopped replication for: " + stopResult.getArn());// Get detailed replication status
DescribeSecretRequest statusRequest = new DescribeSecretRequest()
.withSecretId("global/api/key");
DescribeSecretResult statusResult = client.describeSecret(statusRequest);
System.out.println("Primary Region: " + statusResult.getPrimaryRegion());
if (statusResult.getReplicationStatus() != null) {
for (ReplicationStatusType status : statusResult.getReplicationStatus()) {
System.out.println("Region: " + status.getRegion());
System.out.println(" Status: " + status.getStatus());
System.out.println(" KMS Key: " + status.getKmsKeyId());
System.out.println(" Message: " + status.getStatusMessage());
System.out.println(" Last Accessed: " + status.getLastAccessedDate());
}
} else {
System.out.println("No replication configured");
}enum StatusType {
InSync, // Replication is current and healthy
Failed, // Replication failed
InProgress // Replication is in progress
}public class ReplicationMonitor {
public void checkReplicationHealth(AWSSecretsManager client, String secretId) {
try {
DescribeSecretResult result = client.describeSecret(
new DescribeSecretRequest().withSecretId(secretId));
List<ReplicationStatusType> statuses = result.getReplicationStatus();
if (statuses == null || statuses.isEmpty()) {
System.out.println("No replication configured");
return;
}
boolean allHealthy = true;
for (ReplicationStatusType status : statuses) {
String region = status.getRegion();
String statusValue = status.getStatus();
switch (statusValue) {
case "InSync":
System.out.println("✓ " + region + ": Healthy");
break;
case "InProgress":
System.out.println("⏳ " + region + ": Syncing...");
allHealthy = false;
break;
case "Failed":
System.err.println("✗ " + region + ": FAILED - " +
status.getStatusMessage());
allHealthy = false;
break;
default:
System.out.println("? " + region + ": Unknown status - " + statusValue);
allHealthy = false;
}
}
if (allHealthy) {
System.out.println("All replications are healthy");
} else {
System.out.println("Some replications need attention");
}
} catch (Exception e) {
System.err.println("Error checking replication health: " + e.getMessage());
}
}
}// Set up disaster recovery replication
public void setupDisasterRecovery(String primarySecretId, String drRegion) {
List<ReplicaRegionType> drReplicas = new ArrayList<>();
// Use region-specific KMS key for DR region
drReplicas.add(new ReplicaRegionType()
.withRegion(drRegion)
.withKmsKeyId("arn:aws:kms:" + drRegion + ":123456789012:key/dr-key-id"));
ReplicateSecretToRegionsRequest drRequest = new ReplicateSecretToRegionsRequest()
.withSecretId(primarySecretId)
.withAddReplicaRegions(drReplicas);
try {
ReplicateSecretToRegionsResult result = client.replicateSecretToRegions(drRequest);
System.out.println("DR replication configured for region: " + drRegion);
// Wait for initial sync
waitForReplicationSync(primarySecretId, drRegion);
} catch (Exception e) {
System.err.println("DR setup failed: " + e.getMessage());
}
}
private void waitForReplicationSync(String secretId, String targetRegion) {
int maxWaitMinutes = 10;
int waitIntervalSeconds = 15;
for (int i = 0; i < (maxWaitMinutes * 60 / waitIntervalSeconds); i++) {
try {
DescribeSecretResult result = client.describeSecret(
new DescribeSecretRequest().withSecretId(secretId));
List<ReplicationStatusType> statuses = result.getReplicationStatus();
for (ReplicationStatusType status : statuses) {
if (targetRegion.equals(status.getRegion())) {
if ("InSync".equals(status.getStatus())) {
System.out.println("Replication sync completed for " + targetRegion);
return;
} else if ("Failed".equals(status.getStatus())) {
System.err.println("Replication failed: " + status.getStatusMessage());
return;
}
}
}
Thread.sleep(waitIntervalSeconds * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
System.err.println("Error waiting for sync: " + e.getMessage());
}
}
System.err.println("Replication sync did not complete within expected time");
}// Configure replication for global application
public void configureGlobalReplication(String secretId) {
List<ReplicaRegionType> globalRegions = new ArrayList<>();
// North America
globalRegions.add(new ReplicaRegionType().withRegion("us-east-1"));
globalRegions.add(new ReplicaRegionType().withRegion("us-west-2"));
// Europe
globalRegions.add(new ReplicaRegionType().withRegion("eu-west-1"));
globalRegions.add(new ReplicaRegionType().withRegion("eu-central-1"));
// Asia Pacific
globalRegions.add(new ReplicaRegionType().withRegion("ap-southeast-1"));
globalRegions.add(new ReplicaRegionType().withRegion("ap-northeast-1"));
ReplicateSecretToRegionsRequest globalRequest = new ReplicateSecretToRegionsRequest()
.withSecretId(secretId)
.withAddReplicaRegions(globalRegions);
try {
ReplicateSecretToRegionsResult result = client.replicateSecretToRegions(globalRequest);
System.out.println("Global replication configured");
// Monitor all regions
monitorGlobalReplication(secretId);
} catch (Exception e) {
System.err.println("Global replication setup failed: " + e.getMessage());
}
}
private void monitorGlobalReplication(String secretId) {
DescribeSecretResult result = client.describeSecret(
new DescribeSecretRequest().withSecretId(secretId));
Map<String, Integer> statusCounts = new HashMap<>();
for (ReplicationStatusType status : result.getReplicationStatus()) {
String statusValue = status.getStatus();
statusCounts.put(statusValue, statusCounts.getOrDefault(statusValue, 0) + 1);
}
System.out.println("Global Replication Status Summary:");
for (Map.Entry<String, Integer> entry : statusCounts.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue() + " regions");
}
}// Update KMS key for specific replica regions
public void updateReplicaKMSKeys(String secretId, Map<String, String> regionKeyMap) {
// Remove existing replicas
List<String> regionsToUpdate = new ArrayList<>(regionKeyMap.keySet());
RemoveRegionsFromReplicationRequest removeRequest = new RemoveRegionsFromReplicationRequest()
.withSecretId(secretId)
.withRemoveReplicaRegions(regionsToUpdate);
try {
client.removeRegionsFromReplication(removeRequest);
// Wait a moment for cleanup
Thread.sleep(5000);
// Re-add with new KMS keys
List<ReplicaRegionType> updatedReplicas = new ArrayList<>();
for (Map.Entry<String, String> entry : regionKeyMap.entrySet()) {
updatedReplicas.add(new ReplicaRegionType()
.withRegion(entry.getKey())
.withKmsKeyId(entry.getValue()));
}
ReplicateSecretToRegionsRequest addRequest = new ReplicateSecretToRegionsRequest()
.withSecretId(secretId)
.withAddReplicaRegions(updatedReplicas);
ReplicateSecretToRegionsResult result = client.replicateSecretToRegions(addRequest);
System.out.println("Updated KMS keys for replica regions");
} catch (Exception e) {
System.err.println("KMS key update failed: " + e.getMessage());
}
}// Access secrets from different regions
public class CrossRegionSecretAccess {
private Map<String, AWSSecretsManager> regionClients = new HashMap<>();
public CrossRegionSecretAccess(List<String> regions) {
for (String region : regions) {
regionClients.put(region, AWSSecretsManagerClientBuilder.standard()
.withRegion(region)
.build());
}
}
public GetSecretValueResult getSecretFromClosestRegion(String secretName,
List<String> preferredRegions) {
for (String region : preferredRegions) {
AWSSecretsManager client = regionClients.get(region);
if (client != null) {
try {
GetSecretValueRequest request = new GetSecretValueRequest()
.withSecretId(secretName);
return client.getSecretValue(request);
} catch (ResourceNotFoundException e) {
// Try next region
continue;
} catch (Exception e) {
System.err.println("Error accessing secret in " + region + ": " + e.getMessage());
continue;
}
}
}
throw new RuntimeException("Secret not accessible from any preferred region");
}
public void shutdown() {
for (AWSSecretsManager client : regionClients.values()) {
client.shutdown();
}
}
}public class SecretFailoverManager {
public String getSecretWithFailover(String secretName, String primaryRegion,
List<String> backupRegions) {
// Try primary region first
try {
AWSSecretsManager primaryClient = AWSSecretsManagerClientBuilder.standard()
.withRegion(primaryRegion)
.build();
GetSecretValueResult result = primaryClient.getSecretValue(
new GetSecretValueRequest().withSecretId(secretName));
primaryClient.shutdown();
return result.getSecretString();
} catch (Exception e) {
System.err.println("Primary region failed: " + e.getMessage());
}
// Try backup regions
for (String backupRegion : backupRegions) {
try {
AWSSecretsManager backupClient = AWSSecretsManagerClientBuilder.standard()
.withRegion(backupRegion)
.build();
GetSecretValueResult result = backupClient.getSecretValue(
new GetSecretValueRequest().withSecretId(secretName));
System.out.println("Retrieved secret from backup region: " + backupRegion);
backupClient.shutdown();
return result.getSecretString();
} catch (Exception e) {
System.err.println("Backup region " + backupRegion + " failed: " + e.getMessage());
}
}
throw new RuntimeException("Secret not accessible from any region");
}
}Common replication-related exceptions:
try {
ReplicateSecretToRegionsResult result = client.replicateSecretToRegions(request);
} catch (ResourceNotFoundException e) {
System.err.println("Secret not found: " + e.getMessage());
} catch (InvalidParameterException e) {
System.err.println("Invalid region or KMS key: " + e.getMessage());
} catch (LimitExceededException e) {
System.err.println("Replication limit exceeded: " + e.getMessage());
} catch (ResourceExistsException e) {
// Use forceOverwriteReplicaSecret if intentional
System.err.println("Replica already exists: " + e.getMessage());
} catch (EncryptionFailureException e) {
System.err.println("KMS encryption failed: " + e.getMessage());
} catch (AWSSecretsManagerException e) {
System.err.println("Replication service error: " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-com-amazonaws--aws-java-sdk-secretsmanager