Akeyless is a secrets management and privileged access management platform that provides a unified solution for securing credentials, certificates, and keys across cloud-native environments. For Java applications, Akeyless offers robust programmatic access to secrets while maintaining security best practices.
What is Akeyless Vault?
Akeyless Vault is a SaaS-based secrets management platform that enables Java applications to securely access:
- Database credentials and API keys
- TLS certificates and SSH keys
- Cloud provider access credentials
- Dynamic secrets with automatic rotation
- Encryption keys for application-level crypto
Java SDK Setup and Dependencies
Maven Configuration:
<dependencies> <dependency> <groupId>io.akeyless</groupId> <artifactId>akeyless-java</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.11.0</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> </dependencies>
Gradle Configuration:
dependencies {
implementation 'io.akeyless:akeyless-java:3.4.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.google.code.gson:gson:2.10.1'
}
Authentication Methods
1. API Key Authentication:
@Component
public class AkeylessConfig {
@Value("${akeyless.access.id:${AKEYLESS_ACCESS_ID}}")
private String accessId;
@Value("${akeyless.access.key:${AKEYLESS_ACCESS_KEY}}")
private String accessKey;
@Bean
public ApiClient akeylessApiClient() {
ApiClient client = new ApiClient();
client.setApiKey(accessKey);
client.setApiKeyPrefix(accessId);
client.setBasePath("https://api.akeyless.io");
return client;
}
@Bean
public V2Api akeylessClient(ApiClient apiClient) {
return new V2Api(apiClient);
}
}
2. Kubernetes Service Account Authentication:
@Service
public class KubernetesAuthService {
public String authenticateWithK8s(String accessId, String k8sAuthConfigName) {
V2Api client = getAkeylessClient();
Auth auth = new Auth();
auth.setAccessId(accessId);
auth.setKubernetesAuthConfigName(k8sAuthConfigName);
// This should run in a Kubernetes pod with mounted service account token
String token = client.auth(auth).getToken();
return token;
}
}
3. AWS IAM Authentication:
@Service
public class AwsIamAuthService {
public String authenticateWithAwsIam(String accessId, String awsIamConfigName) {
V2Api client = getAkeylessClient();
Auth auth = new Auth();
auth.setAccessId(accessId);
auth.setAwsIamConfigName(awsIamConfigName);
return client.auth(auth).getToken();
}
}
Secrets Management
SecretService.java:
@Service
@Slf4j
public class SecretService {
private final V2Api akeylessClient;
private final Gson gson;
public SecretService(V2Api akeylessClient) {
this.akeylessClient = akeylessClient;
this.gson = new Gson();
}
public String getSecret(String secretPath) {
try {
GetSecretValue body = new GetSecretValue();
body.setNames(Arrays.asList(secretPath));
body.setToken(getAuthToken());
Map<String, Object> response = akeylessClient.getSecretValue(body);
return (String) response.get(secretPath);
} catch (ApiException e) {
log.error("Failed to retrieve secret from path: {}", secretPath, e);
throw new SecretRetrievalException("Failed to retrieve secret: " + secretPath, e);
}
}
public <T> T getSecretAsObject(String secretPath, Class<T> valueType) {
String secretJson = getSecret(secretPath);
return gson.fromJson(secretJson, valueType);
}
public void createSecret(String secretPath, String secretValue) {
try {
CreateSecret body = new CreateSecret();
body.setName(secretPath);
body.setValue(secretValue);
body.setToken(getAuthToken());
CreateSecretOutput output = akeylessClient.createSecret(body);
log.info("Created secret: {}", output.getName());
} catch (ApiException e) {
throw new SecretManagementException("Failed to create secret: " + secretPath, e);
}
}
public void updateSecret(String secretPath, String newValue) {
try {
UpdateSecretVal body = new UpdateSecretVal();
body.setName(secretPath);
body.setValue(newValue);
body.setToken(getAuthToken());
UpdateSecretValOutput output = akeylessClient.updateSecretVal(body);
log.info("Updated secret: {}", output.getName());
} catch (ApiException e) {
throw new SecretManagementException("Failed to update secret: " + secretPath, e);
}
}
public void deleteSecret(String secretPath) {
try {
DeleteSecret body = new DeleteSecret();
body.setName(secretPath);
body.setToken(getAuthToken());
DeleteSecretOutput output = akeylessClient.deleteSecret(body);
log.info("Deleted secret: {}", output.getDeletedItems());
} catch (ApiException e) {
throw new SecretManagementException("Failed to delete secret: " + secretPath, e);
}
}
private String getAuthToken() {
// Implement token retrieval/caching logic
return System.getenv("AKEYLESS_TOKEN");
}
}
Database Credentials with Dynamic Secrets
DynamicDatabaseConfig.java:
@Configuration
public class DynamicDatabaseConfig {
@Bean
@RefreshScope
public DataSource dataSource(SecretService secretService) {
DatabaseCredentials dbCreds = secretService.getSecretAsObject(
"/production/database/mysql-app", DatabaseCredentials.class);
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(dbCreds.getJdbcUrl());
dataSource.setUsername(dbCreds.getUsername());
dataSource.setPassword(dbCreds.getPassword());
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setMaximumPoolSize(20);
dataSource.setMinimumIdle(5);
return dataSource;
}
@Bean
public ScheduledTask dynamicSecretRefresher(SecretService secretService) {
return new ScheduledTask(() -> {
try {
// Refresh dynamic secret before it expires
secretService.getSecret("/production/database/mysql-app");
log.debug("Refreshed dynamic database credentials");
} catch (Exception e) {
log.error("Failed to refresh dynamic secret", e);
}
}, Duration.ofMinutes(30)); // Refresh every 30 minutes
}
}
@Data
class DatabaseCredentials {
private String username;
private String password;
private String host;
private int port;
private String database;
public String getJdbcUrl() {
return String.format("jdbc:mysql://%s:%d/%s", host, port, database);
}
}
API Key Management
ApiKeyManager.java:
@Service
public class ApiKeyManager {
private final SecretService secretService;
private final V2Api akeylessClient;
public ApiKeyManager(SecretService secretService, V2Api akeylessClient) {
this.secretService = secretService;
this.akeylessClient = akeylessClient;
}
public String getExternalApiKey(String serviceName) {
return secretService.getSecret("/external-apis/" + serviceName + "/api-key");
}
public void rotateApiKey(String serviceName) {
String newApiKey = generateSecureApiKey();
// Update in Akeyless
secretService.updateSecret("/external-apis/" + serviceName + "/api-key", newApiKey);
// Notify dependent services (optional)
notifyApiKeyRotation(serviceName);
}
public Map<String, String> getAllApiKeys() {
// Assuming you have a method to list secrets
List<String> apiKeyPaths = listSecretPaths("/external-apis/");
Map<String, String> apiKeys = new HashMap<>();
for (String path : apiKeyPaths) {
String serviceName = extractServiceName(path);
apiKeys.put(serviceName, secretService.getSecret(path));
}
return apiKeys;
}
private String generateSecureApiKey() {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[32];
random.nextBytes(bytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}
}
TLS Certificate Management
CertificateService.java:
@Service
public class CertificateService {
private final V2Api akeylessClient;
private final SecretService secretService;
public CertificateService(V2Api akeylessClient, SecretService secretService) {
this.akeylessClient = akeylessClient;
this.secretService = secretService;
}
public SSLContext getSSLContextForService(String serviceName) {
try {
String privateKeyPem = secretService.getSecret("/tls/" + serviceName + "/private-key");
String certificatePem = secretService.getSecret("/tls/" + serviceName + "/certificate");
String caBundle = secretService.getSecret("/tls/ca-bundle");
return createSSLContext(privateKeyPem, certificatePem, caBundle);
} catch (Exception e) {
throw new CertificateException("Failed to create SSL context for: " + serviceName, e);
}
}
public X509Certificate getCertificate(String certPath) {
try {
String certPem = secretService.getSecret(certPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(certPem.getBytes())
);
} catch (Exception e) {
throw new CertificateException("Failed to load certificate: " + certPath, e);
}
}
public void requestNewCertificate(String commonName, int validityDays) {
try {
CreatePKICert body = new CreatePKICert();
body.setCommonName(commonName);
body.setTtl(validityDays * 24 * 60 * 60); // Convert to seconds
body.setToken(getAuthToken());
CreatePKICertOutput output = akeylessClient.createPKICert(body);
// Store the generated certificate and key
secretService.createSecret("/tls/" + commonName + "/certificate", output.getData());
secretService.createSecret("/tls/" + commonName + "/private-key", output.getPrivateKey());
} catch (ApiException e) {
throw new CertificateException("Failed to request certificate for: " + commonName, e);
}
}
}
Spring Boot Integration
AkeylessSpringConfiguration.java:
@Configuration
@EnableConfigurationProperties(AkeylessProperties.class)
public class AkeylessSpringConfiguration {
@Bean
@ConditionalOnMissingBean
public SecretService secretService(V2Api akeylessClient) {
return new SecretService(akeylessClient);
}
@Bean
public AkeylessPropertySource akeylessPropertySource(SecretService secretService) {
return new AkeylessPropertySource(secretService);
}
}
@Component
public class AkeylessPropertySource extends PropertySource<SecretService> {
private static final String AKEYLESS_PREFIX = "akeyless:";
public AkeylessPropertySource(SecretService secretService) {
super("AkeylessPropertySource", secretService);
}
@Override
public Object getProperty(String name) {
if (name.startsWith(AKEYLESS_PREFIX)) {
String secretPath = name.substring(AKEYLESS_PREFIX.length());
return getSource().getSecret(secretPath);
}
return null;
}
}
@ConfigurationProperties(prefix = "akeyless")
@Data
public class AkeylessProperties {
private String accessId;
private String accessKey;
private String basePath = "https://api.akeyless.io";
private List<String> preloadSecrets = new ArrayList<>();
}
Kubernetes Integration
K8sAkeylessSidecar.java:
@Component
@Slf4j
public class K8sAkeylessSidecar {
private final SecretService secretService;
private final AkeylessProperties properties;
public K8sAkeylessSidecar(SecretService secretService, AkeylessProperties properties) {
this.secretService = secretService;
this.properties = properties;
}
@PostConstruct
public void initializeSecrets() {
log.info("Initializing Akeyless secrets for Kubernetes deployment");
// Pre-load secrets on startup
for (String secretPath : properties.getPreloadSecrets()) {
try {
String secret = secretService.getSecret(secretPath);
log.debug("Pre-loaded secret: {}", secretPath);
} catch (Exception e) {
log.warn("Failed to pre-load secret: {}", secretPath, e);
}
}
}
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
// Write secrets to filesystem for sidecar consumption
writeSecretsToFilesystem();
}
private void writeSecretsToFilesystem() {
try {
Files.createDirectories(Paths.get("/var/run/akeyless/secrets"));
for (String secretPath : properties.getPreloadSecrets()) {
String secret = secretService.getSecret(secretPath);
String fileName = secretPath.replace("/", "_");
Files.write(
Paths.get("/var/run/akeyless/secrets/" + fileName),
secret.getBytes(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
);
}
} catch (IOException e) {
log.error("Failed to write secrets to filesystem", e);
}
}
}
Security and Best Practices
SecretCacheManager.java:
@Service
@Slf4j
public class SecretCacheManager {
private final SecretService secretService;
private final Cache<String, String> secretCache;
private final Cache<String, Instant> lastAccessCache;
public SecretCacheManager(SecretService secretService) {
this.secretService = secretService;
this.secretCache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(5)) // Cache for 5 minutes
.maximumSize(1000)
.build();
this.lastAccessCache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofHours(1))
.build();
}
public String getSecretWithCache(String secretPath) {
return secretCache.get(secretPath, path -> {
lastAccessCache.put(path, Instant.now());
return secretService.getSecret(path);
});
}
public void refreshCache(String secretPath) {
secretCache.invalidate(secretPath);
getSecretWithCache(secretPath); // Re-populate cache
}
public void refreshAllAccessedSecrets() {
Set<String> accessedSecrets = lastAccessCache.asMap().keySet();
for (String secretPath : accessedSecrets) {
refreshCache(secretPath);
}
}
}
Error Handling and Resilience
AkeylessExceptionHandler.java:
@ControllerAdvice
@Slf4j
public class AkeylessExceptionHandler {
@ExceptionHandler(SecretRetrievalException.class)
public ResponseEntity<ErrorResponse> handleSecretRetrievalException(SecretRetrievalException e) {
log.error("Secret retrieval failed", e);
ErrorResponse error = new ErrorResponse(
"SECRET_RETRIEVAL_FAILED",
"Failed to retrieve required secret",
Map.of("path", e.getSecretPath())
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
@ExceptionHandler(ApiException.class)
public ResponseEntity<ErrorResponse> handleAkeylessApiException(ApiException e) {
log.error("Akeyless API call failed", e);
ErrorResponse error = new ErrorResponse(
"AKEYLESS_API_ERROR",
"Akeyless service unavailable",
Map.of("code", e.getCode(), "message", e.getMessage())
);
return ResponseEntity.status(e.getCode()).body(error);
}
}
@Data
@AllArgsConstructor
class ErrorResponse {
private String code;
private String message;
private Map<String, Object> details;
}
Testing with Akeyless
TestAkeylessIntegration.java:
@SpringBootTest
@TestPropertySource(properties = {
"akeyless.access.id=test-access-id",
"akeyless.access.key=test-access-key"
})
@MockBean({V2Api.class, SecretService.class})
public class TestAkeylessIntegration {
@Autowired
private V2Api mockAkeylessClient;
@Autowired
private SecretService mockSecretService;
@Test
public void testSecretRetrieval() {
when(mockSecretService.getSecret("/database/password"))
.thenReturn("test-password-123");
String password = mockSecretService.getSecret("/database/password");
assertEquals("test-password-123", password);
verify(mockSecretService).getSecret("/database/password");
}
@Test
public void testSecretCache() {
SecretCacheManager cacheManager = new SecretCacheManager(mockSecretService);
when(mockSecretService.getSecret("/api/key"))
.thenReturn("cached-api-key");
// First call should hit the service
String firstResult = cacheManager.getSecretWithCache("/api/key");
// Second call should use cache
String secondResult = cacheManager.getSecretWithCache("/api/key");
assertEquals("cached-api-key", firstResult);
assertEquals("cached-api-key", secondResult);
verify(mockSecretService, times(1)).getSecret("/api/key");
}
}
Best Practices for Java Applications
- Never log secrets - implement proper logging filters
- Use secret caching with appropriate TTL values
- Implement graceful degradation when Akeyless is unavailable
- Rotate credentials regularly using Akeyless dynamic secrets
- Use different access IDs for different environments
- Monitor secret access patterns for security auditing
- Implement circuit breakers for Akeyless API calls
Conclusion
Akeyless Vault provides a comprehensive secrets management solution for Java applications, offering:
- Secure credential storage with encryption at rest and in transit
- Dynamic secrets with automatic rotation
- Multiple authentication methods for different environments
- TLS certificate management for secure communications
- Seamless integration with Spring Boot and Kubernetes
By implementing Akeyless in your Java applications, you can eliminate hardcoded credentials, reduce security risks, and maintain compliance with security best practices across your entire application stack.
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.