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
This commit is contained in:
Rob Crittenden 2011-06-17 16:47:39 -04:00
parent cbffe1d65d
commit 8a32bb3746
12 changed files with 437 additions and 133 deletions

View File

@ -356,6 +356,7 @@ fi
%files server %files server
%defattr(-,root,root,-) %defattr(-,root,root,-)
%doc COPYING README Contributors.txt %doc COPYING README Contributors.txt
%{_sbindir}/ipa-ca-install
%{_sbindir}/ipa-dns-install %{_sbindir}/ipa-dns-install
%{_sbindir}/ipa-server-install %{_sbindir}/ipa-server-install
%{_sbindir}/ipa-replica-conncheck %{_sbindir}/ipa-replica-conncheck
@ -436,6 +437,7 @@ fi
%{_mandir}/man1/ipa-server-certinstall.1.gz %{_mandir}/man1/ipa-server-certinstall.1.gz
%{_mandir}/man1/ipa-server-install.1.gz %{_mandir}/man1/ipa-server-install.1.gz
%{_mandir}/man1/ipa-dns-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-compat-manage.1.gz
%{_mandir}/man1/ipa-nis-manage.1.gz %{_mandir}/man1/ipa-nis-manage.1.gz
%{_mandir}/man1/ipa-host-net-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 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
%changelog %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 * 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 selinux-policy to 3.9.16-18 on F-15+
- Set min nvr of pki-ca to 9.0.7 on F-15+ - Set min nvr of pki-ca to 9.0.7 on F-15+

View File

@ -53,6 +53,8 @@ PY_EXPLICIT_FILES = \
install/tools/ipa-host-net-manage \ install/tools/ipa-host-net-manage \
install/tools/ipa-server-install \ install/tools/ipa-server-install \
install/tools/ipa-ldap-updater \ install/tools/ipa-ldap-updater \
install/tools/ipa-dns-install \
install/tools/ipa-ca-install \
ipa-client/ipa-install/ipa-client-install ipa-client/ipa-install/ipa-client-install
PYTHON_POTFILES = $(PY_FILES) $(PY_EXPLICIT_FILES) PYTHON_POTFILES = $(PY_FILES) $(PY_EXPLICIT_FILES)

View File

@ -5,6 +5,7 @@ SUBDIRS = \
$(NULL) $(NULL)
sbin_SCRIPTS = \ sbin_SCRIPTS = \
ipa-ca-install \
ipa-dns-install \ ipa-dns-install \
ipa-server-install \ ipa-server-install \
ipa-replica-conncheck \ ipa-replica-conncheck \

183
install/tools/ipa-ca-install Executable file
View File

@ -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)

View File

@ -21,17 +21,19 @@
import sys import sys
import socket import socket
import tempfile, os, pwd, traceback, logging, shutil import os, pwd, traceback, logging, shutil
import grp import grp
from ConfigParser import SafeConfigParser
from ipapython import ipautil from ipapython import ipautil
from ipaserver.install import dsinstance, installutils, krbinstance, service from ipaserver.install import dsinstance, installutils, krbinstance, service
from ipaserver.install import bindinstance, httpinstance, ntpinstance, certs 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 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.plugins.ldap2 import ldap2
from ipaserver.install import cainstance
from ipapython import version from ipapython import version
from ipalib import api, errors, util from ipalib import api, errors, util
from ipapython.config import IPAOptionParser from ipapython.config import IPAOptionParser
@ -40,16 +42,6 @@ from ipapython import sysrestore
CACERT="/etc/ipa/ca.crt" CACERT="/etc/ipa/ca.crt"
REPLICA_INFO_TOP_DIR=None 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(): def parse_options():
usage = "%prog [options] REPLICA_FILE" usage = "%prog [options] REPLICA_FILE"
parser = IPAOptionParser(usage=usage, version=version.VERSION) parser = IPAOptionParser(usage=usage, version=version.VERSION)
@ -76,6 +68,8 @@ def parse_options():
default=True, help="disables pkinit setup steps") default=True, help="disables pkinit setup steps")
parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true", parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true",
default=False, help="skip connection check to remote master") 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", parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
default=False, help="unattended installation never prompts the user") default=False, help="unattended installation never prompts the user")
@ -102,98 +96,10 @@ def parse_options():
def get_dirman_password(): def get_dirman_password():
return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) 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): def set_owner(config, dir):
pw = pwd.getpwnam(dsinstance.DS_USER) pw = pwd.getpwnam(dsinstance.DS_USER)
os.chown(dir, pw.pw_uid, pw.pw_gid) 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): def install_replica_ds(config):
dsinstance.check_existing_installation() dsinstance.check_existing_installation()
dsinstance.check_ports() dsinstance.check_ports()
@ -392,7 +298,7 @@ def main():
sys.exit(0) sys.exit(0)
try: try:
top_dir, dir = expand_info(filename, dirman_password) top_dir, dir = expand_replica_info(filename, dirman_password)
global REPLICA_INFO_TOP_DIR global REPLICA_INFO_TOP_DIR
REPLICA_INFO_TOP_DIR = top_dir REPLICA_INFO_TOP_DIR = top_dir
except Exception, e: except Exception, e:
@ -401,9 +307,13 @@ def main():
sys.exit(1) sys.exit(1)
config = ReplicaConfig() config = ReplicaConfig()
read_info(dir, config) read_replica_info(dir, config)
config.dirman_password = dirman_password config.dirman_password = dirman_password
try:
host = get_host_name(options.no_host_dns) host = get_host_name(options.no_host_dns)
except RuntimeError, e:
logging.error(str(e))
sys.exit(1)
if config.host_name != host: if config.host_name != host:
try: try:
print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) 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: except KeyboardInterrupt:
sys.exit(0) sys.exit(0)
config.dir = dir config.dir = dir
config.setup_ca = options.setup_ca
# check connection # check connection
if not options.skip_conncheck: if not options.skip_conncheck:
print "Run connection check to master" replica_conn_check(config.master_host_name, config.host_name, config.realm_name, options.setup_ca, options.admin_password)
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"
# Create the management framework config file # Create the management framework config file
# Note: We must do this before bootstraping and finalizing ipalib.api # Note: We must do this before bootstraping and finalizing ipalib.api
@ -516,7 +406,7 @@ def main():
ntp.create_instance() ntp.create_instance()
# Configure the CA if necessary # Configure the CA if necessary
(CA, cs) = install_ca(config) (CA, cs) = cainstance.install_replica_ca(config)
# Always try to install DNS records # Always try to install DNS records
install_dns_records(config, options) install_dns_records(config, options)
@ -525,7 +415,7 @@ def main():
ds = install_replica_ds(config) ds = install_replica_ds(config)
# We need to ldap_enable the CA now that DS is up and running # 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, CA.ldap_enable('CA', config.host_name, config.dirman_password,
util.realm_to_suffix(config.realm_name)) util.realm_to_suffix(config.realm_name))
cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name)) cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name))
@ -537,6 +427,7 @@ def main():
CA.import_ra_cert(dir + "/ra.p12") CA.import_ra_cert(dir + "/ra.p12")
CA.fix_ra_perms() CA.fix_ra_perms()
service.restart("httpd") service.restart("httpd")
if config.setup_ca:
service.print_msg("Setting the certificate subject base") service.print_msg("Setting the certificate subject base")
CA.set_subject_in_config(util.realm_to_suffix(config.realm_name)) CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))

View File

@ -12,6 +12,7 @@ man1_MANS = \
ipa-server-certinstall.1 \ ipa-server-certinstall.1 \
ipa-server-install.1 \ ipa-server-install.1 \
ipa-dns-install.1 \ ipa-dns-install.1 \
ipa-ca-install.1 \
ipa-ldap-updater.1 \ ipa-ldap-updater.1 \
ipa-compat-manage.1 \ ipa-compat-manage.1 \
ipa-nis-manage.1 \ ipa-nis-manage.1 \

View File

@ -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

View File

@ -33,12 +33,16 @@ Do not configure NTP
\fB\-d\fR, \fB\-\-debug \fB\-d\fR, \fB\-\-debug
Enable debug logging when more verbose output is needed Enable debug logging when more verbose output is needed
.TP .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 Directory Manager (existing master) password
.TP .TP
\fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR \fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR
Admin user Kerberos password used for connection check Admin user Kerberos password used for connection check
.TP .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 \fB\-\-setup\-dns\fR
Generate a DNS zone if it does not exist already and configure the DNS server. 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 This option requires that you either specify at least one DNS forwarder through

View File

@ -52,6 +52,7 @@ from ipaserver.install import service
from ipaserver.install import installutils from ipaserver.install import installutils
from ipaserver.install import dsinstance from ipaserver.install import dsinstance
from ipaserver.install import certs from ipaserver.install import certs
from ipaserver.install.installutils import ReplicaConfig
from ipalib import util from ipalib import util
DEFAULT_DSPORT=7389 DEFAULT_DSPORT=7389
@ -446,6 +447,7 @@ class CAInstance(service.Service):
self.csr_file = None self.csr_file = None
self.cert_file = None self.cert_file = None
self.cert_chain_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 # The same database is used for mod_nss because the NSS context
# will already have been initialized by Apache by the time # will already have been initialized by Apache by the time
@ -521,6 +523,7 @@ class CAInstance(service.Service):
if self.external != 1: if self.external != 1:
if not self.clone: if not self.clone:
self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12) self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12)
if self.create_ra_agent_db:
self.step("creating RA agent certificate database", 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) self.step("importing CA chain to RA certificate database", self.__import_ca_chain)
if not self.clone: if not self.clone:
@ -1091,6 +1094,79 @@ class CAInstance(service.Service):
fd.close() fd.close()
os.chmod(location, 0444) 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__": if __name__ == "__main__":
installutils.standard_logging_setup("install.log", False) installutils.standard_logging_setup("install.log", False)
cs = CADSInstance() cs = CADSInstance()

View File

@ -446,6 +446,7 @@ class CertDB(object):
return cert return cert
else: else:
(cert, start) = find_cert_from_txt(cert, start=0) (cert, start) = find_cert_from_txt(cert, start=0)
cert = x509.strip_header(cert)
dercert = base64.b64decode(cert) dercert = base64.b64decode(cert)
return dercert return dercert
except ipautil.CalledProcessError: except ipautil.CalledProcessError:
@ -475,7 +476,8 @@ class CertDB(object):
service.stop("certmonger") service.stop("certmonger")
cert = self.get_cert_from_db(nickname) 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) m = re.match('New tracking request "(\d+)" added', stdout)
if not m: if not m:
logging.error('Didn\'t get new certmonger request, got %s' % stdout) logging.error('Didn\'t get new certmonger request, got %s' % stdout)

View File

@ -29,6 +29,8 @@ import struct
import fcntl import fcntl
import netaddr import netaddr
import time import time
import tempfile
from ConfigParser import SafeConfigParser
from ipapython import ipautil from ipapython import ipautil
from ipapython import dnsclient from ipapython import dnsclient
@ -36,6 +38,17 @@ from ipapython import dnsclient
class HostnameLocalhost(Exception): class HostnameLocalhost(Exception):
pass 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(): def get_fqdn():
fqdn = "" fqdn = ""
try: try:
@ -442,3 +455,47 @@ def resolve_host(host_name):
return addrinfos[0][4][0] return addrinfos[0][4][0]
except: except:
return None 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")

View File

@ -20,6 +20,7 @@
import time, logging import time, logging
import os import os
import sys
import ldap import ldap
from ipaserver import ipaldap from ipaserver import ipaldap
from ipaserver.install.service import restart from ipaserver.install.service import restart
@ -27,6 +28,7 @@ import installutils
from ldap import modlist from ldap import modlist
from ipalib import util from ipalib import util
from ipalib import errors from ipalib import errors
from ipapython import ipautil
DIRMAN_CN = "cn=directory manager" DIRMAN_CN = "cn=directory manager"
CACERT = "/etc/ipa/ca.crt" CACERT = "/etc/ipa/ca.crt"
@ -40,6 +42,37 @@ TIMEOUT = 120
IPA_REPLICA = 1 IPA_REPLICA = 1
WINSYNC = 2 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(): def check_replication_plugin():
""" """
Confirm that the 389-ds replication is installed. Confirm that the 389-ds replication is installed.