Fixed KRA backend.

The KRA backend has been simplified since most of the tasks have
been moved somewhere else. The transport certificate will be
installed on the client, and it is not needed by KRA backend. The
KRA agent's PEM certificate is now generated during installation
due to permission issue. The kra_host() for now is removed since
the current ldap_enable() cannot register the KRA service, so it
is using the kra_host environment variable.

The KRA installer has been modified to use Dogtag's CLI to create
KRA agent and setup the client authentication.

The proxy settings have been updated to include KRA's URLs.

Some constants have been renamed for clarity. The DOGTAG_AGENT_P12
has been renamed to DOGTAG_ADMIN_P12 since file actually contains
the Dogtag admin's certificate and private key and it can be used
to access both CA and KRA. The DOGTAG_AGENT_PEM has been renamed
to KRA_AGENT_PEM since it can only be used for KRA.

The Dogtag dependency has been updated to 10.2.1-0.1.

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

Reviewed-By: Petr Viktorin <pviktori@redhat.com>
This commit is contained in:
Endi S. Dewata 2014-10-01 14:59:46 -04:00 committed by Petr Viktorin
parent e7edac30a1
commit 0b08043c37
7 changed files with 101 additions and 121 deletions

View File

@ -130,8 +130,8 @@ Requires(post): systemd-units
Requires: selinux-policy >= %{selinux_policy_version}
Requires(post): selinux-policy-base
Requires: slapi-nis >= 0.54-1
Requires: pki-ca >= 10.2.0-3
Requires: pki-kra >= 10.2.0
Requires: pki-ca >= 10.2.1-0.1
Requires: pki-kra >= 10.2.1-0.1
%if 0%{?rhel}
Requires: subscription-manager
%endif

View File

@ -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|^/kra/agent/kra/connector|^/kra/rest/agent/keyrequests|^/kra/rest/agent/keys|^/ca/rest/admin/kraconnector/remove">
<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/account|^/kra/rest/agent/keyrequests|^/kra/rest/agent/keys|^/ca/rest/admin/kraconnector/remove">
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
NSSVerifyClient require
ProxyPassMatch ajp://localhost:$DOGTAG_PORT

View File

@ -138,8 +138,8 @@ class BasePathNamespace(object):
HOME_DIR = "/home"
ROOT_IPA_CACHE = "/root/.ipa_cache"
ROOT_PKI = "/root/.pki"
DOGTAG_AGENT_P12 = "/root/ca-agent.p12"
DOGTAG_AGENT_PEM = "/etc/httpd/alias/agent.pem"
DOGTAG_ADMIN_P12 = "/root/ca-agent.p12"
KRA_AGENT_PEM = "/etc/httpd/alias/kra-agent.pem"
CACERT_P12 = "/root/cacert.p12"
ROOT_IPA_CSR = "/root/ipa.csr"
ROOT_TMP_CA_P12 = "/root/tmp-ca.p12"

View File

@ -514,7 +514,7 @@ class CAInstance(DogtagInstance):
config.set("CA", "pki_admin_nickname", "ipa-ca-agent")
config.set("CA", "pki_admin_subject_dn",
str(DN(('cn', 'ipa-ca-agent'), self.subject_base)))
config.set("CA", "pki_client_admin_cert_p12", paths.DOGTAG_AGENT_P12)
config.set("CA", "pki_client_admin_cert_p12", paths.DOGTAG_ADMIN_P12)
# Directory server
config.set("CA", "pki_ds_ldap_port", str(self.ds_port))
@ -979,7 +979,7 @@ class CAInstance(DogtagInstance):
try:
ipautil.run([paths.PK12UTIL,
"-n", "ipa-ca-agent",
"-o", paths.DOGTAG_AGENT_P12,
"-o", paths.DOGTAG_ADMIN_P12,
"-d", self.agent_db,
"-k", pwd_name,
"-w", pwd_name])

View File

@ -157,7 +157,8 @@ class Backup(admintool.AdminTool):
paths.NTP_CONF,
paths.SMB_CONF,
paths.SAMBA_KEYTAB,
paths.DOGTAG_AGENT_P12,
paths.DOGTAG_ADMIN_P12,
paths.KRA_AGENT_PEM,
paths.CACERT_P12,
paths.KRB5KDC_KDC_CONF,
paths.SYSTEMD_IPA_SERVICE,

View File

@ -169,7 +169,7 @@ class KRAInstance(DogtagInstance):
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)
config.set("KRA", "pki_client_admin_cert_p12", paths.DOGTAG_ADMIN_P12)
# Directory server
config.set("KRA", "pki_ds_ldap_port", str(self.ds_port))
@ -259,16 +259,81 @@ class KRAInstance(DogtagInstance):
"""
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)
# import CA certificate into temporary security database
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"client-cert-import",
"--pkcs12", paths.KRACERT_P12,
"--pkcs12-password", self.admin_password]
ipautil.run(args)
conn.unbind()
# trust CA certificate
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"client-cert-mod", "Certificate Authority - %s" % api.env.realm,
"--trust", "CT,c,"]
ipautil.run(args)
# import Dogtag admin certificate into temporary security database
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"client-cert-import",
"--pkcs12", paths.DOGTAG_ADMIN_P12,
"--pkcs12-password", self.admin_password]
ipautil.run(args)
# as Dogtag admin, create ipakra user in KRA
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"-n", "ipa-ca-agent",
"kra-user-add", "ipakra",
"--fullName", "IPA KRA User"]
ipautil.run(args)
# as Dogtag admin, add ipakra into KRA agents group
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"-n", "ipa-ca-agent",
"kra-user-membership-add", "ipakra", "Data Recovery Manager Agents"]
ipautil.run(args)
# assign ipaCert to ipakra
(file, filename) = tempfile.mkstemp()
os.close(file)
try:
# export ipaCert without private key
args = ["/usr/bin/pki",
"-d", paths.HTTPD_ALIAS_DIR,
"-C", paths.ALIAS_PWDFILE_TXT,
"client-cert-show", "ipaCert",
"--cert", filename]
ipautil.run(args)
# as Dogtag admin, upload and assign ipaCert to ipakra
args = ["/usr/bin/pki",
"-d", self.agent_db,
"-c", self.admin_password,
"-n", "ipa-ca-agent",
"kra-user-cert-add", "ipakra",
"--input", filename]
ipautil.run(args)
finally:
os.remove(filename)
# export ipaCert with private key for client authentication
args = ["/usr/bin/pki",
"-d", paths.HTTPD_ALIAS_DIR,
"-C", paths.ALIAS_PWDFILE_TXT,
"client-cert-show", "ipaCert",
"--client-cert", paths.KRA_AGENT_PEM]
ipautil.run(args)
@staticmethod
def update_cert_config(nickname, cert, dogtag_constants=None):

View File

@ -1890,122 +1890,36 @@ class kra(Backend):
"""
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
def get_client(self):
"""
(p12_pwd_fd, p12_pwd_fname) = tempfile.mkstemp()
(p12_fd, p12_fname) = tempfile.mkstemp()
Returns an authenticated KRA client to access KRA services.
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
Raises a generic exception if KRA is not enabled.
"""
# 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
if not api.env.enable_kra:
# TODO: replace this with a more specific exception
raise RuntimeError('KRA service is not enabled')
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()
crypto = cryptoutil.NSSCryptoProvider(
paths.HTTPD_ALIAS_DIR,
password_file=paths.ALIAS_PWDFILE_TXT)
# set up connection
connection = PKIConnection('https',
self.kra_host,
str(self.kra_port),
'kra')
connection.set_authentication_cert(self.pem_file)
# TODO: obtain KRA host & port from IPA service list or point to KRA load balancer
# https://fedorahosted.org/freeipa/ticket/4557
connection = PKIConnection(
'https',
api.env.kra_host,
str(self.kra_port),
'kra')
crypto = cryptoutil.NSSCryptoProvider(self.sec_dir, self.password)
connection.set_authentication_cert(paths.KRA_AGENT_PEM)
#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
return KRAClient(connection, crypto)
api.register(kra)