mirror of
https://github.com/omar-polo/gmid.git
synced 2024-08-17 08:33:21 +02:00
201 lines
4.4 KiB
Plaintext
201 lines
4.4 KiB
Plaintext
|
#!/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
|