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

Signed-off-by: Fabian Grünbichler <f.gruenbich...@proxmox.com>
---
 PVE/API2/Makefile        |   1 +
 PVE/API2/Certificates.pm | 202 +++++++++++++++++++++++++++++++++++++++++++++++
 PVE/API2/Nodes.pm        |   8 ++
 3 files changed, 211 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..6b66ea67
--- /dev/null
+++ b/PVE/API2/Certificates.pm
@@ -0,0 +1,202 @@
+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' },
+    description => "Get information about node's certificates.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+       },
+    },
+    returns => {
+       type => 'object',
+       properties => {
+           clusterca => {
+               type => 'object',
+           },
+           custom => {
+               type => 'object',
+               optional => 1,
+           }
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $node_path = "/etc/pve/nodes/$param->{node}";
+
+       my $selfsigned_info = eval { 
PVE::Certificate::get_certificate_info("${node_path}/pve-ssl.pem")};
+       $selfsigned_info = { error => "$@" } if $@;
+       my $custom_info = eval { 
PVE::Certificate::get_certificate_info("${node_path}/pveproxy-ssl.pem")};
+       $custom_info = { error => "$@" } if $@;
+       return {
+           clusterca => $selfsigned_info,
+           custom => $custom_info,
+       };
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'upload_custom_cert',
+    path => 'custom',
+    method => 'POST',
+    description => 'Upload or update custom certificate chain and key.',
+    protected => 1,
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           certificates => {
+               type => 'string',
+               description => 'PEM encoded certificate (chain).',
+           },
+           key => {
+               type => 'string',
+               description => 'PEM encoded private key.',
+               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 => {
+       type => 'object',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $certs = extract_param($param, 'certificates');
+       $certs = eval { PVE::Certificate::check_pem($certs, multiple => 1); };
+       raise_param_exc({ certificates => "Failed PEM format check - $@" }) if 
$@;
+
+       my $key = extract_param($param, 'key');
+       $key = eval { PVE::Certificate::check_pem($key, label => qr/.*?/); };
+       raise_param_exc({ key => "Failed PEM format check - $@" }) if $@;
+       
+       my $node = extra_param($param, 'node');
+       my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node);
+
+       my $info;
+
+       my $code = sub {
+           print "Setting custom certificate files\n";
+           $info = PVE::CertHelper::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,
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           restart => {
+               type => 'boolean',
+               description => 'Restart pveproxy.',
+               optional => 1,
+               default => 0,
+           },
+       },
+    },
+    returns => {
+       type => 'object',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $node = extra_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 $@;
+    }});
+
+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


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to