summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2019-10-18 14:08:24 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2019-10-18 14:08:24 (GMT)
commitf44aeac44eecf6dd6075e20080c0bb0b7822f30f (patch) (side-by-side diff)
treebb3d249570d2865970383b9d063f7e2eab7668db
parent7e22b3181f963e62a44620336bdcd7d40baacb3a (diff)
downloadacmeman-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.
Diffstat (more/less context) (ignore whitespace changes)
-rwxr-xr-xacmeman30
-rw-r--r--lib/App/Acmeman.pm88
-rw-r--r--lib/App/Acmeman/Config.pm13
3 files changed, 93 insertions, 38 deletions
diff --git a/acmeman b/acmeman
index e0f22ab..7ab46bb 100755
--- a/acmeman
+++ b/acmeman
@@ -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>);
- close $fh;
- debug(3, "using key_id $key_id");
- } else {
- error("can't open $idfile for reading: $!");
- }
+
+ 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;
+ } else {
+ 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: $!");
- }
- } else {
- $account_key = Crypt::OpenSSL::RSA->generate_key($self->cf->get('core', 'key-size'));
+ 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 {
+ 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

Return to:

Send suggestions and report system problems to the System administrator.