List SSL Certificates validity period

I have a number of SSL certificates that I use internally. It is a good idea to keep an eye on their validity period to check they renew.

Using the website https://crt.sh you can do a search and get the details of the certificates as a JSON output.

I used Node Red as I could control how often the website was hit - The RESTful sensor seems to query quite often.

The only complexity is that you get all current certificates for each domain where you just really want the one that lasts the longest.

Need to work on the Card a bit :laughing:

image

[{"id":"2f0e5d5d.476152","type":"inject","z":"8ec6d5b3.077b58","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"45 23 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":80,"wires":[["55054042.03a8"]]},{"id":"55054042.03a8","type":"http request","z":"8ec6d5b3.077b58","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://crt.sh/?q=%25.mydomain.net&exclude=expired&output=json&deduplicate=Y","tls":"","persist":false,"proxy":"","authType":"","x":390,"y":80,"wires":[["5480311.7ca0fd"]]},{"id":"5480311.7ca0fd","type":"function","z":"8ec6d5b3.077b58","name":"","func":"var newMsg = {};\n\n// https://stackoverflow.com/questions/66898911/javascript-return-most-recent-element-for-each-name\n\nresult = Object.values(msg.payload.reduce((acc, curr) => {\n  const existingItem = acc[curr.name_value];\n\n  if((!existingItem) || (new Date(existingItem.not_after) < new Date(curr.not_after))) {\n    acc[curr.name_value] = curr;\n    acc[curr.name_value].not_after = curr.not_after + \"+00:00\";\n    acc[curr.name_value].days_left = Math.trunc(((new Date(curr.not_after)) - Date.now())/(1000*60*60*24));\n  }\n\n  return acc;\n}, {}));\n\n//node.warn(result);\n\nnewMsg.payload = result;\n\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":580,"y":80,"wires":[["18351eb3.a240a1"]]},{"id":"18351eb3.a240a1","type":"split","z":"8ec6d5b3.077b58","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":750,"y":80,"wires":[["9b03e8bd.b10df8"]]},{"id":"9b03e8bd.b10df8","type":"change","z":"8ec6d5b3.077b58","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"\"cert_expiry/\" & $replace(msg.payload.name_value, \".\",\"_\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":930,"y":80,"wires":[["6c1afb67.753c04"]]}]
1 Like

What about the certificate sensor?

This looks interesting as I need to manually install my ssl certificates. Can you share your sensor code?

It only works if the host is reachable and they are not all reachable from HA.

If for me, it is just an MQTT template sensor.

- platform: mqtt
  name: "cert_expiry_emoncms_borpin_net"
  state_topic: "cert_expiry/emoncms_borpin_net"
  unit_of_measurement: 'days'
  value_template: "{{ value_json.days_left }}"

I came up with with these sensors to let me know how many days left until my ssl certificate expires (every 90 days). This link https://crt.sh/ does not mentioned how to view in json file. However, the OP posted this sample json

[{"id":"2f0e5d5d.476152","type":"inject","z":"8ec6d5b3.077b58","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"45 23 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":80,"wires":[["55054042.03a8"]]},{"id":"55054042.03a8","type":"http request","z":"8ec6d5b3.077b58","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://crt.sh/?q=%25.mydomain.net&exclude=expired&output=json&deduplicate=Y","tls":"","persist":false,"proxy":"","authType":"","x":390,"y":80,"wires":[["5480311.7ca0fd"]]},{"id":"5480311.7ca0fd","type":"function","z":"8ec6d5b3.077b58","name":"","func":"var newMsg = {};\n\n// https://stackoverflow.com/questions/66898911/javascript-return-most-recent-element-for-each-name\n\nresult = Object.values(msg.payload.reduce((acc, curr) => {\n  const existingItem = acc[curr.name_value];\n\n  if((!existingItem) || (new Date(existingItem.not_after) < new Date(curr.not_after))) {\n    acc[curr.name_value] = curr;\n    acc[curr.name_value].not_after = curr.not_after + \"+00:00\";\n    acc[curr.name_value].days_left = Math.trunc(((new Date(curr.not_after)) - Date.now())/(1000*60*60*24));\n  }\n\n  return acc;\n}, {}));\n\n//node.warn(result);\n\nnewMsg.payload = result;\n\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":580,"y":80,"wires":[["18351eb3.a240a1"]]},{"id":"18351eb3.a240a1","type":"split","z":"8ec6d5b3.077b58","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":750,"y":80,"wires":[["9b03e8bd.b10df8"]]},{"id":"9b03e8bd.b10df8","type":"change","z":"8ec6d5b3.077b58","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"\"cert_expiry/\" & $replace(msg.payload.name_value, \".\",\"_\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":930,"y":80,"wires":[["6c1afb67.753c04"]]}]

and I was able to extract what I needed and proceed from there.

https://crt.sh/?q=%25.mydomain.net&exclude=expired&output=json&deduplicate=Y

I’ve created 2 sensors. One to get the date of ssl certificate issued and the second counts down the days to 0 from 90 days.

sensor.yaml (change mydomain.net to your actual domain)

  - platform: rest
    name: SSL Cert Issued
    resource: https://crt.sh/?q=mydomain.net&exclude=expired&output=json&deduplicate=Y
    scan_interval: 14400
    value_template: '{{ value_json[0].not_before }}'

  - platform: template
    sensors:
      ssl_cert_expiry:
        value_template: '{{ 90 - (( as_timestamp(now()) - as_timestamp(strptime(states.sensor.ssl_cert_issued.state, "%Y-%m-%d")) )/ (3600*24)) | round(0) }}'
        unit_of_measurement: Days

From here, you just need to create an automation to remind you to renewal the certificate once sensor.ssl_cert_expiry counts down close to 0 Days.

automation.yaml

  - alias: "SSL Certificate Expiry Notification"
    initial_state: true
    trigger:
      - platform: numeric_state
        entity_id: sensor.ssl_cert_expiry
        below: 3
    action:
      - service: notify.home_assistant
        data_template:
          title: "SSL Certificate Expire Notification"
          message: >
                    <b>Today is {{ now().strftime( '%B %d, %Y') }} </b> <br>
                    <br>
                    Domain my.domain.net ssl certificate expires in {{ states.sensor.ssl_cert_expiry.state }} days. <br>
                    <br>
          data:
            images: []
2 Likes

Does this still work?

I’ve believe so. Though I have since self host my websites and no longer use the sensors.

My original, yes.