[pve-devel] [v3 manager 5/7] add certificates API endpoints

Fabian Grünbichler f.gruenbichler at proxmox.com
Fri Apr 27 14:02:12 CEST 2018


to allow retrieval of certificate information, and uploading or removing
of custom certificate files.

Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
 PVE/API2/Makefile        |   1 +
 PVE/API2/Certificates.pm | 207 +++++++++++++++++++++++++++++++++++++++++++++++
 PVE/API2/Nodes.pm        |   8 ++
 3 files changed, 216 insertions(+)
 create mode 100644 PVE/API2/Certificates.pm

diff --git a/PVE/API2/Makefile b/PVE/API2/Makefile
index 44b9cf7c..9862e498 100644
--- a/PVE/API2/Makefile
+++ b/PVE/API2/Makefile
@@ -14,6 +14,7 @@ PERLSOURCE = 			\
 	Pool.pm			\
 	Tasks.pm		\
 	Network.pm		\
+	Certificates.pm		\
 	ACME.pm			\
 	ACMEAccount.pm		\
 	NodeConfig.pm		\
diff --git a/PVE/API2/Certificates.pm b/PVE/API2/Certificates.pm
new file mode 100644
index 00000000..fd75ba85
--- /dev/null
+++ b/PVE/API2/Certificates.pm
@@ -0,0 +1,207 @@
+package PVE::API2::Certificates;
+
+use strict;
+use warnings;
+
+use PVE::API2::ACME;
+use PVE::Certificate;
+use PVE::CertHelpers;;
+use PVE::Exception qw(raise_param_exc);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools qw(extract_param file_get_contents file_set_contents);
+
+use base qw(PVE::RESTHandler);
+
+
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::ACME",
+    path => 'acme',
+});
+
+__PACKAGE__->register_method ({
+    name => 'index',
+    path => '',
+    method => 'GET',
+    permissions => { user => 'all' },
+    description => "Node index.",
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {},
+	},
+	links => [ { rel => 'child', href => "{name}" } ],
+    },
+    code => sub {
+	my ($param) = @_;
+
+	return [
+	    { name => 'acme' },
+	    { name => 'custom' },
+	    { name => 'info' },
+	];
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'info',
+    path => 'info',
+    method => 'GET',
+    permissions => { user => 'all' },
+    proxyto => 'node',
+    description => "Get information about node's certificates.",
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	},
+    },
+    returns => {
+	type => 'array',
+	items => get_standard_option('pve-certificate-info'),
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $node_path = "/etc/pve/nodes/$param->{node}";
+
+	my $res = [];
+	my $cert_paths = [
+	    '/etc/pve/pve-root-ca.pem',
+	    "$node_path/pve-ssl.pem",
+	    "$node_path/pveproxy-ssl.pem",
+	];
+	for my $path (@$cert_paths) {
+	    eval {
+		my $info = PVE::Certificate::get_certificate_info($path);
+		push @$res, $info if $info;
+	    };
+	}
+	return $res;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'upload_custom_cert',
+    path => 'custom',
+    method => 'POST',
+    description => 'Upload or update custom certificate chain and key.',
+    protected => 1,
+    proxyto => 'node',
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    certificates => {
+		type => 'string',
+		format => 'pem-certificate-chain',
+		description => 'PEM encoded certificate (chain).',
+	    },
+	    key => {
+		type => 'string',
+		description => 'PEM encoded private key.',
+		format => 'pem-string',
+		optional => 1,
+	    },
+	    force => {
+		type => 'boolean',
+		description => 'Overwrite existing custom or ACME certificate files.',
+		optional => 1,
+		default => 0,
+	    },
+	    restart => {
+		type => 'boolean',
+		description => 'Restart pveproxy.',
+		optional => 1,
+		default => 0,
+	    },
+	},
+    },
+    returns => get_standard_option('pve-certificate-info'),
+    code => sub {
+	my ($param) = @_;
+
+	my $node = extract_param($param, 'node');
+	my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node);
+
+	my $certs = extract_param($param, 'certificates');
+	$certs = PVE::Certificate::strip_leading_text($certs);
+
+	my $key = extract_param($param, 'key');
+	if ($key) {
+	    $key = PVE::Certificate::strip_leading_text($key);
+	} else {
+	    raise_param_exc({'key' => "Attempted to upload custom certificate without (existing) key."})
+		if ! -e "${cert_prefix}.key";
+	}
+
+	my $info;
+
+	my $code = sub {
+	    print "Setting custom certificate files\n";
+	    $info = PVE::CertHelpers::set_cert_files($certs, $key, $cert_prefix, $param->{force});
+
+	    if ($param->{restart}) {
+		print "Restarting pveproxy\n";
+		PVE::Tools::run_command(['systemctl', 'reload-or-restart', 'pveproxy']);
+	    }
+	};
+
+	PVE::CertHelpers::cert_lock(10, $code);
+	die "$@\n" if $@;
+
+	return $info;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'remove_custom_cert',
+    path => 'custom',
+    method => 'DELETE',
+    description => 'DELETE custom certificate chain and key.',
+    protected => 1,
+    proxyto => 'node',
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    restart => {
+		type => 'boolean',
+		description => 'Restart pveproxy.',
+		optional => 1,
+		default => 0,
+	    },
+	},
+    },
+    returns => {
+	type => 'null',
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $node = extract_param($param, 'node');
+	my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node);
+
+	my $code = sub {
+	    print "Deleting custom certificate files\n";
+	    unlink "${cert_prefix}.pem";
+	    unlink "${cert_prefix}.key";
+
+	    if ($param->{restart}) {
+		print "Restarting pveproxy\n";
+		PVE::Tools::run_command(['systemctl', 'reload-or-restart', 'pveproxy']);
+	    }
+	};
+
+	PVE::CertHelpers::cert_lock(10, $code);
+	die "$@\n" if $@;
+
+	return undef;
+    }});
+
+1;
diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
index 42b932cf..25f0e180 100644
--- a/PVE/API2/Nodes.pm
+++ b/PVE/API2/Nodes.pm
@@ -41,6 +41,7 @@ use PVE::API2::APT;
 use PVE::API2::Ceph;
 use PVE::API2::Firewall::Host;
 use PVE::API2::Replication;
+use PVE::API2::Certificates;
 use PVE::API2::NodeConfig;
 use Digest::MD5;
 use Digest::SHA;
@@ -119,6 +120,12 @@ __PACKAGE__->register_method ({
     path => 'replication',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Certificates",
+    path => 'certificates',
+});
+
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::NodeConfig",
     path => 'config',
@@ -177,6 +184,7 @@ __PACKAGE__->register_method ({
 	    { name => 'stopall' },
 	    { name => 'netstat' },
 	    { name => 'firewall' },
+	    { name => 'certificates' },
 	    { name => 'config' },
 	    ];
 
-- 
2.14.2





More information about the pve-devel mailing list