[pve-devel] [Patch V2 acme 09/12] Add function setup and teardown.

Wolfgang Link w.link at proxmox.com
Tue Mar 31 12:08:48 CEST 2020


These are the two main functions that a plugin should offer.
Setup creates the endpoint at which Letsencrypt does the validation, teardown does the cleanup.

Signed-off-by: Wolfgang Link <w.link at proxmox.com>
---
 src/PVE/ACME.pm            | 43 ++++++++++++++++++++++++++++++++++++++
 src/PVE/ACME/StandAlone.pm | 16 +++++---------
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/src/PVE/ACME.pm b/src/PVE/ACME.pm
index 114eb41..c10dca2 100644
--- a/src/PVE/ACME.pm
+++ b/src/PVE/ACME.pm
@@ -23,6 +23,9 @@ file_set_contents
 file_get_contents
 );
 
+use PVE::ACME::Challenge;
+use PVE::ACME::StandAlone;
+
 Crypt::OpenSSL::RSA->import_random_seed();
 
 my $LETSENCRYPT_STAGING = 'https://acme-staging-v02.api.letsencrypt.org/directory';
@@ -493,6 +496,46 @@ sub request_challenge_validation {
     return $return;
 }
 
+# Setup the challange
+# At the moment two plugin types are supproted
+# standalone: start an webserver an wait for the challenge
+# dns: add an txt record over the given API
+sub setup {
+    my ($acme, $auth, $node_config) = @_;
+
+    my $fqdn = $auth->{identifier}->{value};
+    my $plugin_data = {};
+    my $plugin_type = "standalone";
+    my $plugin_conf = PVE::ACME::Challenge->load_config();
+
+    # default is standalone if no plugin is set (old config)
+    my $index = 0;
+    while (defined($node_config->{$index})) {
+	if ($node_config->{$index}->{domain} eq $fqdn &&
+	    defined($node_config->{$index}->{plugin})) {
+	    $plugin_data = $plugin_conf->{ids}->{$node_config->{$index}->{plugin}};
+	    $plugin_type = $plugin_data->{type};
+
+	    # Alias mode is only supported for DNSChallange
+	    $plugin_data->{alias} = $node_config->{$index}->{alias} if
+		$node_config->{$index}->{alias};
+	    last;
+	}
+	$index++;
+    }
+    die if $plugin_type eq "standalone";
+    my $plugin = PVE::ACME::Challenge->lookup($plugin_data->{type});
+    return $plugin->setup($acme, $auth, $plugin_data);
+}
+
+#
+#
+sub teardown {
+    my ($self) = @_;
+
+    $self->teardown();
+}
+
 # actually 'do' a $method request on $url
 # $data: input for JWS, optional
 # $use_jwk: use JWK instead of KID in JWD (see sub jws)
diff --git a/src/PVE/ACME/StandAlone.pm b/src/PVE/ACME/StandAlone.pm
index ac75184..8fc8dc9 100644
--- a/src/PVE/ACME/StandAlone.pm
+++ b/src/PVE/ACME/StandAlone.pm
@@ -31,15 +31,8 @@ sub options {
 sub setup {
     my ($class, $acme, $authorization) = @_;
 
-    my $challenges = $authorization->{challenges};
-    die "no challenges defined in authorization\n" if !$challenges;
-
-    my $http_challenges = [ grep {$_->{type} eq 'http-01'} @$challenges ];
-    die "no http-01 challenge defined in authorization\n"
-	if ! scalar $http_challenges;
-
-    my $http_challenge = $http_challenges->[0];
-
+    print "Setting up webserver\n";
+    my $http_challenge = PVE::ACME::extract_challenge($authorization->{challenges}, "http-01");
     die "no token found in http-01 challenge\n" if !$http_challenge->{token};
 
     my $key_authorization = $acme->key_authorization($http_challenge->{token});
@@ -47,7 +40,7 @@ sub setup {
     my $server = HTTP::Daemon->new(
 	LocalPort => 80,
 	ReuseAddr => 1,
-    ) or die "Failed to initialize HTTP daemon\n";
+	) or die "Failed to initialize HTTP daemon\n";
     my $pid = fork() // die "Failed to fork HTTP daemon - $!\n";
     if ($pid) {
 	my $self = {
@@ -62,7 +55,8 @@ sub setup {
     } else {
 	while (my $c = $server->accept()) {
 	    while (my $r = $c->get_request()) {
-		if ($r->method() eq 'GET' and $r->uri->path eq "/.well-known/acme-challenge/$http_challenge->{token}") {
+		if ($r->method() eq 'GET' and
+		    $r->uri->path eq "/.well-known/acme-challenge/$http_challenge->{token}") {
 		    my $resp = HTTP::Response->new(200, 'OK', undef, $key_authorization);
 		    $resp->request($r);
 		    $c->send_response($resp);
-- 
2.20.1





More information about the pve-devel mailing list