/** * POST TITLE: CyberArk Conjur Secrets Management in Java * * Complete implementation of CyberArk Conjur for secrets management in Java applications */ import com.cyberark.conjur.api.Conjur; import com.cyberark.conjur.api.Variables; import com.cyberark.conjur.sdk.ApiException; import com.cyberark.conjur.sdk.Configuration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.vault.annotation.VaultPropertySource; import java.io.*; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.nio.file.*; import java.util.*; import java.util.concurrent.*; import java.security.KeyStore; import javax.net.ssl.*; public class ConjurJavaIntegration { /** * Conjur Configuration Manager */ public static class ConjurConfigManager { private final Path configPath; private final Properties properties; public ConjurConfigManager(Path configPath) { this.configPath = configPath; this.properties = new Properties(); } /** * Conjur Configuration */ public static class ConjurConfiguration { private String applianceUrl; private String account; private String username; private String password; private String apiKey; private String certFile; private String authnUrl; private boolean sslVerification = true; private int timeout = 30; public ConjurConfiguration(String applianceUrl, String account) { this.applianceUrl = applianceUrl; this.account = account; } // Builder methods public ConjurConfiguration withUsername(String username) { this.username = username; return this; } public ConjurConfiguration withPassword(String password) { this.password = password; return this; } public ConjurConfiguration withApiKey(String apiKey) { this.apiKey = apiKey; return this; } public ConjurConfiguration withCertFile(String certFile) { this.certFile = certFile; return this; } public ConjurConfiguration withAuthnUrl(String authnUrl) { this.authnUrl = authnUrl; return this; } public ConjurConfiguration withSslVerification(boolean sslVerification) { this.sslVerification = sslVerification; return this; } public ConjurConfiguration withTimeout(int timeout) { this.timeout = timeout; return this; } // Getters public String getApplianceUrl() { return applianceUrl; } public String getAccount() { return account; } public String getUsername() { return username; } public String getPassword() { return password; } public String getApiKey() { return apiKey; } public String getCertFile() { return certFile; } public String getAuthnUrl() { return authnUrl; } public boolean isSslVerification() { return sslVerification; } public int getTimeout() { return timeout; } } /** * Create Conjur configuration file */ public void createConfiguration(ConjurConfiguration config) throws IOException { properties.setProperty("CONJUR_APPLIANCE_URL", config.getApplianceUrl()); properties.setProperty("CONJUR_ACCOUNT", config.getAccount()); properties.setProperty("CONJUR_AUTHN_URL", config.getAuthnUrl() != null ? config.getAuthnUrl() : config.getApplianceUrl() + "/authn"); if (config.getUsername() != null) { properties.setProperty("CONJUR_AUTHN_LOGIN", config.getUsername()); } if (config.getApiKey() != null) { properties.setProperty("CONJUR_AUTHN_API_KEY", config.getApiKey()); } if (config.getCertFile() != null) { properties.setProperty("CONJUR_CERT_FILE", config.getCertFile()); } properties.setProperty("CONJUR_SSL_CERTIFICATE", config.isSslVerification() ? config.getCertFile() : ""); properties.setProperty("CONJUR_VERIFY_SSL", String.valueOf(config.isSslVerification())); try (FileOutputStream out = new FileOutputStream(configPath.toFile())) { properties.store(out, "Conjur Configuration"); } System.out.println("✅ Conjur configuration created: " + configPath); } /** * Load configuration from file */ public ConjurConfiguration loadConfiguration() throws IOException { try (FileInputStream in = new FileInputStream(configPath.toFile())) { properties.load(in); } return new ConjurConfiguration( properties.getProperty("CONJUR_APPLIANCE_URL"), properties.getProperty("CONJUR_ACCOUNT") ) .withUsername(properties.getProperty("CONJUR_AUTHN_LOGIN")) .withApiKey(properties.getProperty("CONJUR_AUTHN_API_KEY")) .withCertFile(properties.getProperty("CONJUR_CERT_FILE")) .withAuthnUrl(properties.getProperty("CONJUR_AUTHN_URL")) .withSslVerification(Boolean.parseBoolean(properties.getProperty("CONJUR_VERIFY_SSL", "true"))); } /** * Create sample configuration for development */ public void createDevelopmentConfig() throws IOException { ConjurConfiguration config = new ConjurConfiguration( "https://conjur.example.com", "my-account" ) .withUsername("admin@my-account") .withApiKey("your-api-key-here") .withCertFile("/etc/conjur/conjur.pem") .withSslVerification(true) .withTimeout(30); createConfiguration(config); } } /** * Conjur Client Wrapper */ public static class ConjurClient { private final Conjur conjur; private final Variables variables; private final HttpClient httpClient; private final ConjurConfigManager.ConjurConfiguration config; public ConjurClient(ConjurConfigManager.ConjurConfiguration config) { this.config = config; configureConjurSDK(config); this.conjur = new Conjur(); this.variables = conjur.variables(); this.httpClient = createHttpClient(config); } private void configureConjurSDK(ConjurConfigManager.ConjurConfiguration config) { // Configure Conjur SDK Configuration.setApplianceUrl(config.getApplianceUrl()); Configuration.setAccount(config.getAccount()); Configuration.setUsername(config.getUsername()); Configuration.setApiKey(config.getApiKey()); Configuration.setCertFile(config.getCertFile()); Configuration.setSslVerification(config.isSslVerification()); } private HttpClient createHttpClient(ConjurConfigManager.ConjurConfiguration config) { HttpClient.Builder builder = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .connectTimeout(Duration.ofSeconds(config.getTimeout())); if (!config.isSslVerification() && config.getCertFile() != null) { builder.sslContext(createSSLContext(config.getCertFile())); } return builder.build(); } private SSLContext createSSLContext(String certFile) { try { // Load custom trust store with Conjur certificate KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); // Load Conjur certificate CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(certFile)) { Collection<? extends Certificate> certificates = cf.generateCertificates(fis); int i = 0; for (Certificate cert : certificates) { trustStore.setCertificateEntry("conjur-cert-" + i++, cert); } } // Create SSL context TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); return sslContext; } catch (Exception e) { throw new RuntimeException("Failed to create SSL context", e); } } /** * Retrieve secret by variable ID */ public String getSecret(String variableId) { try { System.out.println("🔐 Retrieving secret: " + variableId); String secret = variables.getVariable(variableId).retrieve(); System.out.println("✅ Secret retrieved successfully"); return secret; } catch (ApiException e) { System.err.println("❌ Failed to retrieve secret: " + e.getMessage()); throw new RuntimeException("Secret retrieval failed", e); } } /** * Retrieve secret with retry logic */ public String getSecretWithRetry(String variableId, int maxRetries) { for (int attempt = 1; attempt <= maxRetries; attempt++) { try { return getSecret(variableId); } catch (Exception e) { if (attempt == maxRetries) { throw e; } System.out.println("🔄 Retry attempt " + attempt + " for: " + variableId); try { Thread.sleep(1000 * attempt); // Exponential backoff } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException("Retry interrupted", ie); } } } throw new RuntimeException("All retry attempts failed"); } /** * Retrieve multiple secrets */ public Map<String, String> getSecrets(List<String> variableIds) { Map<String, String> secrets = new HashMap<>(); for (String variableId : variableIds) { try { secrets.put(variableId, getSecret(variableId)); } catch (Exception e) { System.err.println("❌ Failed to retrieve secret: " + variableId); // Continue with other secrets } } return secrets; } /** * Retrieve secrets in batch (parallel) */ public Map<String, String> getSecretsParallel(List<String> variableIds) { ExecutorService executor = Executors.newFixedThreadPool(10); Map<String, String> secrets = new ConcurrentHashMap<>(); List<CompletableFuture<Void>> futures = new ArrayList<>(); for (String variableId : variableIds) { CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { try { String secret = getSecret(variableId); secrets.put(variableId, secret); } catch (Exception e) { System.err.println("❌ Failed to retrieve secret: " + variableId); } }, executor); futures.add(future); } // Wait for all completions CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); executor.shutdown(); return secrets; } /** * Add secret to Conjur */ public void addSecret(String variableId, String secretValue) { try { System.out.println("🔐 Adding secret: " + variableId); variables.getVariable(variableId).addSecret(secretValue); System.out.println("✅ Secret added successfully"); } catch (ApiException e) { System.err.println("❌ Failed to add secret: " + e.getMessage()); throw new RuntimeException("Secret addition failed", e); } } /** * Check if secret exists */ public boolean secretExists(String variableId) { try { variables.getVariable(variableId).retrieve(); return true; } catch (ApiException e) { return false; } } /** * List all variables (requires appropriate permissions) */ public List<String> listVariables() { try { // This is a simplified implementation // In reality, you'd use the appropriate Conjur API endpoint return Collections.emptyList(); } catch (Exception e) { System.err.println("❌ Failed to list variables: " + e.getMessage()); return Collections.emptyList(); } } /** * Test connection to Conjur */ public boolean testConnection() { try { // Try to retrieve a known variable or use health check conjur.variables().getVariable("test").retrieve(); return true; } catch (Exception e) { return false; } } } /** * Secrets Management Service */ public static class SecretsManagementService { private final ConjurClient conjurClient; private final ScheduledExecutorService scheduler; private final Map<String, String> secretCache; private final long cacheRefreshInterval; public SecretsManagementService(ConjurClient conjurClient) { this.conjurClient = conjurClient; this.scheduler = Executors.newScheduledThreadPool(1); this.secretCache = new ConcurrentHashMap<>(); this.cacheRefreshInterval = 300000; // 5 minutes startCacheRefresher(); } /** * Get secret with caching */ public String getSecret(String variableId) { return getSecret(variableId, false); } public String getSecret(String variableId, boolean forceRefresh) { if (forceRefresh || !secretCache.containsKey(variableId)) { String secret = conjurClient.getSecret(variableId); secretCache.put(variableId, secret); return secret; } return secretCache.get(variableId); } /** * Get database configuration secrets */ public DatabaseConfig getDatabaseConfig(String dbVariablePrefix) { Map<String, String> secrets = conjurClient.getSecrets(Arrays.asList( dbVariablePrefix + "/username", dbVariablePrefix + "/password", dbVariablePrefix + "/url", dbVariablePrefix + "/port" )); return new DatabaseConfig( secrets.get(dbVariablePrefix + "/username"), secrets.get(dbVariablePrefix + "/password"), secrets.get(dbVariablePrefix + "/url"), secrets.get(dbVariablePrefix + "/port") ); } /** * Get API configuration secrets */ public ApiConfig getApiConfig(String apiVariablePrefix) { Map<String, String> secrets = conjurClient.getSecrets(Arrays.asList( apiVariablePrefix + "/key", apiVariablePrefix + "/secret", apiVariablePrefix + "/endpoint" )); return new ApiConfig( secrets.get(apiVariablePrefix + "/key"), secrets.get(apiVariablePrefix + "/secret"), secrets.get(apiVariablePrefix + "/endpoint") ); } /** * Get SSL/TLS configuration */ public SSLConfig getSSLConfig(String sslVariablePrefix) { Map<String, String> secrets = conjurClient.getSecrets(Arrays.asList( sslVariablePrefix + "/keystore-password", sslVariablePrefix + "/truststore-password", sslVariablePrefix + "/key-alias" )); return new SSLConfig( secrets.get(sslVariablePrefix + "/keystore-password"), secrets.get(sslVariablePrefix + "/truststore-password"), secrets.get(sslVariablePrefix + "/key-alias") ); } /** * Start background cache refresher */ private void startCacheRefresher() { scheduler.scheduleAtFixedRate(() -> { try { refreshCache(); } catch (Exception e) { System.err.println("❌ Cache refresh failed: " + e.getMessage()); } }, cacheRefreshInterval, cacheRefreshInterval, TimeUnit.MILLISECONDS); } private void refreshCache() { System.out.println("🔄 Refreshing secret cache..."); List<String> keys = new ArrayList<>(secretCache.keySet()); for (String key : keys) { try { String newSecret = conjurClient.getSecret(key); secretCache.put(key, newSecret); } catch (Exception e) { System.err.println("❌ Failed to refresh secret: " + key); // Keep old value for now } } } /** * Clear cache */ public void clearCache() { secretCache.clear(); System.out.println("🧹 Secret cache cleared"); } /** * Get cache statistics */ public CacheStats getCacheStats() { return new CacheStats( secretCache.size(), System.currentTimeMillis() ); } /** * Shutdown service */ public void shutdown() { scheduler.shutdown(); try { if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { scheduler.shutdownNow(); } } catch (InterruptedException e) { scheduler.shutdownNow(); Thread.currentThread().interrupt(); } } } /** * Configuration Classes */ public static class DatabaseConfig { private final String username; private final String password; private final String url; private final String port; public DatabaseConfig(String username, String password, String url, String port) { this.username = username; this.password = password; this.url = url; this.port = port; } // Getters public String getUsername() { return username; } public String getPassword() { return password; } public String getUrl() { return url; } public String getPort() { return port; } public String getConnectionString() { return String.format("jdbc:postgresql://%s:%s/mydb", url, port); } } public static class ApiConfig { private final String apiKey; private final String apiSecret; private final String endpoint; public ApiConfig(String apiKey, String apiSecret, String endpoint) { this.apiKey = apiKey; this.apiSecret = apiSecret; this.endpoint = endpoint; } // Getters public String getApiKey() { return apiKey; } public String getApiSecret() { return apiSecret; } public String getEndpoint() { return endpoint; } } public static class SSLConfig { private final String keystorePassword; private final String truststorePassword; private final String keyAlias; public SSLConfig(String keystorePassword, String truststorePassword, String keyAlias) { this.keystorePassword = keystorePassword; this.truststorePassword = truststorePassword; this.keyAlias = keyAlias; } // Getters public String getKeystorePassword() { return keystorePassword; } public String getTruststorePassword() { return truststorePassword; } public String getKeyAlias() { return keyAlias; } } public static class CacheStats { private final int cacheSize; private final long lastRefresh; public CacheStats(int cacheSize, long lastRefresh) { this.cacheSize = cacheSize; this.lastRefresh = lastRefresh; } // Getters public int getCacheSize() { return cacheSize; } public long getLastRefresh() { return lastRefresh; } } /** * Spring Boot Integration */ @Configuration @ConfigurationProperties(prefix = "conjur") public static class ConjurProperties { private String applianceUrl; private String account; private String username; private String apiKey; private String certFile; private boolean sslVerification = true; // Getters and setters public String getApplianceUrl() { return applianceUrl; } public void setApplianceUrl(String applianceUrl) { this.applianceUrl = applianceUrl; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getApiKey() { return apiKey; } public void setApiKey(String apiKey) { this.apiKey = apiKey; } public String getCertFile() { return certFile; } public void setCertFile(String certFile) { this.certFile = certFile; } public boolean isSslVerification() { return sslVerification; } public void setSslVerification(boolean sslVerification) { this.sslVerification = sslVerification; } } @SpringBootApplication public static class ConjurIntegrationApplication { @Bean public ConjurConfigManager conjurConfigManager(@Value("${conjur.config.path:./conjur.properties}") String configPath) { return new ConjurConfigManager(Paths.get(configPath)); } @Bean public ConjurClient conjurClient(ConjurProperties properties) { ConjurConfigManager.ConjurConfiguration config = new ConjurConfigManager.ConjurConfiguration( properties.getApplianceUrl(), properties.getAccount() ) .withUsername(properties.getUsername()) .withApiKey(properties.getApiKey()) .withCertFile(properties.getCertFile()) .withSslVerification(properties.isSslVerification()); return new ConjurClient(config); } @Bean public SecretsManagementService secretsManagementService(ConjurClient conjurClient) { return new SecretsManagementService(conjurClient); } } @RestController @RequestMapping("/api/secrets") public static class SecretsController { private final SecretsManagementService secretsService; private final ConjurClient conjurClient; public SecretsController(SecretsManagementService secretsService, ConjurClient conjurClient) { this.secretsService = secretsService; this.conjurClient = conjurClient; } @GetMapping("/{variableId}") public ResponseEntity<Map<String, String>> getSecret(@PathVariable String variableId) { try { String secret = secretsService.getSecret(variableId); return ResponseEntity.ok(Map.of( "variableId", variableId, "secret", "***" // Don't expose actual secret in response )); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("error", "Failed to retrieve secret: " + e.getMessage())); } } @PostMapping("/{variableId}") public ResponseEntity<String> addSecret(@PathVariable String variableId, @RequestBody Map<String, String> request) { try { String secretValue = request.get("value"); conjurClient.addSecret(variableId, secretValue); return ResponseEntity.ok("Secret added successfully"); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to add secret: " + e.getMessage()); } } @GetMapping("/database/{prefix}") public ResponseEntity<DatabaseConfig> getDatabaseConfig(@PathVariable String prefix) { try { DatabaseConfig config = secretsService.getDatabaseConfig(prefix); return ResponseEntity.ok(config); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } @GetMapping("/api/{prefix}") public ResponseEntity<ApiConfig> getApiConfig(@PathVariable String prefix) { try { ApiConfig config = secretsService.getApiConfig(prefix); return ResponseEntity.ok(config); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } @GetMapping("/cache/stats") public ResponseEntity<CacheStats> getCacheStats() { try { CacheStats stats = secretsService.getCacheStats(); return ResponseEntity.ok(stats); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } @PostMapping("/cache/clear") public ResponseEntity<String> clearCache() { try { secretsService.clearCache(); return ResponseEntity.ok("Cache cleared successfully"); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to clear cache: " + e.getMessage()); } } @GetMapping("/health") public ResponseEntity<Map<String, String>> healthCheck() { try { boolean healthy = conjurClient.testConnection(); Map<String, String> response = new HashMap<>(); response.put("status", healthy ? "healthy" : "unhealthy"); response.put("timestamp", new Date().toString()); return ResponseEntity.ok(response); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("status", "error", "error", e.getMessage())); } } } /** * Kubernetes Integration for Conjur */ public static class KubernetesConjurIntegration { private final KubernetesClient k8sClient; public KubernetesConjurIntegration(KubernetesClient k8sClient) { this.k8sClient = k8sClient; } /** * Create Kubernetes secret from Conjur variables */ public void createK8sSecretFromConjur(String secretName, String namespace, Map<String, String> conjurVariables, ConjurClient conjurClient) { try { Map<String, String> secrets = conjurClient.getSecrets( new ArrayList<>(conjurVariables.keySet()) ); Map<String, String> data = new HashMap<>(); for (Map.Entry<String, String> entry : conjurVariables.entrySet()) { String conjurVar = entry.getKey(); String k8sKey = entry.getValue(); data.put(k8sKey, secrets.get(conjurVar)); } Secret secret = new SecretBuilder() .withNewMetadata() .withName(secretName) .withNamespace(namespace) .endMetadata() .withStringData(data) .build(); k8sClient.secrets().inNamespace(namespace).createOrReplace(secret); System.out.println("✅ Kubernetes secret created: " + secretName); } catch (Exception e) { System.err.println("❌ Failed to create Kubernetes secret: " + e.getMessage()); throw new RuntimeException("Kubernetes secret creation failed", e); } } /** * Create Conjur-authenticated deployment */ public void createConjurAuthenticatedDeployment(String name, String namespace, String conjurAccount, String conjurAuthnUrl) { try { Deployment deployment = new DeploymentBuilder() .withNewMetadata() .withName(name) .withNamespace(namespace) .endMetadata() .withNewSpec() .withReplicas(1) .withNewSelector() .addToMatchLabels("app", name) .endSelector() .withNewTemplate() .withNewMetadata() .withLabels(Map.of("app", name)) .endMetadata() .withNewSpec() .withContainers(createConjurContainer(name)) .withVolumes(createConjurVolumes()) .endSpec() .endTemplate() .endSpec() .build(); k8sClient.apps().deployments().inNamespace(namespace).createOrReplace(deployment); System.out.println("✅ Conjur-authenticated deployment created: " + name); } catch (Exception e) { System.err.println("❌ Failed to create deployment: " + e.getMessage()); throw new RuntimeException("Deployment creation failed", e); } } private List<Container> createConjurContainer(String name) { Container container = new ContainerBuilder() .withName(name) .withImage("my-app:latest") .withEnv(Arrays.asList( new EnvVarBuilder() .withName("CONJUR_APPLIANCE_URL") .withValueFrom(new EnvVarSourceBuilder() .withSecretKeyRef(new SecretKeySelectorBuilder() .withName("conjur-config") .withKey("appliance-url") .build()) .build()) .build(), new EnvVarBuilder() .withName("CONJUR_ACCOUNT") .withValueFrom(new EnvVarSourceBuilder() .withSecretKeyRef(new SecretKeySelectorBuilder() .withName("conjur-config") .withKey("account") .build()) .build()) .build(), new EnvVarBuilder() .withName("CONJUR_AUTHN_URL") .withValueFrom(new EnvVarSourceBuilder() .withSecretKeyRef(new SecretKeySelectorBuilder() .withName("conjur-config") .withKey("authn-url") .build()) .build()) .build() )) .withVolumeMounts(Arrays.asList( new VolumeMountBuilder() .withName("conjur-cert") .withMountPath("/etc/conjur") .withReadOnly(true) .build() )) .build(); return Arrays.asList(container); } private List<Volume> createConjurVolumes() { return Arrays.asList( new VolumeBuilder() .withName("conjur-cert") .withSecret(new SecretVolumeSourceBuilder() .withSecretName("conjur-certificate") .build()) .build() ); } } /** * Demo and Usage Examples */ public static void main(String[] args) { System.out.println("🔐 CyberArk Conjur Java Integration"); System.out.println("===================================\n"); try { // Demo 1: Configuration Management System.out.println("1. ⚙️ Configuration Management"); Path tempDir = Files.createTempDirectory("conjur-demo"); ConjurConfigManager configManager = new ConjurConfigManager( tempDir.resolve("conjur.properties")); configManager.createDevelopmentConfig(); System.out.println(" Configuration file created"); // Demo 2: Conjur Client System.out.println("\n2. 🔐 Conjur Client Operations"); ConjurConfigManager.ConjurConfiguration config = configManager.loadConfiguration(); ConjurClient conjurClient = new ConjurClient(config); System.out.println(" Conjur client initialized"); System.out.println(" Connection test: " + conjurClient.testConnection()); // Demo 3: Secrets Management System.out.println("\n3. 🗝️ Secrets Management"); SecretsManagementService secretsService = new SecretsManagementService(conjurClient); // Example secret operations (commented out as they require actual Conjur instance) /* String dbPassword = secretsService.getSecret("myapp/database/password"); DatabaseConfig dbConfig = secretsService.getDatabaseConfig("myapp/database"); ApiConfig apiConfig = secretsService.getApiConfig("myapp/external-api"); */ System.out.println(" Secrets management service initialized"); System.out.println(" Automatic cache refresh enabled"); // Demo 4: Cache Management System.out.println("\n4. 💾 Cache Management"); CacheStats stats = secretsService.getCacheStats(); System.out.println(" Cache size: " + stats.getCacheSize()); System.out.println(" Last refresh: " + new Date(stats.getLastRefresh())); // Demo 5: Kubernetes Integration System.out.println("\n5. ☸️ Kubernetes Integration"); try (KubernetesClient k8sClient = new KubernetesClientBuilder().build()) { KubernetesConjurIntegration k8sIntegration = new KubernetesConjurIntegration(k8sClient); System.out.println(" Kubernetes integration ready"); System.out.println(" Can create Conjur-authenticated deployments"); } // Cleanup secretsService.shutdown(); deleteDirectory(tempDir); System.out.println("\n✅ Conjur Java Integration Demo Completed"); System.out.println("\n📚 Key Features:"); System.out.println(" - Secure secrets retrieval and management"); System.out.println(" - Automatic secret caching with refresh"); System.out.println(" - Kubernetes integration for secret injection"); System.out.println(" - SSL/TLS configuration support"); System.out.println(" - Spring Boot auto-configuration"); System.out.println(" - Health checks and monitoring"); } catch (Exception e) { System.err.println("❌ Demo failed: " + e.getMessage()); e.printStackTrace(); } } private static void deleteDirectory(Path path) throws IOException { Files.walk(path) .sorted(Comparator.reverseOrder()) .map(Path::toFile) .forEach(File::delete); } } Maven Dependencies
<!-- pom.xml --> <dependencies> <!-- CyberArk Conjur SDK --> <dependency> <groupId>com.cyberark</groupId> <artifactId>conjur-api</artifactId> <version>2.0.0</version> </dependency> <!-- Kubernetes Client --> <dependency> <groupId>io.fabric8</groupId> <artifactId>kubernetes-client</artifactId> <version>6.8.0</version> </dependency> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>2.7.0</version> </dependency> <!-- HTTP Client --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.20</version> </dependency> </dependencies>
Configuration Examples
application.yml
conjur: appliance-url: https://conjur.example.com account: my-account username: admin@my-account api-key: ${CONJUR_API_KEY} cert-file: /etc/conjur/conjur.pem ssl-verification: true spring: datasource: url: jdbc:postgresql://localhost:5432/mydb username: ${db.username} password: ${db.password} management: endpoints: web: exposure: include: health,info,metrics conjur.properties
CONJUR_APPLIANCE_URL=https://conjur.example.com CONJUR_ACCOUNT=my-account CONJUR_AUTHN_LOGIN=admin@my-account CONJUR_AUTHN_API_KEY=your-api-key-here CONJUR_CERT_FILE=/etc/conjur/conjur.pem CONJUR_VERIFY_SSL=true
Kubernetes Manifest Example
apiVersion: v1 kind: Secret metadata: name: conjur-config namespace: default stringData: appliance-url: https://conjur.example.com account: my-account authn-url: https://conjur.example.com/authn --- apiVersion: apps/v1 kind: Deployment metadata: name: my-app namespace: default spec: replicas: 1 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-app image: my-app:latest env: - name: CONJUR_APPLIANCE_URL valueFrom: secretKeyRef: name: conjur-config key: appliance-url - name: CONJUR_ACCOUNT valueFrom: secretKeyRef: name: conjur-config key: account - name: CONJUR_AUTHN_URL valueFrom: secretKeyRef: name: conjur-config key: authn-url volumeMounts: - name: conjur-cert mountPath: /etc/conjur readOnly: true volumes: - name: conjur-cert secret: secretName: conjur-certificate
Usage Examples
// Initialize Conjur client ConjurConfigManager.ConjurConfiguration config = new ConjurConfigManager.ConjurConfiguration( "https://conjur.example.com", "my-account") .withUsername("admin@my-account") .withApiKey("your-api-key") .withCertFile("/etc/conjur/conjur.pem"); ConjurClient conjurClient = new ConjurClient(config); // Create secrets management service SecretsManagementService secretsService = new SecretsManagementService(conjurClient); // Retrieve secrets String dbPassword = secretsService.getSecret("myapp/database/password"); DatabaseConfig dbConfig = secretsService.getDatabaseConfig("myapp/database"); // Use in application DataSource dataSource = DataSourceBuilder.create() .url(dbConfig.getConnectionString()) .username(dbConfig.getUsername()) .password(dbConfig.getPassword()) .build(); This CyberArk Conjur integration provides:
- Complete Conjur Client implementation with proper authentication
- Secrets Management Service with caching and automatic refresh
- Configuration Management for different environments
- Kubernetes Integration for secret injection and deployments
- Spring Boot Auto-configuration for easy setup
- SSL/TLS Support with custom certificate handling
- Health Monitoring and connection testing
- Batch Operations for efficient secret retrieval
- Error Handling with retry mechanisms
- Security Best Practices for secrets management
The solution enables Java applications to securely manage secrets using CyberArk Conjur while providing enterprise-grade features for production environments.
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.