Article
In Java applications, managing sensitive data like database passwords, API keys, and OAuth tokens has always been challenging. Hardcoding secrets in application.properties or even in environment variables poses significant security risks. The AWS Secrets Manager Container Storage Interface (CSI) Driver solves this by securely injecting secrets directly from AWS Secrets Manager into your Java application Pods at runtime.
For Java teams running on Amazon EKS, this provides a robust, secure, and Kubernetes-native approach to secret management that integrates seamlessly with Spring Boot, Micronaut, and other Java frameworks.
What is the AWS Secrets Manager CSI Driver?
The AWS Secrets Manager CSI Driver is a Kubernetes component that allows you to mount secrets stored in AWS Secrets Manager directly as volumes in your Pods. The driver handles the authentication, retrieval, and periodic rotation of secrets without exposing them in your YAML files or container images.
Key Benefits for Java Applications:
- Security: Secrets never appear in plaintext in etcd, Pod definitions, or environment variables
- Centralized Management: Single source of truth for all secrets across your organization
- Automatic Rotation: Secrets can be rotated in AWS Secrets Manager and automatically refreshed in your applications
- IAM-based Access Control: Fine-grained permissions using AWS IAM roles for service accounts
- Framework Agnostic: Works with any Java framework without code changes
How It Works
The CSI driver operates through a simple yet powerful workflow:
- Secret Creation: Secrets are stored in AWS Secrets Manager
- Pod Creation: Your Java application Pod is created with a reference to the secret
- Volume Mount: The CSI driver mounts the secret as a file in a volume
- Application Access: Your Java application reads the secret from the filesystem
- Automatic Refresh: (Optional) Secrets are automatically refreshed when rotated
Setting Up the AWS Secrets Manager CSI Driver
Prerequisites:
- Amazon EKS cluster
- AWS Secrets Manager CSI driver installed
- IAM OIDC provider configured for your EKS cluster
1. Install the CSI Driver:
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver \ --namespace kube-system \ --set syncSecret.enabled=true
2. Create a Secret in AWS Secrets Manager:
# Create a database password secret
aws secretsmanager create-secret \
--name production/postgres-password \
--description "PostgreSQL password for production" \
--secret-string "supersecretpassword123"
# Create a complex JSON secret for API keys
aws secretsmanager create-secret \
--name production/app-config \
--secret-string '{"apiKey": "abc123xyz", "oauthSecret": "secret456"}'
Integrating with Java Applications
Here's how to configure your Java application to use secrets from the CSI driver.
1. Create a SecretProviderClass:
This custom resource defines which secrets to fetch and how to mount them.
# secret-provider-class.yaml apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: java-app-secrets namespace: java-apps spec: provider: aws parameters: objects: | - objectName: "production/postgres-password" objectType: "secretsmanager" objectAlias: "db-password" # Filename when mounted - objectName: "production/app-config" objectType: "secretsmanager" jmesPath: - path: "apiKey" objectAlias: "api-key" - path: "oauthSecret" objectAlias: "oauth-secret"
2. Configure IAM Access using Service Account:
Create a service account with IAM role that has permission to access the secrets.
# service-account.yaml apiVersion: v1 kind: ServiceAccount metadata: name: java-app-service-account namespace: java-apps annotations: eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/JavaAppSecretsAccessRole
3. Java Application Deployment:
Configure your Spring Boot application to use the mounted secrets.
# spring-boot-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: java-apps spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: serviceAccountName: java-app-service-account containers: - name: app image: myregistry.io/order-service:latest ports: - containerPort: 8080 # Mount the secrets volume volumeMounts: - name: secrets-store mountPath: "/mnt/secrets" readOnly: true env: - name: DB_PASSWORD_FILE value: "/mnt/secrets/db-password" - name: API_KEY_FILE value: "/mnt/secrets/api-key" - name: OAUTH_SECRET_FILE value: "/mnt/secrets/oauth-secret" - name: SPRING_DATASOURCE_PASSWORD valueFrom: secretKeyRef: name: order-service-db-password # Synced Kubernetes secret key: password resources: requests: memory: "512Mi" cpu: "250m" volumes: - name: secrets-store csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "java-app-secrets"
Java Code Implementation
Your Java application can read the secrets from the mounted filesystem:
1. Simple File Reading Approach:
@Service
public class SecretService {
private final String dbPassword;
private final String apiKey;
private final String oauthSecret;
public SecretService(
@Value("${DB_PASSWORD_FILE:/mnt/secrets/db-password}") String dbPasswordPath,
@Value("${API_KEY_FILE:/mnt/secrets/api-key}") String apiKeyPath,
@Value("${OAUTH_SECRET_FILE:/mnt/secrets/oauth-secret}") String oauthSecretPath) {
this.dbPassword = readSecretFromFile(dbPasswordPath);
this.apiKey = readSecretFromFile(apiKeyPath);
this.oauthSecret = readSecretFromFile(oauthSecretPath);
}
private String readSecretFromFile(String filePath) {
try {
return new String(Files.readAllBytes(Paths.get(filePath))).trim();
} catch (IOException e) {
throw new RuntimeException("Failed to read secret from: " + filePath, e);
}
}
public String getDbPassword() {
return dbPassword;
}
public String getApiKey() {
return apiKey;
}
}
2. Spring Boot Configuration Properties:
@Configuration
@ConfigurationProperties(prefix = "app.secrets")
public class SecretConfig {
private String dbPasswordPath = "/mnt/secrets/db-password";
private String apiKeyPath = "/mnt/secrets/api-key";
// Getters and setters
@Bean
public String databasePassword() throws IOException {
return readSecretFromFile(dbPasswordPath);
}
@Bean
public String apiKey() throws IOException {
return readSecretFromFile(apiKeyPath);
}
private String readSecretFromFile(String path) throws IOException {
return new String(Files.readAllBytes(Paths.get(path))).trim();
}
}
3. Database Configuration in Spring Boot:
@Configuration
public class DatabaseConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource(SecretService secretService) {
return DataSourceBuilder.create()
.url("jdbc:postgresql://db-host:5432/orders")
.username("orders_user")
.password(secretService.getDbPassword())
.build();
}
}
Automatic Secret Rotation
The CSI driver supports automatic secret rotation when combined with a sync-to-Kubernetes-secret approach:
# SecretProviderClass with rotation enabled apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: java-app-secrets-rotatable namespace: java-apps spec: provider: aws parameters: objects: | - objectName: "production/postgres-password" objectType: "secretsmanager" secretObjects: # Sync to Kubernetes native secret - data: - key: password objectName: production/postgres-password secretName: order-service-db-password type: Opaque
Your application can watch for changes in the Kubernetes secret or rely on pod restart for secret updates.
Advanced Configuration for Java Applications
1. Multiple Environment Support:
# Use different SecretProviderClasses per environment
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: java-app-secrets-{{ .Values.environment }}
spec:
provider: aws
parameters:
objects: |
- objectName: "{{ .Values.environment }}/postgres-password"
objectType: "secretsmanager"
2. Helm Chart Integration:
# values.yaml
secrets:
database:
secretName: "{{ .Environment.Name }}/postgres-password"
api:
secretName: "{{ .Environment.Name }}/api-keys"
# deployment.yaml
spec:
template:
spec:
volumes:
- name: secrets-store
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "java-app-secrets-{{ .Values.environment }}"
Security Best Practices for Java Teams
- Least Privilege: Ensure your IAM roles only have access to necessary secrets
- Namespace Isolation: Use separate SecretProviderClasses per namespace
- Audit Logging: Enable AWS CloudTrail for secret access auditing
- Encryption: Use AWS KMS customer-managed keys for encryption
- Pod Security Standards: Implement Pod Security Standards to restrict volume types
# Pod Security Policy example apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: java-app-psp spec: allowedVolumes: - secret - configMap - projected - csi # Explicitly allow CSI volumes volumes: - secret - configMap - projected - csi
Troubleshooting Common Issues
# Check if secrets are mounted correctly kubectl exec -it deployment/order-service -n java-apps -- ls -la /mnt/secrets/ # Check CSI driver logs kubectl logs -l app=secrets-store-csi-driver -n kube-system # Verify SecretProviderClass status kubectl get secretproviderclass -n java-apps kubectl describe secretproviderclass java-app-secrets -n java-apps
Conclusion
For Java teams running on Amazon EKS, the AWS Secrets Manager CSI Driver provides an enterprise-grade solution for secret management that aligns perfectly with cloud-native principles. By integrating secret injection directly into the Kubernetes runtime, Java applications can securely access sensitive data without complex key management systems or security compromises.
This approach not only enhances security but also simplifies operations, enables automatic rotation, and provides a consistent secret management pattern across all your Java microservices. As Java applications continue to evolve in cloud environments, adopting the Secrets Manager CSI Driver becomes essential for building secure, maintainable, and production-ready applications.
Java Logistics, Shipping Integration & Enterprise Inventory Automation (Tracking, ERP, RFID & Billing Systems)
https://macronepal.com/blog/aftership-tracking-in-java-enterprise-package-visibility/
Explains how to integrate AfterShip tracking services into Java applications to provide real-time shipment visibility, delivery status updates, and centralized tracking across multiple courier services.
https://macronepal.com/blog/shipping-integration-using-fedex-api-with-java-for-logistics-automation/
Explains how to integrate the FedEx API into Java systems to automate shipping tasks such as creating shipments, calculating delivery costs, generating shipping labels, and tracking packages.
https://macronepal.com/blog/shipping-and-logistics-integrating-ups-apis-with-java-applications/
Explains UPS API integration in Java to enable automated shipping operations including rate calculation, shipment scheduling, tracking, and delivery confirmation management.
https://macronepal.com/blog/generating-and-reading-qr-codes-for-products-in-java/
Explains how Java applications generate and read QR codes for product identification, tracking, and authentication, supporting faster inventory handling and product verification processes.
https://macronepal.com/blog/designing-a-robust-pick-and-pack-workflow-in-java/
Explains how to design an efficient pick-and-pack workflow in Java warehouse systems, covering order processing, item selection, packaging steps, and logistics preparation to improve fulfillment efficiency.
https://macronepal.com/blog/rfid-inventory-management-system-in-java-a-complete-guide/
Explains how RFID technology integrates with Java applications to automate inventory tracking, reduce manual errors, and enable real-time stock monitoring in warehouses and retail environments.
https://macronepal.com/blog/erp-integration-with-odoo-in-java/
Explains how Java applications connect with Odoo ERP systems to synchronize inventory, orders, customer records, and financial data across enterprise systems.
https://macronepal.com/blog/automated-invoice-generation-creating-professional-excel-invoices-with-apache-poi-in-java/
Explains how to automatically generate professional Excel invoices in Java using Apache POI, enabling structured billing documents and automated financial record creation.
https://macronepal.com/blog/enterprise-financial-integration-using-quickbooks-api-in-java-applications/
Explains QuickBooks API integration in Java to automate financial workflows such as invoice management, payment tracking, accounting synchronization, and financial reporting.