install: merge all CA install code paths into one

Merge CA install code paths use in ipa-server-install, ipa-replica-install
in either domain level and ipa-ca-install into one.

https://fedorahosted.org/freeipa/ticket/6392

Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Jan Cholasta
2016-10-24 14:33:19 +02:00
parent 0e232b5f52
commit dc38d53de1
4 changed files with 111 additions and 263 deletions

View File

@@ -25,11 +25,10 @@ import tempfile
from ipapython import ipautil
from ipaserver.install import installutils
from ipaserver.install import certs
from ipaserver.install.installutils import create_replica_config
from ipaserver.install.installutils import check_creds, ReplicaConfig
from ipaserver.install import bindinstance, dsinstance, ca
from ipaserver.install import cainstance, custodiainstance, service
from ipaserver.install import dsinstance, ca
from ipaserver.install import cainstance, service
from ipapython import version
from ipalib import api
from ipalib.constants import DOMAIN_LEVEL_0
@@ -175,26 +174,7 @@ def install_replica(safe_options, options, filename):
options.ca_cert_file = None
ca.install_check(True, config, options)
if options.promote:
ca_data = (os.path.join(config.dir, 'cacert.p12'),
config.dirman_password)
custodia = custodiainstance.CustodiaInstance(config.host_name,
config.realm_name)
custodia.get_ca_keys(config.ca_host_name, ca_data[0], ca_data[1])
CA = cainstance.CAInstance(config.realm_name, certs.NSS_DIR,
host_name=config.host_name)
CA.configure_replica(config.ca_host_name,
config.dirman_password,
subject_base=config.subject_base,
ca_cert_bundle=ca_data)
# Install CA DNS records
if bindinstance.dns_container_exists(api.env.host, api.env.basedn,
ldapi=True, realm=api.env.realm):
bind = bindinstance.BindInstance()
bind.update_system_records()
else:
ca.install(True, config, options)
ca.install(True, config, options)
def install_master(safe_options, options):

View File

@@ -4,7 +4,9 @@
from __future__ import print_function
from ipaserver.install import cainstance, dsinstance, bindinstance
import os.path
from ipaserver.install import cainstance, custodiainstance, dsinstance, bindinstance
from ipapython import ipautil, certdb
from ipapython.admintool import ScriptError
from ipaplatform import services
@@ -31,8 +33,8 @@ def install_check(standalone, replica_config, options):
if standalone and api.env.ra_plugin == 'selfsign':
raise ScriptError('A selfsign CA can not be added')
if ((not options.promote
and not ipautil.file_exists(replica_config.dir + "/cacert.p12"))):
cafile = os.path.join(replica_config.dir, 'cacert.p12')
if not options.promote and not ipautil.file_exists(cafile):
raise ScriptError('CA cannot be installed in CA-less setup.')
if standalone and not options.skip_conncheck:
@@ -42,10 +44,10 @@ def install_check(standalone, replica_config, options):
replica_config.ca_ds_port, options.admin_password,
principal=principal, ca_cert_file=options.ca_cert_file)
if options.skip_schema_check or options.promote:
if options.skip_schema_check:
root_logger.info("Skipping CA DS schema check")
else:
cainstance.replica_ca_install_check(replica_config)
cainstance.replica_ca_install_check(replica_config, options.promote)
return
@@ -119,40 +121,70 @@ def install_step_0(standalone, replica_config, options):
realm_name = options.realm_name
dm_password = options.dm_password
host_name = options.host_name
subject_base = options.subject
if replica_config is not None:
# Configure the CA if necessary
cainstance.install_replica_ca(replica_config, standalone,
ra_p12=getattr(options, 'ra_p12', None))
return
if replica_config is None:
subject_base = options.subject
if options.external_cert_files:
external = 2
elif options.external_ca:
external = 1
ca_signing_algorithm = options.ca_signing_algorithm
if options.external_ca:
ca_type = options.external_ca_type
csr_file = paths.ROOT_IPA_CSR
else:
ca_type = None
csr_file = None
if options.external_cert_files:
cert_file = external_cert_file.name
cert_chain_file = external_ca_file.name
else:
cert_file = None
cert_chain_file = None
pkcs12_info = None
master_host = None
master_replication_port = None
ra_p12 = None
promote = False
else:
external = 0
cafile = os.path.join(replica_config.dir, 'cacert.p12')
if options.promote:
custodia = custodiainstance.CustodiaInstance(
replica_config.host_name,
replica_config.realm_name)
custodia.get_ca_keys(
replica_config.ca_host_name,
cafile,
replica_config.dirman_password)
ca = cainstance.CAInstance(realm_name, certs.NSS_DIR)
if standalone:
subject_base = replica_config.subject_base
ca_signing_algorithm = None
ca_type = None
csr_file = None
cert_file = None
cert_chain_file = None
pkcs12_info = (cafile,)
master_host = replica_config.ca_host_name
master_replication_port = replica_config.ca_ds_port
ra_p12 = os.path.join(replica_config.dir, 'ra.p12')
promote = options.promote
ca = cainstance.CAInstance(realm_name, certs.NSS_DIR,
host_name=host_name)
if standalone or replica_config is not None:
ca.create_ra_agent_db = False
if external == 0:
ca.configure_instance(host_name, dm_password,
dm_password, subject_base=subject_base,
ca_signing_algorithm=options.ca_signing_algorithm)
elif external == 1:
ca.configure_instance(host_name, dm_password,
dm_password, csr_file=paths.ROOT_IPA_CSR,
subject_base=subject_base,
ca_signing_algorithm=options.ca_signing_algorithm,
ca_type=options.external_ca_type)
else:
ca.configure_instance(host_name, dm_password, dm_password,
cert_file=external_cert_file.name,
cert_chain_file=external_ca_file.name,
subject_base=subject_base,
ca_signing_algorithm=options.ca_signing_algorithm)
ca.configure_instance(host_name, dm_password, dm_password,
subject_base=subject_base,
ca_signing_algorithm=ca_signing_algorithm,
ca_type=ca_type,
csr_file=csr_file,
cert_file=cert_file,
cert_chain_file=cert_chain_file,
pkcs12_info=pkcs12_info,
master_host=master_host,
master_replication_port=master_replication_port,
ra_p12=ra_p12,
promote=promote)
def install_step_1(standalone, replica_config, options):
@@ -165,15 +197,7 @@ def install_step_1(standalone, replica_config, options):
ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, host_name=host_name)
if standalone:
ca.stop('pki-tomcat')
# We need to ldap_enable the CA now that DS is up and running
if replica_config is None:
config = ['caRenewalMaster']
else:
config = []
ca.ldap_enable('CA', host_name, dm_password, basedn, config)
ca.stop('pki-tomcat')
# This is done within stopped_service context, which restarts CA
ca.enable_client_auth_to_db(paths.CA_CS_CFG_PATH)
@@ -185,8 +209,9 @@ def install_step_1(standalone, replica_config, options):
#
ca.setup_lightweight_ca_key_retrieval()
serverid = installutils.realm_to_serverid(realm_name)
if standalone and replica_config is None:
serverid = installutils.realm_to_serverid(realm_name)
dirname = dsinstance.config_dirname(serverid)
# Store the new IPA CA cert chain in DS NSS database and LDAP
@@ -207,8 +232,6 @@ def install_step_1(standalone, replica_config, options):
cert, nickname, trust_flags[nickname],
config_ipa=True, config_compat=True)
installutils.restart_dirsrv()
# Store DS CA cert in Dogtag NSS database
dogtagdb = certs.CertDB(realm_name, nssdir=paths.PKI_TOMCAT_ALIAS_DIR)
trust_flags = dict(reversed(dsdb.list_certs()))
@@ -218,12 +241,14 @@ def install_step_1(standalone, replica_config, options):
cert = dsdb.get_cert_from_db(nickname)
dogtagdb.add_cert(cert, nickname, trust_flags[nickname])
installutils.restart_dirsrv()
ca.start('pki-tomcat')
# We need to restart apache as we drop a new config file in there
services.knownservices.httpd.restart(capture_output=True)
if standalone:
ca.start('pki-tomcat')
# We need to restart apache as we drop a new config file in there
services.knownservices.httpd.restart(capture_output=True)
# Install CA DNS records
if bindinstance.dns_container_exists(host_name, basedn, dm_password):
bind = bindinstance.BindInstance()

View File

@@ -57,7 +57,6 @@ from ipapython.certdb import get_ca_nickname
from ipapython.dn import DN
from ipapython.ipa_log_manager import log_mgr,\
standard_logging_setup, root_logger
from ipapython.admintool import ScriptError
from ipapython.secrets.kem import IPAKEMKeys
from ipaserver.install import certs
@@ -65,7 +64,6 @@ from ipaserver.install import dsinstance
from ipaserver.install import installutils
from ipaserver.install import ldapupdate
from ipaserver.install import replication
from ipaserver.install import service
from ipaserver.install import sysupgrade
from ipaserver.install.dogtaginstance import (export_kra_agent_pem,
DogtagInstance)
@@ -332,7 +330,7 @@ class CAInstance(DogtagInstance):
cert_file=None, cert_chain_file=None,
master_replication_port=None,
subject_base=None, ca_signing_algorithm=None,
ca_type=None, ra_p12=None):
ca_type=None, ra_p12=None, promote=False):
"""Create a CA instance.
To create a clone, pass in pkcs12_info.
@@ -345,6 +343,7 @@ class CAInstance(DogtagInstance):
self.fqdn = host_name
self.dm_password = dm_password
self.admin_user = "admin"
self.admin_groups = ADMIN_GROUPS
self.admin_password = admin_password
self.pkcs12_info = pkcs12_info
if self.pkcs12_info is not None:
@@ -363,6 +362,7 @@ class CAInstance(DogtagInstance):
self.ca_type = ca_type
else:
self.ca_type = 'generic'
self.no_db_setup = promote
# Determine if we are installing as an externally-signed CA and
# what stage we're in.
@@ -375,6 +375,11 @@ class CAInstance(DogtagInstance):
self.external = 2
self.step("creating certificate server user", create_ca_user)
if promote:
# Setup Database
self.step("creating certificate server db", self.__create_ds_db)
self.step("setting up initial replication", self.__setup_replication)
self.step("creating installation admin user", self.setup_admin)
self.step("configuring certificate server instance",
self.__spawn_instance)
self.step("stopping certificate server instance to update CS.cfg", self.stop_instance)
@@ -382,6 +387,8 @@ class CAInstance(DogtagInstance):
self.step("disabling nonces", self.__disable_nonce)
self.step("set up CRL publishing", self.__enable_crl_publish)
self.step("enable PKIX certificate path discovery and validation", self.enable_pkix)
if promote:
self.step("destroying installation admin user", self.teardown_admin)
self.step("starting certificate server instance", self.start_instance)
# Step 1 of external is getting a CSR so we don't need to do these
# steps until we get a cert back from the external CA.
@@ -397,7 +404,7 @@ class CAInstance(DogtagInstance):
self.step("exporting RA agent certificate",
lambda: export_kra_agent_pem())
self.step("adding RA agent as a trusted user", self.__create_ca_agent)
elif ra_p12 is not None:
elif not promote and ra_p12 is not None:
self.step("importing RA certificate from PKCS #12 file",
lambda: self.import_ra_cert(ra_p12, configure_renewal=False))
self.step("authorizing RA to modify profiles", configure_profiles_acl)
@@ -410,14 +417,20 @@ class CAInstance(DogtagInstance):
self.step("Configure HTTP to proxy connections",
self.http_proxy)
self.step("restarting certificate server", self.restart_instance)
self.step("migrating certificate profiles to LDAP",
migrate_profiles_to_ldap)
self.step("importing IPA certificate profiles",
import_included_profiles)
self.step("adding default CA ACL", ensure_default_caacl)
self.step("adding 'ipa' CA entry", ensure_ipa_authority_entry)
if not promote:
self.step("migrating certificate profiles to LDAP",
migrate_profiles_to_ldap)
self.step("importing IPA certificate profiles",
import_included_profiles)
self.step("adding default CA ACL", ensure_default_caacl)
self.step("adding 'ipa' CA entry", ensure_ipa_authority_entry)
self.step("updating IPA configuration", update_ipa_conf)
self.step("enabling CA instance", self.__enable_instance)
self.step("configuring certmonger renewal for lightweight CAs",
self.__add_lightweight_ca_tracking_requests)
self.start_creation(runtime=210)
def __spawn_instance(self):
@@ -1170,94 +1183,13 @@ class CAInstance(DogtagInstance):
# Activate Topology for o=ipaca segments
self.__update_topology()
def __client_auth_to_db(self):
self.enable_client_auth_to_db(paths.CA_CS_CFG_PATH)
def __restart_http_instance(self):
# We need to restart apache as we drop a new config file in there
services.knownservices.httpd.restart(capture_output=True)
def __enable_instance(self):
basedn = ipautil.realm_to_suffix(self.realm)
self.ldap_enable('CA', self.fqdn, None, basedn)
def configure_replica(self, master_host, dm_password, subject_base=None,
ca_cert_bundle=None, ca_signing_algorithm=None,
ca_type=None):
"""Creates a replica CA, creating a local DS backend and using
the topology plugin to manage replication.
Requires domain_level >= DOMAIN_LEVEL_1 and custodia on the master.
"""
self.master_host = master_host
self.dm_password = dm_password
self.master_replication_port = 389
if subject_base is None:
self.subject_base = DN(('O', self.realm))
if not self.clone:
config = ['caRenewalMaster']
else:
self.subject_base = subject_base
if ca_signing_algorithm is None:
self.ca_signing_algorithm = 'SHA256withRSA'
else:
self.ca_signing_algorithm = ca_signing_algorithm
if ca_type is not None:
self.ca_type = ca_type
else:
self.ca_type = 'generic'
self.admin_groups = ADMIN_GROUPS
self.pkcs12_info = ca_cert_bundle
self.no_db_setup = True
self.clone = True
# TODO: deal with "Externally signed CA setups"
# Set up steps
self.step("creating certificate server user", create_ca_user)
# Setup Database
self.step("creating certificate server db", self.__create_ds_db)
self.step("setting up initial replication", self.__setup_replication)
self.step("creating installation admin user", self.setup_admin)
# Setup instance
self.step("setting up certificate server", self.__spawn_instance)
self.step("stopping instance to update CS.cfg", self.stop_instance)
self.step("backing up CS.cfg", self.backup_config)
self.step("disabling nonces", self.__disable_nonce)
self.step("set up CRL publishing", self.__enable_crl_publish)
self.step("enable PKIX certificate path discovery and validation",
self.enable_pkix)
self.step("set up client auth to db", self.__client_auth_to_db)
self.step("destroying installation admin user", self.teardown_admin)
self.step("Ensure lightweight CAs container exists",
ensure_lightweight_cas_container)
self.step("Configure lightweight CA key retrieval",
self.setup_lightweight_ca_key_retrieval)
self.step("starting instance", self.start_instance)
self.step("importing CA chain to RA certificate database",
self.__import_ca_chain)
self.step("setting up signing cert profile", self.__setup_sign_profile)
self.step("setting audit signing renewal to 2 years",
self.set_audit_renewal)
self.step("configure certificate renewals",
self.configure_renewal)
self.step("configure Server-Cert certificate renewal",
self.track_servercert)
self.step("Configure HTTP to proxy connections",
self.http_proxy)
self.step("updating IPA configuration", update_ipa_conf)
self.step("Restart HTTP server to pick up changes",
self.__restart_http_instance)
self.step("enabling CA instance", self.__enable_instance)
self.step("configuring certmonger renewal for lightweight CAs",
self.__add_lightweight_ca_tracking_requests)
self.start_creation(runtime=210)
config = []
self.ldap_enable('CA', self.fqdn, None, basedn, config)
def setup_lightweight_ca_key_retrieval(self):
if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'):
@@ -1334,18 +1266,8 @@ class CAInstance(DogtagInstance):
"Did not find any lightweight CAs; nothing to track")
def replica_ca_install_check(config):
if not config.setup_ca:
return
cafile = config.dir + "/cacert.p12"
if not ipautil.file_exists(cafile):
# Replica of old "self-signed" master - CA won't be installed
return
if config.ca_ds_port != 7389:
root_logger.debug(
'Installing CA Replica from master with a merged database')
def replica_ca_install_check(config, promote):
if promote:
return
# Check if the master has the necessary schema in its CA instance
@@ -1381,73 +1303,6 @@ def replica_ca_install_check(config):
exit('IPA schema missing on master CA directory server')
def install_replica_ca(config, postinstall=False, ra_p12=None):
"""
Install a CA on a replica.
There are two modes of doing this controlled:
- While the replica is being installed
- Post-replica installation
config is a ReplicaConfig object
Returns a tuple of the CA and CADS instances
"""
cafile = config.dir + "/cacert.p12"
if not ipautil.file_exists(cafile):
# Replica of old "self-signed" master - skip installing CA
return None
ca = CAInstance(config.realm_name, certs.NSS_DIR)
ca.dm_password = config.dirman_password
ca.subject_base = config.subject_base
if not config.setup_ca:
# We aren't configuring the CA in this step but we still need
# a minimum amount of information on the CA for this IPA install.
return ca
if ca.is_installed():
raise ScriptError("A CA is already configured on this system.")
if postinstall:
# If installing this afterward the Apache NSS database already
# exists, don't remove it.
ca.create_ra_agent_db = False
ca.configure_instance(config.host_name,
config.dirman_password, config.dirman_password,
pkcs12_info=(cafile,), ra_p12=ra_p12,
master_host=config.ca_host_name,
master_replication_port=config.ca_ds_port,
subject_base=config.subject_base)
# Restart httpd since we changed it's config and added ipa-pki-proxy.conf
# Without the restart, CA service status check would fail due to missing
# proxy
if postinstall:
services.knownservices.httpd.restart()
# The dogtag DS instance needs to be restarted after installation.
# The procedure for this is: stop dogtag, stop DS, start DS, start
# dogtag
#
#
# The service_name trickery is due to the service naming we do
# internally. In the case of the dogtag DS the name doesn't match the
# unix service.
service.print_msg("Restarting the directory and certificate servers")
ca.stop('pki-tomcat')
installutils.restart_dirsrv()
ca.start('pki-tomcat')
return ca
def backup_config():
"""
Create a backup copy of CS.cfg

View File

@@ -820,10 +820,6 @@ def install(installer):
options.realm_name = config.realm_name
options.domain_name = config.domain_name
options.host_name = config.host_name
if ca_enabled:
options.ra_p12 = config.dir + "/ra.p12"
ca.install_step_0(False, config, options)
krb = install_krb(config, setup_pkinit=not options.no_pkinit)
@@ -1043,6 +1039,7 @@ def promote_check(installer):
config.master_host_name = api.env.server
config.ca_host_name = api.env.ca_host
config.kra_host_name = config.ca_host_name
config.ca_ds_port = 389
config.setup_ca = options.setup_ca
config.setup_kra = options.setup_kra
config.dir = installer._top_dir
@@ -1295,7 +1292,7 @@ def promote_check(installer):
options.realm_name = config.realm_name
options.host_name = config.host_name
options.subject = config.subject_base
ca.install_check(False, None, options)
ca.install_check(False, config, options)
if config.setup_kra:
try:
@@ -1510,16 +1507,7 @@ def promote(installer):
options.domain_name = config.domain_name
options.host_name = config.host_name
options.dm_password = config.dirman_password
ca_data = (os.path.join(config.dir, 'cacert.p12'),
config.dirman_password)
custodia.get_ca_keys(config.ca_host_name, ca_data[0], ca_data[1])
ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR,
host_name=config.host_name)
ca.configure_replica(config.ca_host_name,
config.dirman_password,
subject_base=config.subject_base,
ca_cert_bundle=ca_data)
ca.install(False, config, options)
if options.setup_kra:
ca_data = (os.path.join(config.dir, 'kracert.p12'),