[Freeipa-devel] [PATCH] 0053..0054 Configure lightweight CA key replication
Fraser Tweedale
ftweedal at redhat.com
Wed May 4 04:04:05 UTC 2016
On Tue, May 03, 2016 at 05:05:58PM +1000, Fraser Tweedale wrote:
> On Tue, Apr 26, 2016 at 10:02:45AM +0200, Jan Cholasta wrote:
> > On 21.4.2016 05:30, Fraser Tweedale wrote:
> > >On Thu, Apr 14, 2016 at 04:39:37PM +1000, Fraser Tweedale wrote:
> > >>Hi all,
> > >>
> > >>The attached patches configure lightweight CA key replication on IPA
> > >>CAs, on upgrade and installation.
> > >>
> > >>Patches 0051..0052 from my other mail are also needed for the system
> > >>to work, but this patchset does not depend on them and can be
> > >>reviewed independently.
> > >>
> > >>There is also no hard dependency on the (unreleased) Dogtag 10.3.0b1
> > >>- it just puts the necessary principals/keys/configuration in place.
> > >>
> > >>Cheers,
> > >>Fraser
> > >>
> > >New patches attached; 0054-2 changes the service name from
> > >'dogtag-ipa-custodia' to just 'dogtag', and adds an ACI to allow the
> > >principal to search server Custodia keys.
> >
> Honza, thanks for review. Comments inline.
>
> > Patch 53:
> >
> > I'm not sure about this approach - the cn of custodia keys in LDAP is a
> > free-form string, I would not tie it to service names, but rather try to
> > keep it short.
> >
> > In the key replication section of the design page, you mention "ca/$NAME", I
> > think this is a good template for the cn and that we should stick to it.
> >
> This scheme (or something like it, *without* '/' as the separator)
> is needed to satisfy the ACI that allows host principals to manage
> Custodia keys:
>
> add:aci: (target = "ldap:///cn=*/($$dn),cn=custodia,cn=ipa,cn=etc,$SUFFIX")
> (version 3.0; acl "IPA server hosts can create own Custodia secrets";
> allow(add) groupdn = "ldap:///cn=ipaservers,cn=hostgroups,cn=accounts,$SUFFIX"
> and userdn = "ldap:///fqdn=($$dn),cn=computers,cn=accounts,$SUFFIX";)
>
> The CN must contain the hostname, and we must also disambiguate on
> key type. The current scheme is:
>
> {sig,enc}~dogtag/<HOSTNAME>
> e.g.
> enc~dogtag/f23-2.ipa.local
>
> The first separator cannot be '/' because the '*' wildcard in the
> ACI is not greedy - the captured text would include the servicename
> and fail to match any userdn.
>
> If you do not like '~' feel free to suggest a different symbol :)
> The alternative is to add more ACIs.
>
> >
> > Patch 54:
> >
> > 1) This belongs to CAInstance.configure_instance():
> >
> > + CA = cainstance.CAInstance(
> > + api.env.realm, certs.NSS_DIR, host_name=api.env.host)
> > + CA.setup_lightweight_ca_key_retrieval()
> >
> See comments for (5).
>
> >
> > 2) Any ACI changes should be in a separate patch. (What happened to patch
> > 52?)
> >
> Patch 52 added an ACI that allowed any authenticated user to see the
> keys. Simo wanted it limited it to the Dogtag principal so I
> rescinded patch 52 and added the ACI in the same patch where the
> principal was added.
>
> Separate patch is no problem; I will resurrect number 52.
>
> >
> > 3) This is not a platform constant, just a constant:
> >
> > + PKI_GSSAPI_SERVICE_NAME = 'dogtag'
> >
> Thanks, will put it in `ipalib.constants'.
>
> >
> > 4) CAInstance.setup_lightweight_ca_key_retrieval() does too much. Please
> > split it into a "setup keytab" and "setup custodia" parts.
> >
> Will extract methods for next patchset.
>
> >
> > 5) This also belongs to CAInstance.configure_instance():
> >
> > + if setup_ca:
> > + # CA was configured before Kerberos;
> > + # add Custodia client princ and keys now
> > + ca_instance.setup_lightweight_ca_key_retrieval()
> >
> > In order for that to work, you need to move the ca.install_step_1() after
> > krb.create_instance(), but that should be OK, since KrbInstance does not
> > talk to the CA.
> >
> `setup_lightweight_ca_key_retrieval' calls `kadmin_addprinc', which
> fails if called before `krb.create_instance' due to missing
> krb5.conf::
>
> 2016-05-03T06:29:23Z DEBUG args=kadmin.local -q addprinc -randkey dogtag/f23-2.ipa.local at IPA.LOCAL -x ipa-setup-override-restrictions
> 2016-05-03T06:29:23Z DEBUG Process finished, return code=1
> 2016-05-03T06:29:23Z DEBUG stdout=
> 2016-05-03T06:29:23Z DEBUG stderr=kadmin.local: unable to get default realm
>
> Moving `ca.install_step_1()' to after `krb.create_instance()' does
> not help, because `CAInstance.configure_instance' is called from
> `ca.install_step_0()'.
>
> However, calling `CAInstance.setup_lightweight_ca_key_retrieval()'
> *directly* from `ca.install_step_1' would probably work. Are you
> happy with putting it there, instead of `configure_instance()'?
>
> Cheers,
> Fraser
>
Updated patches attached, include bringing back 0052-2 for the ACI
change.
Cheers,
Fraser
-------------- next part --------------
From 3d047e3dc1e7f700751c0f52f26326764b70d94d Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 3 May 2016 13:22:39 +1000
Subject: [PATCH] Allow Dogtag service principals to read Custodia keys
The "dogtag/$HOSTNAME@$REALM" service principal uses Custodia to
retrieve lightweight CA signing keys, and therefore needs search and
read access to Custodia keys. Add an ACI to permit this.
Part of: https://fedorahosted.org/freeipa/ticket/4559
---
install/updates/20-aci.update | 3 +++
1 file changed, 3 insertions(+)
diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update
index 4802ae0458e8b870bf3127764ebabac1a48f7cf2..2e9a36da442c392c9161861615b1744eeb6b799c 100644
--- a/install/updates/20-aci.update
+++ b/install/updates/20-aci.update
@@ -136,3 +136,6 @@ add:aci: (target = "ldap:///cn=replication,cn=etc,$SUFFIX")(targetattr = "nsDS5R
dn: cn=ipa,cn=etc,$SUFFIX
add:aci: (target = "ldap:///cn=*/($$dn),cn=custodia,cn=ipa,cn=etc,$SUFFIX")(version 3.0; acl "IPA server hosts can create own Custodia secrets"; allow(add) groupdn = "ldap:///cn=ipaservers,cn=hostgroups,cn=accounts,$SUFFIX" and userdn = "ldap:///fqdn=($$dn),cn=computers,cn=accounts,$SUFFIX";)
add:aci: (target = "ldap:///cn=*/($$dn),cn=custodia,cn=ipa,cn=etc,$SUFFIX")(targetattr = "ipaPublicKey")(version 3.0; acl "IPA server hosts can manage own Custodia secrets"; allow(write) groupdn = "ldap:///cn=ipaservers,cn=hostgroups,cn=accounts,$SUFFIX" and userdn = "ldap:///fqdn=($$dn),cn=computers,cn=accounts,$SUFFIX";)
+
+# Dogtag service principals can search Custodia keys
+add:aci: (target = "ldap:///cn=*,cn=custodia,cn=ipa,cn=etc,$SUFFIX")(targetattr = "ipaPublicKey || ipaKeyUsage || memberPrincipal")(version 3.0; acl "Dogtag service principals can search Custodia keys"; allow(read, search, compare) userdn = "ldap:///krbprincipalname=dogtag/*@$REALM,cn=services,cn=accounts,$SUFFIX";)
--
2.5.5
-------------- next part --------------
From b303284245627e4214d1ba3d03bdb06fc89c3a53 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 11 Apr 2016 12:42:35 +1000
Subject: [PATCH 53/54] Optionally add service name to Custodia key DNs
Lightweight CAs support introduces new service principals for
Dogtag, with Custodia keys. The current Custodia key creation uses
a DN that contains only they key type and the hostname, so keys for
multiple services on the same host cannot be created.
Add the 'generate_keys' method to generate keys for a host or an
arbitrary service. When a service name is given, include the
service name in the DN.
This change does not affect searching because all searching is done
using the ipaKeyUsage and memberPrincipal attributes.
Part of: https://fedorahosted.org/freeipa/ticket/4559
---
ipapython/secrets/kem.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/ipapython/secrets/kem.py b/ipapython/secrets/kem.py
index 1025ed7980f055c82c602634e8845fa490cf0514..533121779241d30e19fef4c050bb69c55d29ec22 100644
--- a/ipapython/secrets/kem.py
+++ b/ipapython/secrets/kem.py
@@ -105,10 +105,11 @@ class KEMLdap(iSecLdap):
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
- def set_key(self, usage, host, principal, key):
+ def set_key(self, usage, servicename, host, principal, key):
public_key = self._format_public_key(key)
conn = self.connect()
- name = '%s/%s' % (KEY_USAGE_MAP[usage], host)
+ service_segment = '~' + servicename if servicename else ''
+ name = '%s%s/%s' % (KEY_USAGE_MAP[usage], service_segment, host)
dn = 'cn=%s,%s' % (name, self.keysbase)
try:
mods = [('objectClass', ['nsContainer',
@@ -170,15 +171,18 @@ class IPAKEMKeys(KEMKeysStore):
return conn.get_key(usage, kid)
def generate_server_keys(self):
- principal = 'host/%s@%s' % (self.host, self.realm)
+ self.generate_keys()
+
+ def generate_keys(self, servicename=None):
+ principal = '%s/%s@%s' % (servicename or 'host', self.host, self.realm)
# Neutralize the key with read if any
self._server_keys = None
# Generate private key and store it
pubkeys = newServerKeys(self.config['server_keys'], principal)
# Store public key in LDAP
ldapconn = KEMLdap(self.ldap_uri)
- ldapconn.set_key(KEY_USAGE_SIG, self.host, principal, pubkeys[0])
- ldapconn.set_key(KEY_USAGE_ENC, self.host, principal, pubkeys[1])
+ ldapconn.set_key(KEY_USAGE_SIG, servicename, self.host, principal, pubkeys[0])
+ ldapconn.set_key(KEY_USAGE_ENC, servicename, self.host, principal, pubkeys[1])
@property
def server_keys(self):
--
2.5.5
-------------- next part --------------
From d38f29d48da644d9cdb9455384ee4ae107e9acc0 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 11 Apr 2016 16:47:33 +1000
Subject: [PATCH 54/54] Setup lightweight CA key retrieval on install/upgrade
To configure Dogtag lightweight CA key replication on installation
and upgrade:
- add the 'dogtag/$HOSTNAME' service principal
- create the pricipal's Custodia keys
- retrieve keytab
- configure the IPACustodiaKeyRetriever in CS.cfg
Part of: https://fedorahosted.org/freeipa/ticket/4559
---
ipalib/constants.py | 1 +
ipaserver/install/ca.py | 9 ++++++-
ipaserver/install/cainstance.py | 52 +++++++++++++++++++++++++++++++++++++
ipaserver/install/server/install.py | 6 ++---
ipaserver/install/server/upgrade.py | 6 ++++-
5 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 021f18cd366b821427bdbfcc5e354d2047ef39b1..d544595898e52d3910cff94fc3cc0276fe099a98 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -261,3 +261,4 @@ REPL_AGMT_STRIP_ATTRS = ('modifiersName',
DOMAIN_SUFFIX_NAME = 'domain'
CA_SUFFIX_NAME = 'ca'
+PKI_GSSAPI_SERVICE_NAME = 'dogtag'
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index acc54334e1b6e64a0b2d4b097e7464c95988f3f5..4d25af5870ce7a130c996d1e7de4a05c2167d494 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -182,7 +182,7 @@ def install_step_1(standalone, replica_config, options):
basedn = ipautil.realm_to_suffix(realm_name)
- ca = cainstance.CAInstance(realm_name, certs.NSS_DIR)
+ ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, host_name=host_name)
if standalone:
ca.stop('pki-tomcat')
@@ -193,6 +193,13 @@ def install_step_1(standalone, replica_config, options):
# This is done within stopped_service context, which restarts CA
ca.enable_client_auth_to_db(paths.CA_CS_CFG_PATH)
+ # Lightweight CA key retrieval is configured in step 1 instead
+ # of CAInstance.configure_instance (which is invoked from step
+ # 0) because kadmin_addprinc fails until krb5.conf is installed
+ # by krb.create_instance.
+ #
+ ca.setup_lightweight_ca_key_retrieval()
+
if standalone and replica_config is None:
serverid = installutils.realm_to_serverid(realm_name)
dirname = dsinstance.config_dirname(serverid)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index a21f7d2671461dfb99797d39fc7ee5706317241f..ec31283972d84f0b682bea444a70286585fa489e 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -45,6 +45,7 @@ from six.moves.configparser import ConfigParser, RawConfigParser
from ipalib import api
from ipalib import pkcs10, x509
from ipalib import errors
+import ipalib.constants
from ipaplatform import services
from ipaplatform.constants import constants
@@ -59,6 +60,7 @@ from ipapython.certdb import get_ca_nickname
from ipapython.dn import DN
from ipapython.ipa_log_manager import log_mgr,\
standard_logging_setup, root_logger
+from ipapython.secrets.kem import IPAKEMKeys
from ipaserver.install import certs
from ipaserver.install import dsinstance
@@ -66,6 +68,7 @@ from ipaserver.install import installutils
from ipaserver.install import ldapupdate
from ipaserver.install import replication
from ipaserver.install import service
+from ipaserver.install import sysupgrade
from ipaserver.install.dogtaginstance import (export_kra_agent_pem,
DogtagInstance)
from ipaserver.plugins import ldap2
@@ -1356,11 +1359,60 @@ class CAInstance(DogtagInstance):
self.step("updating IPA configuration", update_ipa_conf)
self.step("Restart HTTP server to pick up changes",
self.__restart_http_instance)
+ self.step("Configure lightweight CA key retrieval",
+ self.setup_lightweight_ca_key_retrieval)
self.step("enabling CA instance", self.__enable_instance)
self.start_creation(runtime=210)
+ def setup_lightweight_ca_key_retrieval(self):
+ if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'):
+ return
+
+ root_logger.info('[Set up lightweight CA key retrieval]')
+
+ self.__setup_lightweight_ca_key_retrieval_kerberos()
+ self.__setup_lightweight_ca_key_retrieval_custodia()
+
+ root_logger.info('Configuring key retriever')
+ installutils.set_directive(
+ paths.CA_CS_CFG_PATH,
+ 'features.authority.keyRetrieverClass',
+ 'com.netscape.ca.IPACustodiaKeyRetriever',
+ quotes=False, separator='=')
+
+ sysupgrade.set_upgrade_state('dogtag', 'setup_lwca_key_retieval', True)
+
+ def __setup_lightweight_ca_key_retrieval_kerberos(self):
+ service = ipalib.constants.PKI_GSSAPI_SERVICE_NAME
+ principal = '{}/{}@{}'.format(service, api.env.host, self.realm)
+ pent = pwd.getpwnam(constants.PKI_USER)
+
+ root_logger.info('Creating principal')
+ installutils.kadmin_addprinc(principal)
+ self.suffix = ipautil.realm_to_suffix(self.realm)
+ if not self.admin_conn:
+ self.ldap_connect()
+ self.move_service(principal)
+
+ root_logger.info('Retrieving keytab')
+ keytab = os.path.join(paths.PKI_TOMCAT, service + '.keytab')
+ installutils.create_keytab(keytab, principal)
+ os.chmod(keytab, 0o600)
+ os.chown(keytab, pent.pw_uid, pent.pw_gid)
+
+ def __setup_lightweight_ca_key_retrieval_custodia(self):
+ service = ipalib.constants.PKI_GSSAPI_SERVICE_NAME
+ pent = pwd.getpwnam(constants.PKI_USER)
+
+ root_logger.info('Creating Custodia keys')
+ keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys')
+ keystore = IPAKEMKeys({'server_keys': keyfile})
+ keystore.generate_keys(service)
+ os.chmod(keyfile, 0o600)
+ os.chown(keyfile, pent.pw_uid, pent.pw_gid)
+
def replica_ca_install_check(config):
if not config.setup_ca:
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 2d71b3837214683566f37644c41a680953a64207..9f5219887c671f2663a791068d6383ab18443265 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -891,9 +891,6 @@ def install(installer):
# we now need to enable ssl on the ds
ds.enable_ssl()
- if setup_ca:
- ca.install_step_1(False, None, options)
-
krb = krbinstance.KrbInstance(fstore)
if options.pkinit_cert_files:
krb.create_instance(realm_name, host_name, domain_name,
@@ -907,6 +904,9 @@ def install(installer):
setup_pkinit=not options.no_pkinit,
subject_base=options.subject)
+ if setup_ca:
+ ca.install_step_1(False, None, options)
+
# The DS instance is created before the keytab, add the SSL cert we
# generated
ds.add_cert_to_service()
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 4f3a2cb065319a26bfa517b4d1d2cb4b41fb486d..f2e01b546d4be0177eeee1e6a264586321646015 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1467,7 +1467,8 @@ def upgrade_configuration():
if subject_base:
sub_dict['SUBJECT_BASE'] = subject_base
- ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR)
+ ca = cainstance.CAInstance(
+ api.env.realm, certs.NSS_DIR, host_name=api.env.host)
with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'):
# Dogtag must be stopped to be able to backup CS.cfg config
@@ -1663,6 +1664,9 @@ def upgrade_configuration():
ca_import_included_profiles(ca)
add_default_caacl(ca)
+ if ca.is_configured():
+ ca.setup_lightweight_ca_key_retrieval()
+
set_sssd_domain_option('ipa_server_mode', 'True')
if ds_running and not ds.is_running():
--
2.5.5
More information about the Freeipa-devel
mailing list