diff options
-rw-r--r-- | install/conf/ipa-pki-proxy.conf | 4 | ||||
-rw-r--r-- | install/restart_scripts/renew_ca_cert | 13 | ||||
-rwxr-xr-x | install/tools/ipa-ca-install | 2 | ||||
-rwxr-xr-x | install/tools/ipa-replica-install | 31 | ||||
-rwxr-xr-x | install/tools/ipa-server-install | 37 | ||||
-rw-r--r-- | install/tools/ipa-upgradeconfig | 2 | ||||
-rw-r--r-- | ipapython/dogtag.py | 1 | ||||
-rw-r--r-- | ipaserver/install/cainstance.py | 410 | ||||
-rw-r--r-- | ipaserver/install/dogtaginstance.py | 311 | ||||
-rw-r--r-- | ipaserver/install/drminstance.py | 337 | ||||
-rw-r--r-- | ipaserver/install/installutils.py | 17 | ||||
-rw-r--r-- | ipaserver/install/ipa_replica_prepare.py | 1 |
12 files changed, 869 insertions, 297 deletions
diff --git a/install/conf/ipa-pki-proxy.conf b/install/conf/ipa-pki-proxy.conf index 224cdd45b..9a6345898 100644 --- a/install/conf/ipa-pki-proxy.conf +++ b/install/conf/ipa-pki-proxy.conf @@ -11,7 +11,7 @@ ProxyRequests Off </LocationMatch> # matches for admin port and installer -<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/rest/installer/installToken|^/ca/admin/ca/updateNumberRange|^/ca/rest/securityDomain/domainInfo|^/ca/rest/account/login|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/rest/account/logout|^/ca/rest/securityDomain/installToken"> +<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/rest/installer/installToken|^/ca/admin/ca/updateNumberRange|^/ca/rest/securityDomain/domainInfo|^/ca/rest/account/login|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/rest/account/logout|^/ca/rest/securityDomain/installToken|^/ca/admin/ca/updateConnector|^/ca/admin/ca/getSubsystemCert|^/kra/admin/kra/updateNumberRange|^/kra/admin/kra/getConfigEntries"> NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient none ProxyPassMatch ajp://localhost:$DOGTAG_PORT @@ -19,7 +19,7 @@ ProxyRequests Off </LocationMatch> # matches for agent port and eeca port -<LocationMatch "^/ca/agent/ca/displayBySerial|^/ca/agent/ca/doRevoke|^/ca/agent/ca/doUnrevoke|^/ca/agent/ca/updateDomainXML|^/ca/eeca/ca/profileSubmitSSLClient"> +<LocationMatch "^/ca/agent/ca/displayBySerial|^/ca/agent/ca/doRevoke|^/ca/agent/ca/doUnrevoke|^/ca/agent/ca/updateDomainXML|^/ca/eeca/ca/profileSubmitSSLClient|^/kra/agent/kra/connector"> NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient require ProxyPassMatch ajp://localhost:$DOGTAG_PORT diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert index 2663887d6..d9c98d5ce 100644 --- a/install/restart_scripts/renew_ca_cert +++ b/install/restart_scripts/renew_ca_cert @@ -21,17 +21,13 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import sys -import os import syslog -import tempfile -import shutil import traceback -from ipapython import dogtag, certmonger, ipautil +from ipapython import dogtag, ipautil from ipapython import services as ipaservices -from ipalib import api, errors, x509, util -from ipaserver.install import certs, cainstance, installutils -from ipaserver.plugins.ldap2 import ldap2 +from ipalib import api +from ipaserver.install import certs, cainstance def main(): nickname = sys.argv[1] @@ -68,9 +64,8 @@ def main(): syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname) sys.exit(1) - cainstance.update_cert_config(nickname, cert, configured_constants) - ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR) + ca.update_cert_config(nickname, cert, configured_constants) if ca.is_renewal_master(): cainstance.update_people_entry(cert) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 18c81dc1f..d4a287951 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -184,7 +184,7 @@ def main(): ipautil.realm_to_suffix(config.realm_name)) # This is done within stopped_service context, which restarts CA - CA.enable_client_auth_to_db() + CA.enable_client_auth_to_db(CA.dogtag_constants.CS_CFG_PATH) # Install CA DNS records install_dns_records(config, options) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index 41c1a0533..b79aeade2 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -38,9 +38,10 @@ from ipaserver.install import otpdinstance from ipaserver.install.replication import replica_conn_check, ReplicationManager from ipaserver.install.installutils import (ReplicaConfig, expand_replica_info, read_replica_info, get_host_name, BadHostError, private_ccache, - read_replica_info_dogtag_port) + read_replica_info_dogtag_port, read_replica_info_drm_enabled) from ipaserver.plugins.ldap2 import ldap2 from ipaserver.install import cainstance +from ipaserver.install import drminstance from ipalib import api, errors, util from ipalib.constants import CACERT from ipapython import version @@ -63,6 +64,8 @@ def parse_options(): basic_group = OptionGroup(parser, "basic options") basic_group.add_option("--setup-ca", dest="setup_ca", action="store_true", default=False, help="configure a dogtag CA") + basic_group.add_option("--setup-drm", dest="setup_drm", action="store_true", + default=False, help="configure a dogtag DRM") basic_group.add_option("--ip-address", dest="ip_address", type="ip", ip_local=True, help="Replica server IP Address") @@ -541,6 +544,15 @@ def main(): print 'CA cannot be installed in CA-less setup.' sys.exit(1) + config.setup_drm = options.setup_drm + if config.setup_drm: + if not config.setup_ca: + print "CA must be installed with the KRA" + sys.exit(1) + if not read_replica_info_drm_enabled(config.dir): + print "DRM is not installed on the master system" + sys.exit(1) + installutils.verify_fqdn(config.master_host_name, options.no_host_dns) # check connection @@ -574,6 +586,10 @@ def main(): else: fd.write("enable_ra=False\n") fd.write("ra_plugin=none\n") + if config.setup_drm: + fd.write("enable_drm=True\n") + else: + fd.write("enable_drm=False\n") fd.write("mode=production\n") fd.close() finally: @@ -684,7 +700,7 @@ def main(): ipautil.realm_to_suffix(config.realm_name)) # This is done within stopped_service context, which restarts CA - CA.enable_client_auth_to_db() + CA.enable_client_auth_to_db(CA.dogtag_constants.CS_CFG_PATH) krb = install_krb(config, setup_pkinit=options.setup_pkinit) http = install_http(config, auto_redirect=options.ui_redirect) @@ -707,9 +723,14 @@ def main(): service.print_msg("Applying LDAP updates") ds.apply_updates() - # Restart ds and krb after configurations have been changed - service.print_msg("Restarting the directory server") - ds.restart() + if options.setup_drm: + drm = drminstance.install_replica_drm(config) + service.print_msg("Restarting the directory server") + ds.restart() + drm.enable_client_auth_to_db(drm.dogtag_constants.DRM_CS_CFG_PATH) + else: + service.print_msg("Restarting the directory server") + ds.restart() service.print_msg("Restarting the KDC") krb.restart() diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index 232d84a2c..4aa6fcca5 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -3,7 +3,7 @@ # Simo Sorce <ssorce@redhat.com> # Rob Crittenden <rcritten@redhat.com> # -# Copyright (C) 2007-2010 Red Hat +# Copyright (C) 2007-2014 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify @@ -53,6 +53,7 @@ from ipaserver.install import httpinstance from ipaserver.install import ntpinstance from ipaserver.install import certs from ipaserver.install import cainstance +from ipaserver.install import drminstance from ipaserver.install import memcacheinstance from ipaserver.install import otpdinstance from ipaserver.install import sysupgrade @@ -492,11 +493,19 @@ def uninstall(): dogtag_constants=dogtag_constants) if cads_instance.is_configured(): cads_instance.uninstall() - cainstance.stop_tracking_certificates(dogtag_constants) + + drm_instance = drminstance.DRMInstance( + api.env.realm, dogtag_constants=dogtag_constants) + drm_instance.stop_tracking_certificates(dogtag_constants) + if drm_instance.is_installed(): + drm_instance.uninstall() + ca_instance = cainstance.CAInstance( api.env.realm, certs.NSS_DIR, dogtag_constants=dogtag_constants) + ca_instance.stop_tracking_certificates(dogtag_constants) if ca_instance.is_configured(): ca_instance.uninstall() + bindinstance.BindInstance(fstore).uninstall() httpinstance.HTTPInstance(fstore).uninstall() krbinstance.KrbInstance(fstore).uninstall() @@ -755,6 +764,7 @@ def main(): setup_ca = False else: setup_ca = True + setup_drm = True # Figure out what external CA step we're in. See cainstance.py for more # info on the 3 states. @@ -771,6 +781,8 @@ def main(): print "This includes:" if setup_ca: print " * Configure a stand-alone CA (dogtag) for certificate management" + if setup_drm: + print " * Configure a stand-alone DRM (dogtag) for key storage" if options.conf_ntp: print " * Configure the Network Time Daemon (ntpd)" print " * Create and configure an instance of Directory Server" @@ -1017,6 +1029,7 @@ def main(): else: fd.write("enable_ra=False\n") fd.write("ra_plugin=none\n") + fd.write("enable_drm=%s\n" % setup_drm) fd.write("mode=production\n") fd.close() @@ -1118,7 +1131,7 @@ def main(): ipautil.realm_to_suffix(realm_name), ['caRenewalMaster']) # This is done within stopped_service context, which restarts CA - ca.enable_client_auth_to_db() + ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH) krb = krbinstance.KrbInstance(fstore) if options.pkinit_pkcs12: @@ -1195,6 +1208,17 @@ def main(): service.print_msg("Restarting the web server") http.restart() + if setup_drm: + # code to create drm here + drm = drminstance.DRMInstance(realm_name, + dogtag_constants=dogtag.install_constants) + drm.configure_instance(host_name, domain_name, dm_password, + dm_password, subject_base=options.subject) + + # This is done within stopped_service context, which restarts DRM + ds.restart() + drm.enable_client_auth_to_db(drm.dogtag_constants.DRM_CS_CFG_PATH) + # Set the admin user kerberos password ds.change_admin_password(admin_password) @@ -1247,9 +1271,10 @@ def main(): print "" if setup_ca: - print "Be sure to back up the CA certificate stored in /root/cacert.p12" - print "This file is required to create replicas. The password for this" - print "file is the Directory Manager password" + print "Be sure to back up the CA certificates stored in /root/cacert.p12" + print "and the DRM certificates stored in /root/drmcert.p12" + print "These files are required to create replicas. The password for these" + print "files is the Directory Manager password" else: print "In order for Firefox autoconfiguration to work you will need to" print "use a SSL signing certificate. See the IPA documentation for more details." diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig index 265d71c33..5f751becb 100644 --- a/install/tools/ipa-upgradeconfig +++ b/install/tools/ipa-upgradeconfig @@ -675,7 +675,7 @@ def certificate_renewal_update(ca): # Ok, now we need to stop tracking, then we can start tracking them # again with new configuration: - cainstance.stop_tracking_certificates(dogtag_constants) + ca.stop_tracking_certificates(dogtag_constants) if not sysupgrade.get_upgrade_state('dogtag', 'certificate_renewal_update_1'): diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py index f829b9340..8c6c8ff06 100644 --- a/ipapython/dogtag.py +++ b/ipapython/dogtag.py @@ -61,6 +61,7 @@ class Dogtag10Constants(object): PASSWORD_CONF_PATH = '%s/conf/password.conf' % PKI_ROOT SERVICE_PROFILE_DIR = '%s/ca/profiles/ca' % PKI_ROOT ALIAS_DIR = '/etc/pki/pki-tomcat/alias' + DRM_CS_CFG_PATH = '%s/conf/kra/CS.cfg' % PKI_ROOT SERVICE_NAME = 'pki_tomcatd' diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index f52870424..8d627efa3 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -19,51 +19,47 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import pwd +import array +import base64 +import binascii +import ConfigParser +import dbus +import httplib +import ldap import os -import sys +import pwd import re +import shutil +import stat +import subprocess +import sys +import syslog import time -import ldap -import base64 -import array import tempfile -import binascii -import shutil -import httplib import urllib import xml.dom.minidom -import stat -import syslog -import ConfigParser -import dbus -from ipapython import dogtag -from ipapython.certdb import get_ca_nickname -from ipapython import certmonger from ipalib import api from ipalib import pkcs10, x509 from ipalib import errors -from ipapython.dn import DN -import subprocess -import traceback +from ipapython import dogtag +from ipapython import certmonger from ipapython import ipautil from ipapython import services as ipaservices from ipapython import ipaldap -from ipaserver.install import service -from ipaserver.install import installutils -from ipaserver.install import dsinstance -from ipaserver.install import certs -from ipaserver.install.installutils import stopped_service -from ipaserver.plugins import ldap2 +from ipapython.certdb import get_ca_nickname +from ipapython.dn import DN from ipapython.ipa_log_manager import * -HTTPD_CONFD = "/etc/httpd/conf.d/" -DEFAULT_DSPORT = dogtag.install_constants.DS_PORT +from ipaserver.install import certs +from ipaserver.install import dsinstance +from ipaserver.install import installutils +from ipaserver.install import service +from ipaserver.install.dogtaginstance import DogtagInstance +from ipaserver.install.dogtaginstance import PKI_USER, DEFAULT_DSPORT +from ipaserver.plugins import ldap2 -PKI_USER = "pkiuser" -PKI_DS_USER = dogtag.install_constants.DS_USER # When IPA is installed with DNS support, this CNAME should hold all IPA # replicas with CA configured @@ -86,23 +82,6 @@ RootDNPwd= $PASSWORD ConfigFile = /usr/share/pki/ca/conf/database.ldif """ -def check_inst(): - """ - Validate that the appropriate dogtag/RHCS packages have been installed. - """ - - # Check for a couple of binaries we need - if not os.path.exists(dogtag.install_constants.SPAWN_BINARY): - return False - if not os.path.exists(dogtag.install_constants.DESTROY_BINARY): - return False - - # This is the template tomcat file for a CA - if not os.path.exists('/usr/share/pki/ca/conf/server.xml'): - return False - - return True - def get_preop_pin(instance_root, instance_name): # Only used for Dogtag 9 preop_pin = None @@ -282,7 +261,7 @@ class CADSInstance(service.Service): serverid = self.restore_state("serverid") # Just eat this state if it exists - running = self.restore_state("running") + _running = self.restore_state("running") if not enabled is None and not enabled: ipaservices.knownservices.dirsrv.disable() @@ -295,40 +274,14 @@ class CADSInstance(service.Service): dsdb.untrack_server_cert("Server-Cert") dsinstance.erase_ds_instance_data(serverid) - user_exists = self.restore_state("user_exists") + _user_exists = self.restore_state("user_exists") # At one time we removed this user on uninstall. That can potentially # orphan files, or worse, if another useradd runs in the intermim, # cause files to have a new owner. -def stop_tracking_certificates(dogtag_constants): - """Stop tracking our certificates. Called on uninstall. - """ - cmonger = ipaservices.knownservices.certmonger - ipaservices.knownservices.messagebus.start() - cmonger.start() - - for nickname in ['Server-Cert cert-pki-ca', - 'auditSigningCert cert-pki-ca', - 'ocspSigningCert cert-pki-ca', - 'subsystemCert cert-pki-ca']: - try: - certmonger.stop_tracking( - dogtag_constants.ALIAS_DIR, nickname=nickname) - except (ipautil.CalledProcessError, RuntimeError), e: - root_logger.error( - "certmonger failed to stop tracking certificate: %s" % str(e)) - - try: - certmonger.stop_tracking('/etc/httpd/alias', nickname='ipaCert') - except (ipautil.CalledProcessError, RuntimeError), e: - root_logger.error( - "certmonger failed to stop tracking certificate: %s" % str(e)) - cmonger.stop() - - -class CAInstance(service.Service): +class CAInstance(DogtagInstance): """ When using a dogtag CA the DS database contains just the server cert for DS. The mod_nss database will contain the RA agent @@ -349,19 +302,8 @@ class CAInstance(service.Service): if dogtag_constants is None: dogtag_constants = dogtag.configured_constants() - service.Service.__init__(self, - '%sd' % dogtag_constants.PKI_INSTANCE_NAME, - service_desc="certificate server" - ) - - self.dogtag_constants = dogtag_constants - self.realm = realm - self.dm_password = None - self.admin_password = None - self.fqdn = None - self.domain = None - self.pkcs12_info = None - self.clone = False + DogtagInstance.__init__(self, realm, "CA", "certificate server", + dogtag_constants) # for external CAs self.external = 0 @@ -370,23 +312,12 @@ class CAInstance(service.Service): self.cert_chain_file = None self.create_ra_agent_db = True - # The same database is used for mod_nss because the NSS context - # will already have been initialized by Apache by the time - # mod_python wants to do things. self.canickname = get_ca_nickname(realm) - self.basedn = DN(('o', 'ipaca')) - self.ca_agent_db = tempfile.mkdtemp(prefix = "tmp-") self.ra_agent_db = ra_db self.ra_agent_pwd = self.ra_agent_db + "/pwdfile.txt" - self.ds_port = DEFAULT_DSPORT - self.security_domain_name = "IPA" - self.server_root = dogtag_constants.SERVER_ROOT self.ra_cert = None self.requestId = None - def __del__(self): - shutil.rmtree(self.ca_agent_db, ignore_errors=True) - def is_installed(self): """ Installing with an external CA is a two-step process. This @@ -446,10 +377,10 @@ class CAInstance(service.Service): if not ipautil.dir_exists("/var/lib/pki-ca"): self.step("creating pki-ca instance", self.create_instance) self.step("configuring certificate server instance", self.__configure_instance) - self.step("stopping certificate server instance to update CS.cfg", self.__stop) + self.step("stopping certificate server instance to update CS.cfg", self.stop_instance) self.step("disabling nonces", self.__disable_nonce) self.step("set up CRL publishing", self.__enable_crl_publish) - self.step("starting certificate server instance", self.__start) + 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. if self.external != 1: @@ -464,9 +395,10 @@ class CAInstance(service.Service): self.step("enabling Subject Key Identifier", self.enable_subject_key_identifier) self.step("enabling CRL and OCSP extensions for certificates", self.__set_crl_ocsp_extensions) self.step("setting audit signing renewal to 2 years", self.set_audit_renewal) - self.step("configuring certificate server to start on boot", self.__enable) + self.step("configuring certificate server to start on boot", + self.enable) if not self.clone: - self.step("restarting certificate server", self.__restart_instance) + self.step("restarting certificate server", self.restart_instance) self.step("requesting RA certificate from CA", self.__request_ra_certificate) self.step("issuing RA agent certificate", self.__issue_ra_cert) self.step("adding RA agent as a trusted user", self.__configure_ra) @@ -475,22 +407,31 @@ class CAInstance(service.Service): if not self.clone: self.step("configure RA certificate renewal", self.configure_agent_renewal) self.step("configure Server-Cert certificate renewal", self.track_servercert) - self.step("Configure HTTP to proxy connections", self.__http_proxy) + self.step("Configure HTTP to proxy connections", + self.http_proxy) self.start_creation(runtime=210) - def __stop(self): - self.stop() + def enable(self): + DogtagInstance.enable(self) + + def start_instance(self): + DogtagInstance.start_instance(self) - def __start(self): - self.start() + def stop_instance(self): + DogtagInstance.stop_instance(self) + def restart_instance(self): + DogtagInstance.restart_instance(self) + + def http_proxy(self): + DogtagInstance.http_proxy(self) def __spawn_instance(self): """ Create and configure a new CA instance using pkispawn. - pkispawn requires a configuration file with IPA-specific - parameters. + Creates the config file with IPA specific parameters + and passes it to the base class to call pkispawn """ # Create an empty and secured file @@ -512,7 +453,7 @@ class CAInstance(service.Service): config.set("CA", "pki_backup_password", self.admin_password) # Client security database - config.set("CA", "pki_client_database_dir", self.ca_agent_db) + config.set("CA", "pki_client_database_dir", self.agent_db) config.set("CA", "pki_client_database_password", self.admin_password) config.set("CA", "pki_client_database_purge", "False") config.set("CA", "pki_client_pkcs12_password", self.admin_password) @@ -589,21 +530,8 @@ class CAInstance(service.Service): with open(cfg_file, "wb") as f: config.write(f) - # Define the things we don't want logged - nolog = (self.admin_password, self.dm_password,) - - args = ["/usr/sbin/pkispawn", "-s", "CA", "-f", cfg_file ] - - with open(cfg_file) as f: - root_logger.debug( - 'Contents of pkispawn configuration file (%s):\n%s' % - (cfg_file, ipautil.nolog_replace(f.read(), nolog))) - try: - ipautil.run(args, nolog=nolog) - except ipautil.CalledProcessError, e: - root_logger.critical("failed to configure ca instance %s" % e) - raise RuntimeError('Configuration of CA failed') + DogtagInstance.spawn_instance(self, cfg_file) finally: os.remove(cfg_file) @@ -645,14 +573,6 @@ class CAInstance(service.Service): ] ipautil.run(args, env={'PKI_HOSTNAME':self.fqdn}) - def __enable(self): - self.backup_state("enabled", self.is_enabled()) - # We do not let the system start IPA components on its own, - # Instead we reply on the IPA init script to start only enabled - # components as found in our LDAP configuration tree - # We need to install DS before we can actually ldap_enable a service. - # so actual enablement is delayed. - def __create_ca_user(self): try: pwd.getpwnam(PKI_USER) @@ -678,7 +598,7 @@ class CAInstance(service.Service): args = ["/usr/bin/perl", "/usr/bin/pkisilent", "ConfigureCA", "-cs_hostname", self.fqdn, "-cs_port", str(self.dogtag_constants.ADMIN_SECURE_PORT), - "-client_certdb_dir", self.ca_agent_db, + "-client_certdb_dir", self.agent_db, "-client_certdb_pwd", self.admin_password, "-preop_pin" , preop_pin, "-domain_name", self.security_domain_name, @@ -777,14 +697,6 @@ class CAInstance(service.Service): root_logger.debug("completed creating ca instance") - def __restart_instance(self): - try: - self.restart(self.dogtag_constants.PKI_INSTANCE_NAME) - except Exception: - # TODO: roll back here? - root_logger.debug(traceback.format_exc()) - root_logger.critical("Failed to restart the certificate server. See the installation log for details.") - def __disable_nonce(self): # Turn off Nonces update_result = installutils.update_file( @@ -804,7 +716,7 @@ class CAInstance(service.Service): # Look thru the cert chain to get all the certs we need to add # trust for - p = subprocess.Popen(["/usr/bin/certutil", "-d", self.ca_agent_db, + p = subprocess.Popen(["/usr/bin/certutil", "-d", self.agent_db, "-O", "-n", "ipa-ca-agent"], stdout=subprocess.PIPE) chain = p.stdout.read() @@ -823,7 +735,7 @@ class CAInstance(service.Service): self.__run_certutil( ['-M', '-t', 'CT,C,C', '-n', nick], - database=self.ca_agent_db, pwd_file=self.admin_password) + database=self.agent_db, pwd_file=self.admin_password) finally: os.remove(admin_name) @@ -839,12 +751,12 @@ class CAInstance(service.Service): '-v', '-n', 'ipa-ca-agent', '-p', self.admin_password, - '-d', self.ca_agent_db, + '-d', self.agent_db, '-r', '/ca/agent/ca/profileReview?requestId=%s' % self.requestId, '%s' % ipautil.format_netloc( self.fqdn, self.dogtag_constants.AGENT_SECURE_PORT), ] - (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) + (stdout, _stderr, _returncode) = ipautil.run(args, nolog=(self.admin_password,)) data = stdout.split(self.dogtag_constants.RACERT_LINE_SEP) params = get_defList(data) @@ -860,13 +772,13 @@ class CAInstance(service.Service): '-v', '-n', 'ipa-ca-agent', '-p', self.admin_password, - '-d', self.ca_agent_db, + '-d', self.agent_db, '-e', params, '-r', '/ca/agent/ca/profileProcess', '%s' % ipautil.format_netloc( self.fqdn, self.dogtag_constants.AGENT_SECURE_PORT), ] - (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) + (stdout, _stderr, _returncode) = ipautil.run(args, nolog=(self.admin_password,)) data = stdout.split(self.dogtag_constants.RACERT_LINE_SEP) outputList = get_outputList(data) @@ -971,7 +883,7 @@ class CAInstance(service.Service): os.close(f) os.chmod(self.ra_agent_pwd, stat.S_IRUSR) - (stdout, stderr, returncode) = self.__run_certutil(["-N"]) + (_stdout, _stderr, _returncode) = self.__run_certutil(["-N"]) def __get_ca_chain(self): try: @@ -989,7 +901,7 @@ class CAInstance(service.Service): ipautil.run(["/usr/bin/pk12util", "-n", "ipa-ca-agent", "-o", "/root/ca-agent.p12", - "-d", self.ca_agent_db, + "-d", self.agent_db, "-k", pwd_name, "-w", pwd_name]) finally: @@ -1007,7 +919,7 @@ class CAInstance(service.Service): # makes openssl throw up. data = base64.b64decode(chain) - (certlist, stderr, returncode) = ipautil.run(["/usr/bin/openssl", + (certlist, _stderr, _returncode) = ipautil.run(["/usr/bin/openssl", "pkcs7", "-inform", "DER", @@ -1029,7 +941,7 @@ class CAInstance(service.Service): (chain_fd, chain_name) = tempfile.mkstemp() os.write(chain_fd, certlist[st:en+25]) os.close(chain_fd) - (rdn, subject_dn) = certs.get_cert_nickname(certlist[st:en+25]) + (_rdn, subject_dn) = certs.get_cert_nickname(certlist[st:en+25]) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: @@ -1051,7 +963,10 @@ class CAInstance(service.Service): # Generate our CSR. The result gets put into stdout try: - (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", str(DN(('CN', 'IPA RA'), self.subject_base)), "-z", noise_name, "-a"]) + (stdout, _stderr, _returncode) = self.__run_certutil( + ["-R", "-k", "rsa", "-g", "2048", "-s", + str(DN(('CN', 'IPA RA'), self.subject_base)), + "-z", noise_name, "-a"]) finally: os.remove(noise_name) @@ -1266,73 +1181,30 @@ class CAInstance(service.Service): 'OU=pki-ipa, O=IPA', str(self.subject_base)): print "Updating subject_base in CA template failed" - def enable_client_auth_to_db(self): - """ - Enable client auth connection to the internal db. - """ - caconfig = dogtag.install_constants.CS_CFG_PATH - - with stopped_service(self.dogtag_constants.SERVICE_NAME, - instance_name=self.dogtag_constants.PKI_INSTANCE_NAME): - - # Enable file publishing, disable LDAP - installutils.set_directive(caconfig, - 'authz.instance.DirAclAuthz.ldap.ldapauth.authtype', - 'SslClientAuth', quotes=False, separator='=') - installutils.set_directive(caconfig, - 'authz.instance.DirAclAuthz.ldap.ldapauth.bindDN', - 'uid=pkidbuser,ou=people,o=ipa-ca', quotes=False, separator='=') - installutils.set_directive(caconfig, - 'authz.instance.DirAclAuthz.ldap.ldapauth.clientCertNickname', - 'subsystemCert cert-pki-ca', quotes=False, separator='=') - installutils.set_directive(caconfig, - 'authz.instance.DirAclAuthz.ldap.ldapconn.port', - str(dogtag.install_constants.DS_SECURE_PORT), - quotes=False, separator='=') - installutils.set_directive(caconfig, - 'authz.instance.DirAclAuthz.ldap.ldapconn.secureConn', - 'true', quotes=False, separator='=') - - installutils.set_directive(caconfig, 'internaldb.ldapauth.authtype', - 'SslClientAuth', quotes=False, separator='=') - installutils.set_directive(caconfig, 'internaldb.ldapauth.bindDN', - 'uid=pkidbuser,ou=people,o=ipa-ca', quotes=False, separator='=') - installutils.set_directive(caconfig, - 'internaldb.ldapauth.clientCertNickname', - 'subsystemCert cert-pki-ca', quotes=False, separator='=') - installutils.set_directive(caconfig, 'internaldb.ldapconn.port', - str(dogtag.install_constants.DS_SECURE_PORT), - quotes=False, separator='=') - installutils.set_directive(caconfig, - 'internaldb.ldapconn.secureConn', 'true', quotes=False, - separator='=') - def uninstall(self): - if self.is_configured(): - self.print_msg("Unconfiguring CA") - enabled = self.restore_state("enabled") if not enabled is None and not enabled: self.disable() - try: - if self.dogtag_constants.DOGTAG_VERSION >= 10: - ipautil.run(["/usr/sbin/pkidestroy", "-i", - self.dogtag_constants.PKI_INSTANCE_NAME, - "-s", "CA"]) - else: + if self.dogtag_constants.DOGTAG_VERSION >= 10: + DogtagInstance.uninstall(self) + else: + if self.is_configured(): + self.print_msg("Unconfiguring CA") + + try: ipautil.run(["/usr/bin/pkiremove", "-pki_instance_root=/var/lib", "-pki_instance_name=%s" % self.dogtag_constants.PKI_INSTANCE_NAME, "--force"]) - except ipautil.CalledProcessError, e: - root_logger.critical("failed to uninstall CA instance %s" % e) + except ipautil.CalledProcessError, e: + root_logger.critical("failed to uninstall CA instance %s" % e) # At one time we removed this user on uninstall. That can potentially # orphan files, or worse, if another useradd runs in the intermim, # cause files to have a new owner. - user_exists = self.restore_state("user_exists") + _user_exists = self.restore_state("user_exists") ipaservices.knownservices.messagebus.start() cmonger = ipaservices.knownservices.certmonger @@ -1365,23 +1237,12 @@ class CAInstance(service.Service): def publish_ca_cert(self, location): args = ["-L", "-n", self.canickname, "-a"] - (cert, err, returncode) = self.__run_certutil(args) + (cert, _err, _returncode) = self.__run_certutil(args) fd = open(location, "w+") fd.write(cert) fd.close() os.chmod(location, 0444) - def __http_proxy(self): - template_filename = ipautil.SHARE_DIR + "ipa-pki-proxy.conf" - sub_dict = dict( - DOGTAG_PORT=self.dogtag_constants.AJP_PORT, - CLONE='' if self.clone else '#', - FQDN=self.fqdn, - ) - template = ipautil.template_file(template_filename, sub_dict) - with open(HTTPD_CONFD + "ipa-pki-proxy.conf", "w") as fd: - fd.write(template) - def configure_certmonger_renewal(self): """ Create a new CA type for certmonger that will retrieve updated @@ -1425,24 +1286,14 @@ class CAInstance(service.Service): 'Unable to determine PIN for CA instance: %s' % e) def configure_renewal(self): - pin = self.__get_ca_pin() + """ + Configure system certificates for renewal. + """ + nicknames = ['auditSigningCert cert-pki-ca', + 'ocspSigningCert cert-pki-ca', + 'subsystemCert cert-pki-ca'] - # Server-Cert cert-pki-ca is renewed per-server - for nickname in ['auditSigningCert cert-pki-ca', - 'ocspSigningCert cert-pki-ca', - 'subsystemCert cert-pki-ca']: - try: - certmonger.dogtag_start_tracking( - ca='dogtag-ipa-ca-renew-agent', - nickname=nickname, - pin=pin, - pinfile=None, - secdir=self.dogtag_constants.ALIAS_DIR, - pre_command='stop_pkicad', - post_command='renew_ca_cert "%s"' % nickname) - except (ipautil.CalledProcessError, RuntimeError), e: - root_logger.error( - "certmonger failed to start tracking certificate: %s" % e) + DogtagInstance.configure_renewal(self, nicknames) def track_servercert(self): """ @@ -1464,6 +1315,26 @@ class CAInstance(service.Service): root_logger.error( "certmonger failed to start tracking certificate: %s" % e) + def stop_tracking_certificates(self, dogtag_constants): + """Stop tracking our certificates. Called on uninstall. + """ + nicknames = ['Server-Cert cert-pki-ca', + 'auditSigningCert cert-pki-ca', + 'ocspSigningCert cert-pki-ca', + 'subsystemCert cert-pki-ca'] + DogtagInstance.stop_tracking_certificates( + self, dogtag_constants, nicknames) + + cmonger = ipaservices.knownservices.certmonger + ipaservices.knownservices.messagebus.start() + cmonger.start() + try: + certmonger.stop_tracking('/etc/httpd/alias', nickname='ipaCert') + except (ipautil.CalledProcessError, RuntimeError), e: + root_logger.error( + "certmonger failed to stop tracking certificate: %s" % str(e)) + cmonger.stop() + def enable_subject_key_identifier(self): """ See if Subject Key Identifier is set in the profile and if not, add it. @@ -1518,13 +1389,14 @@ class CAInstance(service.Service): """ # Check the default validity period of the audit signing cert # and set it to 2 years if it is 6 months. - range = installutils.get_directive( + cert_range = installutils.get_directive( '%s/caSignedLogCert.cfg' % self.dogtag_constants.SERVICE_PROFILE_DIR, 'policyset.caLogSigningSet.2.default.params.range', separator='=' ) - root_logger.debug('caSignedLogCert.cfg profile validity range is %s' % range) - if range == "180": + root_logger.debug( + 'caSignedLogCert.cfg profile validity range is %s' % cert_range) + if cert_range == "180": installutils.set_directive( '%s/caSignedLogCert.cfg' % self.dogtag_constants.SERVICE_PROFILE_DIR, 'policyset.caLogSigningSet.2.default.params.range', @@ -1549,15 +1421,39 @@ class CAInstance(service.Service): dn = DN(('cn', 'CA'), ('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) - filter = '(ipaConfigString=caRenewalMaster)' + renewal_filter = '(ipaConfigString=caRenewalMaster)' try: - self.admin_conn.get_entries(base_dn=dn, filter=filter, + self.admin_conn.get_entries(base_dn=dn, filter=renewal_filter, attrs_list=[]) except errors.NotFound: return False return True + def update_cert_config(self, nickname, cert, dogtag_constants=None): + """ + When renewing a CA subsystem certificate the configuration file + needs to get the new certificate as well. + + nickname is one of the known nicknames. + cert is a DER-encoded certificate. + """ + + if dogtag_constants is None: + dogtag_constants = dogtag.configured_constants() + + # The cert directive to update per nickname + directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', + 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert', + 'caSigningCert cert-pki-ca': 'ca.signing.cert', + 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', + 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'} + + DogtagInstance.update_cert_config( + self, nickname, cert, directives, + dogtag.configured_constants().CS_CFG_PATH, + dogtag_constants) + def replica_ca_install_check(config): if not config.setup_ca: @@ -1644,11 +1540,6 @@ def install_replica_ca(config, postinstall=False): if ca.is_installed(): sys.exit("A CA is already configured on this system.") - pkcs12_info = None - if ipautil.file_exists(config.dir + "/dogtagcert.p12"): - pkcs12_info = (config.dir + "/dogtagcert.p12", - config.dir + "/dirsrv_pin.txt") - ca = CAInstance(config.realm_name, certs.NSS_DIR, dogtag_constants=dogtag.install_constants) if postinstall: @@ -1687,33 +1578,6 @@ def install_replica_ca(config, postinstall=False): return ca -def update_cert_config(nickname, cert, dogtag_constants=None): - """ - When renewing a CA subsystem certificate the configuration file - needs to get the new certificate as well. - - nickname is one of the known nicknames. - cert is a DER-encoded certificate. - """ - - if dogtag_constants is None: - dogtag_constants = dogtag.configured_constants() - - # The cert directive to update per nickname - directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', - 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert', - 'caSigningCert cert-pki-ca': 'ca.signing.cert', - 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', - 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'} - - with stopped_service(dogtag_constants.SERVICE_NAME, - instance_name=dogtag_constants.PKI_INSTANCE_NAME): - - installutils.set_directive(dogtag.configured_constants().CS_CFG_PATH, - directives[nickname], - base64.b64encode(cert), - quotes=False, separator='=') - def update_people_entry(dercert): """ Update the userCerticate for an entry in the dogtag ou=People. This @@ -1749,11 +1613,11 @@ def update_people_entry(dercert): conn.connect( bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) - filter = conn.make_filter( + db_filter = conn.make_filter( {'description': ';%s;%s' % (issuer, subject)}, exact=False, trailing_wildcard=False) try: - entries = conn.get_entries(base_dn, conn.SCOPE_SUBTREE, filter) + entries = conn.get_entries(base_dn, conn.SCOPE_SUBTREE, db_filter) except errors.NotFound: entries = [] diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py new file mode 100644 index 000000000..b482d8e08 --- /dev/null +++ b/ipaserver/install/dogtaginstance.py @@ -0,0 +1,311 @@ +# Authors: Ade Lee <alee@redhat.com> +# +# Copyright (C) 2014 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import base64 +import os +import shutil +import tempfile +import traceback + +from ipapython import certmonger +from ipapython import dogtag +from ipapython import ipautil +from ipapython import services as ipaservices +from ipapython.dn import DN +from ipaserver.install import service +from ipaserver.install import installutils +from ipaserver.install.installutils import stopped_service +from ipapython.ipa_log_manager import * + +HTTPD_CONFD = "/etc/httpd/conf.d/" +DEFAULT_DSPORT = dogtag.install_constants.DS_PORT + +PKI_USER = "pkiuser" +PKI_DS_USER = dogtag.install_constants.DS_USER + + +def check_inst(subsystem): + """ + Validate that the appropriate dogtag/RHCS packages have been installed. + """ + + # Check for a couple of binaries we need + if not os.path.exists(dogtag.install_constants.SPAWN_BINARY): + return False + if not os.path.exists(dogtag.install_constants.DESTROY_BINARY): + return False + + # This is the template tomcat file for a DRM + if not os.path.exists('/usr/share/pki/%s/conf/server.xml' % subsystem): + return False + + return True + +class DogtagInstance(service.Service): + """ + This is the base class for a Dogtag 10+ instance, which uses a + shared tomcat instance and DS to host the relevant subsystems. + + It contains functions that will be common to installations of the + CA, KRA, and eventually TKS and TPS. + """ + + def __init__(self, realm, subsystem, service_desc, dogtag_constants=None): + if dogtag_constants is None: + dogtag_constants = dogtag.configured_constants() + + service.Service.__init__(self, + '%sd' % dogtag_constants.PKI_INSTANCE_NAME, + service_desc=service_desc + ) + + self.dogtag_constants = dogtag_constants + self.realm = realm + self.dm_password = None + self.admin_password = None + self.fqdn = None + self.domain = None + self.pkcs12_info = None + self.clone = False + + self.basedn = DN(('o', 'ipa%s' % subsystem.lower())) + self.agent_db = tempfile.mkdtemp(prefix = "tmp-") + self.ds_port = DEFAULT_DSPORT + self.server_root = dogtag_constants.SERVER_ROOT + self.subsystem = subsystem + self.security_domain_name = "IPA" + self.tracking_nicknames = None + + def __del__(self): + shutil.rmtree(self.agent_db, ignore_errors=True) + + def is_installed(self): + """ + Determine if subsystem instance has been installed. + + Returns True/False + """ + return os.path.exists(os.path.join( + self.server_root, self.dogtag_constants.PKI_INSTANCE_NAME, + self.subsystem.lower())) + + def spawn_instance(self, cfg_file): + """ + Create and configure a new Dogtag instance using pkispawn. + Passes in a configuration file with IPA-specific + parameters. + """ + subsystem = self.subsystem + + # Define the things we don't want logged + nolog = (self.admin_password, self.dm_password,) + + args = ["/usr/sbin/pkispawn", + "-s", subsystem, + "-f", cfg_file ] + + with open(cfg_file) as f: + root_logger.debug( + 'Contents of pkispawn configuration file (%s):\n%s' % + (cfg_file, ipautil.nolog_replace(f.read(), nolog))) + + try: + ipautil.run(args, nolog=nolog) + except ipautil.CalledProcessError, e: + root_logger.critical("failed to configure %s instance %s" % + (subsystem, e)) + raise RuntimeError('Configuration of %s failed' % subsystem) + + def enable(self): + self.backup_state("enabled", self.is_enabled()) + + def restart_instance(self): + try: + self.restart(self.dogtag_constants.PKI_INSTANCE_NAME) + except Exception: + root_logger.debug(traceback.format_exc()) + root_logger.critical( + "Failed to restart the Dogtag instance." + "See the installation log for details.") + + def start_instance(self): + try: + self.start(self.dogtag_constants.PKI_INSTANCE_NAME) + except Exception: + root_logger.debug(traceback.format_exc()) + root_logger.critical( + "Failed to restart the Dogtag instance." + "See the installation log for details.") + + def stop_instance(self): + try: + self.stop(self.dogtag_constants.PKI_INSTANCE_NAME) + except Exception: + root_logger.debug(traceback.format_exc()) + root_logger.critical( + "Failed to restart the Dogtag instance." + "See the installation log for details.") + + def enable_client_auth_to_db(self, config): + """ + Enable client auth connection to the internal db. + Path to CS.cfg config file passed in. + """ + + with stopped_service(self.dogtag_constants.SERVICE_NAME, + instance_name=self.dogtag_constants.PKI_INSTANCE_NAME): + + installutils.set_directive(config, + 'authz.instance.DirAclAuthz.ldap.ldapauth.authtype', + 'SslClientAuth', quotes=False, separator='=') + installutils.set_directive(config, + 'authz.instance.DirAclAuthz.ldap.ldapauth.bindDN', + 'uid=pkidbuser,ou=people,o=ipaca', quotes=False, separator='=') + installutils.set_directive(config, + 'authz.instance.DirAclAuthz.ldap.ldapauth.clientCertNickname', + 'subsystemCert cert-pki-ca', quotes=False, separator='=') + installutils.set_directive(config, + 'authz.instance.DirAclAuthz.ldap.ldapconn.port', + str(dogtag.install_constants.DS_SECURE_PORT), + quotes=False, separator='=') + installutils.set_directive(config, + 'authz.instance.DirAclAuthz.ldap.ldapconn.secureConn', + 'true', quotes=False, separator='=') + + installutils.set_directive(config, 'internaldb.ldapauth.authtype', + 'SslClientAuth', quotes=False, separator='=') + installutils.set_directive(config, 'internaldb.ldapauth.bindDN', + 'uid=pkidbuser,ou=people,o=ipaca', quotes=False, separator='=') + installutils.set_directive(config, + 'internaldb.ldapauth.clientCertNickname', + 'subsystemCert cert-pki-ca', quotes=False, separator='=') + installutils.set_directive(config, 'internaldb.ldapconn.port', + str(dogtag.install_constants.DS_SECURE_PORT), + quotes=False, separator='=') + installutils.set_directive(config, + 'internaldb.ldapconn.secureConn', 'true', quotes=False, + separator='=') + + def uninstall(self): + if self.is_installed(): + self.print_msg("Unconfiguring %s" % self.subsystem) + + try: + ipautil.run(["/usr/sbin/pkidestroy", "-i", + self.dogtag_constants.PKI_INSTANCE_NAME, + "-s", self.subsystem]) + except ipautil.CalledProcessError, e: + root_logger.critical("failed to uninstall %s instance %s" + % (self.subsystem,e)) + + def http_proxy(self): + ''' Update the http proxy file ''' + template_filename = ipautil.SHARE_DIR + "ipa-pki-proxy.conf" + sub_dict = dict( + DOGTAG_PORT=self.dogtag_constants.AJP_PORT, + CLONE='' if self.clone else '#', + FQDN=self.fqdn, + ) + template = ipautil.template_file(template_filename, sub_dict) + with open(HTTPD_CONFD + "ipa-pki-proxy.conf", "w") as fd: + fd.write(template) + + def __get_pin(self): + try: + return certmonger.get_pin('internal', + dogtag_constants=self.dogtag_constants) + except IOError, e: + root_logger.debug( + 'Unable to determine PIN for DRM instance: %s' % str(e)) + raise RuntimeError(e) + + def configure_renewal(self, nicknames=None): + ''' Configure certmonger to renew system certs + + @param nickname: list of nicknames + ''' + cmonger = ipaservices.knownservices.certmonger + cmonger.enable() + ipaservices.knownservices.messagebus.start() + cmonger.start() + + pin = self.__get_pin() + + if nicknames is None: + nicknames = self.tracking_nicknames + + for nickname in nicknames: + try: + certmonger.dogtag_start_tracking( + ca='dogtag-ipa-ca-renew-agent', + nickname=nickname, + pin=pin, + pinfile=None, + secdir=self.dogtag_constants.ALIAS_DIR, + pre_command='stop_pkicad', + post_command='renew_ca_cert "%s"' % nickname) + except (ipautil.CalledProcessError, RuntimeError), e: + root_logger.error( + "certmonger failed to start tracking certificate: %s" % + str(e)) + + def stop_tracking_certificates(self, dogtag_constants, nicknames = None): + """Stop tracking our certificates. Called on uninstall. + """ + cmonger = ipaservices.knownservices.certmonger + ipaservices.knownservices.messagebus.start() + cmonger.start() + + if nicknames is None: + nicknames = self.tracking_nicknames + + for nickname in nicknames: + try: + certmonger.stop_tracking( + dogtag_constants.ALIAS_DIR, nickname=nickname) + except (ipautil.CalledProcessError, RuntimeError), e: + root_logger.error( + "certmonger failed to stop tracking certificate: %s" + % str(e)) + + cmonger.stop() + + def update_cert_config(self, nickname, cert, directives, cs_cfg, + dogtag_constants=None): + """ + When renewing a DRM subsystem certificate the configuration file + needs to get the new certificate as well. + + nickname is one of the known nicknames. + cert is a DER-encoded certificate. + directives is the list of directives to be updated for the subsystem + cs_cfg is the path to the CS.cfg file + """ + + if dogtag_constants is None: + dogtag_constants = dogtag.configured_constants() + + with stopped_service(dogtag_constants.SERVICE_NAME, + instance_name=dogtag_constants.PKI_INSTANCE_NAME): + installutils.set_directive( + cs_cfg, + directives[nickname], + base64.b64encode(cert), + quotes=False, + separator='=') diff --git a/ipaserver/install/drminstance.py b/ipaserver/install/drminstance.py new file mode 100644 index 000000000..744b0973d --- /dev/null +++ b/ipaserver/install/drminstance.py @@ -0,0 +1,337 @@ +# Authors: Ade Lee <alee@redhat.com> +# +# Copyright (C) 2014 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import ConfigParser +import os +import pwd +import shutil +import sys +import tempfile + +from ipalib import api +from ipapython import dogtag +from ipapython import ipautil +from ipapython import services as ipaservices +from ipapython.dn import DN +from ipaserver.install import certs +from ipaserver.install import cainstance +from ipaserver.install import dsinstance +from ipaserver.install import service +from ipaserver.install.dogtaginstance import DogtagInstance +from ipaserver.install.dogtaginstance import DEFAULT_DSPORT, PKI_USER +from ipapython.ipa_log_manager import * + +# When IPA is installed with DNS support, this CNAME should hold all IPA +# replicas with DRM configured +IPA_DRM_RECORD = "ipa-drm" + +class DRMInstance(DogtagInstance): + """ + We assume that the CA has already been installed, and we use the + same tomcat instance to host both the CA and DRM. + The mod_nss database will contain the RA agent cert that will be used + to do authenticated requests against dogtag. The RA agent cert will + be the same for both the CA and DRM. + """ + + def __init__(self, realm, dogtag_constants=None): + if dogtag_constants is None: + dogtag_constants = dogtag.configured_constants() + + DogtagInstance.__init__(self, realm, "KRA", "DRM server", + dogtag_constants) + self.basedn = DN(('o', 'ipadrm')) + self.tracking_nicknames = ['auditSigningCert cert-pki-drm', + 'transportCert cert-pki-drm', + 'storageCert cert-pki-drm'] + + def configure_instance(self, host_name, domain, dm_password, + admin_password, ds_port=DEFAULT_DSPORT, + pkcs12_info=None, master_host=None, + master_replication_port=None, + subject_base=None): + """Create a DRM instance. + + To create a clone, pass in pkcs12_info. + """ + self.fqdn = host_name + self.domain = domain + self.dm_password = dm_password + self.admin_password = admin_password + self.ds_port = ds_port + self.pkcs12_info = pkcs12_info + if self.pkcs12_info is not None: + self.clone = True + self.master_host = master_host + self.master_replication_port = master_replication_port + if subject_base is None: + self.subject_base = DN(('O', self.realm)) + else: + self.subject_base = subject_base + + # Confirm that a DRM does not already exist + if self.is_installed(): + raise RuntimeError( + "DRM already installed.") + # Confirm that a Dogtag 10 CA instance already exists + ca = cainstance.CAInstance( + api.env.realm, certs.NSS_DIR, + dogtag_constants = dogtag.Dogtag10Constants) + if not ca.is_installed(): + raise RuntimeError( + "DRM configuration failed. " + "A Dogtag CA must be installed first") + + self.step("configuring DRM instance", self.__spawn_instance) + self.step("restarting DRM", self.restart_instance) + self.step("configure certificate renewals", self.configure_renewal) + self.step("Configure HTTP to proxy connections", + self.http_proxy) + + self.start_creation(runtime=210) + + def start_instance(self): + DogtagInstance.start_instance(self) + + def stop_instance(self): + DogtagInstance.stop_instance(self) + + def restart_instance(self): + DogtagInstance.restart_instance(self) + + def http_proxy(self): + DogtagInstance.http_proxy(self) + + def __spawn_instance(self): + """ + Create and configure a new DRM instance using pkispawn. + Creates a configuration file with IPA-specific + parameters and passes it to the base class to call pkispawn + """ + + # Create an empty and secured file + (cfg_fd, cfg_file) = tempfile.mkstemp() + os.close(cfg_fd) + pent = pwd.getpwnam(PKI_USER) + os.chown(cfg_file, pent.pw_uid, pent.pw_gid) + + # Create KRA configuration + config = ConfigParser.ConfigParser() + config.optionxform = str + config.add_section("KRA") + + # Security Domain Authentication + config.set("KRA", "pki_security_domain_https_port", "443") + config.set("KRA", "pki_security_domain_password", self.admin_password) + config.set("KRA", "pki_security_domain_user", "admin") + + # issuing ca + config.set("KRA", "pki_issuing_ca_uri", "https://%s" % + ipautil.format_netloc(self.fqdn, 443)) + + # Server + config.set("KRA", "pki_enable_proxy", "True") + config.set("KRA", "pki_restart_configured_instance", "False") + config.set("KRA", "pki_backup_keys", "True") + config.set("KRA", "pki_backup_password", self.admin_password) + + # Client security database + config.set("KRA", "pki_client_database_dir", self.agent_db) + config.set("KRA", "pki_client_database_password", self.admin_password) + config.set("KRA", "pki_client_database_purge", "False") + config.set("KRA", "pki_client_pkcs12_password", self.admin_password) + + # Administrator + config.set("KRA", "pki_admin_name", "admin") + config.set("KRA", "pki_admin_uid", "admin") + config.set("KRA", "pki_admin_email", "root@localhost") + config.set("KRA", "pki_admin_password", self.admin_password) + config.set("KRA", "pki_admin_nickname", "ipa-ca-agent") + config.set("KRA", "pki_admin_subject_dn", + str(DN(('cn', 'ipa-ca-agent'), self.subject_base))) + config.set("KRA", "pki_import_admin_cert", "True") + config.set("KRA", "pki_admin_cert_file", + "/root/.dogtag/pki-tomcat/ca_admin.cert") + config.set("KRA", "pki_client_admin_cert_p12", "/root/ca-agent.p12") + + # Directory server + config.set("KRA", "pki_ds_ldap_port", str(self.ds_port)) + config.set("KRA", "pki_ds_password", self.dm_password) + config.set("KRA", "pki_ds_base_dn", self.basedn) + config.set("KRA", "pki_ds_database", "ipakra") + + # Certificate subject DN's + config.set("KRA", "pki_subsystem_subject_dn", + str(DN(('cn', 'CA Subsystem'), self.subject_base))) + config.set("KRA", "pki_ssl_server_subject_dn", + str(DN(('cn', self.fqdn), self.subject_base))) + config.set("KRA", "pki_audit_signing_subject_dn", + str(DN(('cn', 'DRM Audit'), self.subject_base))) + config.set("KRA", "pki_transport_subject_dn", + str(DN(('cn', 'DRM Transport Certificate'), self.subject_base))) + config.set("KRA", "pki_storage_subject_dn", + str(DN(('cn', 'DRM Storage Certificate'), self.subject_base))) + + # Certificate nicknames + # Note that both the server certs and subsystem certs reuse + # the ca certs. + config.set("KRA", "pki_subsystem_nickname", + "subsystemCert cert-pki-ca") + config.set("KRA", "pki_ssl_server_nickname", + "Server-Cert cert-pki-ca") + config.set("KRA", "pki_audit_signing_nickname", + "auditSigningCert cert-pki-drm") + config.set("KRA", "pki_transport_nickname", + "transportCert cert-pki-drm") + config.set("KRA", "pki_storage_nickname", + "storageCert cert-pki-drm") + + # Shared db settings + # Needed because CA and KRA share the same database + # We will use the dbuser created for the CA + config.set("KRA", "pki_share_db", "True") + config.set("KRA", "pki_share_dbuser_dn", + str(DN(('uid', 'pkidbuser'),('ou', 'people'),('o','ipaca')))) + + + if (self.clone): + drmfile = self.pkcs12_info[0] + shutil.copy(drmfile, "/tmp/drm.p12") + pent = pwd.getpwnam(PKI_USER) + os.chown("/tmp/drm.p12", pent.pw_uid, pent.pw_gid) + + # Security domain registration + config.set("KRA", "pki_security_domain_hostname", self.master_host) + config.set("KRA", "pki_security_domain_https_port", "443") + config.set("KRA", "pki_security_domain_user", "admin") + config.set("KRA", "pki_security_domain_password", + self.admin_password) + + # Clone + config.set("KRA", "pki_clone", "True") + config.set("KRA", "pki_clone_pkcs12_path", "/tmp/drm.p12") + config.set("KRA", "pki_clone_pkcs12_password", self.dm_password) + config.set("KRA", "pki_clone_replication_security", "TLS") + config.set("KRA", "pki_clone_replication_master_port", + str(self.master_replication_port)) + config.set("KRA", "pki_clone_replication_clone_port", + dogtag.install_constants.DS_PORT) + config.set("KRA", "pki_clone_replicate_schema", "False") + config.set("KRA", "pki_clone_uri", + "https://%s" % ipautil.format_netloc(self.master_host, 443)) + + # Generate configuration file + with open(cfg_file, "wb") as f: + config.write(f) + + try: + DogtagInstance.spawn_instance(self, cfg_file) + finally: + os.remove(cfg_file) + + shutil.move("/var/lib/pki/pki-tomcat/alias/kra_backup_keys.p12", + "/root/kracert.p12") + + root_logger.debug("completed creating DRM instance") + + def update_cert_config(self, nickname, cert, dogtag_constants=None): + """ + When renewing a DRM subsystem certificate the configuration file + needs to get the new certificate as well. + + nickname is one of the known nicknames. + cert is a DER-encoded certificate. + """ + + if dogtag_constants is None: + dogtag_constants = dogtag.configured_constants() + + # The cert directive to update per nickname + directives = { + 'auditSigningCert cert-pki-drm': 'kra.audit_signing.cert', + 'storageCert cert-pki-drm': 'kra.storage.cert', + 'transportCert cert-pki-drm': 'kra.transport.cert', + 'subsystemCert cert-pki-drm': 'kra.subsystem.cert', + 'Server-Cert cert-pki-ca': 'kra.sslserver.cert'} + + DogtagInstance.update_cert_config( + self, nickname, cert, directives, + dogtag.configured_constants().DRM_CS_CFG_PATH, + dogtag_constants) + + +def install_replica_drm(config, postinstall=False): + """ + Install a DRM 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 DRM instance + """ + # note that the cacert.p12 file is regenerated during the + # ipa-replica-prepare process and should include all the certs + # for the CA and DRM + drmfile = config.dir + "/cacert.p12" + + if not ipautil.file_exists(drmfile): + raise RuntimeError( + "Unable to clone DRM." + " cacert.p12 file not found in replica file") + + drm = DRMInstance(config.realm_name, + dogtag_constants=dogtag.install_constants) + drm.dm_password = config.dirman_password + drm.subject_base = config.subject_base + if drm.is_installed(): + sys.exit("A DRM is already configured on this system.") + + drm.configure_instance(config.host_name, config.domain_name, + config.dirman_password, config.dirman_password, + pkcs12_info=(drmfile,), + master_host=config.master_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 + if postinstall: + ipaservices.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 + + service.print_msg("Restarting the directory and DRM servers") + drm.stop(dogtag.install_constants.PKI_INSTANCE_NAME) + ipaservices.knownservices.dirsrv.restart() + drm.start(dogtag.install_constants.PKI_INSTANCE_NAME) + + return drm + +if __name__ == "__main__": + standard_logging_setup("install.log") + ds = dsinstance.DsInstance() + + drm = DRMInstance("EXAMPLE.COM") + drm.configure_instance("drmtest.example.com", "example.com", + "password", "password") diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 7f15d3769..32cf6bb70 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -554,6 +554,23 @@ def read_replica_info_dogtag_port(config_dir): return dogtag_master_ds_port +def read_replica_info_drm_enabled(config_dir): + """ + Check the replica info to determine if a DRM has been installed + on the master + """ + default_file = config_dir + "/default.conf" + if not ipautil.file_exists(default_file): + return False + else: + with open(default_file) as fd: + config = SafeConfigParser() + config.readfp(fd) + + enable_drm = bool(config.get("global", "enable_drm")) + return enable_drm + + def check_server_configuration(): """ Check if IPA server is configured on the system. diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py index e71dd22e4..df3c1a17b 100644 --- a/ipaserver/install/ipa_replica_prepare.py +++ b/ipaserver/install/ipa_replica_prepare.py @@ -370,6 +370,7 @@ class ReplicaPrepare(admintool.AdminTool): cacert_filename = "/var/kerberos/krb5kdc/cacert.pem" if ipautil.file_exists(cacert_filename): self.copy_info_file(cacert_filename, "cacert.pem") + self.copy_info_file("/etc/ipa/default.conf", "default.conf") def save_config(self): self.log.info("Finalizing configuration") |