-
-
Save tmplcl/d68dd0873d103151cfb8e378f1fc6ad0 to your computer and use it in GitHub Desktop.
certs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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