acme: add ipa-acme-manage command

Add the ipa-acme-manage command which can be used to enable or
disable the IPA ACME service.  It must be used on each server.  In
the future we will implement deployment-wide configuration
(including enable/disable) of the ACME service via IPA API, with
configuration stored in and replicated by LDAP.  But until then, we
need a simple command for administrators to use.

Part of: https://pagure.io/freeipa/issue/4751

Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Fraser Tweedale 2020-06-02 20:34:17 +10:00 committed by Rob Crittenden
parent 00a84464ea
commit 083c6aedc6
6 changed files with 125 additions and 0 deletions

View File

@ -1194,6 +1194,7 @@ fi
%{_sbindir}/ipa-pkinit-manage
%{_sbindir}/ipa-crlgen-manage
%{_sbindir}/ipa-cert-fix
%{_sbindir}/ipa-acme-manage
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
%{_libexecdir}/certmonger/ipa-server-guard
%dir %{_libexecdir}/ipa
@ -1262,6 +1263,7 @@ fi
%{_mandir}/man1/ipa-pkinit-manage.1*
%{_mandir}/man1/ipa-crlgen-manage.1*
%{_mandir}/man1/ipa-cert-fix.1*
%{_mandir}/man1/ipa-acme-manage.1*
%files -n python3-ipaserver

View File

@ -35,6 +35,7 @@ dist_noinst_DATA = \
ipa-httpd-kdcproxy.in \
ipa-pki-retrieve-key.in \
ipa-pki-wait-running.in \
ipa-acme-manage.in \
$(NULL)
nodist_sbin_SCRIPTS = \
@ -63,6 +64,7 @@ nodist_sbin_SCRIPTS = \
ipa-pkinit-manage \
ipa-crlgen-manage \
ipa-cert-fix \
ipa-acme-manage \
$(NULL)
appdir = $(libexecdir)/ipa/

View File

@ -0,0 +1,8 @@
#!/usr/bin/python3
#
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
#
from ipaserver.install.ipa_acme_manage import IPAACMEManage
IPAACMEManage.run_cli()

View File

@ -29,6 +29,7 @@ dist_man1_MANS = \
ipa-pkinit-manage.1 \
ipa-crlgen-manage.1 \
ipa-cert-fix.1 \
ipa-acme-manage.1 \
$(NULL)
dist_man8_MANS = \

View File

@ -0,0 +1,33 @@
.\"
.\" Copyright (C) 2020 FreeIPA Contributors see COPYING for license
.\"
.TH "ipa-acme-manage" "1" "Jun 2 2020" "FreeIPA" "FreeIPA Manual Pages"
.SH "NAME"
ipa\-acme\-manage \- Manage the FreeIPA ACME service
.SH "SYNOPSIS"
ipa\-acme\-manage enable|disable
.SH "DESCRIPTION"
Use the \fIipa-acme-manage\fR command to enable or disable the ACME
service on a FreeIPA CA server.
In a FreeIPA topology all CA servers capable of ACME will
have the ACME service deployed. The service is not enabled
by default. It is expected that the ACME service will either be
enabled on all CA servers, or disabled on all CA servers. However
it must be enabled or disabled on each individual server.
.SH "COMMANDS"
.TP
\fBenable\fR
Enable the ACME service on this host.
.TP
\fBdisable\fR
Disable the ACME service on this host.
.SH "EXIT STATUS"
0 if the command was successful
1 if the host is not a CA server
2 if the host is not a FreeIPA server

View File

@ -0,0 +1,79 @@
#
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
#
import enum
import pathlib
from ipaplatform.paths import paths
from ipapython.admintool import AdminTool
from ipapython.directivesetter import DirectiveSetter
from ipaserver.install import cainstance
from ipaserver.install.installutils import is_ipa_configured
# Manages the FreeIPA ACME service on a per-server basis.
#
# This program is a stop-gap until the deployment-wide management of
# the ACME service is implemented. So we will eventually have API
# calls for managing the ACME service, e.g. `ipa acme-enable'.
# After that is implemented, we can either deprecate and eventually
# remove this program, or make it a wrapper for the API commands.
class Command(enum.Enum):
ENABLE = 'enable'
DISABLE = 'disable'
class IPAACMEManage(AdminTool):
command_name = "ipa-acme-manage"
usage = "%prog [enable|disable]"
description = "Manage the IPA ACME service"
def validate_options(self):
# needs root now - if/when this program changes to an API
# wrapper we will no longer need root.
super(IPAACMEManage, self).validate_options(needs_root=True)
if len(self.args) < 1:
self.option_parser.error(f'missing command argument')
else:
try:
self.command = Command(self.args[0])
except ValueError:
self.option_parser.error(f'unknown command "{self.args[0]}"')
def run(self):
if not is_ipa_configured():
print("IPA is not configured.")
return 2
if not cainstance.is_ca_installed_locally():
print("CA is not installed on this server.")
return 1
if self.command == Command.ENABLE:
directive = 'enabled'
value = 'true'
elif self.command == Command.DISABLE:
directive = 'enabled'
value = 'false'
else:
raise RuntimeError('programmer error: unhandled enum case')
with DirectiveSetter(
paths.PKI_ACME_ENGINE_CONF,
separator='=',
quotes=False,
) as ds:
ds.set(directive, value)
# Work around a limitation in PKI ACME service file watching
# where renames (what DirectiveSetter does) are not detected.
# It will be fixed, but keeping the workaround will do no harm.
pathlib.Path(paths.PKI_ACME_ENGINE_CONF).touch()
# Nothing else to do; the Dogtag ACME service monitors engine.conf
# for updates and reconfigures itself as required.
return 0