mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add a KRA to IPA
This patch adds the capability of installing a Dogtag KRA to an IPA instance. With this patch, a KRA is NOT configured by default when ipa-server-install is run. Rather, the command ipa-kra-install must be executed on an instance on which a Dogtag CA has already been configured. The KRA shares the same tomcat instance and DS instance as the Dogtag CA. Moreover, the same admin user/agent (and agent cert) can be used for both subsystems. Certmonger is also confgured to monitor the new subsystem certificates. To create a clone KRA, simply execute ipa-kra-install <replica_file> on a replica on which a Dogtag CA has already been replicated. ipa-kra-install will use the security domain to detect whether the system being installed is a replica, and will error out if a needed replica file is not provided. The install scripts have been refactored somewhat to minimize duplication of code. A new base class dogtagintance.py has been introduced containing code that is common to KRA and CA installs. This will become very useful when we add more PKI subsystems. The KRA will install its database as a subtree of o=ipaca, specifically o=ipakra,o=ipaca. This means that replication agreements created to replicate CA data will also replicate KRA data. No new replication agreements are required. Added dogtag plugin for KRA. This is an initial commit providing the basic vault functionality needed for vault. This plugin will likely be modified as we create the code to call some of these functions. Part of the work for: https://fedorahosted.org/freeipa/ticket/3872 The uninstallation option in ipa-kra-install is temporarily disabled. Reviewed-By: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Petr Viktorin <pviktori@redhat.com>
This commit is contained in:
@@ -112,6 +112,7 @@ Requires: selinux-policy >= 3.12.1-176
|
||||
Requires(post): selinux-policy-base
|
||||
Requires: slapi-nis >= 0.47.7
|
||||
Requires: pki-ca >= 10.1.1
|
||||
Requires: pki-kra >= 10.1.1
|
||||
%if 0%{?rhel}
|
||||
Requires: subscription-manager
|
||||
%endif
|
||||
@@ -570,6 +571,7 @@ fi
|
||||
%{_sbindir}/ipa-restore
|
||||
%{_sbindir}/ipa-ca-install
|
||||
%{_sbindir}/ipa-dns-install
|
||||
%{_sbindir}/ipa-kra-install
|
||||
%{_sbindir}/ipa-server-install
|
||||
%{_sbindir}/ipa-replica-conncheck
|
||||
%{_sbindir}/ipa-replica-install
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# VERSION 4 - DO NOT REMOVE THIS LINE
|
||||
# VERSION 5 - DO NOT REMOVE THIS LINE
|
||||
|
||||
ProxyRequests Off
|
||||
|
||||
@@ -11,7 +11,7 @@ ProxyRequests Off
|
||||
</LocationMatch>
|
||||
|
||||
# matches for admin port and installer
|
||||
<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/rest/installer/installToken|^/ca/admin/ca/updateNumberRange|^/ca/rest/securityDomain/domainInfo|^/ca/rest/account/login|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/rest/account/logout|^/ca/rest/securityDomain/installToken">
|
||||
<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML|^/ca/rest/installer/installToken|^/ca/admin/ca/updateNumberRange|^/ca/rest/securityDomain/domainInfo|^/ca/rest/account/login|^/ca/admin/ca/tokenAuthenticate|^/ca/admin/ca/updateNumberRange|^/ca/admin/ca/updateDomainXML|^/ca/rest/account/logout|^/ca/rest/securityDomain/installToken|^/ca/admin/ca/updateConnector|^/ca/admin/ca/getSubsystemCert|^/kra/admin/kra/updateNumberRange|^/kra/admin/kra/getConfigEntries|^/kra/rest/config/cert/transport">
|
||||
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
|
||||
NSSVerifyClient none
|
||||
ProxyPassMatch ajp://localhost:$DOGTAG_PORT
|
||||
@@ -19,7 +19,7 @@ ProxyRequests Off
|
||||
</LocationMatch>
|
||||
|
||||
# matches for agent port and eeca port
|
||||
<LocationMatch "^/ca/agent/ca/displayBySerial|^/ca/agent/ca/doRevoke|^/ca/agent/ca/doUnrevoke|^/ca/agent/ca/updateDomainXML|^/ca/eeca/ca/profileSubmitSSLClient">
|
||||
<LocationMatch "^/ca/agent/ca/displayBySerial|^/ca/agent/ca/doRevoke|^/ca/agent/ca/doUnrevoke|^/ca/agent/ca/updateDomainXML|^/ca/eeca/ca/profileSubmitSSLClient|^/kra/agent/kra/connector|^/kra/rest/agent/keyrequests|^/kra/rest/agent/keys|^/kra/rest/admin/kraconnector/remove">
|
||||
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
|
||||
NSSVerifyClient require
|
||||
ProxyPassMatch ajp://localhost:$DOGTAG_PORT
|
||||
|
||||
@@ -47,6 +47,7 @@ PY_EXPLICIT_FILES = \
|
||||
install/tools/ipa-csreplica-manage \
|
||||
install/tools/ipactl \
|
||||
install/tools/ipa-dns-install \
|
||||
install/tools/ipa-kra-install \
|
||||
install/tools/ipa-ldap-updater \
|
||||
install/tools/ipa-managed-entries \
|
||||
install/tools/ipa-nis-manage \
|
||||
|
||||
@@ -21,13 +21,12 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import syslog
|
||||
import tempfile
|
||||
import shutil
|
||||
import traceback
|
||||
|
||||
from ipapython import dogtag, certmonger, ipautil
|
||||
from ipapython import dogtag, ipautil
|
||||
from ipapython.dn import DN
|
||||
from ipalib import api, errors, x509, certstore
|
||||
from ipaserver.install import certs, cainstance, installutils
|
||||
@@ -35,6 +34,7 @@ from ipaserver.plugins.ldap2 import ldap2
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
|
||||
def main():
|
||||
nickname = sys.argv[1]
|
||||
|
||||
@@ -70,8 +70,6 @@ def main():
|
||||
syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname)
|
||||
sys.exit(1)
|
||||
|
||||
cainstance.update_cert_config(nickname, cert, configured_constants)
|
||||
|
||||
tmpdir = tempfile.mkdtemp(prefix="tmp-")
|
||||
try:
|
||||
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
||||
@@ -79,6 +77,7 @@ def main():
|
||||
principal)
|
||||
|
||||
ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
|
||||
ca.update_cert_config(nickname, cert, configured_constants)
|
||||
if ca.is_renewal_master():
|
||||
cainstance.update_people_entry(cert)
|
||||
|
||||
@@ -198,7 +197,9 @@ def main():
|
||||
# off the servlet to verify that the CA is actually up and responding so
|
||||
# when this returns it should be good-to-go. The CA was stopped in the
|
||||
# pre-save state.
|
||||
syslog.syslog(syslog.LOG_NOTICE, 'Starting %s' % dogtag_service.service_name)
|
||||
syslog.syslog(
|
||||
syslog.LOG_NOTICE,
|
||||
'Starting %s' % dogtag_service.service_name)
|
||||
try:
|
||||
dogtag_service.start(dogtag_instance)
|
||||
except Exception, e:
|
||||
|
||||
@@ -7,6 +7,7 @@ SUBDIRS = \
|
||||
sbin_SCRIPTS = \
|
||||
ipa-ca-install \
|
||||
ipa-dns-install \
|
||||
ipa-kra-install \
|
||||
ipa-server-install \
|
||||
ipa-adtrust-install \
|
||||
ipa-replica-conncheck \
|
||||
|
||||
@@ -19,23 +19,20 @@
|
||||
#
|
||||
|
||||
import sys
|
||||
import socket
|
||||
|
||||
import os, shutil
|
||||
import os
|
||||
import shutil
|
||||
from ConfigParser import RawConfigParser
|
||||
|
||||
from ipapython import ipautil
|
||||
|
||||
from ipaserver.install import installutils, service
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install import certs
|
||||
from ipaserver.install.installutils import (HostnameLocalhost, ReplicaConfig,
|
||||
expand_replica_info, read_replica_info, get_host_name, BadHostError,
|
||||
private_ccache, read_replica_info_dogtag_port, validate_external_cert)
|
||||
from ipaserver.install.installutils import (
|
||||
ReplicaConfig, private_ccache, create_replica_config,
|
||||
validate_external_cert)
|
||||
from ipaserver.install import dsinstance, cainstance, bindinstance
|
||||
from ipaserver.install.replication import replica_conn_check
|
||||
from ipapython import version
|
||||
from ipalib import api, util, certstore, x509
|
||||
from ipalib.constants import CACERT
|
||||
from ipalib import api, certstore, x509
|
||||
from ipapython.dn import DN
|
||||
from ipapython.config import IPAOptionParser
|
||||
from ipapython import sysrestore
|
||||
@@ -95,8 +92,11 @@ def parse_options():
|
||||
|
||||
return safe_options, options, filename
|
||||
|
||||
|
||||
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 install_dns_records(config, options):
|
||||
|
||||
@@ -115,13 +115,15 @@ def install_dns_records(config, options):
|
||||
bind.add_ipa_ca_dns_records(config.host_name, config.domain_name)
|
||||
finally:
|
||||
if api.Backend.ldap2.isconnected() and disconnect:
|
||||
api.Backend.ldap2.disconnect()
|
||||
api.Backend.ldap2.disconnect()
|
||||
|
||||
|
||||
def install_replica(safe_options, options, filename):
|
||||
standard_logging_setup(log_file_name, debug=options.debug)
|
||||
|
||||
root_logger.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options))
|
||||
root_logger.debug('IPA version %s' % version.VENDOR_VERSION)
|
||||
root_logger.debug('%s was invoked with argument "%s" and options: %s',
|
||||
sys.argv[0], filename, safe_options)
|
||||
root_logger.debug('IPA version %s', version.VENDOR_VERSION)
|
||||
|
||||
if not ipautil.file_exists(filename):
|
||||
sys.exit("Replica file %s does not exist" % filename)
|
||||
@@ -151,38 +153,13 @@ def install_replica(safe_options, options, filename):
|
||||
sys.exit("Directory Manager password required")
|
||||
|
||||
if not options.admin_password and not options.skip_conncheck and \
|
||||
options.unattended:
|
||||
sys.exit('admin password required')
|
||||
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 BadHostError, e:
|
||||
root_logger.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 = create_replica_config(dirman_password, filename, options)
|
||||
global REPLICA_INFO_TOP_DIR
|
||||
REPLICA_INFO_TOP_DIR = config.top_dir
|
||||
config.setup_ca = True
|
||||
config.ca_ds_port = read_replica_info_dogtag_port(config.dir)
|
||||
|
||||
if not ipautil.file_exists(config.dir + "/cacert.p12"):
|
||||
print 'CA cannot be installed in CA-less setup.'
|
||||
@@ -206,7 +183,7 @@ def install_replica(safe_options, options, filename):
|
||||
ipautil.realm_to_suffix(config.realm_name))
|
||||
|
||||
# This is done within stopped_service context, which restarts CA
|
||||
CA.enable_client_auth_to_db()
|
||||
CA.enable_client_auth_to_db(CA.dogtag_constants.CS_CFG_PATH)
|
||||
|
||||
# Install CA DNS records
|
||||
install_dns_records(config, options)
|
||||
@@ -225,12 +202,13 @@ def install_replica(safe_options, options, filename):
|
||||
root_logger.error(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def install_master(safe_options, options):
|
||||
standard_logging_setup(paths.IPASERVER_CA_INSTALL_LOG, debug=options.debug)
|
||||
|
||||
root_logger.debug(
|
||||
"%s was invoked with options: %s" % (sys.argv[0], safe_options))
|
||||
root_logger.debug("IPA version %s" % version.VENDOR_VERSION)
|
||||
"%s was invoked with options: %s", sys.argv[0], safe_options)
|
||||
root_logger.debug("IPA version %s", version.VENDOR_VERSION)
|
||||
|
||||
global sstore
|
||||
sstore = sysrestore.StateFile(paths.SYSRESTORE)
|
||||
@@ -316,7 +294,8 @@ def install_master(safe_options, options):
|
||||
"cannot continue." % (subject, db.secdir))
|
||||
sys.exit(1)
|
||||
|
||||
ca = cainstance.CAInstance(realm_name, certs.NSS_DIR,
|
||||
ca = cainstance.CAInstance(
|
||||
realm_name, certs.NSS_DIR,
|
||||
dogtag_constants=dogtag.install_constants)
|
||||
ca.create_ra_agent_db = False
|
||||
if external == 0:
|
||||
@@ -338,7 +317,7 @@ def install_master(safe_options, options):
|
||||
ca.ldap_enable('CA', host_name, dm_password,
|
||||
ipautil.realm_to_suffix(realm_name), ['caRenewalMaster'])
|
||||
|
||||
ca.enable_client_auth_to_db()
|
||||
ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH)
|
||||
|
||||
# Install CA DNS records
|
||||
config = ReplicaConfig()
|
||||
@@ -396,6 +375,7 @@ def install_master(safe_options, options):
|
||||
|
||||
ca.start(ca.dogtag_constants.PKI_INSTANCE_NAME)
|
||||
|
||||
|
||||
def main():
|
||||
safe_options, options, filename = parse_options()
|
||||
|
||||
@@ -416,8 +396,8 @@ if __name__ == '__main__':
|
||||
try:
|
||||
with private_ccache():
|
||||
installutils.run_script(main, log_file_name=log_file_name,
|
||||
operation_name='ipa-ca-install',
|
||||
fail_message=fail_message)
|
||||
operation_name='ipa-ca-install',
|
||||
fail_message=fail_message)
|
||||
finally:
|
||||
# always try to remove decrypted replica file
|
||||
try:
|
||||
|
||||
@@ -32,6 +32,7 @@ from ipalib import api, errors, util
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.config import IPAOptionParser
|
||||
from ipapython.ipa_log_manager import standard_logging_setup, root_logger
|
||||
from ipapython.ipautil import DN
|
||||
|
||||
log_file_name = paths.IPASERVER_INSTALL_LOG
|
||||
|
||||
|
||||
23
install/tools/ipa-kra-install
Normal file
23
install/tools/ipa-kra-install
Normal file
@@ -0,0 +1,23 @@
|
||||
#! /usr/bin/python2 -E
|
||||
# Authors: Ade Lee <alee@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 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/>.
|
||||
#
|
||||
|
||||
from ipaserver.install.ipa_kra_install import KRAInstall
|
||||
|
||||
KRAInstall.run_cli()
|
||||
@@ -36,12 +36,12 @@ from ipaserver.install import bindinstance, httpinstance, ntpinstance
|
||||
from ipaserver.install import memcacheinstance
|
||||
from ipaserver.install import otpdinstance
|
||||
from ipaserver.install.replication import replica_conn_check, ReplicationManager
|
||||
from ipaserver.install.installutils import (ReplicaConfig, expand_replica_info,
|
||||
read_replica_info, get_host_name, BadHostError, private_ccache,
|
||||
read_replica_info_dogtag_port)
|
||||
from ipaserver.install.installutils import (
|
||||
create_replica_config, read_replica_info_kra_enabled, private_ccache)
|
||||
from ipaserver.plugins.ldap2 import ldap2
|
||||
from ipaserver.install import cainstance
|
||||
from ipalib import api, errors, util, x509, certstore
|
||||
from ipaserver.install import krainstance
|
||||
from ipalib import api, errors, util, certstore, x509
|
||||
from ipalib.constants import CACERT
|
||||
from ipapython import version
|
||||
from ipapython.config import IPAOptionParser
|
||||
@@ -55,8 +55,8 @@ from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
log_file_name = paths.IPAREPLICA_INSTALL_LOG
|
||||
REPLICA_INFO_TOP_DIR = None
|
||||
DIRMAN_DN = DN(('cn', 'directory manager'))
|
||||
REPLICA_INFO_TOP_DIR = None
|
||||
|
||||
def parse_options():
|
||||
usage = "%prog [options] REPLICA_FILE"
|
||||
@@ -65,6 +65,8 @@ def parse_options():
|
||||
basic_group = OptionGroup(parser, "basic options")
|
||||
basic_group.add_option("--setup-ca", dest="setup_ca", action="store_true",
|
||||
default=False, help="configure a dogtag CA")
|
||||
basic_group.add_option("--setup-kra", dest="setup_kra", action="store_true",
|
||||
default=False, help="configure a dogtag KRA")
|
||||
basic_group.add_option("--ip-address", dest="ip_address",
|
||||
type="ip", ip_local=True,
|
||||
help="Replica server IP Address")
|
||||
@@ -206,6 +208,7 @@ def install_krb(config, setup_pkinit=False):
|
||||
|
||||
return krb
|
||||
|
||||
|
||||
def install_ca_cert(ldap, base_dn, realm, cafile):
|
||||
try:
|
||||
try:
|
||||
@@ -508,44 +511,24 @@ def main():
|
||||
if dirman_password is None:
|
||||
sys.exit("Directory Manager 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)
|
||||
root_logger.debug('Installing replica file with version %d (0 means no version in prepared file).' % config.version)
|
||||
if config.version and config.version > version.NUM_VERSION:
|
||||
root_logger.error('A replica file from a newer release (%d) cannot be installed on an older version (%d)' % (config.version, version.NUM_VERSION))
|
||||
sys.exit(1)
|
||||
config.dirman_password = dirman_password
|
||||
try:
|
||||
host = get_host_name(options.no_host_dns)
|
||||
except BadHostError, e:
|
||||
root_logger.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?", False):
|
||||
sys.exit(0)
|
||||
config.host_name = host
|
||||
print ""
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
config.dir = dir
|
||||
config = create_replica_config(dirman_password, filename, options)
|
||||
global REPLICA_INFO_TOP_DIR
|
||||
REPLICA_INFO_TOP_DIR = config.top_dir
|
||||
config.setup_ca = options.setup_ca
|
||||
config.ca_ds_port = read_replica_info_dogtag_port(config.dir)
|
||||
|
||||
if config.setup_ca and not ipautil.file_exists(config.dir + "/cacert.p12"):
|
||||
print 'CA cannot be installed in CA-less setup.'
|
||||
sys.exit(1)
|
||||
|
||||
config.setup_kra = options.setup_kra
|
||||
if config.setup_kra:
|
||||
if not config.setup_ca:
|
||||
print "CA must be installed with the KRA"
|
||||
sys.exit(1)
|
||||
if not read_replica_info_kra_enabled(config.dir):
|
||||
print "KRA is not installed on the master system"
|
||||
sys.exit(1)
|
||||
|
||||
installutils.verify_fqdn(config.master_host_name, options.no_host_dns)
|
||||
|
||||
# check connection
|
||||
@@ -579,6 +562,9 @@ def main():
|
||||
else:
|
||||
fd.write("enable_ra=False\n")
|
||||
fd.write("ra_plugin=none\n")
|
||||
|
||||
fd.write("enable_kra=%s\n" % config.setup_kra)
|
||||
|
||||
fd.write("mode=production\n")
|
||||
fd.close()
|
||||
finally:
|
||||
@@ -611,7 +597,7 @@ def main():
|
||||
|
||||
# Check that we don't already have a replication agreement
|
||||
try:
|
||||
(agreement_cn, agreement_dn) = replman.agreement_dn(host)
|
||||
(agreement_cn, agreement_dn) = replman.agreement_dn(config.host_name)
|
||||
entry = conn.get_entry(agreement_dn, ['*'])
|
||||
except errors.NotFound:
|
||||
pass
|
||||
@@ -621,20 +607,20 @@ def main():
|
||||
print ('A replication agreement for this host already exists. '
|
||||
'It needs to be removed.')
|
||||
print "Run this on the master that generated the info file:"
|
||||
print " %% ipa-replica-manage del %s --force" % host
|
||||
print " %% ipa-replica-manage del %s --force" % config.host_name
|
||||
exit(3)
|
||||
|
||||
# Check pre-existing host entry
|
||||
try:
|
||||
entry = conn.find_entries(u'fqdn=%s' % host, ['fqdn'], DN(api.env.container_host, api.env.basedn))
|
||||
entry = conn.find_entries(u'fqdn=%s' % config.host_name, ['fqdn'], DN(api.env.container_host, api.env.basedn))
|
||||
except errors.NotFound:
|
||||
pass
|
||||
else:
|
||||
root_logger.info(
|
||||
'Error: Host %s already exists on the master server.' % host)
|
||||
print 'The host %s already exists on the master server.' % host
|
||||
'Error: Host %s already exists on the master server.' % config.host_name)
|
||||
print 'The host %s already exists on the master server.' % config.host_name
|
||||
print "You should remove it before proceeding:"
|
||||
print " %% ipa host-del %s" % host
|
||||
print " %% ipa host-del %s" % config.host_name
|
||||
exit(3)
|
||||
|
||||
# Install CA cert so that we can do SSL connections with ldap
|
||||
@@ -694,7 +680,7 @@ def main():
|
||||
ipautil.realm_to_suffix(config.realm_name))
|
||||
|
||||
# This is done within stopped_service context, which restarts CA
|
||||
CA.enable_client_auth_to_db()
|
||||
CA.enable_client_auth_to_db(CA.dogtag_constants.CS_CFG_PATH)
|
||||
|
||||
krb = install_krb(config, setup_pkinit=options.setup_pkinit)
|
||||
http = install_http(config, auto_redirect=options.ui_redirect)
|
||||
@@ -705,7 +691,7 @@ def main():
|
||||
|
||||
if CA:
|
||||
CA.configure_certmonger_renewal()
|
||||
CA.import_ra_cert(dir + "/ra.p12")
|
||||
CA.import_ra_cert(config.dir + "/ra.p12")
|
||||
CA.fix_ra_perms()
|
||||
services.knownservices.httpd.restart()
|
||||
|
||||
@@ -717,9 +703,14 @@ def main():
|
||||
service.print_msg("Applying LDAP updates")
|
||||
ds.apply_updates()
|
||||
|
||||
# Restart ds and krb after configurations have been changed
|
||||
service.print_msg("Restarting the directory server")
|
||||
ds.restart()
|
||||
if options.setup_kra:
|
||||
kra = krainstance.install_replica_kra(config)
|
||||
service.print_msg("Restarting the directory server")
|
||||
ds.restart()
|
||||
kra.enable_client_auth_to_db(kra.dogtag_constants.KRA_CS_CFG_PATH)
|
||||
else:
|
||||
service.print_msg("Restarting the directory server")
|
||||
ds.restart()
|
||||
|
||||
service.print_msg("Restarting the KDC")
|
||||
krb.restart()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Simo Sorce <ssorce@redhat.com>
|
||||
# Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007-2010 Red Hat
|
||||
# Copyright (C) 2007-2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -53,6 +53,7 @@ from ipaserver.install import httpinstance
|
||||
from ipaserver.install import ntpinstance
|
||||
from ipaserver.install import certs
|
||||
from ipaserver.install import cainstance
|
||||
from ipaserver.install import krainstance
|
||||
from ipaserver.install import memcacheinstance
|
||||
from ipaserver.install import otpdinstance
|
||||
from ipaserver.install import sysupgrade
|
||||
@@ -520,11 +521,20 @@ def uninstall():
|
||||
dogtag_constants=dogtag_constants)
|
||||
if cads_instance.is_configured():
|
||||
cads_instance.uninstall()
|
||||
cainstance.stop_tracking_certificates(dogtag_constants)
|
||||
|
||||
kra_instance = krainstance.KRAInstance(
|
||||
api.env.realm, dogtag_constants=dogtag_constants)
|
||||
kra_instance.stop_tracking_certificates(dogtag_constants)
|
||||
if kra_instance.is_installed():
|
||||
kra_instance.uninstall()
|
||||
|
||||
ca_instance = cainstance.CAInstance(
|
||||
api.env.realm, certs.NSS_DIR, dogtag_constants=dogtag_constants)
|
||||
ca_instance.stop_tracking_certificates(dogtag_constants)
|
||||
ca_instance.stop_tracking_agent_certificate(dogtag_constants)
|
||||
if ca_instance.is_configured():
|
||||
ca_instance.uninstall()
|
||||
|
||||
bindinstance.BindInstance(fstore).uninstall()
|
||||
httpinstance.HTTPInstance(fstore).uninstall()
|
||||
krbinstance.KrbInstance(fstore).uninstall()
|
||||
@@ -757,8 +767,13 @@ def main():
|
||||
# We only set up the CA if the PKCS#12 options are not given.
|
||||
if options.dirsrv_pkcs12:
|
||||
setup_ca = False
|
||||
setup_kra = False
|
||||
else:
|
||||
setup_ca = True
|
||||
# setup_kra is set to False until Dogtag 10.2 is available for IPA to consume
|
||||
# Until then users that want to install the KRA need to use ipa-install-kra
|
||||
# TODO set setup_kra = True when Dogtag 10.2 is available
|
||||
setup_kra = False
|
||||
|
||||
# Figure out what external CA step we're in. See cainstance.py for more
|
||||
# info on the 3 states.
|
||||
@@ -775,6 +790,8 @@ def main():
|
||||
print "This includes:"
|
||||
if setup_ca:
|
||||
print " * Configure a stand-alone CA (dogtag) for certificate management"
|
||||
if setup_kra:
|
||||
print " * Configure a stand-alone KRA (dogtag) for key storage"
|
||||
if options.conf_ntp:
|
||||
print " * Configure the Network Time Daemon (ntpd)"
|
||||
print " * Create and configure an instance of Directory Server"
|
||||
@@ -1021,6 +1038,7 @@ def main():
|
||||
else:
|
||||
fd.write("enable_ra=False\n")
|
||||
fd.write("ra_plugin=none\n")
|
||||
fd.write("enable_kra=%s\n" % setup_kra)
|
||||
fd.write("mode=production\n")
|
||||
fd.close()
|
||||
|
||||
@@ -1122,7 +1140,7 @@ def main():
|
||||
ipautil.realm_to_suffix(realm_name), ['caRenewalMaster'])
|
||||
|
||||
# This is done within stopped_service context, which restarts CA
|
||||
ca.enable_client_auth_to_db()
|
||||
ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH)
|
||||
|
||||
krb = krbinstance.KrbInstance(fstore)
|
||||
if options.pkinit_pkcs12:
|
||||
@@ -1204,6 +1222,20 @@ def main():
|
||||
service.print_msg("Restarting the web server")
|
||||
http.restart()
|
||||
|
||||
if setup_kra:
|
||||
kra = krainstance.KRAInstance(realm_name,
|
||||
dogtag_constants=dogtag.install_constants)
|
||||
kra.configure_instance(host_name, domain_name, dm_password,
|
||||
dm_password, subject_base=options.subject)
|
||||
|
||||
# This is done within stopped_service context, which restarts KRA
|
||||
service.print_msg("Restarting the directory server")
|
||||
ds.restart()
|
||||
|
||||
service.print_msg("Enabling KRA to authenticate with the database "
|
||||
"using client certificates")
|
||||
kra.enable_client_auth_to_db(kra.dogtag_constants.KRA_CS_CFG_PATH)
|
||||
|
||||
# Set the admin user kerberos password
|
||||
ds.change_admin_password(admin_password)
|
||||
|
||||
@@ -1256,9 +1288,11 @@ def main():
|
||||
|
||||
print ""
|
||||
if setup_ca:
|
||||
print "Be sure to back up the CA certificate stored in /root/cacert.p12"
|
||||
print "This file is required to create replicas. The password for this"
|
||||
print "file is the Directory Manager password"
|
||||
print "Be sure to back up the CA certificates stored in " + paths.CACERT_P12
|
||||
if setup_kra:
|
||||
print "and the KRA certificates stored in " + paths.KRACERT_P12
|
||||
print "These files are required to create replicas. The password for these"
|
||||
print "files is the Directory Manager password"
|
||||
else:
|
||||
print "In order for Firefox autoconfiguration to work you will need to"
|
||||
print "use a SSL signing certificate. See the IPA documentation for more details."
|
||||
|
||||
@@ -537,12 +537,15 @@ def named_update_gssapi_configuration():
|
||||
return False
|
||||
|
||||
try:
|
||||
bindinstance.named_conf_set_directive('tkey-gssapi-credential', None,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
bindinstance.named_conf_set_directive('tkey-domain', None,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
bindinstance.named_conf_set_directive('tkey-gssapi-keytab', paths.NAMED_KEYTAB,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
bindinstance.named_conf_set_directive(
|
||||
'tkey-gssapi-credential', None,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
bindinstance.named_conf_set_directive(
|
||||
'tkey-domain', None,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
bindinstance.named_conf_set_directive(
|
||||
'tkey-gssapi-keytab', paths.NAMED_KEYTAB,
|
||||
bindinstance.NAMED_SECTION_OPTIONS)
|
||||
except IOError, e:
|
||||
root_logger.error('Cannot update GSSAPI configuration in %s: %s',
|
||||
bindinstance.NAMED_CONF, e)
|
||||
@@ -553,6 +556,7 @@ def named_update_gssapi_configuration():
|
||||
sysupgrade.set_upgrade_state('named.conf', 'gssapi_updated', True)
|
||||
return True
|
||||
|
||||
|
||||
def named_update_pid_file():
|
||||
"""
|
||||
Make sure that named reads the pid file from the right file
|
||||
@@ -723,7 +727,7 @@ def certificate_renewal_update(ca):
|
||||
|
||||
# Ok, now we need to stop tracking, then we can start tracking them
|
||||
# again with new configuration:
|
||||
cainstance.stop_tracking_certificates(dogtag_constants)
|
||||
ca.stop_tracking_certificates(dogtag_constants)
|
||||
|
||||
if not sysupgrade.get_upgrade_state('dogtag',
|
||||
'certificate_renewal_update_1'):
|
||||
@@ -884,71 +888,9 @@ def add_ca_dns_records():
|
||||
def find_subject_base():
|
||||
"""
|
||||
Try to find the current value of certificate subject base.
|
||||
1) Look in sysupgrade first
|
||||
2) If no value is found there, look in DS (start DS if necessary)
|
||||
3) Last resort, look in the certmap.conf itself
|
||||
4) If all fails, log loudly and return None
|
||||
See the docstring in dsinstance.DsInstance for details.
|
||||
"""
|
||||
root_logger.debug('Trying to find certificate subject base in sysupgrade')
|
||||
subject_base = sysupgrade.get_upgrade_state('certmap.conf', 'subject_base')
|
||||
|
||||
if subject_base:
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in sysupgrade: %s',
|
||||
subject_base
|
||||
)
|
||||
return subject_base
|
||||
|
||||
root_logger.debug('Unable to find certificate subject base in sysupgrade')
|
||||
root_logger.debug('Trying to find certificate subject base in DS')
|
||||
|
||||
ds_is_running = services.knownservices.dirsrv.is_running()
|
||||
if not ds_is_running:
|
||||
try:
|
||||
services.knownservices.dirsrv.start()
|
||||
except ipautil.CalledProcessError as e:
|
||||
root_logger.error('Cannot start DS to find certificate '
|
||||
'subject base: %s', e)
|
||||
else:
|
||||
ds_is_running = True
|
||||
|
||||
if ds_is_running:
|
||||
try:
|
||||
api.Backend.ldap2.connect(autobind=True)
|
||||
except ipalib.errors.PublicError, e:
|
||||
root_logger.error('Cannot connect to DS to find certificate '
|
||||
'subject base: %s', e)
|
||||
else:
|
||||
ret = api.Command['config_show']()
|
||||
api.Backend.ldap2.disconnect()
|
||||
subject_base = str(ret['result']['ipacertificatesubjectbase'][0])
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in DS: %s',
|
||||
subject_base
|
||||
)
|
||||
|
||||
if not subject_base:
|
||||
root_logger.debug('Unable to find certificate subject base in DS')
|
||||
root_logger.debug('Trying to find certificate subject base in '
|
||||
'certmap.conf')
|
||||
|
||||
certmap_dir = dsinstance.config_dirname(
|
||||
dsinstance.realm_to_serverid(api.env.realm)
|
||||
)
|
||||
try:
|
||||
with open(os.path.join(certmap_dir, 'certmap.conf')) as f:
|
||||
for line in f:
|
||||
if line.startswith('certmap ipaca'):
|
||||
subject_base = line.strip().split(',')[-1]
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in certmap.conf: '
|
||||
'%s',
|
||||
subject_base
|
||||
)
|
||||
|
||||
except IOError as e:
|
||||
root_logger.error('Cannot open certmap.conf to find certificate '
|
||||
'subject base: %s', e.strerror)
|
||||
subject_base = dsinstance.DsInstance().find_subject_base()
|
||||
|
||||
if subject_base:
|
||||
sysupgrade.set_upgrade_state(
|
||||
@@ -958,8 +900,6 @@ def find_subject_base():
|
||||
)
|
||||
return subject_base
|
||||
|
||||
root_logger.debug('Unable to find certificate subject base in '
|
||||
'certmap.conf')
|
||||
root_logger.error('Unable to determine certificate subject base. '
|
||||
'certmap.conf will not be updated.')
|
||||
|
||||
|
||||
@@ -155,6 +155,8 @@ DEFAULT_CONFIG = (
|
||||
('ca_agent_install_port', None),
|
||||
('ca_ee_install_port', None),
|
||||
|
||||
# KRA plugin
|
||||
('kra_host', FQDN), # Set in Env._finalize_core()
|
||||
|
||||
# Special CLI:
|
||||
('prompt_all', False),
|
||||
|
||||
@@ -125,7 +125,8 @@ class BasePathNamespace(object):
|
||||
HOME_DIR = "/home"
|
||||
ROOT_IPA_CACHE = "/root/.ipa_cache"
|
||||
ROOT_PKI = "/root/.pki"
|
||||
CA_AGENT_P12 = "/root/ca-agent.p12"
|
||||
DOGTAG_AGENT_P12 = "/root/ca-agent.p12"
|
||||
DOGTAG_AGENT_PEM = "/etc/httpd/alias/agent.pem"
|
||||
CACERT_P12 = "/root/cacert.p12"
|
||||
ROOT_IPA_CSR = "/root/ipa.csr"
|
||||
ROOT_TMP_CA_P12 = "/root/tmp-ca.p12"
|
||||
@@ -218,7 +219,7 @@ class BasePathNamespace(object):
|
||||
SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/schema_compat.uldif"
|
||||
IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins"
|
||||
UPDATES_DIR = "/usr/share/ipa/updates/"
|
||||
PKI_CONF_SERVER_XML = "/usr/share/pki/ca/conf/server.xml"
|
||||
PKI_CONF_SERVER_XML_TEMPLATE = "/usr/share/pki/%s/conf/server.xml"
|
||||
CACHE_IPA_SESSIONS = "/var/cache/ipa/sessions"
|
||||
VAR_KERBEROS_KRB5KDC_DIR = "/var/kerberos/krb5kdc/"
|
||||
VAR_KRB5KDC_K5_REALM = "/var/kerberos/krb5kdc/.k5."
|
||||
@@ -254,6 +255,8 @@ class BasePathNamespace(object):
|
||||
PKI_ALIAS_CA_P12 = "/var/lib/pki-ca/alias/ca.p12"
|
||||
VAR_LIB_PKI_TOMCAT_DIR = "/var/lib/pki/pki-tomcat"
|
||||
CA_BACKUP_KEYS_P12 = "/var/lib/pki/pki-tomcat/alias/ca_backup_keys.p12"
|
||||
KRA_BACKUP_KEYS_P12 = "/var/lib/pki/pki-tomcat/alias/kra_backup_keys.p12"
|
||||
KRACERT_P12 = "/root/kracert.p12"
|
||||
SAMBA_DIR = "/var/lib/samba/"
|
||||
SSSD_MC_GROUP = "/var/lib/sss/mc/group"
|
||||
SSSD_MC_PASSWD = "/var/lib/sss/mc/passwd"
|
||||
@@ -282,6 +285,8 @@ class BasePathNamespace(object):
|
||||
PKI_CA_LOG_DIR = "/var/log/pki-ca"
|
||||
PKI_CA_INSTALL_LOG = "/var/log/pki-ca-install.log"
|
||||
PKI_CA_UNINSTALL_LOG = "/var/log/pki-ca-uninstall.log"
|
||||
PKI_KRA_INSTALL_LOG = "/var/log/pki-kra-install.log"
|
||||
PKI_KRA_UNINSTALL_LOG = "/var/log/pki-kra-uninstall.log"
|
||||
VAR_LOG_PKI_DIR = "/var/log/pki/"
|
||||
TOMCAT_TOPLEVEL_DIR = "/var/log/pki/pki-tomcat"
|
||||
TOMCAT_CA_DIR = "/var/log/pki/pki-tomcat/ca"
|
||||
@@ -296,5 +301,8 @@ class BasePathNamespace(object):
|
||||
KRB5CC_SAMBA = "/var/run/samba/krb5cc_samba"
|
||||
SLAPD_INSTANCE_SOCKET_TEMPLATE = "/var/run/slapd-%s.socket"
|
||||
ALL_SLAPD_INSTANCE_SOCKETS = "/var/run/slapd-*.socket"
|
||||
ADMIN_CERT_PATH = '/root/.dogtag/pki-tomcat/ca_admin.cert'
|
||||
ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail'
|
||||
|
||||
|
||||
path_namespace = BasePathNamespace
|
||||
|
||||
@@ -24,10 +24,9 @@ import ConfigParser
|
||||
from urllib import urlencode
|
||||
|
||||
import nss.nss as nss
|
||||
from nss.error import NSPRError
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipalib.errors import NetworkError, CertificateOperationError
|
||||
from ipalib.errors import NetworkError
|
||||
from ipalib.text import _
|
||||
from ipapython import nsslib, ipautil
|
||||
from ipaplatform.paths import paths
|
||||
@@ -42,6 +41,7 @@ from ipapython.ipa_log_manager import *
|
||||
# The configured_constants() function below provides constants relevant to
|
||||
# the configured version.
|
||||
|
||||
|
||||
class Dogtag10Constants(object):
|
||||
DOGTAG_VERSION = 10
|
||||
UNSECURE_PORT = 8080
|
||||
@@ -63,6 +63,7 @@ class Dogtag10Constants(object):
|
||||
SERVICE_PROFILE_DIR = '%s/ca/profiles/ca' % PKI_ROOT
|
||||
ALIAS_DIR = paths.PKI_TOMCAT_ALIAS_DIR.rstrip('/')
|
||||
SYSCONFIG_FILE_PATH = '%s/%s' % (paths.ETC_SYSCONFIG_DIR, PKI_INSTANCE_NAME)
|
||||
KRA_CS_CFG_PATH = '%s/conf/kra/CS.cfg' % PKI_ROOT
|
||||
|
||||
SERVICE_NAME = 'pki_tomcatd'
|
||||
|
||||
@@ -165,7 +166,8 @@ def get_ca_certchain(ca_host=None, dogtag_constants=None):
|
||||
if dogtag_constants is None:
|
||||
dogtag_constants = configured_constants()
|
||||
chain = None
|
||||
conn = httplib.HTTPConnection(ca_host,
|
||||
conn = httplib.HTTPConnection(
|
||||
ca_host,
|
||||
api.env.ca_install_port or dogtag_constants.UNSECURE_PORT)
|
||||
conn.request("GET", "/ca/ee/ca/getCertChain")
|
||||
res = conn.getresponse()
|
||||
@@ -244,7 +246,7 @@ def https_request(host, port, url, secdir, password, nickname, **kw):
|
||||
|
||||
body = urlencode(kw)
|
||||
return _httplib_request(
|
||||
'https', host, port, url, connection_factory, body)
|
||||
'https', host, port, url, connection_factory, body)
|
||||
|
||||
|
||||
def http_request(host, port, url, **kw):
|
||||
@@ -291,7 +293,8 @@ def _httplib_request(
|
||||
root_logger.debug('request body %r', request_body)
|
||||
try:
|
||||
conn = connection_factory(host, port)
|
||||
conn.request('POST', uri,
|
||||
conn.request(
|
||||
'POST', uri,
|
||||
body=request_body,
|
||||
headers={'Content-type': 'application/x-www-form-urlencoded'},
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
399
ipaserver/install/dogtaginstance.py
Normal file
399
ipaserver/install/dogtaginstance.py
Normal file
@@ -0,0 +1,399 @@
|
||||
# Authors: Ade Lee <alee@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 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 base64
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import traceback
|
||||
|
||||
from pki.client import PKIConnection
|
||||
import pki.system
|
||||
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import certmonger
|
||||
from ipapython import dogtag
|
||||
from ipapython import ipaldap
|
||||
from ipapython import ipautil
|
||||
from ipapython.dn import DN
|
||||
from ipaserver.install import service
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install.installutils import stopped_service
|
||||
from ipapython.ipa_log_manager import log_mgr
|
||||
|
||||
DEFAULT_DSPORT = dogtag.install_constants.DS_PORT
|
||||
|
||||
PKI_USER = "pkiuser"
|
||||
PKI_DS_USER = dogtag.install_constants.DS_USER
|
||||
|
||||
|
||||
def check_inst(subsystem):
|
||||
"""
|
||||
Validate that the appropriate dogtag/RHCS packages have been installed.
|
||||
"""
|
||||
|
||||
# Check for a couple of binaries we need
|
||||
if not os.path.exists(dogtag.install_constants.SPAWN_BINARY):
|
||||
return False
|
||||
if not os.path.exists(dogtag.install_constants.DESTROY_BINARY):
|
||||
return False
|
||||
|
||||
if not os.path.exists(paths.PKI_CONF_SERVER_XML_TEMPLATE % subsystem):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_security_domain():
|
||||
"""
|
||||
Get the security domain from the REST interface on the local Dogtag CA
|
||||
This function will succeed if the local dogtag CA is up.
|
||||
"""
|
||||
connection = PKIConnection()
|
||||
domain_client = pki.system.SecurityDomainClient(connection)
|
||||
info = domain_client.get_security_domain_info()
|
||||
return info
|
||||
|
||||
|
||||
def is_installing_replica(sys_type):
|
||||
"""
|
||||
We expect only one of each type of Dogtag subsystem in an IPA deployment.
|
||||
That means that if a subsystem of the specified type has already been
|
||||
deployed - and therefore appears in the security domain - then we must be
|
||||
installing a replica.
|
||||
"""
|
||||
info = get_security_domain()
|
||||
try:
|
||||
sys_list = info.systems[sys_type]
|
||||
return len(sys_list.hosts) > 0
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
class DogtagInstance(service.Service):
|
||||
"""
|
||||
This is the base class for a Dogtag 10+ instance, which uses a
|
||||
shared tomcat instance and DS to host the relevant subsystems.
|
||||
|
||||
It contains functions that will be common to installations of the
|
||||
CA, KRA, and eventually TKS and TPS.
|
||||
"""
|
||||
|
||||
def __init__(self, realm, subsystem, service_desc, dogtag_constants=None,
|
||||
host_name=None, dm_password=None, ldapi=True):
|
||||
"""Initializer"""
|
||||
|
||||
if dogtag_constants is None:
|
||||
dogtag_constants = dogtag.configured_constants()
|
||||
|
||||
super(DogtagInstance, self).__init__(
|
||||
'%sd' % dogtag_constants.PKI_INSTANCE_NAME,
|
||||
service_desc=service_desc,
|
||||
dm_password=dm_password,
|
||||
ldapi=ldapi
|
||||
)
|
||||
|
||||
self.dogtag_constants = dogtag_constants
|
||||
self.realm = realm
|
||||
self.dm_password = None
|
||||
self.admin_password = None
|
||||
self.fqdn = host_name
|
||||
self.domain = None
|
||||
self.pkcs12_info = None
|
||||
self.clone = False
|
||||
|
||||
self.basedn = DN(('o', 'ipa%s' % subsystem.lower()))
|
||||
self.admin_user = DN(('uid', 'admin'), ('ou', 'people'), ('o', 'ipaca'))
|
||||
self.agent_db = tempfile.mkdtemp(prefix="tmp-")
|
||||
self.ds_port = DEFAULT_DSPORT
|
||||
self.server_root = dogtag_constants.SERVER_ROOT
|
||||
self.subsystem = subsystem
|
||||
self.security_domain_name = "IPA"
|
||||
self.tracking_reqs = None
|
||||
|
||||
# replication parameters
|
||||
self.master_host = None
|
||||
self.master_replication_port = None
|
||||
self.subject_base = None
|
||||
|
||||
self.log = log_mgr.get_logger(self)
|
||||
|
||||
def __del__(self):
|
||||
shutil.rmtree(self.agent_db, ignore_errors=True)
|
||||
|
||||
def is_installed(self):
|
||||
"""
|
||||
Determine if subsystem instance has been installed.
|
||||
|
||||
Returns True/False
|
||||
"""
|
||||
return os.path.exists(os.path.join(
|
||||
self.server_root, self.dogtag_constants.PKI_INSTANCE_NAME,
|
||||
self.subsystem.lower()))
|
||||
|
||||
def spawn_instance(self, cfg_file, nolog_list=None):
|
||||
"""
|
||||
Create and configure a new Dogtag instance using pkispawn.
|
||||
Passes in a configuration file with IPA-specific
|
||||
parameters.
|
||||
"""
|
||||
subsystem = self.subsystem
|
||||
|
||||
# Define the things we don't want logged
|
||||
if nolog_list is None:
|
||||
nolog_list = []
|
||||
nolog = tuple(nolog_list) + (self.admin_password, self.dm_password)
|
||||
|
||||
args = [paths.PKISPAWN,
|
||||
"-s", subsystem,
|
||||
"-f", cfg_file]
|
||||
|
||||
with open(cfg_file) as f:
|
||||
self.log.debug(
|
||||
'Contents of pkispawn configuration file (%s):\n%s',
|
||||
cfg_file, ipautil.nolog_replace(f.read(), nolog))
|
||||
|
||||
try:
|
||||
ipautil.run(args, nolog=nolog)
|
||||
except ipautil.CalledProcessError, e:
|
||||
self.log.critical("failed to configure %s instance %s",
|
||||
subsystem, e)
|
||||
raise RuntimeError('Configuration of %s failed' % subsystem)
|
||||
|
||||
def enable(self):
|
||||
self.backup_state("enabled", self.is_enabled())
|
||||
# We do not let the system start IPA components on its own,
|
||||
# Instead we reply on the IPA init script to start only enabled
|
||||
# components as found in our LDAP configuration tree
|
||||
# We need to install DS before we can actually ldap_enable a service.
|
||||
# so actual enablement is delayed.
|
||||
|
||||
def restart_instance(self):
|
||||
try:
|
||||
self.restart(self.dogtag_constants.PKI_INSTANCE_NAME)
|
||||
except Exception:
|
||||
self.log.debug(traceback.format_exc())
|
||||
self.log.critical(
|
||||
"Failed to restart the Dogtag instance."
|
||||
"See the installation log for details.")
|
||||
|
||||
def start_instance(self):
|
||||
try:
|
||||
self.start(self.dogtag_constants.PKI_INSTANCE_NAME)
|
||||
except Exception:
|
||||
self.log.debug(traceback.format_exc())
|
||||
self.log.critical(
|
||||
"Failed to restart the Dogtag instance."
|
||||
"See the installation log for details.")
|
||||
|
||||
def stop_instance(self):
|
||||
try:
|
||||
self.stop(self.dogtag_constants.PKI_INSTANCE_NAME)
|
||||
except Exception:
|
||||
self.log.debug(traceback.format_exc())
|
||||
self.log.critical(
|
||||
"Failed to restart the Dogtag instance."
|
||||
"See the installation log for details.")
|
||||
|
||||
def enable_client_auth_to_db(self, config):
|
||||
"""
|
||||
Enable client auth connection to the internal db.
|
||||
Path to CS.cfg config file passed in.
|
||||
"""
|
||||
|
||||
with stopped_service(
|
||||
self.dogtag_constants.SERVICE_NAME,
|
||||
instance_name=self.dogtag_constants.PKI_INSTANCE_NAME):
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'authz.instance.DirAclAuthz.ldap.ldapauth.authtype',
|
||||
'SslClientAuth', quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'authz.instance.DirAclAuthz.ldap.ldapauth.bindDN',
|
||||
'uid=pkidbuser,ou=people,o=ipaca', quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'authz.instance.DirAclAuthz.ldap.ldapauth.clientCertNickname',
|
||||
'subsystemCert cert-pki-ca', quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'authz.instance.DirAclAuthz.ldap.ldapconn.port',
|
||||
str(dogtag.install_constants.DS_SECURE_PORT),
|
||||
quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'authz.instance.DirAclAuthz.ldap.ldapconn.secureConn',
|
||||
'true', quotes=False, separator='=')
|
||||
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'internaldb.ldapauth.authtype',
|
||||
'SslClientAuth', quotes=False, separator='=')
|
||||
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'internaldb.ldapauth.bindDN',
|
||||
'uid=pkidbuser,ou=people,o=ipaca', quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'internaldb.ldapauth.clientCertNickname',
|
||||
'subsystemCert cert-pki-ca', quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'internaldb.ldapconn.port',
|
||||
str(dogtag.install_constants.DS_SECURE_PORT),
|
||||
quotes=False, separator='=')
|
||||
installutils.set_directive(
|
||||
config,
|
||||
'internaldb.ldapconn.secureConn', 'true', quotes=False,
|
||||
separator='=')
|
||||
|
||||
def uninstall(self):
|
||||
if self.is_installed():
|
||||
self.print_msg("Unconfiguring %s" % self.subsystem)
|
||||
|
||||
try:
|
||||
ipautil.run([paths.PKIDESTROY, "-i",
|
||||
self.dogtag_constants.PKI_INSTANCE_NAME,
|
||||
"-s", self.subsystem])
|
||||
except ipautil.CalledProcessError, e:
|
||||
self.log.critical("failed to uninstall %s instance %s",
|
||||
self.subsystem, e)
|
||||
|
||||
def http_proxy(self):
|
||||
""" Update the http proxy file """
|
||||
template_filename = ipautil.SHARE_DIR + "ipa-pki-proxy.conf"
|
||||
sub_dict = dict(
|
||||
DOGTAG_PORT=self.dogtag_constants.AJP_PORT,
|
||||
CLONE='' if self.clone else '#',
|
||||
FQDN=self.fqdn,
|
||||
)
|
||||
template = ipautil.template_file(template_filename, sub_dict)
|
||||
with open(paths.HTTPD_IPA_PKI_PROXY_CONF, "w") as fd:
|
||||
fd.write(template)
|
||||
|
||||
def __get_pin(self):
|
||||
try:
|
||||
return certmonger.get_pin('internal',
|
||||
dogtag_constants=self.dogtag_constants)
|
||||
except IOError, e:
|
||||
self.log.debug(
|
||||
'Unable to determine PIN for the Dogtag instance: %s', e)
|
||||
raise RuntimeError(e)
|
||||
|
||||
def configure_renewal(self, reqs=None):
|
||||
""" Configure certmonger to renew system certs
|
||||
|
||||
@param reqs: list of nicknames and profiles
|
||||
"""
|
||||
cmonger = services.knownservices.certmonger
|
||||
cmonger.enable()
|
||||
services.knownservices.messagebus.start()
|
||||
cmonger.start()
|
||||
|
||||
pin = self.__get_pin()
|
||||
|
||||
if reqs is None:
|
||||
reqs = self.tracking_reqs
|
||||
|
||||
for nickname, profile in reqs:
|
||||
try:
|
||||
certmonger.dogtag_start_tracking(
|
||||
ca='dogtag-ipa-ca-renew-agent',
|
||||
nickname=nickname,
|
||||
pin=pin,
|
||||
pinfile=None,
|
||||
secdir=self.dogtag_constants.ALIAS_DIR,
|
||||
pre_command='stop_pkicad',
|
||||
post_command='renew_ca_cert "%s"' % nickname,
|
||||
profile=profile)
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
self.log.error(
|
||||
"certmonger failed to start tracking certificate: %s", e)
|
||||
|
||||
def stop_tracking_certificates(self, dogtag_constants, reqs=None):
|
||||
"""Stop tracking our certificates. Called on uninstall.
|
||||
"""
|
||||
cmonger = services.knownservices.certmonger
|
||||
services.knownservices.messagebus.start()
|
||||
cmonger.start()
|
||||
|
||||
if reqs is None:
|
||||
reqs = self.tracking_reqs
|
||||
|
||||
for nickname, _profile in reqs:
|
||||
try:
|
||||
certmonger.stop_tracking(
|
||||
dogtag_constants.ALIAS_DIR, nickname=nickname)
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
self.log.error(
|
||||
"certmonger failed to stop tracking certificate: %s", e)
|
||||
|
||||
cmonger.stop()
|
||||
|
||||
@staticmethod
|
||||
def update_cert_cs_cfg(nickname, cert, directives, cs_cfg,
|
||||
dogtag_constants=None):
|
||||
"""
|
||||
When renewing a Dogtag subsystem certificate the configuration file
|
||||
needs to get the new certificate as well.
|
||||
|
||||
nickname is one of the known nicknames.
|
||||
cert is a DER-encoded certificate.
|
||||
directives is the list of directives to be updated for the subsystem
|
||||
cs_cfg is the path to the CS.cfg file
|
||||
"""
|
||||
|
||||
if dogtag_constants is None:
|
||||
dogtag_constants = dogtag.configured_constants()
|
||||
|
||||
with stopped_service(dogtag_constants.SERVICE_NAME,
|
||||
instance_name=dogtag_constants.PKI_INSTANCE_NAME):
|
||||
installutils.set_directive(
|
||||
cs_cfg,
|
||||
directives[nickname],
|
||||
base64.b64encode(cert),
|
||||
quotes=False,
|
||||
separator='=')
|
||||
|
||||
def get_admin_cert(self):
|
||||
"""
|
||||
Get the certificate for the admin user by checking the ldap entry
|
||||
for the user. There should be only one certificate per user.
|
||||
"""
|
||||
self.log.debug('Trying to find the certificate for the admin user')
|
||||
conn = None
|
||||
|
||||
try:
|
||||
conn = ipaldap.IPAdmin(self.fqdn, self.ds_port)
|
||||
conn.do_simple_bind(
|
||||
DN(('cn', 'Directory Manager')),
|
||||
self.dm_password)
|
||||
|
||||
entry_attrs = conn.get_entry(self.admin_user, ['usercertificate'])
|
||||
admin_cert = entry_attrs.get('usercertificate')[0]
|
||||
|
||||
# TODO(edewata) Add check to warn if there is more than one cert.
|
||||
finally:
|
||||
if conn is not None:
|
||||
conn.unbind()
|
||||
|
||||
return base64.b64encode(admin_cert)
|
||||
@@ -25,7 +25,6 @@ import os
|
||||
import re
|
||||
import time
|
||||
import tempfile
|
||||
import base64
|
||||
import stat
|
||||
import grp
|
||||
|
||||
@@ -38,7 +37,9 @@ import ldap
|
||||
from ipaserver.install import ldapupdate
|
||||
from ipaserver.install import replication
|
||||
from ipaserver.install import sysupgrade
|
||||
from ipalib import errors, certstore
|
||||
from ipalib import api
|
||||
from ipalib import certstore
|
||||
from ipalib import errors
|
||||
from ipaplatform.tasks import tasks
|
||||
from ipalib.constants import CACERT
|
||||
from ipapython.dn import DN
|
||||
@@ -952,3 +953,85 @@ class DsInstance(service.Service):
|
||||
pass
|
||||
|
||||
self.ldap_disconnect()
|
||||
|
||||
def find_subject_base(self):
|
||||
"""
|
||||
Try to find the current value of certificate subject base.
|
||||
1) Look in sysupgrade first
|
||||
2) If no value is found there, look in DS (start DS if necessary)
|
||||
3) Last resort, look in the certmap.conf itself
|
||||
4) If all fails, log loudly and return None
|
||||
|
||||
Note that this method can only be executed AFTER the ipa server
|
||||
is configured, the api is initialized elsewhere and
|
||||
that a ticket already have been acquired.
|
||||
"""
|
||||
root_logger.debug(
|
||||
'Trying to find certificate subject base in sysupgrade')
|
||||
subject_base = sysupgrade.get_upgrade_state(
|
||||
'certmap.conf', 'subject_base')
|
||||
|
||||
if subject_base:
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in sysupgrade: %s',
|
||||
subject_base)
|
||||
return subject_base
|
||||
|
||||
root_logger.debug(
|
||||
'Unable to find certificate subject base in sysupgrade')
|
||||
root_logger.debug(
|
||||
'Trying to find certificate subject base in DS')
|
||||
|
||||
ds_is_running = is_ds_running()
|
||||
if not ds_is_running:
|
||||
try:
|
||||
self.start()
|
||||
ds_is_running = True
|
||||
except ipautil.CalledProcessError as e:
|
||||
root_logger.error('Cannot start DS to find certificate '
|
||||
'subject base: %s', e)
|
||||
|
||||
if ds_is_running:
|
||||
try:
|
||||
api.Backend.ldap2.connect(autobind=True)
|
||||
ret = api.Command['config_show']()
|
||||
subject_base = str(
|
||||
ret['result']['ipacertificatesubjectbase'][0])
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in DS: %s', subject_base)
|
||||
except errors.PublicError, e:
|
||||
root_logger.error('Cannot connect to DS to find certificate '
|
||||
'subject base: %s', e)
|
||||
finally:
|
||||
try:
|
||||
api.Backend.ldap2.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not subject_base:
|
||||
root_logger.debug('Unable to find certificate subject base in DS')
|
||||
root_logger.debug('Trying to find certificate subject base in '
|
||||
'certmap.conf')
|
||||
|
||||
certmap_dir = config_dirname(
|
||||
realm_to_serverid(api.env.realm)
|
||||
)
|
||||
try:
|
||||
with open(os.path.join(certmap_dir, 'certmap.conf')) as f:
|
||||
for line in f:
|
||||
if line.startswith('certmap ipaca'):
|
||||
subject_base = line.strip().split(',')[-1]
|
||||
root_logger.debug(
|
||||
'Found certificate subject base in certmap.conf: '
|
||||
'%s', subject_base)
|
||||
|
||||
except IOError as e:
|
||||
root_logger.error('Cannot open certmap.conf to find certificate '
|
||||
'subject base: %s', e.strerror)
|
||||
|
||||
if subject_base:
|
||||
return subject_base
|
||||
|
||||
root_logger.debug('Unable to find certificate subject base in '
|
||||
'certmap.conf')
|
||||
return None
|
||||
|
||||
@@ -35,9 +35,9 @@ from dns.exception import DNSException
|
||||
import ldap
|
||||
from nss.error import NSPRError
|
||||
|
||||
from ipapython import ipautil, sysrestore, admintool, dogtag
|
||||
from ipapython import ipautil, sysrestore, admintool, dogtag, version
|
||||
from ipapython.admintool import ScriptError
|
||||
from ipapython.ipa_log_manager import *
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
from ipalib.util import validate_hostname
|
||||
from ipapython import config
|
||||
from ipalib import errors, x509
|
||||
@@ -68,7 +68,7 @@ class HostnameLocalhost(HostLookupError):
|
||||
pass
|
||||
|
||||
class ReplicaConfig:
|
||||
def __init__(self):
|
||||
def __init__(self, top_dir=None):
|
||||
self.realm_name = ""
|
||||
self.domain_name = ""
|
||||
self.master_host_name = ""
|
||||
@@ -78,6 +78,7 @@ class ReplicaConfig:
|
||||
self.subject_base = None
|
||||
self.setup_ca = False
|
||||
self.version = 0
|
||||
self.top_dir = top_dir
|
||||
|
||||
subject_base = ipautil.dn_attribute_property('_subject_base')
|
||||
|
||||
@@ -174,7 +175,7 @@ def verify_fqdn(host_name, no_host_dns=False, local_hostname=True):
|
||||
raise HostReverseLookupError("The host name %s does not match the reverse lookup %s" % (host_name, revname))
|
||||
verified.add(address)
|
||||
|
||||
def record_in_hosts(ip, host_name=None, file=paths.HOSTS):
|
||||
def record_in_hosts(ip, host_name=None, conf_file=paths.HOSTS):
|
||||
"""
|
||||
Search record in /etc/hosts - static table lookup for hostnames
|
||||
|
||||
@@ -184,9 +185,9 @@ def record_in_hosts(ip, host_name=None, file=paths.HOSTS):
|
||||
|
||||
:param ip: IP address
|
||||
:param host_name: Optional hostname to search
|
||||
:param file: Optional path to the lookup table
|
||||
:param conf_file: Optional path to the lookup table
|
||||
"""
|
||||
hosts = open(file, 'r').readlines()
|
||||
hosts = open(conf_file, 'r').readlines()
|
||||
for line in hosts:
|
||||
line = line.rstrip('\n')
|
||||
fields = line.partition('#')[0].split()
|
||||
@@ -206,13 +207,13 @@ def record_in_hosts(ip, host_name=None, file=paths.HOSTS):
|
||||
return None
|
||||
return (hosts_ip, names)
|
||||
except IndexError:
|
||||
print "Warning: Erroneous line '%s' in %s" % (line, file)
|
||||
print "Warning: Erroneous line '%s' in %s" % (line, conf_file)
|
||||
continue
|
||||
|
||||
return None
|
||||
|
||||
def add_record_to_hosts(ip, host_name, file=paths.HOSTS):
|
||||
hosts_fd = open(file, 'r+')
|
||||
def add_record_to_hosts(ip, host_name, conf_file=paths.HOSTS):
|
||||
hosts_fd = open(conf_file, 'r+')
|
||||
hosts_fd.seek(0, 2)
|
||||
hosts_fd.write(ip+'\t'+host_name+' '+host_name.split('.')[0]+'\n')
|
||||
hosts_fd.close()
|
||||
@@ -512,20 +513,20 @@ def expand_replica_info(filename, password):
|
||||
"""
|
||||
top_dir = tempfile.mkdtemp("ipa")
|
||||
tarfile = top_dir+"/files.tar"
|
||||
dir = top_dir + "/realm_info"
|
||||
dir_path = 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
|
||||
return top_dir, dir_path
|
||||
|
||||
def read_replica_info(dir, rconfig):
|
||||
def read_replica_info(dir_path, rconfig):
|
||||
"""
|
||||
Read the contents of a replica installation file.
|
||||
|
||||
rconfig is a ReplicaConfig object
|
||||
"""
|
||||
filename = dir + "/realm_info"
|
||||
filename = dir_path + "/realm_info"
|
||||
fd = open(filename)
|
||||
config = SafeConfigParser()
|
||||
config.readfp(fd)
|
||||
@@ -556,6 +557,67 @@ def read_replica_info_dogtag_port(config_dir):
|
||||
|
||||
return dogtag_master_ds_port
|
||||
|
||||
def read_replica_info_kra_enabled(config_dir):
|
||||
"""
|
||||
Check the replica info to determine if a KRA has been installed
|
||||
on the master
|
||||
"""
|
||||
default_file = config_dir + "/default.conf"
|
||||
if not ipautil.file_exists(default_file):
|
||||
return False
|
||||
else:
|
||||
with open(default_file) as fd:
|
||||
config = SafeConfigParser()
|
||||
config.readfp(fd)
|
||||
|
||||
enable_kra = bool(config.get("global", "enable_kra"))
|
||||
return enable_kra
|
||||
|
||||
|
||||
def create_replica_config(dirman_password, filename, options):
|
||||
top_dir = None
|
||||
try:
|
||||
top_dir, dir = expand_replica_info(filename, dirman_password)
|
||||
except Exception, e:
|
||||
root_logger.error("Failed to decrypt or open the replica file.")
|
||||
print "ERROR: Failed to decrypt or open the replica file."
|
||||
print "Verify you entered the correct Directory Manager password."
|
||||
sys.exit(1)
|
||||
config = ReplicaConfig(top_dir)
|
||||
read_replica_info(dir, config)
|
||||
root_logger.debug(
|
||||
'Installing replica file with version %d (0 means no version in prepared file).',
|
||||
config.version)
|
||||
if config.version and config.version > version.NUM_VERSION:
|
||||
root_logger.error(
|
||||
'A replica file from a newer release (%d) cannot be installed on an older version (%d)',
|
||||
config.version, version.NUM_VERSION)
|
||||
sys.exit(1)
|
||||
config.dirman_password = dirman_password
|
||||
try:
|
||||
host = get_host_name(options.no_host_dns)
|
||||
except BadHostError, e:
|
||||
root_logger.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?", False):
|
||||
root_logger.debug(
|
||||
"Replica was created for %s but machine is named %s "
|
||||
"User chose to exit",
|
||||
config.host_name, host)
|
||||
sys.exit(0)
|
||||
config.host_name = host
|
||||
print ""
|
||||
except KeyboardInterrupt:
|
||||
root_logger.debug("Keyboard Interrupt")
|
||||
sys.exit(0)
|
||||
config.dir = dir
|
||||
config.ca_ds_port = read_replica_info_dogtag_port(config.dir)
|
||||
return config
|
||||
|
||||
|
||||
def check_server_configuration():
|
||||
"""
|
||||
Check if IPA server is configured on the system.
|
||||
@@ -572,6 +634,7 @@ def check_server_configuration():
|
||||
if not server_fstore.has_files():
|
||||
raise RuntimeError("IPA is not configured on this system.")
|
||||
|
||||
|
||||
def remove_file(filename):
|
||||
"""
|
||||
Remove a file and log any exceptions raised.
|
||||
@@ -582,6 +645,7 @@ def remove_file(filename):
|
||||
except Exception, e:
|
||||
root_logger.error('Error removing %s: %s' % (filename, str(e)))
|
||||
|
||||
|
||||
def rmtree(path):
|
||||
"""
|
||||
Remove a directory structure and log any exceptions raised.
|
||||
@@ -592,6 +656,7 @@ def rmtree(path):
|
||||
except Exception, e:
|
||||
root_logger.error('Error removing %s: %s' % (path, str(e)))
|
||||
|
||||
|
||||
def is_ipa_configured():
|
||||
"""
|
||||
Using the state and index install files determine if IPA is already
|
||||
@@ -764,7 +829,7 @@ def check_pkcs12(pkcs12_info, ca_file, hostname):
|
||||
raise ScriptError(
|
||||
'%s server certificates found in %s, expecting only one' %
|
||||
(len(server_certs), pkcs12_filename))
|
||||
[(server_cert_name, server_cert_trust)] = server_certs
|
||||
[(server_cert_name, _server_cert_trust)] = server_certs
|
||||
|
||||
# Check we have the whole cert chain & the CA is in it
|
||||
trust_chain = nssdb.get_trust_chain(server_cert_name)
|
||||
@@ -849,23 +914,23 @@ def stopped_service(service, instance_name=""):
|
||||
root_logger.debug('Starting %s%s.', service, log_instance_name)
|
||||
services.knownservices[service].start(instance_name)
|
||||
|
||||
|
||||
def check_entropy():
|
||||
'''
|
||||
"""
|
||||
Checks if the system has enough entropy, if not, displays warning message
|
||||
'''
|
||||
"""
|
||||
try:
|
||||
with open('/proc/sys/kernel/random/entropy_avail', 'r') as efname:
|
||||
with open(paths.ENTROPY_AVAIL, 'r') as efname:
|
||||
if int(efname.read()) < 200:
|
||||
emsg = 'WARNING: Your system is running out of entropy, ' \
|
||||
'you may experience long delays'
|
||||
service.print_msg(emsg)
|
||||
root_logger.debug(emsg)
|
||||
except IOError as e:
|
||||
root_logger.debug("Could not open /proc/sys/kernel/random/entropy_avail: %s" % \
|
||||
e)
|
||||
root_logger.debug(
|
||||
"Could not open %s: %s", paths.ENTROPY_AVAIL, e)
|
||||
except ValueError as e:
|
||||
root_logger.debug("Invalid value in /proc/sys/kernel/random/entropy_avail %s" % \
|
||||
e)
|
||||
root_logger.debug("Invalid value in %s %s", paths.ENTROPY_AVAIL, e)
|
||||
|
||||
def validate_external_cert(cert_file, ca_file, subject_base):
|
||||
extcert = None
|
||||
|
||||
@@ -157,7 +157,7 @@ class Backup(admintool.AdminTool):
|
||||
paths.NTP_CONF,
|
||||
paths.SMB_CONF,
|
||||
paths.SAMBA_KEYTAB,
|
||||
paths.CA_AGENT_P12,
|
||||
paths.DOGTAG_AGENT_P12,
|
||||
paths.CACERT_P12,
|
||||
paths.KRB5KDC_KDC_CONF,
|
||||
paths.SYSTEMD_IPA_SERVICE,
|
||||
|
||||
243
ipaserver/install/ipa_kra_install.py
Normal file
243
ipaserver/install/ipa_kra_install.py
Normal file
@@ -0,0 +1,243 @@
|
||||
#! /usr/bin/python2 -E
|
||||
# Authors: Ade Lee <alee@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 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/>.
|
||||
#
|
||||
|
||||
from ConfigParser import RawConfigParser
|
||||
from textwrap import dedent
|
||||
from ipalib import api
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import admintool
|
||||
from ipapython import dogtag
|
||||
from ipapython import ipautil
|
||||
from ipaserver.install import cainstance
|
||||
from ipaserver.install import dogtaginstance
|
||||
from ipaserver.install import krainstance
|
||||
from ipaserver.install import dsinstance
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install import service
|
||||
from ipaserver.install.installutils import (
|
||||
read_replica_info_kra_enabled, create_replica_config)
|
||||
|
||||
|
||||
class KRAInstall(admintool.AdminTool):
|
||||
|
||||
command_name = 'ipa-kra-install'
|
||||
|
||||
usage = "%prog [options] [replica_file]"
|
||||
|
||||
description = "Install a master or replica KRA."
|
||||
|
||||
@classmethod
|
||||
def add_options(cls, parser, debug_option=True):
|
||||
super(KRAInstall, cls).add_options(parser, debug_option=True)
|
||||
|
||||
parser.add_option(
|
||||
"-p", "--password",
|
||||
dest="password", sensitive=True,
|
||||
help="Directory Manager (existing master) password")
|
||||
|
||||
parser.add_option(
|
||||
"-U", "--unattended",
|
||||
dest="unattended", action="store_true", default=False,
|
||||
help="unattended installation never prompts the user")
|
||||
|
||||
parser.add_option(
|
||||
"--uninstall",
|
||||
dest="uninstall", action="store_true", default=False,
|
||||
help="uninstall an existing installation. The uninstall can "
|
||||
"be run with --unattended option")
|
||||
|
||||
def validate_options(self, needs_root=True):
|
||||
super(KRAInstall, self).validate_options(needs_root=True)
|
||||
|
||||
installutils.check_server_configuration()
|
||||
|
||||
if self.options.unattended and self.options.password is None:
|
||||
self.option_parser.error(
|
||||
"Directory Manager password must be specified using -p"
|
||||
" in unattended mode"
|
||||
)
|
||||
|
||||
api.bootstrap(in_server=True)
|
||||
api.finalize()
|
||||
|
||||
def ask_for_options(self):
|
||||
super(KRAInstall, self).ask_for_options()
|
||||
|
||||
if not self.options.password:
|
||||
self.options.password = installutils.read_password(
|
||||
"Directory Manager", confirm=False,
|
||||
validate=False, retry=False)
|
||||
if self.options.password is None:
|
||||
raise admintool.ScriptError(
|
||||
"Directory Manager password required")
|
||||
|
||||
@classmethod
|
||||
def get_command_class(cls, options, args):
|
||||
if options.uninstall:
|
||||
return KRAUninstaller
|
||||
else:
|
||||
return KRAInstaller
|
||||
|
||||
|
||||
class KRAUninstaller(KRAInstall):
|
||||
log_file_name = paths.PKI_KRA_UNINSTALL_LOG
|
||||
|
||||
def validate_options(self, needs_root=True):
|
||||
super(KRAUninstaller, self).validate_options(needs_root=True)
|
||||
|
||||
if self.args:
|
||||
self.option_parser.error("Too many parameters provided.")
|
||||
|
||||
if not api.env.enable_kra:
|
||||
self.option_parser.error(
|
||||
"Cannot uninstall. There is no KRA installed on this system."
|
||||
)
|
||||
|
||||
def run(self):
|
||||
super(KRAUninstaller, self).run()
|
||||
dogtag_constants = dogtag.configured_constants()
|
||||
|
||||
# temporarily disable uninstall until Dogtag ticket:
|
||||
# https://fedorahosted.org/pki/ticket/1113 is fixed
|
||||
# TODO(alee) remove this once the above ticket is fixed
|
||||
raise admintool.ScriptError(
|
||||
"Uninstall is temporarily disabled. To uninstall, please "
|
||||
"use ipa-server-install --uninstall"
|
||||
)
|
||||
|
||||
kra_instance = krainstance.KRAInstance(
|
||||
api.env.realm, dogtag_constants=dogtag_constants)
|
||||
kra_instance.stop_tracking_certificates(dogtag_constants)
|
||||
if kra_instance.is_installed():
|
||||
kra_instance.uninstall()
|
||||
|
||||
# Update config file
|
||||
parser = RawConfigParser()
|
||||
parser.read(paths.IPA_DEFAULT_CONF)
|
||||
parser.set('global', 'enable_kra', 'False')
|
||||
|
||||
with open(paths.IPA_DEFAULT_CONF, 'w') as f:
|
||||
parser.write(f)
|
||||
|
||||
|
||||
class KRAInstaller(KRAInstall):
|
||||
log_file_name = paths.PKI_KRA_INSTALL_LOG
|
||||
|
||||
INSTALLER_START_MESSAGE = '''
|
||||
===================================================================
|
||||
This program will setup Dogtag KRA for the FreeIPA Server.
|
||||
|
||||
'''
|
||||
|
||||
FAIL_MESSAGE = '''
|
||||
Your system may be partly configured.
|
||||
Run ipa-kra-install --uninstall to clean up.
|
||||
'''
|
||||
|
||||
def validate_options(self, needs_root=True):
|
||||
super(KRAInstaller, self).validate_options(needs_root=True)
|
||||
|
||||
dogtag_version = int(api.env.dogtag_version)
|
||||
enable_kra = api.env.enable_kra
|
||||
|
||||
if enable_kra:
|
||||
self.option_parser.error("KRA is already installed.")
|
||||
|
||||
ca_installed = cainstance.is_ca_installed_locally()
|
||||
|
||||
if ca_installed:
|
||||
if dogtag_version >= 10:
|
||||
# correct dogtag version of CA installed
|
||||
pass
|
||||
else:
|
||||
self.option_parser.error(
|
||||
"Dogtag must be version 10.2 or above to install KRA")
|
||||
else:
|
||||
self.option_parser.error(
|
||||
"Dogtag CA is not installed. Please install the CA first")
|
||||
|
||||
self.installing_replica = dogtaginstance.is_installing_replica("KRA")
|
||||
if self.installing_replica:
|
||||
if not self.args:
|
||||
self.option_parser.error("A replica file is required.")
|
||||
if len(self.args) > 1:
|
||||
self.option_parser.error("Too many arguments provided")
|
||||
|
||||
self.replica_file = self.args[0]
|
||||
if not ipautil.file_exists(self.replica_file):
|
||||
self.option_parser.error(
|
||||
"Replica file %s does not exist" % self.replica_file)
|
||||
else:
|
||||
if self.args:
|
||||
self.option_parser.error("Too many parameters provided. "
|
||||
"No replica file is required.")
|
||||
|
||||
def _run(self):
|
||||
super(KRAInstaller, self).run()
|
||||
print dedent(self.INSTALLER_START_MESSAGE)
|
||||
|
||||
subject = dsinstance.DsInstance().find_subject_base()
|
||||
if not self.installing_replica:
|
||||
kra = krainstance.KRAInstance(
|
||||
api.env.realm,
|
||||
dogtag_constants=dogtag.install_constants)
|
||||
|
||||
kra.configure_instance(
|
||||
api.env.host, api.env.domain, self.options.password,
|
||||
self.options.password, subject_base=subject)
|
||||
else:
|
||||
replica_config = create_replica_config(
|
||||
self.options.password,
|
||||
self.replica_file,
|
||||
self.options)
|
||||
|
||||
if not read_replica_info_kra_enabled(replica_config.dir):
|
||||
raise admintool.ScriptError(
|
||||
"Either KRA is not installed on the master system or "
|
||||
"your replica file is out of date"
|
||||
)
|
||||
|
||||
kra = krainstance.install_replica_kra(replica_config)
|
||||
service.print_msg("Restarting the directory server")
|
||||
|
||||
ds = dsinstance.DsInstance()
|
||||
ds.restart()
|
||||
|
||||
kra.enable_client_auth_to_db(kra.dogtag_constants.KRA_CS_CFG_PATH)
|
||||
|
||||
# Restart apache for new proxy config file
|
||||
services.knownservices.httpd.restart(capture_output=True)
|
||||
|
||||
# Update config file
|
||||
parser = RawConfigParser()
|
||||
parser.read(paths.IPA_DEFAULT_CONF)
|
||||
parser.set('global', 'enable_kra', 'True')
|
||||
|
||||
with open(paths.IPA_DEFAULT_CONF, 'w') as f:
|
||||
parser.write(f)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self._run()
|
||||
except:
|
||||
self.log.error(dedent(self.FAIL_MESSAGE))
|
||||
raise
|
||||
|
||||
@@ -371,6 +371,7 @@ class ReplicaPrepare(admintool.AdminTool):
|
||||
cacert_filename = paths.CACERT_PEM
|
||||
if ipautil.file_exists(cacert_filename):
|
||||
self.copy_info_file(cacert_filename, "cacert.pem")
|
||||
self.copy_info_file(paths.IPA_DEFAULT_CONF, "default.conf")
|
||||
|
||||
def save_config(self):
|
||||
self.log.info("Finalizing configuration")
|
||||
|
||||
346
ipaserver/install/krainstance.py
Normal file
346
ipaserver/install/krainstance.py
Normal file
@@ -0,0 +1,346 @@
|
||||
# Authors: Ade Lee <alee@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 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 ConfigParser
|
||||
import os
|
||||
import pwd
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from ipalib import api
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import dogtag
|
||||
from ipapython import ipaldap
|
||||
from ipapython import ipautil
|
||||
from ipapython.dn import DN
|
||||
from ipaserver.install import certs
|
||||
from ipaserver.install import cainstance
|
||||
from ipaserver.install import service
|
||||
from ipaserver.install.dogtaginstance import DogtagInstance
|
||||
from ipaserver.install.dogtaginstance import DEFAULT_DSPORT, PKI_USER
|
||||
from ipapython.ipa_log_manager import log_mgr
|
||||
|
||||
# When IPA is installed with DNS support, this CNAME should hold all IPA
|
||||
# replicas with KRA configured
|
||||
IPA_KRA_RECORD = "ipa-kra"
|
||||
|
||||
|
||||
class KRAInstance(DogtagInstance):
|
||||
"""
|
||||
We assume that the CA has already been installed, and we use the
|
||||
same tomcat instance to host both the CA and KRA.
|
||||
The mod_nss database will contain the RA agent cert that will be used
|
||||
to do authenticated requests against dogtag. The RA agent cert will
|
||||
be the same for both the CA and KRA.
|
||||
"""
|
||||
|
||||
def __init__(self, realm, dogtag_constants=None):
|
||||
if dogtag_constants is None:
|
||||
dogtag_constants = dogtag.configured_constants()
|
||||
|
||||
super(KRAInstance, self).__init__(
|
||||
realm=realm,
|
||||
subsystem="KRA",
|
||||
service_desc="KRA server",
|
||||
dogtag_constants=dogtag_constants
|
||||
)
|
||||
|
||||
self.basedn = DN(('o', 'kra'), ('o', 'ipaca'))
|
||||
self.tracking_reqs = (('auditSigningCert cert-pki-kra', None),
|
||||
('transportCert cert-pki-kra', None),
|
||||
('storageCert cert-pki-kra', None))
|
||||
self.log = log_mgr.get_logger(self)
|
||||
|
||||
def configure_instance(self, host_name, domain, dm_password,
|
||||
admin_password, ds_port=DEFAULT_DSPORT,
|
||||
pkcs12_info=None, master_host=None,
|
||||
master_replication_port=None,
|
||||
subject_base=None):
|
||||
"""Create a KRA instance.
|
||||
|
||||
To create a clone, pass in pkcs12_info.
|
||||
"""
|
||||
self.fqdn = host_name
|
||||
self.domain = domain
|
||||
self.dm_password = dm_password
|
||||
self.admin_password = admin_password
|
||||
self.ds_port = ds_port
|
||||
self.pkcs12_info = pkcs12_info
|
||||
if self.pkcs12_info is not None:
|
||||
self.clone = True
|
||||
self.master_host = master_host
|
||||
self.master_replication_port = master_replication_port
|
||||
if subject_base is None:
|
||||
self.subject_base = DN(('O', self.realm))
|
||||
else:
|
||||
self.subject_base = subject_base
|
||||
|
||||
# Confirm that a KRA does not already exist
|
||||
if self.is_installed():
|
||||
raise RuntimeError(
|
||||
"KRA already installed.")
|
||||
# Confirm that a Dogtag 10 CA instance already exists
|
||||
ca = cainstance.CAInstance(
|
||||
api.env.realm, certs.NSS_DIR,
|
||||
dogtag_constants=dogtag.Dogtag10Constants)
|
||||
if not ca.is_installed():
|
||||
raise RuntimeError(
|
||||
"KRA configuration failed. "
|
||||
"A Dogtag CA must be installed first")
|
||||
|
||||
self.step("configuring KRA instance", self.__spawn_instance)
|
||||
if not self.clone:
|
||||
self.step("add RA user to KRA agent group",
|
||||
self.__add_ra_user_to_agent_group)
|
||||
self.step("restarting KRA", self.restart_instance)
|
||||
self.step("configure certificate renewals", self.configure_renewal)
|
||||
self.step("Configure HTTP to proxy connections",
|
||||
self.http_proxy)
|
||||
|
||||
self.start_creation(runtime=126)
|
||||
|
||||
def __spawn_instance(self):
|
||||
"""
|
||||
Create and configure a new KRA instance using pkispawn.
|
||||
Creates a configuration file with IPA-specific
|
||||
parameters and passes it to the base class to call pkispawn
|
||||
"""
|
||||
|
||||
# Create an empty and secured file
|
||||
(cfg_fd, cfg_file) = tempfile.mkstemp()
|
||||
os.close(cfg_fd)
|
||||
pent = pwd.getpwnam(PKI_USER)
|
||||
os.chown(cfg_file, pent.pw_uid, pent.pw_gid)
|
||||
|
||||
# Create KRA configuration
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.optionxform = str
|
||||
config.add_section("KRA")
|
||||
|
||||
# Security Domain Authentication
|
||||
config.set("KRA", "pki_security_domain_https_port", "443")
|
||||
config.set("KRA", "pki_security_domain_password", self.admin_password)
|
||||
config.set("KRA", "pki_security_domain_user", "admin")
|
||||
|
||||
# issuing ca
|
||||
config.set("KRA", "pki_issuing_ca_uri", "https://%s" %
|
||||
ipautil.format_netloc(self.fqdn, 443))
|
||||
|
||||
# Server
|
||||
config.set("KRA", "pki_enable_proxy", "True")
|
||||
config.set("KRA", "pki_restart_configured_instance", "False")
|
||||
config.set("KRA", "pki_backup_keys", "True")
|
||||
config.set("KRA", "pki_backup_password", self.admin_password)
|
||||
|
||||
# Client security database
|
||||
config.set("KRA", "pki_client_database_dir", self.agent_db)
|
||||
config.set("KRA", "pki_client_database_password", self.admin_password)
|
||||
config.set("KRA", "pki_client_database_purge", "False")
|
||||
config.set("KRA", "pki_client_pkcs12_password", self.admin_password)
|
||||
|
||||
# Administrator
|
||||
config.set("KRA", "pki_admin_name", "admin")
|
||||
config.set("KRA", "pki_admin_uid", "admin")
|
||||
config.set("KRA", "pki_admin_email", "root@localhost")
|
||||
config.set("KRA", "pki_admin_password", self.admin_password)
|
||||
config.set("KRA", "pki_admin_nickname", "ipa-ca-agent")
|
||||
config.set("KRA", "pki_admin_subject_dn",
|
||||
str(DN(('cn', 'ipa-ca-agent'), self.subject_base)))
|
||||
config.set("KRA", "pki_import_admin_cert", "True")
|
||||
config.set("KRA", "pki_admin_cert_file", paths.ADMIN_CERT_PATH)
|
||||
config.set("KRA", "pki_client_admin_cert_p12", paths.DOGTAG_AGENT_P12)
|
||||
|
||||
# Directory server
|
||||
config.set("KRA", "pki_ds_ldap_port", str(self.ds_port))
|
||||
config.set("KRA", "pki_ds_password", self.dm_password)
|
||||
config.set("KRA", "pki_ds_base_dn", self.basedn)
|
||||
config.set("KRA", "pki_ds_database", "ipaca")
|
||||
config.set("KRA", "pki_ds_create_new_db", "False")
|
||||
|
||||
# Certificate subject DNs
|
||||
config.set("KRA", "pki_subsystem_subject_dn",
|
||||
str(DN(('cn', 'CA Subsystem'), self.subject_base)))
|
||||
config.set("KRA", "pki_ssl_server_subject_dn",
|
||||
str(DN(('cn', self.fqdn), self.subject_base)))
|
||||
config.set("KRA", "pki_audit_signing_subject_dn",
|
||||
str(DN(('cn', 'KRA Audit'), self.subject_base)))
|
||||
config.set(
|
||||
"KRA", "pki_transport_subject_dn",
|
||||
str(DN(('cn', 'KRA Transport Certificate'), self.subject_base)))
|
||||
config.set(
|
||||
"KRA", "pki_storage_subject_dn",
|
||||
str(DN(('cn', 'KRA Storage Certificate'), self.subject_base)))
|
||||
|
||||
# Certificate nicknames
|
||||
# Note that both the server certs and subsystem certs reuse
|
||||
# the ca certs.
|
||||
config.set("KRA", "pki_subsystem_nickname",
|
||||
"subsystemCert cert-pki-ca")
|
||||
config.set("KRA", "pki_ssl_server_nickname",
|
||||
"Server-Cert cert-pki-ca")
|
||||
config.set("KRA", "pki_audit_signing_nickname",
|
||||
"auditSigningCert cert-pki-kra")
|
||||
config.set("KRA", "pki_transport_nickname",
|
||||
"transportCert cert-pki-kra")
|
||||
config.set("KRA", "pki_storage_nickname",
|
||||
"storageCert cert-pki-kra")
|
||||
|
||||
# Shared db settings
|
||||
# Needed because CA and KRA share the same database
|
||||
# We will use the dbuser created for the CA
|
||||
config.set("KRA", "pki_share_db", "True")
|
||||
config.set(
|
||||
"KRA", "pki_share_dbuser_dn",
|
||||
str(DN(('uid', 'pkidbuser'), ('ou', 'people'), ('o', 'ipaca'))))
|
||||
|
||||
_p12_tmpfile_handle, p12_tmpfile_name = tempfile.mkstemp(dir=paths.TMP)
|
||||
if self.clone:
|
||||
krafile = self.pkcs12_info[0]
|
||||
shutil.copy(krafile, p12_tmpfile_name)
|
||||
pent = pwd.getpwnam(PKI_USER)
|
||||
os.chown(p12_tmpfile_name, pent.pw_uid, pent.pw_gid)
|
||||
|
||||
# create admin cert file if it does not exist
|
||||
cert = DogtagInstance.get_admin_cert(self)
|
||||
with open(paths.ADMIN_CERT_PATH, "w") as admin_path:
|
||||
admin_path.write(cert)
|
||||
|
||||
# Security domain registration
|
||||
config.set("KRA", "pki_security_domain_hostname", self.master_host)
|
||||
config.set("KRA", "pki_security_domain_https_port", "443")
|
||||
config.set("KRA", "pki_security_domain_user", "admin")
|
||||
config.set("KRA", "pki_security_domain_password",
|
||||
self.admin_password)
|
||||
|
||||
# Clone
|
||||
config.set("KRA", "pki_clone", "True")
|
||||
config.set("KRA", "pki_clone_pkcs12_path", p12_tmpfile_name)
|
||||
config.set("KRA", "pki_clone_pkcs12_password", self.dm_password)
|
||||
config.set("KRA", "pki_clone_setup_replication", "False")
|
||||
config.set(
|
||||
"KRA", "pki_clone_uri",
|
||||
"https://%s" % ipautil.format_netloc(self.master_host, 443))
|
||||
|
||||
# Generate configuration file
|
||||
with open(cfg_file, "wb") as f:
|
||||
config.write(f)
|
||||
|
||||
try:
|
||||
DogtagInstance.spawn_instance(self, cfg_file)
|
||||
finally:
|
||||
os.remove(p12_tmpfile_name)
|
||||
os.remove(cfg_file)
|
||||
|
||||
shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12)
|
||||
self.log.debug("completed creating KRA instance")
|
||||
|
||||
def __add_ra_user_to_agent_group(self):
|
||||
"""
|
||||
Add RA agent created for CA to KRA agent group.
|
||||
"""
|
||||
conn = ipaldap.IPAdmin(self.fqdn, self.ds_port)
|
||||
conn.do_simple_bind(DN(('cn', 'Directory Manager')), self.dm_password)
|
||||
|
||||
entry_dn = DN(('uid', "ipara"), ('ou', 'People'), ('o', 'ipaca'))
|
||||
dn = DN(('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'),
|
||||
self.basedn)
|
||||
modlist = [(0, 'uniqueMember', '%s' % entry_dn)]
|
||||
conn.modify_s(dn, modlist)
|
||||
|
||||
conn.unbind()
|
||||
|
||||
@staticmethod
|
||||
def update_cert_config(nickname, cert, dogtag_constants=None):
|
||||
"""
|
||||
When renewing a KRA subsystem certificate the configuration file
|
||||
needs to get the new certificate as well.
|
||||
|
||||
nickname is one of the known nicknames.
|
||||
cert is a DER-encoded certificate.
|
||||
"""
|
||||
|
||||
if dogtag_constants is None:
|
||||
dogtag_constants = dogtag.configured_constants()
|
||||
|
||||
# The cert directive to update per nickname
|
||||
directives = {
|
||||
'auditSigningCert cert-pki-kra': 'kra.audit_signing.cert',
|
||||
'storageCert cert-pki-kra': 'kra.storage.cert',
|
||||
'transportCert cert-pki-kra': 'kra.transport.cert',
|
||||
'subsystemCert cert-pki-kra': 'kra.subsystem.cert',
|
||||
'Server-Cert cert-pki-ca': 'kra.sslserver.cert'}
|
||||
|
||||
DogtagInstance.update_cert_cs_cfg(
|
||||
nickname, cert, directives,
|
||||
dogtag.configured_constants().KRA_CS_CFG_PATH,
|
||||
dogtag_constants)
|
||||
|
||||
|
||||
def install_replica_kra(config, postinstall=False):
|
||||
"""
|
||||
Install a KRA 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 KRA instance
|
||||
"""
|
||||
# note that the cacert.p12 file is regenerated during the
|
||||
# ipa-replica-prepare process and should include all the certs
|
||||
# for the CA and KRA
|
||||
krafile = config.dir + "/cacert.p12"
|
||||
|
||||
if not ipautil.file_exists(krafile):
|
||||
raise RuntimeError(
|
||||
"Unable to clone KRA."
|
||||
" cacert.p12 file not found in replica file")
|
||||
|
||||
_kra = KRAInstance(config.realm_name,
|
||||
dogtag_constants=dogtag.install_constants)
|
||||
_kra.dm_password = config.dirman_password
|
||||
_kra.subject_base = config.subject_base
|
||||
if _kra.is_installed():
|
||||
sys.exit("A KRA is already configured on this system.")
|
||||
|
||||
_kra.configure_instance(config.host_name, config.domain_name,
|
||||
config.dirman_password, config.dirman_password,
|
||||
pkcs12_info=(krafile,),
|
||||
master_host=config.master_host_name,
|
||||
master_replication_port=config.ca_ds_port,
|
||||
subject_base=config.subject_base)
|
||||
|
||||
# Restart httpd since we changed it's config and added ipa-pki-proxy.conf
|
||||
if postinstall:
|
||||
services.knownservices.httpd.restart()
|
||||
|
||||
# The dogtag DS instance needs to be restarted after installation.
|
||||
# The procedure for this is: stop dogtag, stop DS, start DS, start
|
||||
# dogtag
|
||||
|
||||
service.print_msg("Restarting the directory and KRA servers")
|
||||
_kra.stop(dogtag.install_constants.PKI_INSTANCE_NAME)
|
||||
services.knownservices.dirsrv.restart()
|
||||
_kra.start(dogtag.install_constants.PKI_INSTANCE_NAME)
|
||||
|
||||
return _kra
|
||||
@@ -1,10 +1,11 @@
|
||||
# Authors:
|
||||
# Ade Lee <alee@redhat.com>
|
||||
# Andrew Wnuk <awnuk@redhat.com>
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
# Rob Crittenden <rcritten@@redhat.com>
|
||||
# John Dennis <jdennis@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,7 +35,7 @@ variety of names, the open source version is called "dogtag".
|
||||
|
||||
CMS consists of a number of servlets which in rough terms can be thought of as
|
||||
RPC commands. A servlet is invoked by making an HTTP request to a specific URL
|
||||
and passing URL arguments. Normally CMS responds with an HTTP reponse consisting
|
||||
and passing URL arguments. Normally CMS responds with an HTTP response consisting
|
||||
of HTML to be rendered by a web browser. This HTTP HTML response has both
|
||||
Javascript SCRIPT components and HTML rendering code. One of the Javascript
|
||||
SCRIPT blocks holds the data for the result. The rest of the response is derived
|
||||
@@ -42,13 +43,13 @@ from templates associated with the servlet which may be customized. The
|
||||
templates pull the result data from Javascript variables.
|
||||
|
||||
One way to get the result data is to parse the HTML looking for the Javascript
|
||||
varible initializations. Simple string searchs are not a robust method. First of
|
||||
variable initializations. Simple string searches are not a robust method. First of
|
||||
all one must be sure the string is only found in a Javascript SCRIPT block and
|
||||
not somewhere else in the HTML document. Some of the Javascript variable
|
||||
initializations are rather complex (e.g. lists of structures). It would be hard
|
||||
to correctly parse such complex and diverse Javascript. Existing Javascript
|
||||
parsers are not generally available. Finally, it's important to know the
|
||||
character encoding for strings. There is a somewhat complex set of precident
|
||||
character encoding for strings. There is a somewhat complex set of precedent
|
||||
rules for determining the current character encoding from the HTTP header,
|
||||
meta-equiv tags, mime Content-Type and charset attributes on HTML elements. All
|
||||
of this means trying to read the result data from a CMS HTML response is
|
||||
@@ -119,7 +120,7 @@ values. Python also nicely handles type promotion transparently between int
|
||||
and long objects. For example if you multiply two int objects you may get back
|
||||
a long object if necessary. In general Python int and long objects may be
|
||||
freely mixed without the programmer needing to be aware of which type of
|
||||
intergral object is being operated on.
|
||||
integral object is being operated on.
|
||||
|
||||
The leads to the following rule, always parse a string representing an
|
||||
integral value using the int() constructor even if it might have large
|
||||
@@ -229,20 +230,28 @@ as a dict via the 'namespaces' keyword parameter of etree.XPath(). The predicate
|
||||
for the second location step uses the 're:' namespace to find the function name
|
||||
'match'. The re:match() takes a string to search as its first argument and a
|
||||
regular expression pattern as its second argument. In this example the string
|
||||
to seach is the node name of the location step because we called the built-in
|
||||
to search is the node name of the location step because we called the built-in
|
||||
node() function of XPath. The regular expression pattern we've passed says it's
|
||||
a match if the string begins with 'chapter' is followed by any number of
|
||||
digits and nothing else follows.
|
||||
|
||||
'''
|
||||
|
||||
from lxml import etree
|
||||
import urllib2
|
||||
import datetime
|
||||
from lxml import etree
|
||||
import tempfile
|
||||
import time
|
||||
import urllib2
|
||||
|
||||
from pki.client import PKIConnection
|
||||
import pki.crypto as cryptoutil
|
||||
from pki.kra import KRAClient
|
||||
|
||||
from ipalib import Backend
|
||||
from ipapython.dn import DN
|
||||
import ipapython.dogtag
|
||||
from ipapython import ipautil
|
||||
from ipaserver.install.certs import CertDB
|
||||
|
||||
# These are general status return values used when
|
||||
# CMSServlet.outputError() is invoked.
|
||||
@@ -260,6 +269,7 @@ CMS_STATUS_REJECTED = 5
|
||||
CMS_STATUS_ERROR = 6
|
||||
CMS_STATUS_EXCEPTION = 7
|
||||
|
||||
|
||||
def cms_request_status_to_string(request_status):
|
||||
'''
|
||||
:param request_status: The integral request status value
|
||||
@@ -290,7 +300,7 @@ def parse_and_set_boolean_xml(node, response, response_name):
|
||||
'''
|
||||
:param node: xml node object containing value to parse for boolean result
|
||||
:param response: response dict to set boolean result in
|
||||
:param response_name: name of the respone value to set
|
||||
:param response_name: name of the response value to set
|
||||
:except ValueError:
|
||||
|
||||
Read the value out of a xml text node and interpret it as a boolean value.
|
||||
@@ -646,7 +656,7 @@ def parse_check_request_result_xml(doc):
|
||||
+-------------------------+---------------+-------------------+-----------------+
|
||||
|requestId |string |request_id |string |
|
||||
+-------------------------+---------------+-------------------+-----------------+
|
||||
|staus |string |cert_request_status|unicode [1]_ |
|
||||
|status |string |cert_request_status|unicode [1]_ |
|
||||
+-------------------------+---------------+-------------------+-----------------+
|
||||
|createdOn |long, timestamp|created_on |datetime.datetime|
|
||||
+-------------------------+---------------+-------------------+-----------------+
|
||||
@@ -1199,6 +1209,57 @@ def parse_unrevoke_cert_xml(doc):
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def host_has_service(host, ldap2, service='CA'):
|
||||
"""
|
||||
:param host: A host which might be a master for a service.
|
||||
:param ldap2: connection to the local database
|
||||
:param service: The service for which the host might be a master.
|
||||
:return: (true, false)
|
||||
|
||||
Check if a specified host is a master for a specified service.
|
||||
"""
|
||||
base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'),
|
||||
('cn', 'etc'), api.env.basedn)
|
||||
filter_attrs = {
|
||||
'objectClass': 'ipaConfigObject',
|
||||
'cn': service,
|
||||
'ipaConfigString': 'enabledService',
|
||||
}
|
||||
query_filter = ldap2.make_filter(filter_attrs, rules='&')
|
||||
try:
|
||||
ent, trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn)
|
||||
if len(ent):
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def select_any_master(ldap2, service='CA'):
|
||||
"""
|
||||
:param ldap2: connection to the local database
|
||||
:param service: The service for which we're looking for a master.
|
||||
:return: host as str
|
||||
|
||||
Select any host which is a master for a specified service.
|
||||
"""
|
||||
base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
|
||||
api.env.basedn)
|
||||
filter_attrs = {
|
||||
'objectClass': 'ipaConfigObject',
|
||||
'cn': service,
|
||||
'ipaConfigString': 'enabledService',}
|
||||
query_filter = ldap2.make_filter(filter_attrs, rules='&')
|
||||
try:
|
||||
ent, trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn)
|
||||
if len(ent):
|
||||
entry = random.choice(ent)
|
||||
return entry.dn[1].value
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
from ipalib import api, SkipPluginModule
|
||||
@@ -1214,6 +1275,7 @@ from ipapython import dogtag
|
||||
from ipalib import _
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
|
||||
class ra(rabase.rabase):
|
||||
"""
|
||||
Request Authority backend plugin.
|
||||
@@ -1258,57 +1320,6 @@ class ra(rabase.rabase):
|
||||
self.error('%s.%s(): %s', self.fullname, func_name, err_msg)
|
||||
raise CertificateOperationError(error=err_msg)
|
||||
|
||||
def _host_has_service(self, host, service='CA'):
|
||||
"""
|
||||
:param host: A host which might be a master for a service.
|
||||
:param service: The service for which the host might be a master.
|
||||
:return: (true, false)
|
||||
|
||||
Check if a specified host is a master for a specified service.
|
||||
"""
|
||||
ldap2 = self.api.Backend.ldap2
|
||||
base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'),
|
||||
('cn', 'etc'), api.env.basedn)
|
||||
filter_attrs = {
|
||||
'objectClass': 'ipaConfigObject',
|
||||
'cn': service,
|
||||
'ipaConfigString': 'enabledService',
|
||||
}
|
||||
filter = ldap2.make_filter(filter_attrs, rules='&')
|
||||
try:
|
||||
ent, trunc = ldap2.find_entries(filter=filter, base_dn=base_dn)
|
||||
if len(ent):
|
||||
return True
|
||||
except Exception, e:
|
||||
pass
|
||||
return False
|
||||
|
||||
def _select_any_master(self, service='CA'):
|
||||
"""
|
||||
:param service: The service for which we're looking for a master.
|
||||
:return: host
|
||||
as str
|
||||
|
||||
Select any host which is a master for a specified service.
|
||||
"""
|
||||
ldap2 = self.api.Backend.ldap2
|
||||
base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
|
||||
api.env.basedn)
|
||||
filter_attrs = {
|
||||
'objectClass': 'ipaConfigObject',
|
||||
'cn': service,
|
||||
'ipaConfigString': 'enabledService',
|
||||
}
|
||||
filter = ldap2.make_filter(filter_attrs, rules='&')
|
||||
try:
|
||||
ent, trunc = ldap2.find_entries(filter=filter, base_dn=base_dn)
|
||||
if len(ent):
|
||||
entry = random.choice(ent)
|
||||
return entry.dn[1].value
|
||||
except Exception, e:
|
||||
pass
|
||||
return None
|
||||
|
||||
@cachedproperty
|
||||
def ca_host(self):
|
||||
"""
|
||||
@@ -1317,12 +1328,13 @@ class ra(rabase.rabase):
|
||||
|
||||
Select our CA host.
|
||||
"""
|
||||
if self._host_has_service(host=api.env.ca_host):
|
||||
ldap2 = self.api.Backend.ldap2
|
||||
if host_has_service(api.env.ca_host, ldap2, "CA"):
|
||||
return api.env.ca_host
|
||||
if api.env.host != api.env.ca_host:
|
||||
if self._host_has_service(host=api.env.host):
|
||||
if host_has_service(api.env.host, ldap2, "CA"):
|
||||
return api.env.host
|
||||
host = self._select_any_master()
|
||||
host = select_any_master(ldap2)
|
||||
if host:
|
||||
return host
|
||||
else:
|
||||
@@ -1363,7 +1375,8 @@ class ra(rabase.rabase):
|
||||
parser = etree.XMLParser()
|
||||
doc = etree.fromstring(xml_text, parser)
|
||||
result = parse_func(doc)
|
||||
self.debug("%s() xml_text:\n%s\nparse_result:\n%s" % (parse_func.__name__, xml_text, result))
|
||||
self.debug("%s() xml_text:\n%s\n"
|
||||
"parse_result:\n%s" % (parse_func.__name__, xml_text, result))
|
||||
return result
|
||||
|
||||
def check_request_status(self, request_id):
|
||||
@@ -1410,7 +1423,7 @@ class ra(rabase.rabase):
|
||||
xml='true')
|
||||
|
||||
# Parse and handle errors
|
||||
if (http_status != 200):
|
||||
if http_status != 200:
|
||||
self.raise_certificate_operation_error('check_request_status',
|
||||
detail=http_reason_phrase)
|
||||
|
||||
@@ -1440,10 +1453,10 @@ class ra(rabase.rabase):
|
||||
Retrieve an existing certificate.
|
||||
|
||||
:param serial_number: Certificate serial number. Must be a string value
|
||||
because serial numbers may be of any magnitue and
|
||||
because serial numbers may be of any magnitude and
|
||||
XMLRPC cannot handle integers larger than 64-bit.
|
||||
The string value should be decimal, but may optionally
|
||||
be prefixed with a hex radix prefix if the integal value
|
||||
be prefixed with a hex radix prefix if the integral value
|
||||
is represented as hexadecimal. If no radix prefix is
|
||||
supplied the string will be interpreted as decimal.
|
||||
|
||||
@@ -1496,7 +1509,7 @@ class ra(rabase.rabase):
|
||||
|
||||
|
||||
# Parse and handle errors
|
||||
if (http_status != 200):
|
||||
if http_status != 200:
|
||||
self.raise_certificate_operation_error('get_certificate',
|
||||
detail=http_reason_phrase)
|
||||
|
||||
@@ -1563,7 +1576,7 @@ class ra(rabase.rabase):
|
||||
cert_request=csr,
|
||||
xml='true')
|
||||
# Parse and handle errors
|
||||
if (http_status != 200):
|
||||
if http_status != 200:
|
||||
self.raise_certificate_operation_error('request_certificate',
|
||||
detail=http_reason_phrase)
|
||||
|
||||
@@ -1604,10 +1617,10 @@ class ra(rabase.rabase):
|
||||
def revoke_certificate(self, serial_number, revocation_reason=0):
|
||||
"""
|
||||
:param serial_number: Certificate serial number. Must be a string value
|
||||
because serial numbers may be of any magnitue and
|
||||
because serial numbers may be of any magnitude and
|
||||
XMLRPC cannot handle integers larger than 64-bit.
|
||||
The string value should be decimal, but may optionally
|
||||
be prefixed with a hex radix prefix if the integal value
|
||||
be prefixed with a hex radix prefix if the integral value
|
||||
is represented as hexadecimal. If no radix prefix is
|
||||
supplied the string will be interpreted as decimal.
|
||||
:param revocation_reason: Integer code of revocation reason.
|
||||
@@ -1644,7 +1657,7 @@ class ra(rabase.rabase):
|
||||
xml='true')
|
||||
|
||||
# Parse and handle errors
|
||||
if (http_status != 200):
|
||||
if http_status != 200:
|
||||
self.raise_certificate_operation_error('revoke_certificate',
|
||||
detail=http_reason_phrase)
|
||||
|
||||
@@ -1668,10 +1681,10 @@ class ra(rabase.rabase):
|
||||
def take_certificate_off_hold(self, serial_number):
|
||||
"""
|
||||
:param serial_number: Certificate serial number. Must be a string value
|
||||
because serial numbers may be of any magnitue and
|
||||
because serial numbers may be of any magnitude and
|
||||
XMLRPC cannot handle integers larger than 64-bit.
|
||||
The string value should be decimal, but may optionally
|
||||
be prefixed with a hex radix prefix if the integal value
|
||||
be prefixed with a hex radix prefix if the integral value
|
||||
is represented as hexadecimal. If no radix prefix is
|
||||
supplied the string will be interpreted as decimal.
|
||||
|
||||
@@ -1704,7 +1717,7 @@ class ra(rabase.rabase):
|
||||
xml='true')
|
||||
|
||||
# Parse and handle errors
|
||||
if (http_status != 200):
|
||||
if http_status != 200:
|
||||
self.raise_certificate_operation_error('take_certificate_off_hold',
|
||||
detail=http_reason_phrase)
|
||||
|
||||
@@ -1866,4 +1879,133 @@ class ra(rabase.rabase):
|
||||
|
||||
return results
|
||||
|
||||
|
||||
api.register(ra)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
class kra(Backend):
|
||||
"""
|
||||
KRA backend plugin (for Vault)
|
||||
"""
|
||||
|
||||
def __init__(self, kra_port=443):
|
||||
if api.env.in_tree:
|
||||
self.sec_dir = os.path.join(api.env.dot_ipa, 'alias')
|
||||
pwd_file = os.path.join(self.sec_dir, '.pwd')
|
||||
self.pem_file = os.path.join(self.sec_dir, ".pemfile")
|
||||
else:
|
||||
self.sec_dir = paths.HTTPD_ALIAS_DIR
|
||||
pwd_file = paths.ALIAS_PWDFILE_TXT
|
||||
self.pem_file = paths.DOGTAG_AGENT_PEM
|
||||
|
||||
self.kra_port = kra_port
|
||||
self.transport_nick = "IPA KRA Transport Cert"
|
||||
self.password = ""
|
||||
with open(pwd_file, "r") as f:
|
||||
self.password = f.readline().strip()
|
||||
|
||||
self.keyclient = None
|
||||
super(kra, self).__init__()
|
||||
|
||||
def _create_pem_file(self):
|
||||
""" Create PEM file used by KRA plugin for authentication.
|
||||
|
||||
This function reads the IPA HTTPD database and extracts the
|
||||
Dogtag agent certificate and keys into a PKCS#12 temporary file.
|
||||
The PKCS#12 file is then converted into PEM format so that it
|
||||
can be used by python-requests to authenticate to the KRA.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
(p12_pwd_fd, p12_pwd_fname) = tempfile.mkstemp()
|
||||
(p12_fd, p12_fname) = tempfile.mkstemp()
|
||||
|
||||
try:
|
||||
os.write(p12_pwd_fd, self.password)
|
||||
os.close(p12_pwd_fd)
|
||||
os.close(p12_fd)
|
||||
|
||||
certdb = CertDB(api.env.realm)
|
||||
certdb.export_pkcs12(p12_fname, p12_pwd_fname, "ipaCert")
|
||||
|
||||
certdb.install_pem_from_p12(p12_fname, self.password, self.pem_file)
|
||||
except:
|
||||
self.debug("Error when creating PEM file for KRA operations")
|
||||
raise
|
||||
finally:
|
||||
os.remove(p12_fname)
|
||||
os.remove(p12_pwd_fname)
|
||||
|
||||
def _transport_cert_present(self):
|
||||
""" Check if the client certDB contains the KRA transport certificate
|
||||
:return: True/False
|
||||
"""
|
||||
# certutil -L -d db_dir -n cert_nick
|
||||
certdb = CertDB(api.env.realm)
|
||||
return certdb.has_nickname(self.transport_nick)
|
||||
|
||||
def _setup(self):
|
||||
""" Do initial setup and crypto initialization of the KRA client
|
||||
|
||||
Creates a PEM file containing the KRA agent cert/keys to be used for
|
||||
authentication to the KRA (if it does not already exist), Sets up a
|
||||
connection to the KRA and initializes an NSS certificate database to
|
||||
store the transport certificate, Retrieves the transport certificate
|
||||
if it is not already present.
|
||||
"""
|
||||
#set up pem file if not present
|
||||
if not os.path.exists(self.pem_file):
|
||||
self._create_pem_file()
|
||||
|
||||
# set up connection
|
||||
connection = PKIConnection('https',
|
||||
self.kra_host,
|
||||
str(self.kra_port),
|
||||
'kra')
|
||||
connection.set_authentication_cert(self.pem_file)
|
||||
|
||||
crypto = cryptoutil.NSSCryptoProvider(self.sec_dir, self.password)
|
||||
|
||||
#create kraclient
|
||||
kraclient = KRAClient(connection, crypto)
|
||||
|
||||
# get transport cert if needed
|
||||
if not self._transport_cert_present():
|
||||
transport_cert = kraclient.system_certs.get_transport_cert()
|
||||
crypto.import_cert(self.transport_nick, transport_cert, "u,u,u")
|
||||
|
||||
crypto.initialize()
|
||||
|
||||
self.keyclient = kraclient.keys
|
||||
self.keyclient.set_transport_cert(self.transport_nick)
|
||||
|
||||
@cachedproperty
|
||||
def kra_host(self):
|
||||
"""
|
||||
:return: host
|
||||
as str
|
||||
|
||||
Select our KRA host.
|
||||
"""
|
||||
ldap2 = self.api.Backend.ldap2
|
||||
if host_has_service(api.env.kra_host, ldap2, "kra"):
|
||||
return api.env.kra_host
|
||||
if api.env.host != api.env.kra_host:
|
||||
if host_has_service(api.env.host, ldap2, "kra"):
|
||||
return api.env.host
|
||||
host = select_any_master(ldap2, "kra")
|
||||
if host:
|
||||
return host
|
||||
else:
|
||||
return api.env.kra_host
|
||||
|
||||
def get_keyclient(self):
|
||||
"""Return a keyclient to perform key archival and retrieval.
|
||||
:return: pki.key.keyclient
|
||||
"""
|
||||
if self.keyclient is None:
|
||||
self._setup()
|
||||
return self.keyclient
|
||||
|
||||
api.register(kra)
|
||||
|
||||
Reference in New Issue
Block a user