diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-10-18 17:08:24 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-10-18 17:08:24 +0300 |
commit | f44aeac44eecf6dd6075e20080c0bb0b7822f30f (patch) | |
tree | bb3d249570d2865970383b9d063f7e2eab7668db | |
parent | 7e22b3181f963e62a44620336bdcd7d40baacb3a (diff) | |
download | acmeman-f44aeac44eecf6dd6075e20080c0bb0b7822f30f.tar.gz acmeman-f44aeac44eecf6dd6075e20080c0bb0b7822f30f.tar.bz2 |
Clean up account credential handling.
Credentials are saved in files specified by configuration directives
account.id and account.key. The directive account.directory specifies
the directory for these files.
-rwxr-xr-x | acmeman | 30 | ||||
-rw-r--r-- | lib/App/Acmeman.pm | 74 | ||||
-rw-r--r-- | lib/App/Acmeman/Config.pm | 13 |
3 files changed, 86 insertions, 31 deletions
@@ -448,6 +448,36 @@ hostname. =back +=head2 B<[account]> + +Configures where to store ACME account credentials: account key ID and +account private key. Both values are stored in separate files on disk. +If the files do not exist B<acmeman> will initiate creation of a new +account and will save its credentials for further use. + +=over 4 + +=item B<directory=>I<DIR> + +Directory where to store credential files. Defaults to +F</etc/ssl/acme>. + +=item B<id=>I<FILE> + +Name of the file with account key ID. Unless I<FILE> begins with a +directory separator, it is taken relative to B<account.directory>. + +Default: F</etc/ssl/acme/key.id>. + +=item B<key=>I<FILE> + +Name of the file with account key. Unless I<FILE> begins with a +directory separator, it is taken relative to B<account.directory>. + +Default: F</etc/ssl/acme/key.pem>. + +=back + =head2 B<[domain I<CN>]> Declares the domain for which a certificate should be maintained. I<CN> is diff --git a/lib/App/Acmeman.pm b/lib/App/Acmeman.pm index b95f87f..285342c 100644 --- a/lib/App/Acmeman.pm +++ b/lib/App/Acmeman.pm @@ -24,7 +24,7 @@ use Text::ParseWords; use App::Acmeman::Log qw(:all :sysexits); use feature 'state'; -our $VERSION = '2.90'; +our $VERSION = '2.02'; my $progdescr = "manages ACME certificates"; @@ -411,42 +411,60 @@ sub save_challenge { } } -sub acme { +sub account_key { my $self = shift; - my $key_id; - my $account_key; - my $idfile = File::Spec->catfile($self->cf->get('core','rootdir'), - 'account.key_id'); - my $keyfile = File::Spec->catfile($self->cf->get('core','rootdir'), - 'account.pem'); - if (-r $idfile) { - if (open(my $fh, '<', $idfile)) { - chomp($key_id = <$fh>); + unless ($self->{_account_key}) { + my $keyfile = $self->cf->get('account', 'key'); + if (-r $keyfile) { + if (open(my $fh, '<', $keyfile)) { + local $/ = undef; + $self->{_account_key} = Crypt::OpenSSL::RSA->new_private_key(<$fh>); close $fh; - debug(3, "using key_id $key_id"); } else { - error("can't open $idfile for reading: $!"); + error("can't open $keyfile for reading: $!"); + } + } else { + $self->{_account_key} = Crypt::OpenSSL::RSA->generate_key($self->cf->get('core', 'key-size')); + } } + return $self->{_account_key}; } - if (-r $keyfile) { - if (open(my $fh, '<', $keyfile)) { - local $/ = undef; - $account_key = Crypt::OpenSSL::RSA->new_private_key(<$fh>); +sub account_key_id { + my $self = shift; + + my $idfile = $self->cf->get('account', 'id'); + if (my $val = shift) { + $self->{_account_key_id} = $val; + $self->prep_dir($idfile); + if (open(my $fh, '>', $idfile)) { + print $fh $val; close $fh; } else { - error("can't open $keyfile for reading: $!"); + error("can't open $idfile for writing: $!"); } + } elsif (!$self->{_account_key_id}) { + if (-r $idfile) { + if (open(my $fh, '<', $idfile)) { + chomp($self->{_account_key_id} = <$fh>); + close $fh; + debug(3, "using key_id $self->{_account_key_id}"); } else { - $account_key = Crypt::OpenSSL::RSA->generate_key($self->cf->get('core', 'key-size')); + error("can't open $idfile for reading: $!"); + } + } + } + return $self->{_account_key_id}; } +sub acme { + my $self = shift; unless ($self->{_acme}) { my $acme = Net::ACME2::LetsEncrypt->new( environment => $self->acme_host, - key => $account_key->get_private_key_string(), - key_id => $key_id + key => $self->account_key->get_private_key_string(), + key_id => $self->account_key_id ); $self->{_acme} = $acme; @@ -456,19 +474,13 @@ sub acme { my $terms_url = $acme->get_terms_of_service(); $acme->create_account(termsOfServiceAgreed => 1); debug(3, "saving account credentials"); - - if (open(my $fh, '>', $idfile)) { - print $fh $acme->key_id(); - close $fh; - } else { - error("can't open $idfile for writing: $!"); - } - + $self->account_key_id($acme->key_id()); + my $keyfile = $self->cf->get('account', 'key'); if (open(my $fh, '>', $keyfile)) { - print $fh $account_key->get_private_key_string(); + print $fh $self->account_key->get_private_key_string(); close $fh; } else { - error("can't open $idfile for writing: $!"); + error("can't open $keyfile for writing: $!"); } } } diff --git a/lib/App/Acmeman/Config.pm b/lib/App/Acmeman/Config.pm index 6707ee0..da60700 100644 --- a/lib/App/Acmeman/Config.pm +++ b/lib/App/Acmeman/Config.pm @@ -6,6 +6,7 @@ use Carp; use parent 'Config::Parser::Ini'; use Text::ParseWords; use App::Acmeman::Log qw(debug_level :sysexits); +use File::Spec; sub new { my $class = shift; @@ -103,6 +104,14 @@ sub mangle { } } + my $dir = $self->get(qw(account directory)); + for my $k (qw(id key)) { + my $file = $self->get('account', $k); + unless (File::Spec->file_name_is_absolute($file)) { + $self->set('account', $k, File::Spec->catfile($dir, $file)); + } + } + exit(EX_CONFIG) if $err; } @@ -119,6 +128,10 @@ __DATA__ my-ip = STRING :array key-size = NUMBER :default=4096 verbose = NUMBER :default=0 +[account] + directory = STRING :default=/etc/ssl/acme + id = STRING :default=key.id + key = STRING :default=key.pem [files ANY] type = STRING :re="^(single|split)$" certificate-file = STRING |