Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
awit-certmaster
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
allworldit
awit-certmaster
Commits
5a6e393d
Commit
5a6e393d
authored
Oct 31, 2016
by
Nigel Kukard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added --check-only, --force, --live and --only options
parent
cc285544
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
146 additions
and
38 deletions
+146
-38
awit-certmaster
awit-certmaster
+146
-38
No files found.
awit-certmaster
View file @
5a6e393d
...
...
@@ -26,6 +26,8 @@ package AWIT::CertMaster;
use
strict
;
use
warnings
;
use
List
::
MoreUtils
qw
(
any
);
our
$
VERSION
=
'1.00'
;
...
...
@@ -97,7 +99,7 @@ sub accountInit
}
# Check if the file exists, if it does, we need to create else login
my $keyFile =
"/etc/awit-certmaster/account.key"
;
my $keyFile =
sprintf("/etc/awit-certmaster/account.key%s",$self->{'file_suffix'})
;
if (-e $keyFile) {
my $keyPEM = "";
...
...
@@ -182,6 +184,7 @@ sub webserverCheckNginx
my
$
self
=
shift
;
#
Grab
the
current
datetime
my
$
now
=
DateTime
->
now
();
#
Open
the
main
nginx
sites
-
available
directory
and
take
a
peek
...
...
@@ -262,11 +265,33 @@ sub webserverCheckNginx
# Lets look for the certificate files...
(my $certBaseName = $vhostName) =~ s/\./-/g;
# Grab our filenames
$vhost->{'
cert_file
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
crt
',$certBaseName);
$vhost->{'
cert_cafile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
cacrt
',$certBaseName);
$vhost->{'
cert_bundlefile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
bundle
',$certBaseName);
$vhost->{'
cert_keyfile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
key
',$certBaseName);
$vhost->{'
cert_file
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
crt
%
s
',$certBaseName,$self->{'
file_suffix
'});
$vhost->{'
cert_cafile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
cacrt
%
s
',$certBaseName,$self->{'
file_suffix
'});
$vhost->{'
cert_bundlefile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
bundle
%
s
',$certBaseName,$self->{'
file_suffix
'});
$vhost->{'
cert_keyfile
'} = sprintf('
/
etc
/
ssl
/
private
/%
s
.
key
%
s
',$certBaseName,$self->{'
file_suffix
'});
# Check if we'
re
only
processing
a
certain
vhost
if
(
defined
(
my
$
onlyVhosts
=
$
self
->{
'only_vhosts'
}))
{
#
Check
if
this
is
the
host
we
're forcing
if (@{$onlyVhosts} > 0) {
# Check if its not in the list
if (! any {$_ eq $vhostName} @{$onlyVhosts}) {
$self->logger("INFO","WEBSERVER: - Skipping regeneration of certificate for '
%
s
', not in --only list",$vhostName);
goto SKIP;
}
}
}
# Check if we need to force certificate generation
if (defined(my $forceVhosts = $self->{'
force_vhosts
'})) {
# Check if this is the host we'
re
forcing
if
(
any
{$
_
eq
$
vhostName
}
@{$
forceVhosts
})
{
$
self
->
logger
(
"WARNING"
,
"WEBSERVER: - Forcing regeneration of certificate for '%s'"
,$
vhostName
);
next
;
}
}
#
Check
if
the
files
exist
if
(! -f $vhost->{'cert_file'} || ! -f $vhost->{'cert_cafile'} || ! -f $vhost->{'cert_bundlefile'} ||
...
...
@@ -295,19 +320,22 @@ sub webserverCheckNginx
}
# Loop with server names and check if the domain is in the certificate
my @missingDomains = ();
foreach my $domain (keys %{$vhost->{'server_names'}}) {
# Check if the domain is in the certificate
if (!defined($vhost->{'certificate_names'}->{$domain})) {
$self->logger("WARNING","WEBSERVER: - The vhost '%s' contains a domain '%s' not in the certificate, adding to regeneration list",$vhostName,$domain);
next
;
push(@missingDomains,$domain)
;
}
}
next if (@missingDomains);
# Output a notice if the cert will be re-applied for in the next 3 days
if ($daysToExpire < 34) {
$self->logger("NOTICE","WEBSERVER: - Certificate for vhost '%s' expires soon, it will be renewed in %s days",$vhostName,$daysToExpire);
}
SKIP:
# All is good, remove from the vhost from further processing
delete($vhostConfig->{$vhostName});
}
...
...
@@ -317,6 +345,25 @@ sub webserverCheckNginx
return $self;
}
# Check if we're going to check only...
if ($self->{'check_only'}) {
$self->logger("NOTICE","WEBSERVER: Check only...");
# Loop with vhosts
foreach my $vhostName (keys %{$vhostConfig}) {
my $vhost = $vhostConfig->{$vhostName};
$self->logger("NOTICE","WEBSERVER: - Vhost '%s' needs a certificate",$vhostName);
# Loop with domains in the vhost
foreach my $domain (keys %{$vhost->{'server_names'}}) {
$self->logger("NOTICE","WEBSERVER: - Domain '%s'",$domain);
}
}
return $self;
}
# If we still have entries, we need to start processing!
$self->accountInit();
...
...
@@ -336,7 +383,7 @@ sub webserverCheckNginx
# Write out files
umask(0122);
if (open(my $fh,'
>
',my $filename = $vhost->{'
cert_file
'}
.".new"
)) {
if (open(my $fh,'>',my $filename = $vhost->{'cert_file'})) {
print($fh $certs->{'certificate'});
close($fh);
$self->logger("INFO","WEBSERVER: - Certificate file '$filename'");
...
...
@@ -345,7 +392,7 @@ sub webserverCheckNginx
next
;
}
if (open(my $fh,'
>
',my $filename = $vhost->{'
cert_cafile
'}
.".new"
)) {
if
(
open
(
my
$
fh
,
'>'
,
my
$
filename
=
$
vhost
->{
'cert_cafile'
}))
{
print
($
fh
$
certs
->{
'chain'
});
close
($
fh
);
$
self
->
logger
(
"INFO"
,
"WEBSERVER: - Certificate CA file '$filename'"
);
...
...
@@ -354,7 +401,7 @@ sub webserverCheckNginx
next
;
}
if (open(my $fh,'
>
',my $filename = $vhost->{'
cert_bundlefile
'}
.".new"
)) {
if
(
open
(
my
$
fh
,
'>'
,
my
$
filename
=
$
vhost
->{
'cert_bundlefile'
}))
{
print
($
fh
$
certs
->{
'certificate'
});
print
($
fh
$
certs
->{
'chain'
});
close
($
fh
);
...
...
@@ -365,7 +412,7 @@ sub webserverCheckNginx
}
umask
(
0127
);
if (open(my $fh,'
>
',my $filename = $vhost->{'
cert_keyfile
'}
.".new"
)) {
if
(
open
(
my
$
fh
,
'>'
,
my
$
filename
=
$
vhost
->{
'cert_keyfile'
}))
{
print
($
fh
$
certs
->{
'key'
});
close
($
fh
);
$
self
->
logger
(
"INFO"
,
"WEBSERVER: - Certificate key file '$filename'"
);
...
...
@@ -376,13 +423,25 @@ sub webserverCheckNginx
}
#
Check
if
the
configtest
passes
system('
service
nginx
configtest
>
/
dev
/
null
2
>&
1
');
if ($? >> 8) {
$self->logger("ERROR","NGINX: Failed configtest, reload NOT done");
return $self;
}
if
($
self
->{
'live'
})
{
#
Check
if
Nginx
config
is
OK
system
(
'service nginx configtest > /dev/null 2>&1'
);
if
($?
>>
8
)
{
$
self
->
logger
(
"ERROR"
,
"NGINX: Failed configtest, reload NOT done"
);
return
$
self
;
}
$self->logger("INFO","NGINX: Successful configtest");
$
self
->
logger
(
"INFO"
,
"NGINX: Successful configtest"
);
#
Reload
Nginx
config
system
(
'service nginx reload > /dev/null 2>&1'
);
if
($?
>>
8
)
{
$
self
->
logger
(
"ERROR"
,
"NGINX: Failed reload"
);
return
$
self
;
}
$
self
->
logger
(
"INFO"
,
"NGINX: Successful reload"
);
}
return
$
self
;
}
...
...
@@ -411,10 +470,34 @@ sub logger
#
Internal
_init
function
sub
_init
{
my $self = shift;
my
($
self
,$
opts
)
=
@
_
;
#
If
we
're running in live mode, don'
t
use
a
suffix
if
(
defined
($
opts
->{
'live'
})
&&
$
opts
->{
'live'
})
{
$
self
->{
'file_suffix'
}
=
''
;
$
self
->{
'live'
}
=
1
;
}
else
{
$
self
->{
'file_suffix'
}
=
'.test'
;
$
self
->{
'live'
}
=
0
;
}
#
Check
if
we
're checking only...
if (defined($opts->{'
check_only
'}) && $opts->{'
check_only
'}) {
$self->{'
check_only
'} = 1;
} else {
$self->{'
check_only
'} = 0;
}
# Init properties
$self->{'
key
'} = undef;
# Keep track of what we'
re
processing
$
self
->{
'force_vhosts'
}
=
$
opts
->{
'force_vhosts'
}
//
[
];
$
self
->{
'only_vhosts'
}
=
$
opts
->{
'only_vhosts'
}
//
[
];
return
$
self
;
}
...
...
@@ -649,13 +732,20 @@ sub NID_SUBJECT_ALT_NAME { 85; }
# Class initialization
sub _init
{
my $self = shift;
my ($self,$opts,@args) = @_;
# Call parent _init(), VERY important!
$self->SUPER::_init($opts,@args);
$self->SUPER::_init();
# Set server to use
if ($self->{'live'}) {
$self->{'server'} = "https://acme-v01.api.letsencrypt.org/directory";
} else {
$self->{'server'} = "https://acme-staging.api.letsencrypt.org/directory";
}
# Initialize properties
$self->{'
server
'} = "https://acme-staging.api.letsencrypt.org/directory";
# We need to track the nonce we get from the remote server
$self->{'nonce'} = undef;
# Setup user agent
...
...
@@ -1144,13 +1234,30 @@ sub leHandleChallenge
$self->logger("INFO","LE: Creating challenge for domain '%s'",$domain);
# Create JWK
my $jwk = $self->_encode_json({
'kty' => "RSA",
'e' => $self->{'key'}->{'e'},
'n' => $self->{'key'}->{'n'},
});
# Create fingerprint
my $fingerprint = encode_base64url(sha256($jwk));
# Find the HTTP challenge
my $httpChallenge;
foreach my $challenge (@{$self->{'challenges'}->{$domain}}) {
$self->logger("INFO","LE: - Challeng for '%s' received, URI is '%s'",$challenge->{'type'},
$challenge->{'uri'});
# Create authorization key
my $keyAuthorization = sprintf('%s.%s',$challenge->{'token'},$fingerprint);
# Check if this is the challenge we're looking for
if ($challenge->{'type'} eq "http-01") {
$challenge->{'key_authorization'} = $keyAuthorization;
$httpChallenge = $challenge;
las
t;
nex
t;
}
}
...
...
@@ -1172,17 +1279,6 @@ sub leHandleChallenge
exit 1;
}
# Create JWK
my $jwk = $self->_encode_json({
'kty' => "RSA",
'e' => $self->{'key'}->{'e'},
'n' => $self->{'key'}->{'n'},
});
# Create fingerprint
my $fingerprint = encode_base64url(sha256($jwk));
my $keyAuthorization = sprintf('%s.%s',$httpChallenge->{'token'},$fingerprint);
#
...
...
@@ -1207,7 +1303,7 @@ sub leHandleChallenge
umask(0022);
if (open(my $FH,'>',$challengeFile)) {
# Write out contents
print($FH $
keyAuthorization
);
print($FH $
httpChallenge->{'key_authorization'}
);
close($FH);
# If the open failed, ERR out
} else {
...
...
@@ -1228,7 +1324,7 @@ sub leHandleChallenge
#
Build
the
verification
we
need
to
send
back
to
state
we
've complied
my $json = $self->_encode_json({
'
resource
' => "challenge",
'
keyAuthorization
' => $
keyAuthorization
,
'
keyAuthorization
' => $
httpChallenge->{'
key_authorization
'}
,
});
my $jws = $self->_leCreateJWS($json);
...
...
@@ -1414,7 +1510,7 @@ use Getopt::Long;
my $NAME = "
AWIT
-
CertMaster
";
our $VERSION = "
1.0.
0
";
our $VERSION = "
1.0.
1
";
...
...
@@ -1428,6 +1524,10 @@ GetOptions(\%optctl,
"
help
|?
",
"
version
",
"
check
-
only
",
"
force
=
s
@
",
"
live
",
"
only
=
s
@
",
) or exit 1;
# Check for help
...
...
@@ -1444,7 +1544,12 @@ if (defined($optctl{'version'})) {
my $cm = AWIT::CertMaster::LetsEncrypt->new();
my $cm = AWIT::CertMaster::LetsEncrypt->new({
'check_only' => $optctl{'check-only'},
'force_vhosts' => $optctl{'force'},
'live' => $optctl{'live'},
'only_vhosts' => $optctl{'only'},
});
$cm->webserverCheckNginx();
...
...
@@ -1474,7 +1579,10 @@ sub displayHelp
--version Display version.
Certificate Functions:
--xxxxx yyyyyyyyy something here.
--check-only Only check, don't do anything.
--force <VHOST> Force certificate generation.
--live Run live and manage production certs.
--only <VHOST> Only process this VHOST.
EOF
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment