Skip to content

Instantly share code, notes, and snippets.

@tmplcl
Created December 11, 2021 14:01
Show Gist options
  • Save tmplcl/d68dd0873d103151cfb8e378f1fc6ad0 to your computer and use it in GitHub Desktop.
Save tmplcl/d68dd0873d103151cfb8e378f1fc6ad0 to your computer and use it in GitHub Desktop.
certs
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class CertificateCheckerApplication {
private static final Logger LOG = LoggerFactory.getLogger(CertificateCheckerApplication.class);
public static void main(String[] args) throws Exception {
List<CertificateChecks> configuration = parseConfiguration();
LOG.info("Read config: {}", configuration);
try (var client = CloudWatchClient.builder().region(Region.EU_CENTRAL_1).build()) {
configuration.parallelStream().forEach(check -> {
try {
checkCertAndWriteMetric(client, check.host, check.application, check.name);
} catch (IOException e) {
LOG.error("Error while reading certificate", e);
}
});
}
}
private static List<CertificateChecks> parseConfiguration() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
var node = objectMapper.readValue(new File("checks.yml"), ObjectNode.class);
var list = new ArrayList<CertificateChecks>();
node.fields().forEachRemaining(stringJsonNodeEntry -> {
var application = stringJsonNodeEntry.getKey();
stringJsonNodeEntry.getValue().forEach(jsonNode -> {
var host = jsonNode.get("host").asText();
var name = jsonNode.get("name").asText();
list.add(new CertificateChecks(application, host, name));
});
});
return list;
}
private static void checkCertAndWriteMetric(CloudWatchClient client, String hostname, String application, String name) throws IOException {
var certificateExpirationDate = getCertificateExpirationDate(hostname);
certificateExpirationDate.ifPresent(expiryDate -> {
long remainingDaysUntilExpiration = ChronoUnit.DAYS.between(LocalDate.now(), expiryDate);
LOG.info("Certificate for hostname {} will expire on {} with {} days remaining!", hostname, expiryDate, remainingDaysUntilExpiration);
writeMetric(client, hostname, application, name, (double) remainingDaysUntilExpiration);
});
}
private static void writeMetric(CloudWatchClient client, String hostname, String application, String name, double remainingDaysUntilExpiration) {
client.putMetricData(putMetricsDataRequest -> putMetricsDataRequest
.namespace("certificate-expiration")
.metricData(metricData -> metricData
.timestamp(Instant.now())
.metricName("expire in")
.dimensions(
dimension -> dimension
.name("hostname")
.value(hostname),
dimension -> dimension
.name("application")
.value(application),
dimension -> dimension
.name("name")
.value(name)
)
.value(remainingDaysUntilExpiration)
)
);
}
private static Optional<LocalDate> getCertificateExpirationDate(String hostname) throws IOException {
URL url = new URL("https://" + hostname);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.connect();
return Arrays.stream(conn.getServerCertificates())
.map(X509Certificate.class::cast)
.filter(x509Certificate -> x509Certificate.getSubjectX500Principal().getName().contains(hostname))
.findFirst()
.map(x509Certificate -> LocalDate.ofInstant(x509Certificate.getNotAfter().toInstant(), ZoneId.systemDefault()));
}
}
class CertificateChecks {
public String application;
public String host;
public String name;
public CertificateChecks(String application, String host, String name) {
this.application = application;
this.host = host;
this.name = name;
}
@Override
public String toString() {
return "CertificateChecks{" +
"application='" + application + '\'' +
", host='" + host + '\'' +
", name='" + name + '\'' +
'}';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment