A dogtag replica file is created as usual. When the replica is installed dogtag is optional and not installed by default. Adding the --setup-ca option will configure it when the replica is installed.

A new tool ipa-ca-install will configure dogtag if it wasn't configured when the replica was initially installed.


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

See the ticket for testing suggestions.

rob
>From b8f0a609557f1d15ab8b83ef7db350cac6693b59 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Fri, 17 Jun 2011 16:47:39 -0400
Subject: [PATCH] Make dogtag an optional (and default un-) installed component in a replica.

A dogtag replica file is created as usual. When the replica is installed
dogtag is optional and not installed by default. Adding the --setup-ca
option will configure it when the replica is installed.

A new tool ipa-ca-install will configure dogtag if it wasn't configured
when the replica was initially installed.

https://fedorahosted.org/freeipa/ticket/1251
---
 freeipa.spec.in                    |    4 +
 install/tools/Makefile.am          |    1 +
 install/tools/ipa-ca-install       |  276 ++++++++++++++++++++++++++++++++++++
 install/tools/ipa-replica-install  |   47 ++----
 install/tools/man/ipa-ca-install.1 |   49 +++++++
 ipaserver/install/cainstance.py    |    4 +-
 ipaserver/install/certs.py         |    3 +-
 ipaserver/install/replication.py   |   33 +++++
 8 files changed, 384 insertions(+), 33 deletions(-)
 create mode 100755 install/tools/ipa-ca-install
 create mode 100644 install/tools/man/ipa-ca-install.1

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 36281f8..3451589 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -356,6 +356,7 @@ fi
 %files server
 %defattr(-,root,root,-)
 %doc COPYING README Contributors.txt
+%{_sbindir}/ipa-ca-install
 %{_sbindir}/ipa-dns-install
 %{_sbindir}/ipa-server-install
 %{_sbindir}/ipa-replica-conncheck
@@ -498,6 +499,9 @@ fi
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
 
 %changelog
+* Fri Jun 17 2011 Rob Crittenden <rcrit...@redhat.com> - 2.0.90-4
+- Ship ipa-ca-install utility
+
 * Thu May 12 2011 Rob Crittenden <rcrit...@redhat.com> - 2.0.90-3
 - Set min nvr of selinux-policy to 3.9.16-18 on F-15+
 - Set min nvr of pki-ca to 9.0.7 on F-15+
diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
index 9004bb2..c6ecd92 100644
--- a/install/tools/Makefile.am
+++ b/install/tools/Makefile.am
@@ -5,6 +5,7 @@ SUBDIRS = 			\
         $(NULL)
 
 sbin_SCRIPTS =			\
+	ipa-ca-install		\
 	ipa-dns-install		\
 	ipa-server-install	\
 	ipa-replica-conncheck	\
diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
new file mode 100755
index 0000000..5f02d37
--- /dev/null
+++ b/install/tools/ipa-ca-install
@@ -0,0 +1,276 @@
+#! /usr/bin/python -E
+# Authors: Rob Crittenden <rcrit...@redhat.com>
+#
+# Copyright (C) 2011  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 sys
+import socket
+
+import tempfile, os, traceback, logging, shutil
+from ConfigParser import SafeConfigParser
+
+from ipapython import ipautil
+
+from ipaserver.install import installutils, service
+from ipaserver.install import certs
+from ipaserver.install.installutils import HostnameLocalhost
+from ipaserver.install import dsinstance, cainstance
+from ipaserver.install.replication import replica_conn_check
+from ipapython import version
+from ipalib import api, util
+from ipapython.config import IPAOptionParser
+from ipapython import sysrestore
+
+CACERT="/etc/ipa/ca.crt"
+REPLICA_INFO_TOP_DIR=None
+
+class ReplicaConfig:
+    def __init__(self):
+        self.realm_name = ""
+        self.domain_name = ""
+        self.master_host_name = ""
+        self.dirman_password = ""
+        self.host_name = ""
+        self.dir = ""
+        self.subject_base = ""
+
+def parse_options():
+    usage = "%prog [options] REPLICA_FILE"
+    parser = IPAOptionParser(usage=usage, version=version.VERSION)
+    parser.add_option("-d", "--debug", dest="debug", action="store_true",
+                      default=False, help="gather extra debugging information")
+    parser.add_option("-p", "--password", dest="password", sensitive=True,
+                      help="Directory Manager (existing master) password")
+    parser.add_option("-w", "--admin-password", dest="admin_password", sensitive=True,
+                      help="Admin user Kerberos password used for connection check")
+    parser.add_option("--no-host-dns", dest="no_host_dns", action="store_true",
+                      default=False,
+                      help="Do not use DNS for hostname lookup during installation")
+    parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true",
+                      default=False, help="skip connection check to remote master")
+    parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
+                      default=False, help="unattended installation never prompts the user")
+
+    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")
+
+    return safe_options, options, args[0]
+
+def get_dirman_password():
+    return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False)
+
+def expand_info(filename, password):
+    top_dir = tempfile.mkdtemp("ipa")
+    tarfile = top_dir+"/files.tar"
+    dir = top_dir + "/realm_info"
+    ipautil.decrypt_file(filename, tarfile, password, top_dir)
+    ipautil.run(["tar", "xf", tarfile, "-C", top_dir])
+    os.remove(tarfile)
+
+    return top_dir, dir
+
+def read_info(dir, rconfig):
+    filename = dir + "/realm_info"
+    fd = open(filename)
+    config = SafeConfigParser()
+    config.readfp(fd)
+
+    rconfig.realm_name = config.get("realm", "realm_name")
+    rconfig.master_host_name = config.get("realm", "master_host_name")
+    rconfig.domain_name = config.get("realm", "domain_name")
+    rconfig.host_name = config.get("realm", "destination_host")
+    rconfig.subject_base = config.get("realm", "subject_base")
+
+def get_host_name(no_host_dns):
+    hostname = installutils.get_fqdn()
+    try:
+        installutils.verify_fqdn(hostname, no_host_dns)
+    except RuntimeError, e:
+        logging.error(str(e))
+        sys.exit(1)
+
+    return hostname
+
+def install_ca(config):
+    # FIXME, need to pass along the CA plugin to use
+    cafile = config.dir + "/cacert.p12"
+
+    if not ipautil.file_exists(cafile):
+        # not a dogtag CA replica
+        sys.exit('Not a dogtag CA installation')
+
+    ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR)
+    ca.dm_password = config.dirman_password
+    ca.subject_base = config.subject_base
+    if ca.is_installed():
+        sys.exit("A CA is already configured on this system.")
+
+    if not cainstance.check_inst():
+        print "A CA was specified but the dogtag certificate server"
+        print "is not installed on the system"
+        print "Please install dogtag and restart the setup program"
+        sys.exit(1)
+
+    pkcs12_info = None
+    if ipautil.file_exists(config.dir + "/dogtagcert.p12"):
+        pkcs12_info = (config.dir + "/dogtagcert.p12",
+                       config.dir + "/dirsrv_pin.txt")
+    cs = cainstance.CADSInstance()
+    cs.create_instance(config.realm_name, config.host_name,
+                       config.domain_name, config.dirman_password,
+                       pkcs12_info)
+    cs.load_pkcs12()
+    cs.enable_ssl()
+    cs.restart_instance()
+    ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR)
+    ca.create_ra_agent_db = False
+    ca.configure_instance(config.host_name, config.dirman_password,
+                          config.dirman_password, pkcs12_info=(cafile,),
+                          master_host=config.master_host_name,
+                          subject_base=config.subject_base)
+
+    # 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_name = cs.service_name
+    service.print_msg("Restarting the directory and certificate servers")
+    cs.service_name = "dirsrv"
+    ca.stop()
+    cs.stop("PKI-IPA")
+    cs.start("PKI-IPA")
+    ca.start()
+    cs.service_name = service_name
+
+    return (ca, cs)
+
+def main():
+    safe_options, options, filename = parse_options()
+    installutils.standard_logging_setup("/var/log/ipareplica-ca-install.log", options.debug)
+    logging.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options))
+
+    if not ipautil.file_exists(filename):
+        sys.exit("Replica file %s does not exist" % filename)
+
+    global sstore
+    sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore')
+
+    if not dsinstance.DsInstance().is_configured():
+        sys.exit("IPA server is not configured on this system.\n")
+
+    # get the directory manager password
+    dirman_password = options.password
+    if not dirman_password:
+        if options.unattended:
+            sys.exit('Directory Manager password required')
+        try:
+            dirman_password = get_dirman_password()
+        except KeyboardInterrupt:
+            sys.exit(0)
+
+    if not options.admin_password and not options.skip_conncheck and \
+        options.unattended:
+            sys.exit('admin password required')
+
+    try:
+        top_dir, dir = expand_info(filename, dirman_password)
+        global REPLICA_INFO_TOP_DIR
+        REPLICA_INFO_TOP_DIR = top_dir
+    except Exception, e:
+        print "ERROR: Failed to decrypt or open the replica file."
+        print "Verify you entered the correct Directory Manager password."
+        sys.exit(1)
+
+    config = ReplicaConfig()
+    read_info(dir, config)
+    config.dirman_password = dirman_password
+    host = get_host_name(options.no_host_dns)
+    if config.host_name != host:
+        try:
+            print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host)
+            if not ipautil.user_input("This may cause problems. Continue?", True):
+                sys.exit(0)
+            config.host_name = host
+            print ""
+        except KeyboardInterrupt:
+            sys.exit(0)
+    config.dir = dir
+
+    if not options.skip_conncheck:
+        replica_conn_check(config.master_host_name, config.host_name, config.realm_name, True, options.admin_password)
+
+    api.bootstrap(in_server=True)
+    api.finalize()
+
+    # Configure the CA if necessary
+    (CA, cs) = install_ca(config)
+
+    # We need to ldap_enable the CA now that DS is up and running
+    CA.ldap_enable('CA', config.host_name, config.dirman_password,
+                   util.realm_to_suffix(config.realm_name))
+    cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name))
+    cs.add_cert_to_service()
+
+    service.print_msg("Setting the certificate subject base")
+    CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))
+
+try:
+    if not os.geteuid()==0:
+        sys.exit("\nYou must be root to run this script.\n")
+
+    main()
+    sys.exit(0)
+except SystemExit, e:
+    sys.exit(e)
+except socket.error, (errno, errstr):
+    print errstr
+except HostnameLocalhost:
+    print "The hostname resolves to the localhost address (127.0.0.1/::1)"
+    print "Please change your /etc/hosts file so that the hostname"
+    print "resolves to the ip address of your network interface."
+    print ""
+    print "Please fix your /etc/hosts file and restart the setup program"
+except Exception, e:
+    print "creation of replica failed: %s" % str(e)
+    message = str(e)
+    for str in traceback.format_tb(sys.exc_info()[2]):
+        message = message + "\n" + str
+    logging.debug(message)
+except KeyboardInterrupt:
+    print "Installation cancelled." 
+finally:
+    # always try to remove decrypted replica file
+    try:
+        if REPLICA_INFO_TOP_DIR:
+            shutil.rmtree(REPLICA_INFO_TOP_DIR)
+    except OSError:
+        pass
+
+print ""
+print "Your system may be partly configured." 
+print "Run /usr/sbin/ipa-server-install --uninstall to clean up."
+
+# the only way to get here is on error or ^C
+sys.exit(1)
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index f91ac51..7582588 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -29,9 +29,10 @@ from ipapython import ipautil
 
 from ipaserver.install import dsinstance, installutils, krbinstance, service
 from ipaserver.install import bindinstance, httpinstance, ntpinstance, certs
-from ipaserver.install.replication import check_replication_plugin
+from ipaserver.install.replication import check_replication_plugin, replica_conn_check
 from ipaserver.install.installutils import HostnameLocalhost, resolve_host
 from ipaserver.plugins.ldap2 import ldap2
+from ipaserver.install import cainstance
 from ipapython import version
 from ipalib import api, errors, util
 from ipapython.config import IPAOptionParser
@@ -49,6 +50,7 @@ class ReplicaConfig:
         self.host_name = ""
         self.dir = ""
         self.subject_base = ""
+        self.setup_ca = False
 
 def parse_options():
     usage = "%prog [options] REPLICA_FILE"
@@ -76,6 +78,8 @@ def parse_options():
                       default=True, help="disables pkinit setup steps")
     parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true",
                       default=False, help="skip connection check to remote master")
+    parser.add_option("--setup-ca", dest="setup_ca", action="store_true",
+                      default=False, help="configure a dogtag CA")
     parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
                       default=False, help="unattended installation never prompts the user")
 
@@ -146,11 +150,11 @@ def install_ca(config):
         # CA not used on the server, return empty instances
         return (None, None)
 
-    try:
-        from ipaserver.install import cainstance
-    except ImportError:
-        print >> sys.stderr, "Import failed: %s" % sys.exc_value
-        sys.exit(1)
+    if not config.setup_ca:
+        ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR)
+        ca.dm_password = config.dirman_password
+        ca.subject_base = config.subject_base
+        return (ca, None)
 
     if not cainstance.check_inst():
         print "A CA was specified but the dogtag certificate server"
@@ -414,32 +418,12 @@ def main():
         except KeyboardInterrupt:
             sys.exit(0)
     config.dir = dir
+    config.setup_ca = options.setup_ca
 
 
     # check connection
     if not options.skip_conncheck:
-        print "Run connection check to master"
-        args = ["/usr/sbin/ipa-replica-conncheck", "--master", config.master_host_name,
-                "--auto-master-check", "--realm", config.realm_name,
-                "--principal", "admin",
-                "--hostname", config.host_name]
-
-        if options.admin_password:
-            args.extend(["--password", options.admin_password])
-
-        cafile = config.dir + "/cacert.p12"
-        if ipautil.file_exists(cafile): # with CA
-            args.append('--check-ca')
-        logging.debug("Running ipa-replica-conncheck with following arguments: %s" %
-                " ".join(args))
-        (stdin, stderr, returncode) = ipautil.run(args,raiseonerr=False, capture_output=False)
-
-        if returncode != 0:
-            sys.exit("Connection check failed!" +
-                     "\nPlease fix your network settings according to error messages above." +
-                     "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.")
-        else:
-            print "Connection check OK"
+        replica_conn_check(config.master_host_name, config.host_name, config.realm_name, options.setup_ca, options.admin_password)
 
     # Create the management framework config file
     # Note: We must do this before bootstraping and finalizing ipalib.api
@@ -520,7 +504,7 @@ def main():
     ds = install_replica_ds(config)
 
     # We need to ldap_enable the CA now that DS is up and running
-    if CA:
+    if CA and config.setup_ca:
         CA.ldap_enable('CA', config.host_name, config.dirman_password,
                        util.realm_to_suffix(config.realm_name))
         cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name))
@@ -532,8 +516,9 @@ def main():
         CA.import_ra_cert(dir + "/ra.p12")
         CA.fix_ra_perms()
         service.restart("httpd")
-        service.print_msg("Setting the certificate subject base")
-        CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))
+        if config.setup_ca:
+            service.print_msg("Setting the certificate subject base")
+            CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))
 
     # The DS instance is created before the keytab, add the SSL cert we
     # generated
diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1
new file mode 100644
index 0000000..9fe2733
--- /dev/null
+++ b/install/tools/man/ipa-ca-install.1
@@ -0,0 +1,49 @@
+.\" A man page for ipa-replica-install
+.\" Copyright (C) 2011 Red Hat, Inc.
+.\" 
+.\" 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/>.
+.\" 
+.\" Author: Rob Crittenden <rcrit...@redhat.com>
+.\" 
+.TH "ipa-ca-install" "1" "Jun 17 2011" "freeipa" ""
+.SH "NAME"
+ipa\-ca\-install \- Install a CA on a replica
+.SH "SYNOPSIS"
+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.
+.SH "OPTIONS"
+\fB\-d\fR, \fB\-\-debug
+Enable debug logging when more verbose output is needed
+.TP 
+\fB\-p\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR
+Directory Manager (existing master) password
+.TP 
+\fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR
+Admin user Kerberos password used for connection check
+.TP 
+\fB\-\-no\-host\-dns\fR
+Do not use DNS for hostname lookup during installation
+.TP 
+\fB\-\-skip\-conncheck\fR
+Skip connection check to remote master
+.TP 
+\fB\-U\fR, \fB\-\-unattended\fR
+An unattended installation that will never prompt for user input
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 001e6eb..62fce4b 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -446,6 +446,7 @@ class CAInstance(service.Service):
         self.csr_file = None
         self.cert_file = None
         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
@@ -522,7 +523,8 @@ class CAInstance(service.Service):
             self.step("restarting certificate server", self.__restart_instance)
             if not self.clone:
                 self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12)
-            self.step("creating RA agent certificate database", self.__create_ra_agent_db)
+            if self.create_ra_agent_db:
+                self.step("creating RA agent certificate database", self.__create_ra_agent_db)
             self.step("importing CA chain to RA certificate database", self.__import_ca_chain)
             if not self.clone:
                 self.step("restarting certificate server", self.__restart_instance)
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 07dda2c..30dfbf6 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -475,7 +475,8 @@ class CertDB(object):
 
         service.stop("certmonger")
         cert = self.get_cert_from_db(nickname)
-        subject = str(x509.get_subject(cert))
+        nsscert = x509.load_certificate(cert, dbdir=self.secdir)
+        subject = str(nsscert.subject)
         m = re.match('New tracking request "(\d+)" added', stdout)
         if not m:
             logging.error('Didn\'t get new certmonger request, got %s' % stdout)
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index e640873..fddb737 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -20,6 +20,7 @@
 import time, logging
 
 import os
+import sys
 import ldap
 from ipaserver import ipaldap
 from ipaserver.install.service import restart
@@ -27,6 +28,7 @@ import installutils
 from ldap import modlist
 from ipalib import util
 from ipalib import errors
+from ipapython import ipautil
 
 DIRMAN_CN = "cn=directory manager"
 CACERT = "/etc/ipa/ca.crt"
@@ -40,6 +42,37 @@ TIMEOUT = 120
 IPA_REPLICA = 1
 WINSYNC = 2
 
+def replica_conn_check(master_host, host_name, realm, check_ca,
+                       admin_password=None):
+    """
+    Check the ports used by the replica both locally and remotely to be sure
+    that replication will work.
+
+    Does not return a value, will sys.exit() on failure.
+    """
+    print "Run connection check to master"
+    args = ["/usr/sbin/ipa-replica-conncheck", "--master", master_host,
+            "--auto-master-check", "--realm", realm,
+            "--principal", "admin",
+            "--hostname", host_name]
+
+    if admin_password:
+        args.extend(["--password", admin_password])
+
+    if check_ca:
+        args.append('--check-ca')
+    logging.debug("Running ipa-replica-conncheck with following arguments: %s" %
+            " ".join(args))
+    (stdin, stderr, returncode) = ipautil.run(args,raiseonerr=False, capture_output=False)
+
+    if returncode != 0:
+        sys.exit("Connection check failed!" +
+                 "\nPlease fix your network settings according to error messages above." +
+                 "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.")
+    else:
+        print "Connection check OK"
+
+
 def check_replication_plugin():
     """
     Confirm that the 389-ds replication is installed.
-- 
1.7.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to