diff options
author | Omar Polo <op@omarpolo.com> | 2021-10-11 14:42:11 +0000 |
---|---|---|
committer | Omar Polo <op@omarpolo.com> | 2021-10-11 14:42:11 +0000 |
commit | 536026c565c7108d1672f2a37c4eb813b756f952 (patch) | |
tree | b1917d2332c27655b50af717adf7b850c54ec5c9 /contrib | |
parent | f0a01fc742e83b3f4736b5d64af3ab18148afc5a (diff) |
add script to automatically renew self-signed certificates
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/README | 6 | ||||
-rwxr-xr-x | contrib/renew-certs | 200 |
2 files changed, 206 insertions, 0 deletions
diff --git a/contrib/README b/contrib/README index d4fa347..94aa4d7 100644 --- a/contrib/README +++ b/contrib/README @@ -17,6 +17,12 @@ gmid.service Simple systemd service file. +renew-certs + + Flexible script meant to be run in a cronjob to watch for cert + expiration. It can optionally regen the (self-signed) + certificate in place and restart the server too. + vim Syntax highlighting of gmid configuration for vim, to be diff --git a/contrib/renew-certs b/contrib/renew-certs new file mode 100755 index 0000000..9caf3a5 --- /dev/null +++ b/contrib/renew-certs @@ -0,0 +1,200 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2021 Omar Polo <op@omarpolo.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# You can read the documentation for this script using +# +# $ perldoc renew-certs +# + +use v5.10; +use strict; +use warnings; + +use Getopt::Std; +use Time::Piece; + +my $auto = 0; +my $conf = '/etc/gmid.conf'; +my $days = 365; +my $gmid = 'gmid'; +my $restart = 0; +my $threshold = 24 * 60 * 60; + +my %options = (); +getopts("ac:d:g:r", \%options); + +foreach my $flag (keys %options) { + if ($flag eq 'a') { + $auto = 1; + } elsif ($flag eq 'c') { + $conf = $options{c}; + } elsif ($flag eq 'd') { + $days = int($options{d}) or exit 1; + } elsif ($flag eq 'g') { + $gmid = $options{g}; + } elsif ($flag eq 'r') { + $auto = 1; + $restart = 1; + } elsif ($flag eq 't') { + $threshold = int($options{t}) or exit 1; + } +} + +my $now = localtime()->epoch + $threshold; +my $found_one = 0; + +my $c = `$gmid -nn -c $conf @ARGV 2>/dev/null`; +die "$gmid failed to parse $conf" if $? != 0; + +while ($c =~ /server \"(.*)\"/g) { + my $server = $1; + + $c =~ /cert \"(.*)\"/gc; + my $cert = $1; + + $c =~ /key \"(.*)\"/gc; + my $key = $1; + + if (expired($cert)) { + $found_one = 1; + if ($auto) { + renew($server, $cert, $key); + } else { + say $server; + } + } +} + +if ($found_one && $restart) { + my @cmd = ("pkill", "-HUP", $gmid); + system(@cmd); +} + +exit !$found_one; + +sub expired { + my ($cert) = @_; + + my $exp = `openssl x509 -noout -enddate -in $cert`; + die 'failed to execute openssl' if $? != 0; + chomp $exp; + + my $d = Time::Piece->strptime($exp, "notAfter=%b %e %T %Y %Z"); + return $d->epoch < $now; +} + +sub renew { + my ($hostname, $cert, $key) = @_; + my @cmd = ( + "openssl", "req", "-x509", + "-newkey", "rsa:4096", + "-out", $cert, + "-keyout", $key, + "-days", $days, + "-nodes", + "-subj", "/CN=".$hostname, + ); + + system(@cmd) == 0 + or die "system @cmd failed: $?"; +} + +__END__ + +=head1 NAME + +B<renew-certs> - automatically renew gmid certificates + +=head1 SYNOPSIS + +B<renew-certs> [-ar] [-c I<conf>] [-d I<days>] [-g I<gmid>] [-t I<threshold>] [-- I<gmid flags...>] + +=head1 DESCRIPTION + +B<renew-certs> attempts to renew the certificates used by gmid if they +are close to the expiration date and can optionally restart the +server. It's meant to be used in a crontab(5) file. + +B<renew-certs> needs at least B<gmid> 1.8. + +The arguments are as follows: + +=over + +=item -a + +Automatically generate a new set of certificates. + +=item -c I<conf> + +Path to the gmid configuration. By default is F</etc/gmid.conf>. + +=item -d I<days> + +Number of I<days> the newly generated certificates will be valid for; +365 by default. + +=item -g I<gmid> + +Path to the gmid(1) executable. + +=item -r + +Restart B<gmid> after re-generating the certificates by killing it +with SIGHUP. Implies -a. + +=item -t I<threshold> + +Tweak the expiring I<threshold>. Certificates whose I<notAfter> field +ends before I<threshold> seconds will be considered outdated. By +default is 86400, or 24 * 60 * 60, 24 hours. + +=item I<gmid flags> + +Additional flags to be passed to gmid(1). + +=back + +=head1 EXIT STATUS + +The B<renew-certs> utility exits on 0 when at least one certificate is +about to expire and >0 otherwise, or if an error occurs. + +=head1 EXAMPLES + +Some examples of how to use B<renew-certs> in a crontab(5) file +follows: + + # automatically renew and restart gmid + 0 0 * * * renew-certs -r + + # like the previous, but pass a custom flag to gmid + 0 0 * * * renew-certs -r -- -Dcerts=/etc/ssl/ + + # automatically renew the certs but use a custom + # command (rcctl in this case) to restart the server + 0 0 * * * renew-certs -a && rcctl restart gmid + + # only check for expiration. `cmd' can read the names of the + # servers with an expiring certificate from stdin, one per + # line + 0 0 * * * renew-certs | cmd + +=head1 SEE ALSO + +crontab(1) gmid(1) openssl(1) crontab(5) + +=cut |