Java client library for AWS Secrets Manager enabling secure storage, management, and retrieval of secrets.
—
Resource-based access control through IAM policies and organizational management through resource tagging for governance, compliance, and cost allocation.
Resource policies in AWS Secrets Manager control access to individual secrets using JSON policy documents. These policies work alongside IAM user/role policies to determine final permissions.
class GetResourcePolicyRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
}class GetResourcePolicyResult {
String arn; // Secret ARN
String name; // Secret name
String resourcePolicy; // JSON policy document
}// Get current resource policy
GetResourcePolicyRequest getPolicyRequest = new GetResourcePolicyRequest()
.withSecretId("prod/database/credentials");
try {
GetResourcePolicyResult policyResult = client.getResourcePolicy(getPolicyRequest);
System.out.println("Secret: " + policyResult.getName());
System.out.println("Policy: " + policyResult.getResourcePolicy());
} catch (ResourceNotFoundException e) {
System.out.println("No resource policy attached to this secret");
}class PutResourcePolicyRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
String resourcePolicy; // Required: JSON policy document
Boolean blockPublicPolicy; // Block policies that allow public access
}class PutResourcePolicyResult {
String arn; // Secret ARN
String name; // Secret name
}// Create a resource policy allowing cross-account access
String policyDocument = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Sid\": \"AllowCrossAccountRead\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": {\n" +
" \"AWS\": \"arn:aws:iam::123456789012:role/CrossAccountRole\"\n" +
" },\n" +
" \"Action\": [\n" +
" \"secretsmanager:GetSecretValue\",\n" +
" \"secretsmanager:DescribeSecret\"\n" +
" ],\n" +
" \"Resource\": \"*\",\n" +
" \"Condition\": {\n" +
" \"DateLessThan\": {\n" +
" \"aws:CurrentTime\": \"2024-12-31T23:59:59Z\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
PutResourcePolicyRequest putPolicyRequest = new PutResourcePolicyRequest()
.withSecretId("shared/api/credentials")
.withResourcePolicy(policyDocument)
.withBlockPublicPolicy(true);
PutResourcePolicyResult putResult = client.putResourcePolicy(putPolicyRequest);
System.out.println("Resource policy applied to: " + putResult.getName());// Policy allowing access only from specific VPC
public String createVPCRestrictedPolicy(String allowedVpcId) {
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Sid\": \"AllowVPCAccess\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": {\n" +
" \"AWS\": \"*\"\n" +
" },\n" +
" \"Action\": \"secretsmanager:GetSecretValue\",\n" +
" \"Resource\": \"*\",\n" +
" \"Condition\": {\n" +
" \"StringEquals\": {\n" +
" \"aws:sourceVpc\": \"" + allowedVpcId + "\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
}
// Policy allowing access only during specific time window
public String createTimeRestrictedPolicy(String startTime, String endTime) {
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Sid\": \"AllowTimeWindowAccess\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": {\n" +
" \"AWS\": \"*\"\n" +
" },\n" +
" \"Action\": \"secretsmanager:GetSecretValue\",\n" +
" \"Resource\": \"*\",\n" +
" \"Condition\": {\n" +
" \"DateGreaterThan\": {\n" +
" \"aws:CurrentTime\": \"" + startTime + "\"\n" +
" },\n" +
" \"DateLessThan\": {\n" +
" \"aws:CurrentTime\": \"" + endTime + "\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
}
// Policy allowing read-only access to specific roles
public String createReadOnlyPolicy(List<String> allowedRoleArns) {
StringBuilder principals = new StringBuilder();
for (int i = 0; i < allowedRoleArns.size(); i++) {
if (i > 0) principals.append(", ");
principals.append("\"").append(allowedRoleArns.get(i)).append("\"");
}
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Sid\": \"AllowReadOnlyAccess\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": {\n" +
" \"AWS\": [" + principals.toString() + "]\n" +
" },\n" +
" \"Action\": [\n" +
" \"secretsmanager:GetSecretValue\",\n" +
" \"secretsmanager:DescribeSecret\",\n" +
" \"secretsmanager:ListSecretVersionIds\"\n" +
" ],\n" +
" \"Resource\": \"*\"\n" +
" }\n" +
" ]\n" +
"}";
}class ValidateResourcePolicyRequest extends AmazonWebServiceRequest {
String secretId; // Secret identifier (optional for validation)
String resourcePolicy; // Required: JSON policy document to validate
}class ValidateResourcePolicyResult {
Boolean policyValidationPassed; // Whether validation passed
List<ValidationErrorsEntry> validationErrors; // Validation errors if any
}class ValidationErrorsEntry {
String checkName; // Name of the validation check
String errorMessage; // Detailed error message
}// Validate a policy before applying it
String testPolicy = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" + // This might trigger validation warnings
" \"Action\": \"secretsmanager:*\",\n" +
" \"Resource\": \"*\"\n" +
" }\n" +
" ]\n" +
"}";
ValidateResourcePolicyRequest validateRequest = new ValidateResourcePolicyRequest()
.withResourcePolicy(testPolicy)
.withSecretId("test/secret");
ValidateResourcePolicyResult validateResult = client.validateResourcePolicy(validateRequest);
if (validateResult.getPolicyValidationPassed()) {
System.out.println("Policy validation passed");
} else {
System.out.println("Policy validation failed:");
for (ValidationErrorsEntry error : validateResult.getValidationErrors()) {
System.out.println(" " + error.getCheckName() + ": " + error.getErrorMessage());
}
}class DeleteResourcePolicyRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
}class DeleteResourcePolicyResult {
String arn; // Secret ARN
String name; // Secret name
}// Remove resource policy from a secret
DeleteResourcePolicyRequest deleteRequest = new DeleteResourcePolicyRequest()
.withSecretId("prod/database/credentials");
try {
DeleteResourcePolicyResult deleteResult = client.deleteResourcePolicy(deleteRequest);
System.out.println("Removed resource policy from: " + deleteResult.getName());
} catch (ResourceNotFoundException e) {
System.out.println("No resource policy found to delete");
}Tags help organize secrets for cost allocation, access control, and operational management. Tags are key-value pairs that can be used in IAM policies and billing reports.
class TagResourceRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
List<Tag> tags; // Required: Tags to add
}class TagResourceResult {
// No properties - success indicated by no exception
}class Tag {
String key; // Required: Tag key (1-128 chars)
String value; // Required: Tag value (0-256 chars)
}// Add tags to a secret
List<Tag> tags = new ArrayList<>();
tags.add(new Tag().withKey("Environment").withValue("Production"));
tags.add(new Tag().withKey("Team").withValue("Backend"));
tags.add(new Tag().withKey("Application").withValue("UserService"));
tags.add(new Tag().withKey("CostCenter").withValue("Engineering"));
tags.add(new Tag().withKey("Owner").withValue("john.doe@company.com"));
TagResourceRequest tagRequest = new TagResourceRequest()
.withSecretId("prod/user-service/db-credentials")
.withTags(tags);
TagResourceResult tagResult = client.tagResource(tagRequest);
System.out.println("Tags added successfully");
// Add additional tags (existing tags remain)
List<Tag> additionalTags = new ArrayList<>();
additionalTags.add(new Tag().withKey("BackupSchedule").withValue("Daily"));
additionalTags.add(new Tag().withKey("Compliance").withValue("SOX"));
TagResourceRequest additionalTagRequest = new TagResourceRequest()
.withSecretId("prod/user-service/db-credentials")
.withTags(additionalTags);
client.tagResource(additionalTagRequest);class UntagResourceRequest extends AmazonWebServiceRequest {
String secretId; // Required: Secret identifier
List<String> tagKeys; // Required: Tag keys to remove
}class UntagResourceResult {
// No properties - success indicated by no exception
}// Remove specific tags
List<String> keysToRemove = Arrays.asList("BackupSchedule", "Compliance");
UntagResourceRequest untagRequest = new UntagResourceRequest()
.withSecretId("prod/user-service/db-credentials")
.withTagKeys(keysToRemove);
UntagResourceResult untagResult = client.untagResource(untagRequest);
System.out.println("Tags removed successfully");Tags can be viewed through the DescribeSecret operation:
// View all tags on a secret
DescribeSecretRequest describeRequest = new DescribeSecretRequest()
.withSecretId("prod/user-service/db-credentials");
DescribeSecretResult describeResult = client.describeSecret(describeRequest);
List<Tag> currentTags = describeResult.getTags();
if (currentTags != null && !currentTags.isEmpty()) {
System.out.println("Current tags:");
for (Tag tag : currentTags) {
System.out.println(" " + tag.getKey() + " = " + tag.getValue());
}
} else {
System.out.println("No tags found");
}// List secrets filtered by specific tags
List<Filter> tagFilters = new ArrayList<>();
// Filter by tag key
tagFilters.add(new Filter()
.withKey(FilterNameStringType.Tag_key)
.withValues("Environment"));
// Filter by tag value
tagFilters.add(new Filter()
.withKey(FilterNameStringType.Tag_value)
.withValues("Production"));
ListSecretsRequest filteredRequest = new ListSecretsRequest()
.withFilters(tagFilters);
ListSecretsResult filteredResult = client.listSecrets(filteredRequest);
System.out.println("Production secrets:");
for (SecretListEntry secret : filteredResult.getSecretList()) {
System.out.println(" " + secret.getName());
// Show relevant tags
for (Tag tag : secret.getTags()) {
if ("Environment".equals(tag.getKey()) || "Team".equals(tag.getKey())) {
System.out.println(" " + tag.getKey() + ": " + tag.getValue());
}
}
}// Apply consistent tags to multiple secrets
public void bulkTagSecrets(List<String> secretIds, List<Tag> commonTags) {
for (String secretId : secretIds) {
try {
TagResourceRequest tagRequest = new TagResourceRequest()
.withSecretId(secretId)
.withTags(commonTags);
client.tagResource(tagRequest);
System.out.println("Tagged: " + secretId);
} catch (Exception e) {
System.err.println("Failed to tag " + secretId + ": " + e.getMessage());
}
}
}
// Example usage
List<String> productionSecrets = Arrays.asList(
"prod/database/primary",
"prod/database/replica",
"prod/api/external-service",
"prod/cache/redis"
);
List<Tag> productionTags = Arrays.asList(
new Tag().withKey("Environment").withValue("Production"),
new Tag().withKey("MonitoringLevel").withValue("Critical"),
new Tag().withKey("BackupRequired").withValue("Yes")
);
bulkTagSecrets(productionSecrets, productionTags);// Create cost allocation tags for billing
public void setupCostAllocationTags(String secretId, String project,
String department, String costCenter) {
List<Tag> costTags = new ArrayList<>();
costTags.add(new Tag().withKey("Project").withValue(project));
costTags.add(new Tag().withKey("Department").withValue(department));
costTags.add(new Tag().withKey("CostCenter").withValue(costCenter));
costTags.add(new Tag().withKey("BillingMonth").withValue("2024-01"));
TagResourceRequest costTagRequest = new TagResourceRequest()
.withSecretId(secretId)
.withTags(costTags);
client.tagResource(costTagRequest);
System.out.println("Cost allocation tags applied");
}
// Usage
setupCostAllocationTags("prod/app/database", "WebApp", "Engineering", "ENG001");// Create IAM policy condition based on tags
public String createTagBasedAccessPolicy(String tagKey, String tagValue) {
return "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Action\": [\n" +
" \"secretsmanager:GetSecretValue\",\n" +
" \"secretsmanager:DescribeSecret\"\n" +
" ],\n" +
" \"Resource\": \"*\",\n" +
" \"Condition\": {\n" +
" \"StringEquals\": {\n" +
" \"secretsmanager:ResourceTag/" + tagKey + "\": \"" + tagValue + "\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
}
// This policy allows access only to secrets tagged with Team=Backend
String backendTeamPolicy = createTagBasedAccessPolicy("Team", "Backend");public class ComplianceTagManager {
// Standard compliance tags
public static final String CLASSIFICATION_KEY = "DataClassification";
public static final String RETENTION_KEY = "RetentionPeriod";
public static final String COMPLIANCE_KEY = "ComplianceFramework";
public static final String REVIEWED_KEY = "LastReviewed";
public void applyComplianceTags(String secretId, String classification,
String retentionPeriod, List<String> frameworks) {
List<Tag> complianceTags = new ArrayList<>();
complianceTags.add(new Tag()
.withKey(CLASSIFICATION_KEY)
.withValue(classification)); // "Public", "Internal", "Confidential", "Restricted"
complianceTags.add(new Tag()
.withKey(RETENTION_KEY)
.withValue(retentionPeriod)); // "1Year", "3Years", "7Years", "Indefinite"
complianceTags.add(new Tag()
.withKey(COMPLIANCE_KEY)
.withValue(String.join(",", frameworks))); // "SOX", "GDPR", "HIPAA", "PCI"
complianceTags.add(new Tag()
.withKey(REVIEWED_KEY)
.withValue(java.time.LocalDate.now().toString()));
TagResourceRequest complianceRequest = new TagResourceRequest()
.withSecretId(secretId)
.withTags(complianceTags);
try {
client.tagResource(complianceRequest);
System.out.println("Compliance tags applied to: " + secretId);
} catch (Exception e) {
System.err.println("Failed to apply compliance tags: " + e.getMessage());
}
}
public void auditComplianceTags() {
ListSecretsRequest listRequest = new ListSecretsRequest();
ListSecretsResult listResult = client.listSecrets(listRequest);
System.out.println("Compliance Audit Report:");
System.out.println("========================");
for (SecretListEntry secret : listResult.getSecretList()) {
boolean hasClassification = false;
boolean hasRetention = false;
boolean hasCompliance = false;
if (secret.getTags() != null) {
for (Tag tag : secret.getTags()) {
switch (tag.getKey()) {
case CLASSIFICATION_KEY:
hasClassification = true;
break;
case RETENTION_KEY:
hasRetention = true;
break;
case COMPLIANCE_KEY:
hasCompliance = true;
break;
}
}
}
System.out.println("Secret: " + secret.getName());
System.out.println(" Classification: " + (hasClassification ? "✓" : "✗"));
System.out.println(" Retention: " + (hasRetention ? "✓" : "✗"));
System.out.println(" Compliance: " + (hasCompliance ? "✓" : "✗"));
if (!hasClassification || !hasRetention || !hasCompliance) {
System.out.println(" STATUS: NON-COMPLIANT");
}
System.out.println();
}
}
}public class AutomatedTagManager {
public void enforceTaggingStandards(String secretId) {
try {
DescribeSecretResult secret = client.describeSecret(
new DescribeSecretRequest().withSecretId(secretId));
List<Tag> currentTags = secret.getTags();
List<Tag> requiredTags = new ArrayList<>();
// Check and add missing required tags
if (!hasTag(currentTags, "Environment")) {
// Infer environment from secret name
String environment = inferEnvironmentFromName(secret.getName());
requiredTags.add(new Tag().withKey("Environment").withValue(environment));
}
if (!hasTag(currentTags, "CreatedBy")) {
requiredTags.add(new Tag().withKey("CreatedBy").withValue("AutomatedTagging"));
}
if (!hasTag(currentTags, "CreatedDate")) {
requiredTags.add(new Tag().withKey("CreatedDate")
.withValue(secret.getCreatedDate().toString()));
}
if (!requiredTags.isEmpty()) {
TagResourceRequest tagRequest = new TagResourceRequest()
.withSecretId(secretId)
.withTags(requiredTags);
client.tagResource(tagRequest);
System.out.println("Applied missing tags to: " + secretId);
}
} catch (Exception e) {
System.err.println("Failed to enforce tagging standards: " + e.getMessage());
}
}
private boolean hasTag(List<Tag> tags, String key) {
if (tags == null) return false;
return tags.stream().anyMatch(tag -> key.equals(tag.getKey()));
}
private String inferEnvironmentFromName(String secretName) {
String lowerName = secretName.toLowerCase();
if (lowerName.contains("prod")) return "Production";
if (lowerName.contains("dev")) return "Development";
if (lowerName.contains("test")) return "Testing";
if (lowerName.contains("stage")) return "Staging";
return "Unknown";
}
}Common policy and tagging exceptions:
try {
PutResourcePolicyResult result = client.putResourcePolicy(request);
} catch (MalformedPolicyDocumentException e) {
System.err.println("Invalid policy document: " + e.getMessage());
} catch (PublicPolicyException e) {
System.err.println("Policy allows public access (blocked): " + e.getMessage());
} catch (InvalidParameterException e) {
System.err.println("Invalid policy or tag parameter: " + e.getMessage());
} catch (LimitExceededException e) {
System.err.println("Tag limit exceeded: " + e.getMessage());
} catch (ResourceNotFoundException e) {
System.err.println("Resource not found: " + e.getMessage());
} catch (AWSSecretsManagerException e) {
System.err.println("Service error: " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-com-amazonaws--aws-java-sdk-secretsmanager