Skip to content

Commit

Permalink
Expose guage metric for SSL cert timetamps
Browse files Browse the repository at this point in the history
Signed-off-by: “Nithin <[email protected]>
  • Loading branch information
“Nithin committed Mar 13, 2024
1 parent fb95900 commit ffc3866
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package hlf.java.rest.client.config;

import hlf.java.rest.client.util.FabricClientConstants;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -65,7 +67,7 @@ public DefaultKafkaConsumerFactory<String, String> consumerFactory(
// Adding SSL configuration if Kafka Cluster is SSL secured
if (kafkaConsumerProperties.isSslAuthRequired()) {

SSLAuthFilesCreationHelper.createSSLAuthFiles(kafkaConsumerProperties);
SSLAuthFilesHelper.createSSLAuthFiles(kafkaConsumerProperties);

props.put(
CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,
Expand All @@ -83,6 +85,33 @@ public DefaultKafkaConsumerFactory<String, String> consumerFactory(
SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG,
kafkaConsumerProperties.getSslTruststorePassword());
props.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, kafkaConsumerProperties.getSslKeyPassword());

try {
Timestamp keyStoreCertExpiryTimestamp =
SSLAuthFilesHelper.getExpiryTimestampForKeyStore(
kafkaConsumerProperties.getSslKeystoreLocation(),
kafkaConsumerProperties.getSslKeystorePassword());
Timestamp trustStoreCertExpiryTimestamp =
SSLAuthFilesHelper.getExpiryTimestampForKeyStore(
kafkaConsumerProperties.getSslTruststoreLocation(),
kafkaConsumerProperties.getSslTruststorePassword());

Gauge.builder(
"consumer." + kafkaConsumerProperties.getTopic() + ".keystore.expiryTs",
keyStoreCertExpiryTimestamp::getTime)
.strongReference(true)
.register(meterRegistry);

Gauge.builder(
"consumer." + kafkaConsumerProperties.getTopic() + ".truststore.expiryTs",
trustStoreCertExpiryTimestamp::getTime)
.strongReference(true)
.register(meterRegistry);

} catch (Exception e) {
log.error(
"Failed to extract expiry details of Consumer SSL Certs. Metrics for Consumer SSL cert-expiry will not be available.");
}
}

log.info("Generating Kafka consumer factory..");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package hlf.java.rest.client.config;

import hlf.java.rest.client.util.FabricClientConstants;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -57,7 +59,7 @@ public ProducerFactory<String, String> eventProducerFactory(
// Adding SSL configuration if Kafka Cluster is SSL secured
if (kafkaProducerProperties.isSslAuthRequired()) {

SSLAuthFilesCreationHelper.createSSLAuthFiles(kafkaProducerProperties);
SSLAuthFilesHelper.createSSLAuthFiles(kafkaProducerProperties);

props.put(
CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,
Expand All @@ -75,6 +77,33 @@ public ProducerFactory<String, String> eventProducerFactory(
SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG,
kafkaProducerProperties.getSslTruststorePassword());
props.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, kafkaProducerProperties.getSslKeyPassword());

try {
Timestamp keyStoreCertExpiryTimestamp =
SSLAuthFilesHelper.getExpiryTimestampForKeyStore(
kafkaProducerProperties.getSslKeystoreLocation(),
kafkaProducerProperties.getSslKeystorePassword());
Timestamp trustStoreCertExpiryTimestamp =
SSLAuthFilesHelper.getExpiryTimestampForKeyStore(
kafkaProducerProperties.getSslTruststoreLocation(),
kafkaProducerProperties.getSslTruststorePassword());

Gauge.builder(
"producer." + kafkaProducerProperties.getTopic() + ".keystore.expiryTs",
keyStoreCertExpiryTimestamp::getTime)
.strongReference(true)
.register(meterRegistry);

Gauge.builder(
"producer." + kafkaProducerProperties.getTopic() + ".truststore.expiryTs",
trustStoreCertExpiryTimestamp::getTime)
.strongReference(true)
.register(meterRegistry);

} catch (Exception e) {
log.error(
"Failed to extract expiry details of Producer SSL Certs. Metrics for Producer SSL cert-expiry will not be available.");
}
}

log.info("Generating Kafka producer factory..");
Expand Down

This file was deleted.

82 changes: 82 additions & 0 deletions src/main/java/hlf/java/rest/client/config/SSLAuthFilesHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package hlf.java.rest.client.config;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.Timestamp;
import java.util.Base64;
import java.util.Enumeration;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@UtilityClass
public class SSLAuthFilesHelper {

void createSSLAuthFiles(KafkaProperties.SSLProperties kafkaSSLProperties) {

log.info("Creating Kafka ssl keystore file");
createSSLFileFromBase64(
kafkaSSLProperties.getSslKeystoreBase64(), kafkaSSLProperties.getSslKeystoreLocation());

log.info("Keystore file created at {}", kafkaSSLProperties.getSslKeystoreLocation());

log.info("Creating Kafka ssl truststore file");
createSSLFileFromBase64(
kafkaSSLProperties.getSslTruststoreBase64(), kafkaSSLProperties.getSslTruststoreLocation());

log.info("TrustStore file created at {}", kafkaSSLProperties.getSslTruststoreLocation());
}

private static void createSSLFileFromBase64(
String sslKeystoreBase64, String sslKeystoreLocation) {
log.info("Creating file at: {}", sslKeystoreLocation);
try {
final Path path = Paths.get(sslKeystoreLocation);
final Path parentPath = path.getParent();
if (!Files.isDirectory(parentPath)) {
log.info("Creating directory: {}", parentPath);
Files.createDirectory(parentPath);
}
Files.write(path, Base64.getDecoder().decode(sslKeystoreBase64));
} catch (IOException e) {
log.error("Failed to create the ssl auth file at location: {}", sslKeystoreLocation, e);
}
}

Timestamp getExpiryTimestampForKeyStore(String keyStorePath, String keyStorePassword)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {

KeyStore keyStore = loadKeyStore(keyStorePath, keyStorePassword);

Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
X509Certificate x509Cert = (X509Certificate) cert;
return new Timestamp(x509Cert.getNotAfter().getTime());
}
}

throw new CertificateException(
"Couldn't extract an instance of X509Certificate for fetching expiry details");
}

private static KeyStore loadKeyStore(String path, String password)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream fis = new FileInputStream(path)) {
keyStore.load(fis, password.toCharArray());
}
return keyStore;
}
}

0 comments on commit ffc3866

Please sign in to comment.