summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Kupka <dkupka@redhat.com>2015-11-26 09:01:27 +0100
committerJan Cholasta <jcholast@redhat.com>2015-12-03 09:32:39 +0100
commit2f51f0dce2e804bc4661441f97c04dc84b84fa21 (patch)
treeb1d30211edc5747cc894b361d04ca558a937641f
parent498471e4aed1367b72cd74d15811d0584a6ee268 (diff)
downloadfreeipa-2f51f0dce2e804bc4661441f97c04dc84b84fa21.tar.gz
freeipa-2f51f0dce2e804bc4661441f97c04dc84b84fa21.tar.xz
freeipa-2f51f0dce2e804bc4661441f97c04dc84b84fa21.zip
ipa-replica-install support caless install with promotion.
https://fedorahosted.org/freeipa/ticket/5441 Reviewed-By: Jan Cholasta <jcholast@redhat.com>
-rw-r--r--ipaserver/install/custodiainstance.py6
-rw-r--r--ipaserver/install/dsinstance.py3
-rw-r--r--ipaserver/install/server/common.py6
-rw-r--r--ipaserver/install/server/install.py58
-rw-r--r--ipaserver/install/server/replicainstall.py168
5 files changed, 199 insertions, 42 deletions
diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
index df99962a7..dbe36af6d 100644
--- a/ipaserver/install/custodiainstance.py
+++ b/ipaserver/install/custodiainstance.py
@@ -17,7 +17,7 @@ import tempfile
class CustodiaInstance(SimpleServiceInstance):
- def __init__(self, host_name=None, realm=None):
+ def __init__(self, host_name=None, realm=None, ca_is_configured=True):
super(CustodiaInstance, self).__init__("ipa-custodia")
self.config_file = paths.IPA_CUSTODIA_CONF
self.server_keys = os.path.join(paths.IPA_CUSTODIA_CONF_DIR,
@@ -25,6 +25,7 @@ class CustodiaInstance(SimpleServiceInstance):
self.ldap_uri = None
self.fqdn = host_name
self.realm = realm
+ self.ca_is_configured = ca_is_configured
def __config_file(self):
template_file = os.path.basename(self.config_file) + '.template'
@@ -68,7 +69,8 @@ class CustodiaInstance(SimpleServiceInstance):
self.step("Generating ipa-custodia config file", self.__config_file)
self.step("Generating ipa-custodia keys", self.__gen_keys)
- self.step("Importing RA Key", self.__import_ra_key)
+ if self.ca_is_configured:
+ self.step("Importing RA Key", self.__import_ra_key)
super(CustodiaInstance, self).create_instance(gensvc_name='KEYS',
fqdn=self.fqdn,
ldap_suffix=suffix,
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index e47e85ca6..a58b0f7c2 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -381,7 +381,8 @@ class DsInstance(service.Service):
if self.promote:
self.step("creating DS keytab", self.__get_ds_keytab)
- self.step("retrieving DS Certificate", self.__get_ds_cert)
+ if self.ca_is_configured:
+ self.step("retrieving DS Certificate", self.__get_ds_cert)
self.step("restarting directory server", self.__restart_instance)
self.step("setting up initial replication", self.__setup_replica)
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
index 376c39dfa..1c161120b 100644
--- a/ipaserver/install/server/common.py
+++ b/ipaserver/install/server/common.py
@@ -53,7 +53,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
description=("File containing the Directory Server SSL certificate "
"and private key"),
cli_name='dirsrv-cert-file',
- cli_aliases=['dirsrv_pkcs12'],
cli_metavar='FILE',
)
@@ -62,7 +61,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
description=("File containing the Apache Server SSL certificate and "
"private key"),
cli_name='http-cert-file',
- cli_aliases=['http_pkcs12'],
cli_metavar='FILE',
)
@@ -71,7 +69,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
description=("File containing the Kerberos KDC SSL certificate and "
"private key"),
cli_name='pkinit-cert-file',
- cli_aliases=['pkinit_pkcs12'],
cli_metavar='FILE',
)
@@ -79,7 +76,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
str, None,
sensitive=True,
description="The password to unlock the Directory Server private key",
- cli_aliases=['dirsrv_pin'],
cli_metavar='PIN',
)
@@ -87,7 +83,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
str, None,
sensitive=True,
description="The password to unlock the Apache Server private key",
- cli_aliases=['http_pin'],
cli_metavar='PIN',
)
@@ -95,7 +90,6 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
str, None,
sensitive=True,
description="The password to unlock the Kerberos KDC private key",
- cli_aliases=['pkinit_pin'],
cli_metavar='PIN',
)
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index dbc8f5cd3..b6f1b98c5 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -49,7 +49,7 @@ try:
except ImportError:
_server_trust_ad_installed = False
-from .common import BaseServer
+from .common import BaseServer, BaseServerCA
SYSRESTORE_DIR_PATH = paths.SYSRESTORE
@@ -1268,6 +1268,54 @@ def uninstall(installer):
sys.exit(rv)
+class ServerCA(BaseServerCA):
+
+ # FIXME: Following Knobs are inherited because framework is not able to
+ # help groups correctly.
+
+ external_ca = Knob(BaseServerCA.external_ca)
+ external_ca_type = Knob(BaseServerCA.external_ca_type)
+ external_cert_files = Knob(BaseServerCA.external_cert_files)
+
+ dirsrv_cert_files = Knob(
+ BaseServerCA.dirsrv_cert_files,
+ cli_aliases=['dirsrv_pkcs12'],
+ )
+
+ http_cert_files = Knob(
+ BaseServerCA.http_cert_files,
+ cli_aliases=['http_pkcs12'],
+ )
+
+ pkinit_cert_files = Knob(
+ BaseServerCA.pkinit_cert_files,
+ cli_aliases=['pkinit_pkcs12'],
+ )
+
+ dirsrv_pin = Knob(
+ BaseServerCA.dirsrv_pin,
+ cli_aliases=['dirsrv_pin'],
+ )
+
+ http_pin = Knob(
+ BaseServerCA.http_pin,
+ cli_aliases=['http_pin'],
+ )
+
+ pkinit_pin = Knob(
+ BaseServerCA.pkinit_pin,
+ cli_aliases=['pkinit_pin'],
+ )
+
+ dirsrv_cert_name = Knob(BaseServerCA.dirsrv_cert_name)
+ http_cert_name = Knob(BaseServerCA.http_cert_name)
+ pkinit_cert_name = Knob(BaseServerCA.pkinit_cert_name)
+ ca_cert_files = Knob(BaseServerCA.ca_cert_files)
+ subject = Knob(BaseServerCA.subject)
+ ca_signing_algorithm = Knob(BaseServerCA.ca_signing_algorithm)
+ skip_schema_check = None
+
+
class Server(BaseServer):
realm_name = Knob(BaseServer.realm_name)
domain_name = Knob(BaseServer.domain_name)
@@ -1361,9 +1409,6 @@ class Server(BaseServer):
"topology (domain level 1+)",
)
- # ca
- skip_schema_check = None
-
# dns
dnssec_master = None
disable_dnssec_master = None
@@ -1387,6 +1432,8 @@ class Server(BaseServer):
self._ca_cert = None
self._update_hosts_file = False
+ # pylint: disable=no-member
+
if self.uninstalling:
if (self.realm_name or self.admin_password or
self.master_password):
@@ -1399,7 +1446,6 @@ class Server(BaseServer):
"In unattended mode you need to provide at least -r, -p "
"and -a options")
if self.setup_dns:
- #pylint: disable=no-member
if (not self.dns.forwarders and not self.dns.no_forwarders
and not self.dns.auto_forwarders):
raise RuntimeError(
@@ -1416,6 +1462,8 @@ class Server(BaseServer):
"idmax (%s) cannot be smaller than idstart (%s)" %
(self.idmax, self.idstart))
+ ca = core.Component(ServerCA)
+
@step()
def main(self):
install_check(self)
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 74069f0fb..ec77ab21b 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -33,6 +33,7 @@ from ipaserver.install import (
ntpinstance, otpdinstance, custodiainstance, service)
from ipaserver.install.installutils import create_replica_config
from ipaserver.install.installutils import ReplicaConfig
+from ipaserver.install.installutils import load_pkcs12
from ipaserver.install.replication import (
ReplicationManager, replica_conn_check)
import SSSDConfig
@@ -88,13 +89,21 @@ def install_http_certs(config, fstore):
# FIXME: need Signing-Cert too ?
-def install_replica_ds(config, options, promote=False):
+def install_replica_ds(config, options, ca_is_configured, promote=False,
+ pkcs12_info=None):
dsinstance.check_ports()
# if we have a pkcs12 file, create the cert db from
# that. Otherwise the ds setup will create the CA
# cert
- pkcs12_info = make_pkcs12_info(config.dir, "dscert.p12", "dirsrv_pin.txt")
+ if pkcs12_info is None:
+ pkcs12_info = make_pkcs12_info(config.dir, "dscert.p12",
+ "dirsrv_pin.txt")
+
+ if promote:
+ ca_file = paths.IPA_CA_CRT
+ else:
+ ca_file = os.path.join(config.dir, "ca.crt")
ds = dsinstance.DsInstance(
config_ldif=options.dirsrv_config_file)
@@ -106,8 +115,8 @@ def install_replica_ds(config, options, promote=False):
dm_password=config.dirman_password,
subject_base=config.subject_base,
pkcs12_info=pkcs12_info,
- ca_is_configured=ipautil.file_exists(config.dir + "/cacert.p12"),
- ca_file=config.dir + "/ca.crt",
+ ca_is_configured=ca_is_configured,
+ ca_file=ca_file,
promote=promote,
)
@@ -145,11 +154,19 @@ def install_ca_cert(ldap, base_dn, realm, cafile):
sys.exit(1)
-def install_http(config, auto_redirect, promote=False):
+def install_http(config, auto_redirect, ca_is_configured, promote=False,
+ pkcs12_info=None):
# if we have a pkcs12 file, create the cert db from
# that. Otherwise the ds setup will create the CA
# cert
- pkcs12_info = make_pkcs12_info(config.dir, "httpcert.p12", "http_pin.txt")
+ if pkcs12_info is None:
+ pkcs12_info = make_pkcs12_info(config.dir, "httpcert.p12",
+ "http_pin.txt")
+
+ if promote:
+ ca_file = paths.IPA_CA_CRT
+ else:
+ ca_file = os.path.join(config.dir, "ca.crt")
memcache = memcacheinstance.MemcacheInstance()
memcache.create_instance('MEMCACHE', config.host_name,
@@ -160,9 +177,8 @@ def install_http(config, auto_redirect, promote=False):
http.create_instance(
config.realm_name, config.host_name, config.domain_name,
config.dirman_password, False, pkcs12_info,
- auto_redirect=auto_redirect, ca_file=config.dir + "/ca.crt",
- ca_is_configured=ipautil.file_exists(config.dir + "/cacert.p12"),
- promote=promote)
+ auto_redirect=auto_redirect, ca_file=ca_file,
+ ca_is_configured=ca_is_configured, promote=promote)
http.setup_firefox_extension(config.realm_name, config.domain_name)
@@ -655,7 +671,7 @@ def install(installer):
ntp.create_instance()
# Configure dirsrv
- ds = install_replica_ds(config, options)
+ ds = install_replica_ds(config, options, installer._ca_enabled)
# Always try to install DNS records
install_dns_records(config, options, remote_api)
@@ -676,7 +692,8 @@ def install(installer):
ca.install(False, config, options)
krb = install_krb(config, setup_pkinit=not options.no_pkinit)
- http = install_http(config, auto_redirect=not options.no_ui_redirect)
+ http = install_http(config, auto_redirect=not options.no_ui_redirect,
+ ca_is_configured=installer._ca_enabled)
otpd = otpdinstance.OtpdInstance()
otpd.create_instance('OTPD', config.host_name, config.dirman_password,
@@ -845,6 +862,67 @@ def promote_check(installer):
config.setup_kra = options.setup_kra
config.dir = installer._top_dir
+ http_pkcs12_file = None
+ http_pkcs12_info = None
+ dirsrv_pkcs12_file = None
+ dirsrv_pkcs12_info = None
+ pkinit_pkcs12_file = None
+ pkinit_pkcs12_info = None
+
+ if options.http_cert_files:
+ if options.http_pin is None:
+ options.http_pin = installutils.read_password(
+ "Enter Apache Server private key unlock",
+ confirm=False, validate=False)
+ if options.http_pin is None:
+ sys.exit(
+ "Apache Server private key unlock password required")
+ http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
+ cert_files=options.http_cert_files,
+ key_password=options.http_pin,
+ key_nickname=options.http_cert_name,
+ ca_cert_files=options.ca_cert_files,
+ host_name=config.host_name)
+ http_pkcs12_info = (http_pkcs12_file.name, http_pin)
+
+ if options.dirsrv_cert_files:
+ if options.dirsrv_pin is None:
+ options.dirsrv_pin = installutils.read_password(
+ "Enter Directory Server private key unlock",
+ confirm=False, validate=False)
+ if options.dirsrv_pin is None:
+ sys.exit(
+ "Directory Server private key unlock password required")
+ dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
+ cert_files=options.dirsrv_cert_files,
+ key_password=options.dirsrv_pin,
+ key_nickname=options.dirsrv_cert_name,
+ ca_cert_files=options.ca_cert_files,
+ host_name=config.host_name)
+ dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)
+
+ if options.pkinit_cert_files:
+ if options.pkinit_pin is None:
+ options.pkinit_pin = installutils.read_password(
+ "Enter Kerberos KDC private key unlock",
+ confirm=False, validate=False)
+ if options.pkinit_pin is None:
+ sys.exit(
+ "Kerberos KDC private key unlock password required")
+ pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12(
+ cert_files=options.pkinit_cert_files,
+ key_password=options.pkinit_pin,
+ key_nickname=options.pkinit_cert_name,
+ ca_cert_files=options.ca_cert_files,
+ host_name=config.host_name)
+ pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)
+
+ if (options.http_cert_files and options.dirsrv_cert_files and
+ http_ca_cert != dirsrv_ca_cert):
+ raise RuntimeError("Apache Server SSL certificate and Directory "
+ "Server SSL certificate are not signed by the same"
+ " CA certificate")
+
installutils.verify_fqdn(config.host_name, options.no_host_dns)
installutils.verify_fqdn(config.master_host_name, options.no_host_dns)
installutils.check_creds(options, config.realm_name)
@@ -953,11 +1031,18 @@ def promote_check(installer):
if ca_host is not None:
config.ca_host_name = ca_host
ca_enabled = True
+ if options.dirsrv_cert_files:
+ root_logger.error("Certificates could not be provided when "
+ "CA is present on some master.")
+ sys.exit(3)
else:
- # FIXME: add way to pass in certificates
- root_logger.error("The remote master does not have a CA "
- "installed, can't proceed without certs")
- sys.exit(3)
+ ca_enabled = False
+ if not options.dirsrv_cert_files:
+ root_logger.error("Cannot issue certificates: a CA is not "
+ "installed. Use the --http-cert-file, "
+ "--dirsrv-cert-file options to provide "
+ "custom certificates.")
+ sys.exit(3)
config.kra_host_name = service.find_providing_server('KRA', conn,
api.env.server)
@@ -1015,6 +1100,12 @@ def promote_check(installer):
installer._fstore = fstore
installer._sstore = sstore
installer._config = config
+ installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file
+ installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info
+ installer._http_pkcs12_file = http_pkcs12_file
+ installer._http_pkcs12_info = http_pkcs12_info
+ installer._pkinit_pkcs12_file = pkinit_pkcs12_file
+ installer._pkinit_pkcs12_info = pkinit_pkcs12_info
@common_cleanup
@@ -1023,6 +1114,12 @@ def promote(installer):
fstore = installer._fstore
sstore = installer._sstore
config = installer._config
+ dirsrv_pkcs12_file = installer._dirsrv_pkcs12_file
+ dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
+ http_pkcs12_file = installer._http_pkcs12_file
+ http_pkcs12_info = installer._http_pkcs12_info
+ pkinit_pkcs12_file = installer._pkinit_pkcs12_file
+ pkinit_pkcs12_info = installer._pkinit_pkcs12_info
# Save client file and merge in server directives
target_fname = paths.IPA_DEFAULT_CONF
@@ -1049,7 +1146,8 @@ def promote(installer):
try:
# Configure dirsrv
- ds = install_replica_ds(config, options, promote=True)
+ ds = install_replica_ds(config, options, installer._ca_enabled,
+ promote=True, pkcs12_info=dirsrv_pkcs12_info)
# Always try to install DNS records
install_dns_records(config, options, api)
@@ -1082,7 +1180,8 @@ def promote(installer):
os.chmod(target_fname, 0o644) # must be readable for httpd
custodia = custodiainstance.CustodiaInstance(config.host_name,
- config.realm_name)
+ config.realm_name,
+ installer._ca_enabled)
custodia.create_replica(config.master_host_name)
krb = install_krb(config,
@@ -1091,7 +1190,8 @@ def promote(installer):
http = install_http(config,
auto_redirect=not options.no_ui_redirect,
- promote=True)
+ promote=True, pkcs12_info=http_pkcs12_info,
+ ca_is_configured=installer._ca_enabled)
# Apply any LDAP updates. Needs to be done after the replica is synced-up
service.print_msg("Applying LDAP updates")
@@ -1217,15 +1317,6 @@ class Replica(BaseServer):
external_ca = None
external_ca_type = None
external_cert_files = None
- dirsrv_cert_files = None
- http_cert_files = None
- pkinit_cert_files = None
- dirsrv_pin = None
- http_pin = None
- pkinit_pin = None
- dirsrv_cert_name = None
- http_cert_name = None
- pkinit_cert_name = None
ca_cert_files = None
subject = None
ca_signing_algorithm = None
@@ -1243,14 +1334,36 @@ class Replica(BaseServer):
self._top_dir = None
self._config = None
self._update_hosts_file = False
+ self._dirsrv_pkcs12_file = None
+ self._http_pkcs12_file = None
+ self._pkinit_pkcs12_file = None
+ self._dirsrv_pkcs12_info = None
+ self._http_pkcs12_info = None
+ self._pkinit_pkcs12_info = None
+
+ # pylint: disable=no-member
+
+ cert_file_req = (self.ca.dirsrv_cert_files, self.ca.http_cert_files)
+ cert_file_opt = (self.ca.pkinit_cert_files,)
if self.replica_file is None:
self.promote = True
+ # If any of the PKCS#12 options are selected, all are required.
+ if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
+ raise RuntimeError("--dirsrv-cert-file and --http-cert-file "
+ "are required if any PKCS#12 options are "
+ "used")
else:
if not ipautil.file_exists(self.replica_file):
raise RuntimeError("Replica file %s does not exist"
% self.replica_file)
+ if any(cert_file_req + cert_file_opt):
+ raise RuntimeError("You cannot specify any of "
+ "--dirsrv-cert-file, --http-cert-file, or "
+ "--pkinit-cert-file together with replica "
+ "file")
+
CLIKnob = collections.namedtuple('CLIKnob', ('value', 'name'))
conflicting_knobs = (
@@ -1274,7 +1387,6 @@ class Replica(BaseServer):
)
if self.setup_dns:
- #pylint: disable=no-member
if (not self.dns.forwarders and not self.dns.no_forwarders
and not self.dns.auto_forwarders):
raise RuntimeError(