From: Stoiko Ivanov <s.ivanov@proxmox.com>
To: Wolfgang Bumiller <w.bumiller@proxmox.com>
Cc: pmg-devel@lists.proxmox.com
Subject: Re: [pmg-devel] [PATCH v2 api 8/8] add acme and cert subcommands to pmgconfig
Date: Mon, 15 Mar 2021 22:39:44 +0100 [thread overview]
Message-ID: <20210315223944.08e0138b@rosa.proxmox.com> (raw)
In-Reply-To: <20210312152421.30114-9-w.bumiller@proxmox.com>
On Fri, 12 Mar 2021 16:23:57 +0100
Wolfgang Bumiller <w.bumiller@proxmox.com> wrote:
> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
> ---
> src/PMG/CLI/pmgconfig.pm | 178 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 178 insertions(+)
>
> diff --git a/src/PMG/CLI/pmgconfig.pm b/src/PMG/CLI/pmgconfig.pm
> index 85edfa5..4f948cf 100644
> --- a/src/PMG/CLI/pmgconfig.pm
> +++ b/src/PMG/CLI/pmgconfig.pm
> @@ -5,10 +5,13 @@ use warnings;
> use IO::File;
> use Data::Dumper;
>
> +use Term::ReadLine;
> +
> use PVE::SafeSyslog;
> use PVE::Tools qw(extract_param);
> use PVE::INotify;
> use PVE::CLIHandler;
> +use PVE::JSONSchema qw(get_standard_option);
>
> use PMG::RESTEnvironment;
> use PMG::RuleDB;
> @@ -18,14 +21,52 @@ use PMG::LDAPConfig;
> use PMG::LDAPSet;
> use PMG::Config;
> use PMG::Ticket;
> +
> +use PMG::API2::ACME;
> +use PMG::API2::ACMEPlugin;
> +use PMG::API2::Certificates;
> use PMG::API2::DKIMSign;
>
> use base qw(PVE::CLIHandler);
>
> +my $nodename = PVE::INotify::nodename();
> +
> sub setup_environment {
> PMG::RESTEnvironment->setup_default_cli_env();
> }
>
> +my $upid_exit = sub {
> + my $upid = shift;
> + my $status = PVE::Tools::upid_read_status($upid);
> + print "Task $status\n";
> + exit($status eq 'OK' ? 0 : -1);
> +};
> +
> +sub param_mapping {
> + my ($name) = @_;
> +
> + my $load_file_and_encode = sub {
> + my ($filename) = @_;
> +
> + return PVE::ACME::Challenge->encode_value('string', 'data', PVE::Tools::file_get_contents($filename));
> + };
> +
> + my $mapping = {
> + 'upload_custom_cert' => [
> + 'certificates',
> + 'key',
> + ],
> + 'add_plugin' => [
> + ['data', $load_file_and_encode, "File with one key-value pair per line, will be base64url encode for storage in plugin config.", 0],
> + ],
> + 'update_plugin' => [
> + ['data', $load_file_and_encode, "File with one key-value pair per line, will be base64url encode for storage in plugin config.", 0],
> + ],
> + };
> +
> + return $mapping->{$name};
> +}
> +
> __PACKAGE__->register_method ({
> name => 'dump',
> path => 'dump',
> @@ -184,6 +225,84 @@ __PACKAGE__->register_method ({
> return undef;
> }});
>
> +__PACKAGE__->register_method({
> + name => 'acme_register',
> + path => 'acme_register',
> + method => 'POST',
> + description => "Register a new ACME account with a compatible CA.",
> + parameters => {
> + additionalProperties => 0,
> + properties => {
> + name => get_standard_option('pmg-acme-account-name'),
> + contact => get_standard_option('pmg-acme-account-contact'),
> + directory => get_standard_option('pmg-acme-directory-url', {
> + optional => 1,
> + }),
> + },
> + },
> + returns => { type => 'null' },
> + code => sub {
> + my ($param) = @_;
> +
> + if (!$param->{directory}) {
> + my $directories = PMG::API2::ACME->get_directories({});
> + print "Directory endpoints:\n";
> + my $i = 0;
> + while ($i < @$directories) {
> + print $i, ") ", $directories->[$i]->{name}, " (", $directories->[$i]->{url}, ")\n";
> + $i++;
> + }
> + print $i, ") Custom\n";
> +
> + my $term = Term::ReadLine->new('pmgconfig');
> + my $get_dir_selection = sub {
> + my $selection = $term->readline("Enter selection: ");
> + if ($selection =~ /^(\d+)$/) {
> + $selection = $1;
> + if ($selection == $i) {
> + $param->{directory} = $term->readline("Enter custom URL: ");
> + return;
> + } elsif ($selection < $i && $selection >= 0) {
> + $param->{directory} = $directories->[$selection]->{url};
> + return;
> + }
> + }
> + print "Invalid selection.\n";
> + };
> +
> + my $attempts = 0;
> + while (!$param->{directory}) {
> + die "Aborting.\n" if $attempts > 3;
> + $get_dir_selection->();
> + $attempts++;
> + }
> + }
> + print "\nAttempting to fetch Terms of Service from '$param->{directory}'..\n";
> + my $tos = PMG::API2::ACME->get_tos({ directory => $param->{directory} });
> + if ($tos) {
> + print "Terms of Service: $tos\n";
> + my $term = Term::ReadLine->new('pvenode');
> + my $agreed = $term->readline('Do you agree to the above terms? [y|N]: ');
> + die "Cannot continue without agreeing to ToS, aborting.\n"
> + if ($agreed !~ /^y$/i);
> +
> + $param->{tos_url} = $tos;
> + } else {
> + print "No Terms of Service found, proceeding.\n";
> + }
> + print "\nAttempting to register account with '$param->{directory}'..\n";
> +
> + $upid_exit->(PMG::API2::ACME->register_account($param));
> + }});
> +
> +my $print_cert_info = sub {
> + my ($schema, $cert, $options) = @_;
> +
> + my $order = [qw(filename fingerprint subject issuer notbefore notafter public-key-type public-key-bits san)];
> + PVE::CLIFormatter::print_api_result(
> + $cert, $schema, $order, { %$options, noheader => 1, sort_key => 0 });
> +};
> +
> our $cmddef = {
> 'dump' => [ __PACKAGE__, 'dump', []],
> sync => [ __PACKAGE__, 'sync', []],
> @@ -198,6 +317,65 @@ our $cmddef = {
> die "no dkim_selector configured\n" if !defined($res->{record});
> print "$res->{record}\n";
> }],
> +
> + cert => {
> + info => [ 'PMG::API2::Certificates', 'info', [], { node => $nodename }, sub {
> + my ($res, $schema, $options) = @_;
> +
> + if (!$options->{'output-format'} || $options->{'output-format'} eq 'text') {
> + for my $cert (sort { $a->{filename} cmp $b->{filename} } @$res) {
> + $print_cert_info->($schema->{items}, $cert, $options);
> + }
> + } else {
> + PVE::CLIFormatter::print_api_result($res, $schema, undef, $options);
> + }
> +
> + }, $PVE::RESTHandler::standard_output_options],
> + set => [ 'PMG::API2::Certificates', 'upload_custom_cert', ['type', 'certificates', 'key'], { node => $nodename }, sub {
> + my ($res, $schema, $options) = @_;
> + $print_cert_info->($schema, $res, $options);
> + }, $PVE::RESTHandler::standard_output_options],
> + delete => [ 'PMG::API2::Certificates', 'remove_custom_cert', ['type', 'restart'], { node => $nodename } ],
small nit: by adding 'restart' as fixed parameter here I get an
uninitialized warning in JSONSchema - maybe just drop it?
> + },
> +
> + acme => {
> + account => {
> + list => [ 'PMG::API2::ACME', 'account_index', [], {}, sub {
> + my ($res) = @_;
> + for my $acc (@$res) {
> + print "$acc->{name}\n";
> + }
> + }],
> + register => [ __PACKAGE__, 'acme_register', ['name', 'contact'], {}, $upid_exit ],
> + deactivate => [ 'PMG::API2::ACME', 'deactivate_account', ['name'], {}, $upid_exit ],
> + info => [ 'PMG::API2::ACME', 'get_account', ['name'], {}, sub {
> + my ($data, $schema, $options) = @_;
> + PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
> + }, $PVE::RESTHandler::standard_output_options],
> + update => [ 'PMG::API2::ACME', 'update_account', ['name'], {}, $upid_exit ],
> + },
> + cert => {
> + order => [ 'PMG::API2::Certificates', 'new_acme_cert', ['type'], { node => $nodename }, $upid_exit ],
> +
> +
> + renew => [ 'PMG::API2::Certificates', 'renew_acme_cert', ['type'], { node => $nodename }, $upid_exit ],
> + revoke => [ 'PMG::API2::Certificates', 'revoke_acme_cert', ['type'], { node => $nodename }, $upid_exit ],
> + },
> + plugin => {
> + list => [ 'PMG::API2::ACMEPlugin', 'index', [], {}, sub {
> + my ($data, $schema, $options) = @_;
> + PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
> + }, $PVE::RESTHandler::standard_output_options ],
> + config => [ 'PMG::API2::ACMEPlugin', 'get_plugin_config', ['id'], {}, sub {
> + my ($data, $schema, $options) = @_;
> + PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
> + }, $PVE::RESTHandler::standard_output_options ],
> + add => [ 'PMG::API2::ACMEPlugin', 'add_plugin', ['type', 'id'] ],
> + set => [ 'PMG::API2::ACMEPlugin', 'update_plugin', ['id'] ],
> + remove => [ 'PMG::API2::ACMEPlugin', 'delete_plugin', ['id'] ],
> + },
> +
> + },
> };
>
>
next prev parent reply other threads:[~2021-03-15 21:39 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-12 15:23 [pmg-devel] [PATCH v2 api/gui/wtk/acme 0/many] Certificates & ACME Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 1/8] depend on libpmg-rs-perl and proxmox-acme Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 2/8] add PMG::CertHelpers module Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 3/8] add PMG::NodeConfig module Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 4/8] cluster: sync acme/ and acme-plugins.conf Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 5/8] api: add ACME and ACMEPlugin module Wolfgang Bumiller
2021-03-15 11:07 ` Fabian Grünbichler
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 6/8] add certificates api endpoint Wolfgang Bumiller
2021-03-15 11:08 ` Fabian Grünbichler
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 7/8] add node-config api entry points Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 8/8] add acme and cert subcommands to pmgconfig Wolfgang Bumiller
2021-03-15 17:57 ` Stoiko Ivanov
2021-03-15 21:39 ` Stoiko Ivanov [this message]
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 1/8] depend on libpmg-rs-perl and proxmox-acme Wolfgang Bumiller
2021-03-12 15:23 ` [pmg-devel] [PATCH v2 api 2/8] add PMG::CertHelpers module Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 3/8] add PMG::NodeConfig module Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 4/8] cluster: sync acme/ and acme-plugins.conf Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 5/8] api: add ACME and ACMEPlugin module Wolfgang Bumiller
2021-03-15 18:37 ` Stoiko Ivanov
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 6/8] add certificates api endpoint Wolfgang Bumiller
2021-03-15 18:14 ` Stoiko Ivanov
2021-03-15 20:51 ` Stoiko Ivanov
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 7/8] add node-config api entry points Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 api 8/8] add acme and cert subcommands to pmgconfig Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 gui] add certificates and acme view Wolfgang Bumiller
2021-03-12 15:24 ` Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 1/7] Utils: add ACME related utilities Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 2/7] add ACME related data models Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 3/7] add ACME forms Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 4/7] add certificate panel Wolfgang Bumiller
2021-03-15 17:22 ` Stoiko Ivanov
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 5/7] add ACME account panel Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 6/7] add ACME plugin editing Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 7/7] add ACME domain editing Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 1/7] Utils: add ACME related utilities Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 2/7] add ACME related data models Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 3/7] add ACME forms Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 4/7] add certificate panel Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 5/7] add ACME account panel Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 6/7] add ACME plugin editing Wolfgang Bumiller
2021-03-12 15:24 ` [pmg-devel] [PATCH v2 widget-toolkit 7/7] add ACME domain editing Wolfgang Bumiller
2021-03-15 18:45 ` [pmg-devel] [PATCH v2 api/gui/wtk/acme 0/many] Certificates & ACME Stoiko Ivanov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210315223944.08e0138b@rosa.proxmox.com \
--to=s.ivanov@proxmox.com \
--cc=pmg-devel@lists.proxmox.com \
--cc=w.bumiller@proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox