Mercurial > prosody-modules
annotate mod_checkcerts/mod_checkcerts.lua @ 5668:ecfd7aece33b
mod_measure_modules: Report module statuses via OpenMetrics
Someone in the chat asked about a health check endpoint, which reminded
me of mod_http_status, which provides access to module statuses with
full details. After that, this idea came about, which seems natural.
As noted in the README, it could be used to monitor that critical
modules are in fact loaded correctly.
As more modules use the status API, the more useful this module and
mod_http_status becomes.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 06 Oct 2023 18:34:39 +0200 |
parents | c8ccaac78f64 |
children |
rev | line source |
---|---|
2945
ec7f9c8f2a5f
mod_checkcerts: Fixed luacheck warnings
Michel Le Bihan <michel@lebihan.pl>
parents:
1880
diff
changeset
|
1 local config = require "core.configmanager"; |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
2 local ssl = require"ssl"; |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
3 local datetime_parse = require"util.datetime".parse; |
1672
d9fcf9d8e787
mod_checkcerts: Fix for removal of globals in LuaSec
Kim Alvefur <zash@zash.se>
parents:
1098
diff
changeset
|
4 local load_cert = ssl.loadcertificate; |
941
a6c2345bcf87
mod_checkcerts: Nag admins about certs that have, or are about to expire. Often.
Kim Alvefur <zash@zash.se>
parents:
855
diff
changeset
|
5 local st = require"util.stanza" |
855
1983d4d51e1a
mod_checkcerts: Improve, add comments, add forward compatibility.
Kim Alvefur <zash@zash.se>
parents:
667
diff
changeset
|
6 |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
7 -- These are in days. |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
8 local nag_time = module:get_option_number("checkcerts_notify", 7) * 86400; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
9 |
855
1983d4d51e1a
mod_checkcerts: Improve, add comments, add forward compatibility.
Kim Alvefur <zash@zash.se>
parents:
667
diff
changeset
|
10 if not load_cert then |
1983d4d51e1a
mod_checkcerts: Improve, add comments, add forward compatibility.
Kim Alvefur <zash@zash.se>
parents:
667
diff
changeset
|
11 module:log("error", "This version of LuaSec (%s) does not support certificate checking", ssl._VERSION); |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
12 return |
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
13 end |
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
14 |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
15 local pat = "^([JFMAONSD][ceupao][glptbvyncr]) ?(%d%d?) (%d%d):(%d%d):(%d%d) (%d%d%d%d) GMT$"; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
16 local months = {Jan=1,Feb=2,Mar=3,Apr=4,May=5,Jun=6,Jul=7,Aug=8,Sep=9,Oct=10,Nov=11,Dec=12}; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
17 local function parse_x509_datetime(s) |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
18 local month, day, hour, min, sec, year = s:match(pat); month = months[month]; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
19 return datetime_parse(("%04d-%02d-%02dT%02d:%02d:%02dZ"):format(year, month, day, hour, min, sec)); |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
20 end |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
21 |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
22 local timeunits = {"minute",60,"hour",3600,"day",86400,"week",604800,"month",2629746,"year",31556952,}; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
23 local function humantime(timediff) |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
24 local ret = {}; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
25 for i=#timeunits,2,-2 do |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
26 if timeunits[i] < timediff then |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
27 local n = math.floor(timediff / timeunits[i]); |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
28 if n > 0 and #ret < 2 then |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
29 ret[#ret+1] = ("%d %s%s"):format(n, timeunits[i-1], n ~= 1 and "s" or ""); |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
30 timediff = timediff - n*timeunits[i]; |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
31 end |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
32 end |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
33 end |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
34 return table.concat(ret, " and ") |
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
35 end |
941
a6c2345bcf87
mod_checkcerts: Nag admins about certs that have, or are about to expire. Often.
Kim Alvefur <zash@zash.se>
parents:
855
diff
changeset
|
36 |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
37 local function check_certs_validity() |
941
a6c2345bcf87
mod_checkcerts: Nag admins about certs that have, or are about to expire. Often.
Kim Alvefur <zash@zash.se>
parents:
855
diff
changeset
|
38 local now = os.time(); |
a6c2345bcf87
mod_checkcerts: Nag admins about certs that have, or are about to expire. Often.
Kim Alvefur <zash@zash.se>
parents:
855
diff
changeset
|
39 |
855
1983d4d51e1a
mod_checkcerts: Improve, add comments, add forward compatibility.
Kim Alvefur <zash@zash.se>
parents:
667
diff
changeset
|
40 -- First, let's find out what certificate this host uses. |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
41 local ssl_config = config.rawget(module.host, "ssl"); |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
42 if not ssl_config or not ssl_config.certificate then |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
43 ssl_config = config.get(module.host:match("%.(.*)"), "ssl"); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
44 end |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
45 if not ssl_config or not ssl_config.certificate then |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
46 ssl_config = config.get("*", "ssl"); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
47 end |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
48 if not ssl_config or not ssl_config.certificate then |
2945
ec7f9c8f2a5f
mod_checkcerts: Fixed luacheck warnings
Michel Le Bihan <michel@lebihan.pl>
parents:
1880
diff
changeset
|
49 module:log("warn", "Could not find a certificate to check"); |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
50 return; |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
51 end |
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
52 |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
53 local certfile = ssl_config.certificate; |
1880
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
54 local fh, ferr = io.open(certfile); -- Load the file. |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
55 if not fh then |
2945
ec7f9c8f2a5f
mod_checkcerts: Fixed luacheck warnings
Michel Le Bihan <michel@lebihan.pl>
parents:
1880
diff
changeset
|
56 module:log("warn", "Could not open certificate %s", ferr); |
1880
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
57 return; |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
58 end |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
59 local cert, lerr = load_cert(fh:read("*a")); -- And parse |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
60 fh:close(); |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
61 if not cert then |
2945
ec7f9c8f2a5f
mod_checkcerts: Fixed luacheck warnings
Michel Le Bihan <michel@lebihan.pl>
parents:
1880
diff
changeset
|
62 module:log("warn", "Could not parse certificate %s: %s", certfile, lerr or ""); |
1880
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
63 return; |
a7c1f1b6ef05
mod_checkcerts: Improve error handling when loading certificate
Kim Alvefur <zash@zash.se>
parents:
1879
diff
changeset
|
64 end |
855
1983d4d51e1a
mod_checkcerts: Improve, add comments, add forward compatibility.
Kim Alvefur <zash@zash.se>
parents:
667
diff
changeset
|
65 |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
66 local expires_at = parse_x509_datetime(cert:notafter()); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
67 local expires_in = os.difftime(expires_at, now); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
68 local fmt = "Certificate %s expires in %s" |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
69 local nag_admin = expires_in < nag_time; |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
70 local log_warn = expires_in < nag_time * 2; |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
71 local timediff = expires_in; |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
72 if expires_in < 0 then |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
73 fmt = "Certificate %s expired %s ago"; |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
74 timediff = -timediff; |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
75 end |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
76 timediff = humantime(timediff); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
77 module:log(log_warn and "warn" or "info", fmt, certfile, timediff); |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
78 if nag_admin then |
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
79 local body = fmt:format("for host ".. module.host, timediff); |
4607
c8ccaac78f64
mod_checkcerts: Notify both host-local and global admins
Kim Alvefur <zash@zash.se>
parents:
2945
diff
changeset
|
80 for admin in module:get_option_inherited_set("admins", {}) do |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
81 module:send(st.message({ from = module.host, to = admin, type = "chat" }, body)); |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
82 end |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
83 end |
1879
18123e0f5d58
mod_checkcerts: Improve logic for finding an ssl section with a certificate
Kim Alvefur <zash@zash.se>
parents:
1672
diff
changeset
|
84 return math.max(86400, expires_in / 3); |
667
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
85 end |
ea9941812721
mod_checkcerts: New module that logs a warning when your cert is about to expire.
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
86 |
1098
cbbeac61f1ab
mod_checkcerts: Add timestamp parsing, format time until expiry more human-readable, adjust check intervals to time left.
Kim Alvefur <zash@zash.se>
parents:
943
diff
changeset
|
87 module:add_timer(1, check_certs_validity); |