mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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:
parent
cbffe1d65d
commit
8a32bb3746
@ -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+
|
||||||
|
@ -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)
|
||||||
|
@ -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
183
install/tools/ipa-ca-install
Executable 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)
|
@ -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
|
||||||
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:
|
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,8 +427,9 @@ 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")
|
||||||
service.print_msg("Setting the certificate subject base")
|
if config.setup_ca:
|
||||||
CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))
|
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
|
# The DS instance is created before the keytab, add the SSL cert we
|
||||||
# generated
|
# generated
|
||||||
|
@ -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 \
|
||||||
|
49
install/tools/man/ipa-ca-install.1
Normal file
49
install/tools/man/ipa-ca-install.1
Normal 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
|
@ -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
|
||||||
|
@ -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,7 +523,8 @@ 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)
|
||||||
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)
|
self.step("importing CA chain to RA certificate database", self.__import_ca_chain)
|
||||||
if not self.clone:
|
if not self.clone:
|
||||||
self.step("restarting certificate server", self.__restart_instance)
|
self.step("restarting certificate server", self.__restart_instance)
|
||||||
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user