mirror of
				https://git.proxmox.com/git/pve-manager
				synced 2025-11-04 14:19:12 +00:00 
			
		
		
		
	add certificates API endpoints
to allow retrieval of certificate information, and uploading or removing of custom certificate files. Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
		
							parent
							
								
									9945a5018e
								
							
						
					
					
						commit
						036475f89a
					
				
							
								
								
									
										207
									
								
								PVE/API2/Certificates.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								PVE/API2/Certificates.pm
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
				
			||||||
@ -14,6 +14,7 @@ PERLSOURCE = 			\
 | 
				
			|||||||
	Pool.pm			\
 | 
						Pool.pm			\
 | 
				
			||||||
	Tasks.pm		\
 | 
						Tasks.pm		\
 | 
				
			||||||
	Network.pm		\
 | 
						Network.pm		\
 | 
				
			||||||
 | 
						Certificates.pm		\
 | 
				
			||||||
	ACME.pm			\
 | 
						ACME.pm			\
 | 
				
			||||||
	ACMEAccount.pm		\
 | 
						ACMEAccount.pm		\
 | 
				
			||||||
	NodeConfig.pm		\
 | 
						NodeConfig.pm		\
 | 
				
			||||||
 | 
				
			|||||||
@ -41,6 +41,7 @@ use PVE::API2::APT;
 | 
				
			|||||||
use PVE::API2::Ceph;
 | 
					use PVE::API2::Ceph;
 | 
				
			||||||
use PVE::API2::Firewall::Host;
 | 
					use PVE::API2::Firewall::Host;
 | 
				
			||||||
use PVE::API2::Replication;
 | 
					use PVE::API2::Replication;
 | 
				
			||||||
 | 
					use PVE::API2::Certificates;
 | 
				
			||||||
use PVE::API2::NodeConfig;
 | 
					use PVE::API2::NodeConfig;
 | 
				
			||||||
use Digest::MD5;
 | 
					use Digest::MD5;
 | 
				
			||||||
use Digest::SHA;
 | 
					use Digest::SHA;
 | 
				
			||||||
@ -119,6 +120,12 @@ __PACKAGE__->register_method ({
 | 
				
			|||||||
    path => 'replication',
 | 
					    path => 'replication',
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__PACKAGE__->register_method ({
 | 
				
			||||||
 | 
					    subclass => "PVE::API2::Certificates",
 | 
				
			||||||
 | 
					    path => 'certificates',
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__PACKAGE__->register_method ({
 | 
					__PACKAGE__->register_method ({
 | 
				
			||||||
    subclass => "PVE::API2::NodeConfig",
 | 
					    subclass => "PVE::API2::NodeConfig",
 | 
				
			||||||
    path => 'config',
 | 
					    path => 'config',
 | 
				
			||||||
@ -177,6 +184,7 @@ __PACKAGE__->register_method ({
 | 
				
			|||||||
	    { name => 'stopall' },
 | 
						    { name => 'stopall' },
 | 
				
			||||||
	    { name => 'netstat' },
 | 
						    { name => 'netstat' },
 | 
				
			||||||
	    { name => 'firewall' },
 | 
						    { name => 'firewall' },
 | 
				
			||||||
 | 
						    { name => 'certificates' },
 | 
				
			||||||
	    { name => 'config' },
 | 
						    { name => 'config' },
 | 
				
			||||||
	    ];
 | 
						    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user