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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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);