summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2011-06-17 16:47:39 -0400
committerRob Crittenden <rcritten@redhat.com>2011-06-23 19:04:33 -0400
commit8a32bb3746802a29b2655e4ad2cbbba8481e1eaf (patch)
tree14c7e77b744d31e303d78313cf9866502dad1ef9
parentcbffe1d65df222acf6eb26cdaa121932a01f9ba7 (diff)
downloadfreeipa-8a32bb3746802a29b2655e4ad2cbbba8481e1eaf.zip
freeipa-8a32bb3746802a29b2655e4ad2cbbba8481e1eaf.tar.gz
freeipa-8a32bb3746802a29b2655e4ad2cbbba8481e1eaf.tar.xz
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. This moves a fair bit of code out of ipa-replica-install into installutils and cainstance to avoid duplication. https://fedorahosted.org/freeipa/ticket/1251
-rw-r--r--freeipa.spec.in5
-rw-r--r--install/po/Makefile.in2
-rw-r--r--install/tools/Makefile.am1
-rwxr-xr-xinstall/tools/ipa-ca-install183
-rwxr-xr-xinstall/tools/ipa-replica-install151
-rw-r--r--install/tools/man/Makefile.am1
-rw-r--r--install/tools/man/ipa-ca-install.149
-rw-r--r--install/tools/man/ipa-replica-install.16
-rw-r--r--ipaserver/install/cainstance.py78
-rw-r--r--ipaserver/install/certs.py4
-rw-r--r--ipaserver/install/installutils.py57
-rw-r--r--ipaserver/install/replication.py33
12 files changed, 437 insertions, 133 deletions
diff --git a/freeipa.spec.in b/freeipa.spec.in
index c49ca2b..5ba38cb 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
@@ -436,6 +437,7 @@ fi
%{_mandir}/man1/ipa-server-certinstall.1.gz
%{_mandir}/man1/ipa-server-install.1.gz
%{_mandir}/man1/ipa-dns-install.1.gz
+%{_mandir}/man1/ipa-ca-install.1.gz
%{_mandir}/man1/ipa-compat-manage.1.gz
%{_mandir}/man1/ipa-nis-manage.1.gz
%{_mandir}/man1/ipa-host-net-manage.1.gz
@@ -498,6 +500,9 @@ fi
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
%changelog
+* Fri Jun 17 2011 Rob Crittenden <rcritten@redhat.com> - 2.0.90-4
+- Ship ipa-ca-install utility
+
* Thu May 12 2011 Rob Crittenden <rcritten@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/po/Makefile.in b/install/po/Makefile.in
index a1e804f..a546875 100644
--- a/install/po/Makefile.in
+++ b/install/po/Makefile.in
@@ -53,6 +53,8 @@ PY_EXPLICIT_FILES = \
install/tools/ipa-host-net-manage \
install/tools/ipa-server-install \
install/tools/ipa-ldap-updater \
+ install/tools/ipa-dns-install \
+ install/tools/ipa-ca-install \
ipa-client/ipa-install/ipa-client-install
PYTHON_POTFILES = $(PY_FILES) $(PY_EXPLICIT_FILES)
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..edd8f4c
--- /dev/null
+++ b/install/tools/ipa-ca-install
@@ -0,0 +1,183 @@
+#! /usr/bin/python -E
+# Authors: Rob Crittenden <rcritten@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 os, traceback, logging, shutil
+
+from ipapython import ipautil
+
+from ipaserver.install import installutils, service
+from ipaserver.install import certs
+from ipaserver.install.installutils import HostnameLocalhost
+from ipaserver.install.installutils import ReplicaConfig, expand_replica_info, read_replica_info
+from ipaserver.install.installutils import get_host_name
+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
+
+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 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_replica_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_replica_info(dir, config)
+ config.dirman_password = dirman_password
+ try:
+ host = get_host_name(options.no_host_dns)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
+ 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
+ config.setup_ca = True
+
+ 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) = cainstance.install_replica_ca(config, postinstall=True)
+
+ # 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 3feb2a9..7daa0e8 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -21,17 +21,19 @@
import sys
import socket
-import tempfile, os, pwd, traceback, logging, shutil
+import os, pwd, traceback, logging, shutil
import grp
-from ConfigParser import SafeConfigParser
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.install.installutils import ReplicaConfig, expand_replica_info, read_replica_info
+from ipaserver.install.installutils import get_host_name
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
@@ -40,16 +42,6 @@ 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)
@@ -76,6 +68,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")
@@ -102,98 +96,10 @@ def parse_options():
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 set_owner(config, dir):
pw = pwd.getpwnam(dsinstance.DS_USER)
os.chown(dir, pw.pw_uid, pw.pw_gid)
-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):
- # 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 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.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 install_replica_ds(config):
dsinstance.check_existing_installation()
dsinstance.check_ports()
@@ -392,7 +298,7 @@ def main():
sys.exit(0)
try:
- top_dir, dir = expand_info(filename, dirman_password)
+ top_dir, dir = expand_replica_info(filename, dirman_password)
global REPLICA_INFO_TOP_DIR
REPLICA_INFO_TOP_DIR = top_dir
except Exception, e:
@@ -401,9 +307,13 @@ def main():
sys.exit(1)
config = ReplicaConfig()
- read_info(dir, config)
+ read_replica_info(dir, config)
config.dirman_password = dirman_password
- host = get_host_name(options.no_host_dns)
+ try:
+ host = get_host_name(options.no_host_dns)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
if config.host_name != host:
try:
print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host)
@@ -414,32 +324,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
@@ -516,7 +406,7 @@ def main():
ntp.create_instance()
# Configure the CA if necessary
- (CA, cs) = install_ca(config)
+ (CA, cs) = cainstance.install_replica_ca(config)
# Always try to install DNS records
install_dns_records(config, options)
@@ -525,7 +415,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))
@@ -537,8 +427,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/Makefile.am b/install/tools/man/Makefile.am
index be2524e..63a598a 100644
--- a/install/tools/man/Makefile.am
+++ b/install/tools/man/Makefile.am
@@ -12,6 +12,7 @@ man1_MANS = \
ipa-server-certinstall.1 \
ipa-server-install.1 \
ipa-dns-install.1 \
+ ipa-ca-install.1 \
ipa-ldap-updater.1 \
ipa-compat-manage.1 \
ipa-nis-manage.1 \
diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1
new file mode 100644
index 0000000..90ea846
--- /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 <rcritten@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\fR
+Enable debug logging when more verbose output is needed
+.TP
+\fB\-p\fR \fIDM_PASSWORD\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/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
index 8889235..1dac5fa 100644
--- a/install/tools/man/ipa-replica-install.1
+++ b/install/tools/man/ipa-replica-install.1
@@ -33,12 +33,16 @@ Do not configure NTP
\fB\-d\fR, \fB\-\-debug
Enable debug logging when more verbose output is needed
.TP
-\fB\-p\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR
+\fB\-p\fR \fIDM_PASSWORD\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\-\-setup\-ca\fR
+Install and configure a CA on this replica. If a CA is not configured then
+certificate operations will be forwarded to a master with a CA installed.
+.TP
\fB\-\-setup\-dns\fR
Generate a DNS zone if it does not exist already and configure the DNS server.
This option requires that you either specify at least one DNS forwarder through
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 928d01e..4ace26d 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -52,6 +52,7 @@ 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 ReplicaConfig
from ipalib import util
DEFAULT_DSPORT=7389
@@ -446,6 +447,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
@@ -521,7 +523,8 @@ class CAInstance(service.Service):
if self.external != 1:
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)
@@ -1091,6 +1094,79 @@ class CAInstance(service.Service):
fd.close()
os.chmod(location, 0444)
+def install_replica_ca(config, postinstall=False):
+ """
+ Install a CA on a replica.
+
+ There are two modes of doing this controlled:
+ - While the replica is being installed
+ - Post-replica installation
+
+ config is a ReplicaConfig object
+
+ Returns a tuple of the CA and CADS instances
+ """
+ cafile = config.dir + "/cacert.p12"
+
+ if not ipautil.file_exists(cafile):
+ # not a dogtag CA replica
+ sys.exit('Not a dogtag CA installation')
+
+ if not config.setup_ca:
+ # We aren't configuring the CA in this step but we still need
+ # a minimum amount of information on the CA for this IPA install.
+ ca = CAInstance(config.realm_name, certs.NSS_DIR)
+ ca.dm_password = config.dirman_password
+ ca.subject_base = config.subject_base
+ return (ca, None)
+
+ ca = 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.")
+
+ pkcs12_info = None
+ if ipautil.file_exists(config.dir + "/dogtagcert.p12"):
+ pkcs12_info = (config.dir + "/dogtagcert.p12",
+ config.dir + "/dirsrv_pin.txt")
+ cs = 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(config.realm_name, certs.NSS_DIR)
+ if postinstall:
+ # If installing this afterward the Apache NSS database already
+ # exists, don't remove it.
+ ca.create_ra_agent_db = False
+ ca.configure_instance(config.host_name, config.dirman_password,
+ config.dirman_password, pkcs12_info=(cafile,),
+ 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)
+
if __name__ == "__main__":
installutils.standard_logging_setup("install.log", False)
cs = CADSInstance()
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 07dda2c..ebe654d 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -446,6 +446,7 @@ class CertDB(object):
return cert
else:
(cert, start) = find_cert_from_txt(cert, start=0)
+ cert = x509.strip_header(cert)
dercert = base64.b64decode(cert)
return dercert
except ipautil.CalledProcessError:
@@ -475,7 +476,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/installutils.py b/ipaserver/install/installutils.py
index f5a8625..68fce7e 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -29,6 +29,8 @@ import struct
import fcntl
import netaddr
import time
+import tempfile
+from ConfigParser import SafeConfigParser
from ipapython import ipautil
from ipapython import dnsclient
@@ -36,6 +38,17 @@ from ipapython import dnsclient
class HostnameLocalhost(Exception):
pass
+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 = ""
+ self.setup_ca = False
+
def get_fqdn():
fqdn = ""
try:
@@ -442,3 +455,47 @@ def resolve_host(host_name):
return addrinfos[0][4][0]
except:
return None
+
+def get_host_name(no_host_dns):
+ """
+ Get the current FQDN from the socket and verify that it is valid.
+
+ no_host_dns is a boolean that determines whether we enforce that the
+ hostname is resolvable.
+
+ Will raise a RuntimeError on error, returns hostname on success
+ """
+ hostname = get_fqdn()
+ verify_fqdn(hostname, no_host_dns)
+ return hostname
+
+def expand_replica_info(filename, password):
+ """
+ Decrypt and expand a replica installation file into a temporary
+ location. The caller is responsible to remove this directory.
+ """
+ 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_replica_info(dir, rconfig):
+ """
+ Read the contents of a replica installation file.
+
+ rconfig is a ReplicaConfig object
+ """
+ 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")
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.