summaryrefslogtreecommitdiff
path: root/sys/jobs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/jobs')
-rw-r--r--sys/jobs/default.nix5
-rw-r--r--sys/jobs/pki-expiry/default.nix60
-rw-r--r--sys/jobs/pki-expiry/pki-expiry.sh108
3 files changed, 173 insertions, 0 deletions
diff --git a/sys/jobs/default.nix b/sys/jobs/default.nix
new file mode 100644
index 0000000..24d6c73
--- /dev/null
+++ b/sys/jobs/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./pki-expiry
+ ];
+}
diff --git a/sys/jobs/pki-expiry/default.nix b/sys/jobs/pki-expiry/default.nix
new file mode 100644
index 0000000..d0d551f
--- /dev/null
+++ b/sys/jobs/pki-expiry/default.nix
@@ -0,0 +1,60 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.jobs.pkiExpiry;
+ inherit (config.local) pki;
+in {
+ options.local.jobs.pkiExpiry = {
+ enable = mkEnableOption "PKI expiration reminder";
+ };
+
+ config = mkIf cfg.enable {
+ systemd = {
+ services.pki-expiry = {
+ after = ["postfix.service"];
+ path = ["/run/wrappers"];
+
+ environment.PKI_PUBLIC = let
+ mkdir = "mkdir -p $out/{ca,cert,crl}";
+
+ cas = mapAttrsToList (_: ca: "ln -s ${ca.cert} $out/ca/${ca.path}") pki.ca;
+ crls = mapAttrsToList (_: ca: "ln -s ${ca.crl} $out/crl/${ca.path}") pki.ca;
+
+ certs =
+ mapAttrsToList
+ (path: leaf: "ln -s ${leaf.cert} $out/cert/${path}")
+ (filterAttrs (_: object: ! object ? leaves) pki.byPath);
+
+ pkiPublic = pkgs.runCommandLocal "pki-public" {} (concatLines ([mkdir] ++ cas ++ crls ++ certs));
+ in "${pkiPublic}";
+
+ serviceConfig = {
+ Type = "oneshot";
+ StateDirectory = "pki-expiry";
+ WorkingDirectory = "/var/lib/pki-expiry";
+
+ ExecStart = let
+ script = pkgs.writeShellApplication {
+ name = "pki-expiry";
+ text = readFile ./pki-expiry.sh;
+ runtimeInputs = with pkgs; [diffutils openssl];
+ };
+ in "${getExe script}";
+ };
+ };
+
+ timers.pki-expiry = {
+ wantedBy = ["timers.target"];
+
+ timerConfig = {
+ OnStartupSec = "10m";
+ OnUnitInactiveSec = "3d";
+ };
+ };
+ };
+ };
+}
diff --git a/sys/jobs/pki-expiry/pki-expiry.sh b/sys/jobs/pki-expiry/pki-expiry.sh
new file mode 100644
index 0000000..0e95a26
--- /dev/null
+++ b/sys/jobs/pki-expiry/pki-expiry.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+#
+function will_expire() {
+ expiry_status=""
+ expiry_vars="$(openssl "$openssl_cmd" -in "$object_path" -noout "${openssl_var_opts[@]}")"
+
+ expiry_date="$(echo "$expiry_vars" | grep "^$openssl_expiry_var=" | sed 's/^.\+=//g')"
+ if [ -z "$expiry_date" ]; then
+ return 1
+ fi
+
+ expiry_secs="$(date +%s -d "$expiry_date")"
+ diff="$((expiry_secs - now))"
+
+ if [ "$diff" -gt "$1" ]; then
+ return 1
+ elif [ "$diff" -lt 0 ]; then
+ remaining=0
+ else
+ remaining="$((diff / 86400))"
+ fi
+
+ total_matches="$((total_matches + 1))"
+
+ if [ -z "$min_expiry" ]; then
+ min_expiry="$remaining"
+ elif [ "$remaining" -lt "$min_expiry" ]; then
+ min_expiry="$remaining"
+ fi
+}
+
+function has_expired() {
+ if ! will_expire 0; then
+ return 1
+ fi
+
+ expiry_status="has expired"
+}
+
+function will_expire_days() {
+ if ! will_expire "$(($1 * 86400))"; then
+ return 1
+ fi
+
+ expiry_status="will expire in $remaining days"
+}
+
+function check_object() {
+ object_id="$(basename "$1")"
+ object_path="$1"
+
+ if has_expired || will_expire_days 3 || will_expire_days 7 || will_expire_days 15 || will_expire_days 30; then
+ {
+ echo
+ echo "$object_repr '$object_id' $expiry_status"
+ echo "$expiry_vars"
+ } >>"$mail_out"
+ fi
+}
+
+function check_dir() {
+ object_repr="$2"
+
+ for path in "$PKI_PUBLIC/$1"/*; do
+ check_object "$path"
+ done
+}
+
+if [ -z "$PKI_PUBLIC" ]; then
+ echo "$0: \$PKI_PUBLIC not set"
+ exit 1
+elif [ ! -d "$PKI_PUBLIC" ]; then
+ echo "$0: invalid \$PKI_PUBLIC: $PKI_PUBLIC"
+ exit 1
+fi
+
+mail_out="$(mktemp)"
+trap 'rm -f -- "$mail_out"' EXIT
+
+now="$(date +%s)"
+min_expiry=""
+total_matches=0
+
+openssl_cmd=x509
+openssl_var_opts=(-startdate -enddate)
+openssl_expiry_var="notAfter"
+
+check_dir ca "CA"
+check_dir cert "Certificate"
+
+openssl_cmd=crl
+openssl_var_opts=(-lastupdate -nextupdate)
+openssl_expiry_var="nextUpdate"
+
+check_dir crl "CRL for CA"
+
+if [ -s "$mail_out" ] && ! cmp -s last-mail "$mail_out"; then
+ sendmail -t <<- EOF
+ From: PKI expiration reminder <pki-expiry>
+ To: sysadmin
+ Subject: $total_matches PKI objects will expire in $min_expiry days
+
+ The following PKI objects are due for renewal:
+ $(<"$mail_out")
+ EOF
+
+ mv -- "$mail_out" last-mail
+fi