{"id":9778,"date":"2023-01-27T15:32:00","date_gmt":"2023-01-27T20:32:00","guid":{"rendered":"https:\/\/www.rushworth.us\/lisa\/?p=9778"},"modified":"2023-01-27T15:54:35","modified_gmt":"2023-01-27T20:54:35","slug":"python-script-checking-certificate-expiry-dates","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=9778","title":{"rendered":"Python Script: Checking Certificate Expiry Dates"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A long time ago, before the company I work for paid for an external SSL certificate management platform that does nice things like clue you into the fact your cert is expiring tomorrow night, we had an outage due to an expired certificate. One. I put together a perl script that parsed output from the openssl client and proactively alerted us of any pending expiration events. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That script went away quite some time ago &#8212; although I still have a copy running at home that ensures our SMTP and web server certs are current. This morning, though, our K8s environment fell over due to expired certificates. Digging into it, the certs <em>are<\/em> in the management platform (my first guess was self-signed certificates that <em>wouldn&#8217;t<\/em> have been included in the pending expiry notices) but were not delivered to those of us who actually manage the servers. Luckily it was our <em>dev<\/em> k8s environment and we now know the prod one will be expiring in a week or so. But I figured it was a good impetus to resurrect the old script. Unfortunately, none of the modules I used for date calculation were installed on our script server. Seemed like a hint that I should rewrite the script in Python. So &#8230; here is a quick Python script that gets certificates from hosts and calculates how long until the certificate expires. Add on a &#8220;if&#8221; statement and a notification function, and we shouldn&#8217;t come in to failed environments needing certificate renewals. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom cryptography import x509\nfrom cryptography.hazmat.backends import default_backend\nimport socket\nimport ssl\nfrom datetime import datetime, timedelta\n\n# Dictionary of hosts:port combinations to check for expiry\ndictHostsToCheck = {\n&quot;tableau.example.com&quot;: 443       # Tableau \n,&quot;kibana.example.com&quot;: 5601      # ELK Kibana\n,&quot;elkmaster.example.com&quot;: 9200   # ELK Master\n,&quot;kafka.example.com&quot;: 9093       # Kafka server\n}\nfor strHostName in dictHostsToCheck:\n    iPort = dictHostsToCheck&#x5B;strHostName]\n\n    datetimeNow = datetime.utcnow()\n\n    # create default context\n    context = ssl.create_default_context()\n\n    # Do not verify cert chain or hostname so we ensure we always check the certificate\n    context.check_hostname = False\n    context.verify_mode = ssl.CERT_NONE\n\n    with socket.create_connection((strHostName, iPort)) as sock:\n        with context.wrap_socket(sock, server_hostname=strHostName) as ssock:\n            objDERCert = ssock.getpeercert(True)\n            objPEMCert = ssl.DER_cert_to_PEM_cert(objDERCert)\n            objCertificate = x509.load_pem_x509_certificate(str.encode(objPEMCert),backend=default_backend())\n\n            print(f&quot;{strHostName}\\t{iPort}\\t{objCertificate.not_valid_after}\\t{(objCertificate.not_valid_after - datetimeNow).days} days&quot;)\n\n\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>A long time ago, before the company I work for paid for an external SSL certificate management platform that does nice things like clue you into the fact your cert is expiring tomorrow night, we had an outage due to an expired certificate. One. I put together a perl script that parsed output from the &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30],"tags":[304,1803,664,1801,1804,1802],"class_list":["post-9778","post","type-post","status-publish","format-standard","hentry","category-system-administration","tag-automation","tag-cert-expiry","tag-python","tag-scripts","tag-ssl-certificate-expiration","tag-ssl-expiry"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/9778","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9778"}],"version-history":[{"count":1,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/9778\/revisions"}],"predecessor-version":[{"id":9779,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/9778\/revisions\/9779"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}