summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2014-06-16 10:41:57 +0200
committerPetr Viktorin <pviktori@redhat.com>2014-07-30 16:04:21 +0200
commitd27e77adc56f5a04f3bdd1aaed5440a89ed3acad (patch)
tree2b1128a264eec58603a467521daefe7b2b75a9be /install
parent8bbdfff102849c0f573e56530a734643a568e0dd (diff)
downloadfreeipa-d27e77adc56f5a04f3bdd1aaed5440a89ed3acad.tar.gz
freeipa-d27e77adc56f5a04f3bdd1aaed5440a89ed3acad.tar.xz
freeipa-d27e77adc56f5a04f3bdd1aaed5440a89ed3acad.zip
Allow upgrading CA-less to CA-full using ipa-ca-install.
Part of https://fedorahosted.org/freeipa/ticket/3737 Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Diffstat (limited to 'install')
-rwxr-xr-xinstall/tools/ipa-ca-install231
-rw-r--r--install/tools/man/ipa-ca-install.18
2 files changed, 222 insertions, 17 deletions
diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 3c9307edf..fc8941248 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -22,6 +22,7 @@ import sys
import socket
import os, shutil
+from ConfigParser import RawConfigParser
from ipapython import ipautil
@@ -29,15 +30,17 @@ from ipaserver.install import installutils, service
from ipaserver.install import certs
from ipaserver.install.installutils import (HostnameLocalhost, ReplicaConfig,
expand_replica_info, read_replica_info, get_host_name, BadHostError,
- private_ccache, read_replica_info_dogtag_port)
+ private_ccache, read_replica_info_dogtag_port, validate_external_cert)
from ipaserver.install import dsinstance, cainstance, bindinstance
from ipaserver.install.replication import replica_conn_check
from ipapython import version
-from ipalib import api, util
+from ipalib import api, util, certstore, x509
+from ipalib.constants import CACERT
from ipapython.dn import DN
from ipapython.config import IPAOptionParser
from ipapython import sysrestore
from ipapython import dogtag
+from ipapython import certdb
from ipapython.ipa_log_manager import *
from ipaplatform import services
from ipaplatform.paths import paths
@@ -63,14 +66,34 @@ def parse_options():
default=False, help="skip check for updated CA DS schema on the remote master")
parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
default=False, help="unattended installation never prompts the user")
+ parser.add_option("--external-ca", dest="external_ca", action="store_true",
+ default=False, help="Generate a CSR to be signed by an external CA")
+ parser.add_option("--external_cert_file", dest="external_cert_file",
+ help="PEM file containing a certificate signed by the external CA")
+ parser.add_option("--external_ca_file", dest="external_ca_file",
+ help="PEM file containing the external CA chain")
options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)
- if len(args) != 1:
- parser.error("you must provide a file generated by ipa-replica-prepare")
+ if args:
+ filename = args[0]
- return safe_options, options, args[0]
+ if len(args) != 1:
+ parser.error("you must provide a file generated by "
+ "ipa-replica-prepare")
+ else:
+ filename = None
+
+ if options.external_ca:
+ if options.external_cert_file:
+ parser.error("You cannot specify --external_cert_file "
+ "together with --external-ca")
+ if options.external_ca_file:
+ parser.error("You cannot specify --external_ca_file together "
+ "with --external-ca")
+
+ return safe_options, options, filename
def get_dirman_password():
return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False)
@@ -83,20 +106,18 @@ def install_dns_records(config, options):
return
bind = bindinstance.BindInstance(dm_password=config.dirman_password)
+ disconnect = False
try:
- api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
- bind_pw=config.dirman_password)
+ if not api.Backend.ldap2.isconnected():
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
+ bind_pw=config.dirman_password)
+ disconnect = True
bind.add_ipa_ca_dns_records(config.host_name, config.domain_name)
finally:
- if api.Backend.ldap2.isconnected():
+ if api.Backend.ldap2.isconnected() and disconnect:
api.Backend.ldap2.disconnect()
-def main():
- safe_options, options, filename = parse_options()
-
- if os.geteuid() != 0:
- sys.exit("\nYou must be root to run this script.\n")
-
+def install_replica(safe_options, options, filename):
standard_logging_setup(log_file_name, debug=options.debug)
root_logger.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options))
@@ -204,6 +225,188 @@ def main():
root_logger.error(str(e))
sys.exit(1)
+def install_master(safe_options, options):
+ standard_logging_setup(paths.IPASERVER_CA_INSTALL_LOG, debug=options.debug)
+
+ root_logger.debug(
+ "%s was invoked with options: %s" % (sys.argv[0], safe_options))
+ root_logger.debug("IPA version %s" % version.VENDOR_VERSION)
+
+ global sstore
+ sstore = sysrestore.StateFile(paths.SYSRESTORE)
+
+ if not dsinstance.DsInstance().is_configured():
+ sys.exit("IPA server is not configured on this system.\n")
+
+ api.bootstrap(in_server=True)
+ api.finalize()
+
+ if api.env.enable_ra:
+ sys.exit("CA is already installed.\n")
+
+ dm_password = options.password
+ if not dm_password:
+ if options.unattended:
+ sys.exit('Directory Manager password required')
+ try:
+ dm_password = get_dirman_password()
+ except KeyboardInterrupt:
+ sys.exit(0)
+ if dm_password is None:
+ sys.exit("Directory Manager password required")
+
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
+ bind_pw=dm_password)
+
+ config = api.Command['config_show']()['result']
+ subject_base = config['ipacertificatesubjectbase'][0]
+
+ if options.external_ca:
+ if cainstance.is_step_one_done():
+ print ("CA is already installed.\nRun the installer with "
+ "--external-cert-file and --external-ca-file.")
+ sys.exit(1)
+ elif options.external_cert_file:
+ if not cainstance.is_step_one_done():
+ print ("CA is not installed yet. To install with an external CA "
+ "is a two-stage process.\nFirst run the installer with "
+ "--external-ca.")
+ sys.exit(1)
+
+ try:
+ validate_external_cert(options.external_cert_file,
+ options.external_ca_file, subject_base)
+ except ValueError, e:
+ print e
+ sys.exit(1)
+
+ if options.external_cert_file:
+ external = 2
+ elif options.external_ca:
+ external = 1
+ else:
+ external = 0
+
+ realm_name = api.env.realm
+ domain_name = api.env.domain
+ host_name = api.env.host
+
+ dirname = dsinstance.config_dirname(
+ dsinstance.realm_to_serverid(realm_name))
+ cadb = certs.CertDB(realm_name, subject_base=subject_base)
+ dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base)
+
+ for db in (cadb, dsdb):
+ for nickname, trust_flags in db.list_certs():
+ if nickname in (certdb.get_ca_nickname(realm_name),
+ 'ipaCert',
+ 'Signing-Cert'):
+ print ("Certificate with nickname %s is present in %s, "
+ "cannot continue." % (nickname, db.secdir))
+ sys.exit(1)
+
+ cert = db.get_cert_from_db(nickname)
+ if not cert:
+ continue
+ subject = DN(str(x509.get_subject(cert)))
+ if subject in (DN('CN=Certificate Authority', subject_base),
+ DN('CN=IPA RA', subject_base),
+ DN('CN=Object Signing Cert', subject_base)):
+ print ("Certificate with subject %s is present in %s, "
+ "cannot continue." % (subject, db.secdir))
+ sys.exit(1)
+
+ ca = cainstance.CAInstance(realm_name, certs.NSS_DIR,
+ dogtag_constants=dogtag.install_constants)
+ ca.create_ra_agent_db = False
+ if external == 0:
+ ca.configure_instance(host_name, domain_name, dm_password,
+ dm_password, subject_base=subject_base)
+ elif external == 1:
+ ca.configure_instance(host_name, domain_name, dm_password,
+ dm_password, csr_file=paths.ROOT_IPA_CSR,
+ subject_base=subject_base)
+ else:
+ ca.configure_instance(host_name, domain_name, dm_password,
+ dm_password,
+ cert_file=options.external_cert_file,
+ cert_chain_file=options.external_ca_file,
+ subject_base=subject_base)
+
+ ca.stop(ca.dogtag_constants.PKI_INSTANCE_NAME)
+
+ ca.ldap_enable('CA', host_name, dm_password,
+ ipautil.realm_to_suffix(realm_name), ['caRenewalMaster'])
+
+ ca.enable_client_auth_to_db()
+
+ # Install CA DNS records
+ config = ReplicaConfig()
+ config.realm_name = realm_name
+ config.domain_name = domain_name
+ config.host_name = config.master_host_name = host_name
+ config.dirman_password = dm_password
+ install_dns_records(config, options)
+
+ # We need to restart apache as we drop a new config file in there
+ services.knownservices.httpd.restart(capture_output=True)
+
+ # Update config file
+ parser = RawConfigParser()
+ parser.read(paths.IPA_DEFAULT_CONF)
+ parser.set('global', 'enable_ra', 'True')
+ parser.set('global', 'ra_plugin', 'dogtag')
+ parser.set('global', 'dogtag_version',
+ str(ca.dogtag_constants.DOGTAG_VERSION))
+ with open(paths.IPA_DEFAULT_CONF, 'w') as f:
+ parser.write(f)
+
+ # Store the new IPA CA cert chain in DS NSS database and LDAP
+ cadb = certs.CertDB(realm_name, subject_base=subject_base)
+ dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base)
+ trust_flags = dict(reversed(cadb.list_certs()))
+ trust_chain = cadb.find_root_cert('ipaCert')[:-1]
+ for nickname in trust_chain[:-1]:
+ cert = cadb.get_cert_from_db(nickname, pem=False)
+ dsdb.add_cert(cert, nickname, trust_flags[nickname])
+ certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn,
+ cert, nickname, trust_flags[nickname])
+
+ nickname = trust_chain[-1]
+ cert = cadb.get_cert_from_db(nickname, pem=False)
+ dsdb.add_cert(cert, nickname, trust_flags[nickname])
+ certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn,
+ cert, nickname, trust_flags[nickname],
+ config_ipa=True, config_compat=True)
+
+ # Restart DS
+ ds = dsinstance.DsInstance()
+ ds.init_info(realm_name, host_name, domain_name, dm_password, subject_base,
+ 1101, 1100, None)
+ ds.restart(ds.serverid)
+
+ # Store DS CA cert in Dogtag NSS database
+ dogtagdb = certs.CertDB(realm_name, nssdir=ca.dogtag_constants.ALIAS_DIR)
+ trust_flags = dict(reversed(dsdb.list_certs()))
+ server_certs = dsdb.find_server_certs()
+ trust_chain = dsdb.find_root_cert(server_certs[0][0])[:-1]
+ nickname = trust_chain[-1]
+ cert = dsdb.get_cert_from_db(nickname)
+ dogtagdb.add_cert(cert, nickname, trust_flags[nickname])
+
+ ca.start(ca.dogtag_constants.PKI_INSTANCE_NAME)
+
+def main():
+ safe_options, options, filename = parse_options()
+
+ if os.geteuid() != 0:
+ sys.exit("\nYou must be root to run this script.\n")
+
+ if filename is not None:
+ install_replica(safe_options, options, filename)
+ else:
+ install_master(safe_options, options)
+
fail_message = '''
Your system may be partly configured.
Run /usr/sbin/ipa-server-install --uninstall to clean up.
diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1
index 13ef43a80..2e0b0795a 100644
--- a/install/tools/man/ipa-ca-install.1
+++ b/install/tools/man/ipa-ca-install.1
@@ -1,4 +1,4 @@
-.\" A man page for ipa-replica-install
+.\" A man page for ipa-ca-install
.\" Copyright (C) 2011 Red Hat, Inc.
.\"
.\" This program is free software; you can redistribute it and/or modify
@@ -18,13 +18,15 @@
.\"
.TH "ipa-ca-install" "1" "Jun 17 2011" "FreeIPA" "FreeIPA Manual Pages"
.SH "NAME"
-ipa\-ca\-install \- Install a CA on a replica
+ipa\-ca\-install \- Install a CA on a server
.SH "SYNOPSIS"
-ipa\-ca\-install [\fIOPTION\fR]... replica_file
+ipa\-ca\-install [\fIOPTION\fR]... [replica_file]
.SH "DESCRIPTION"
Adds a CA as an IPA\-managed service. This requires that the IPA server is already installed and configured.
The replica_file is created using the ipa\-replica\-prepare utility and should be the same one used when originally installing the replica.
+
+Alternatively, you can run ipa\-ca\-install without replica_file to upgrade from CA-less to CA-full.
.SH "OPTIONS"
\fB\-d\fR, \fB\-\-debug\fR
Enable debug logging when more verbose output is needed