3 # Copyright (c) 2021 Omar Polo <op@omarpolo.com>
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 # You can read the documentation for this script using
19 # $ perldoc renew-certs
30 my $conf = '/etc/gmid.conf';
34 my $threshold = 24 * 60 * 60;
37 getopts("ac:d:g:r", \%options);
39 foreach my $flag (keys %options) {
42 } elsif ($flag eq 'c') {
44 } elsif ($flag eq 'd') {
45 $days = int($options{d}) or exit 1;
46 } elsif ($flag eq 'g') {
48 } elsif ($flag eq 'r') {
51 } elsif ($flag eq 't') {
52 $threshold = int($options{t}) or exit 1;
56 my $now = localtime()->epoch + $threshold;
59 my $c = `$gmid -nn -c $conf @ARGV 2>/dev/null`;
60 die "$gmid failed to parse $conf" if $? != 0;
62 while ($c =~ /server \"(.*)\"/g) {
65 $c =~ /cert \"(.*)\"/gc;
68 $c =~ /key \"(.*)\"/gc;
74 renew($server, $cert, $key);
81 if ($found_one && $restart) {
82 my @cmd = ("pkill", "-HUP", $gmid);
91 my $exp = `openssl x509 -noout -enddate -in $cert`;
92 die 'failed to execute openssl' if $? != 0;
95 my $d = Time::Piece->strptime($exp, "notAfter=%b %e %T %Y %Z");
96 return $d->epoch < $now;
100 my ($hostname, $cert, $key) = @_;
102 "openssl", "req", "-x509",
103 "-newkey", "rsa:4096",
108 "-subj", "/CN=".$hostname,
112 or die "system @cmd failed: $?";
119 B<renew-certs> - automatically renew gmid certificates
123 B<renew-certs> [-ar] [-c I<conf>] [-d I<days>] [-g I<gmid>] [-t I<threshold>] [-- I<gmid flags...>]
127 B<renew-certs> attempts to renew the certificates used by gmid if they
128 are close to the expiration date and can optionally restart the
129 server. It's meant to be used in a crontab(5) file.
131 B<renew-certs> needs at least B<gmid> 1.8.
133 The arguments are as follows:
139 Automatically generate a new set of certificates.
143 Path to the gmid configuration. By default is F</etc/gmid.conf>.
147 Number of I<days> the newly generated certificates will be valid for;
152 Path to the gmid(1) executable.
156 Restart B<gmid> after re-generating the certificates by killing it
157 with SIGHUP. Implies -a.
159 =item -t I<threshold>
161 Tweak the expiring I<threshold>. Certificates whose I<notAfter> field
162 ends before I<threshold> seconds will be considered outdated. By
163 default is 86400, or 24 * 60 * 60, 24 hours.
167 Additional flags to be passed to gmid(1).
173 The B<renew-certs> utility exits on 0 when at least one certificate is
174 about to expire and >0 otherwise, or if an error occurs.
178 Some examples of how to use B<renew-certs> in a crontab(5) file
181 # automatically renew and restart gmid
182 0 0 * * * renew-certs -r
184 # like the previous, but pass a custom flag to gmid
185 0 0 * * * renew-certs -r -- -Dcerts=/etc/ssl/
187 # automatically renew the certs but use a custom
188 # command (rcctl in this case) to restart the server
189 0 0 * * * renew-certs -a && rcctl restart gmid
191 # only check for expiration. `cmd' can read the names of the
192 # servers with an expiring certificate from stdin, one per
194 0 0 * * * renew-certs | cmd
198 crontab(1) gmid(1) openssl(1) crontab(5)