|
|
ac7d03 |
From 2558a0336e9d61b2b7e321b7dfa32426151b4bbb Mon Sep 17 00:00:00 2001
|
|
|
ac7d03 |
From: Jan Cholasta <jcholast@redhat.com>
|
|
|
ac7d03 |
Date: Wed, 3 May 2017 06:09:03 +0000
|
|
|
ac7d03 |
Subject: [PATCH] server install: fix KDC PKINIT configuration
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Set `pkinit_pool` in `kdc.conf` to a CA certificate bundle of all CAs known
|
|
|
ac7d03 |
to IPA.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Make sure `cacert.pem` is exported in all installation code paths.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Use the KDC certificate itself as a PKINIT anchor in `login_password`.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
https://pagure.io/freeipa/issue/6831
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
|
|
|
ac7d03 |
Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
|
|
|
ac7d03 |
---
|
|
|
ac7d03 |
install/restart_scripts/Makefile.am | 1 +
|
|
|
ac7d03 |
install/restart_scripts/renew_kdc_cert | 31 ++++++++++++++++++
|
|
|
ac7d03 |
install/share/kdc.conf.template | 2 ++
|
|
|
ac7d03 |
ipaclient/install/ipa_certupdate.py | 1 +
|
|
|
ac7d03 |
ipalib/install/kinit.py | 7 +++--
|
|
|
ac7d03 |
ipaserver/install/krbinstance.py | 27 +++++++++-------
|
|
|
ac7d03 |
ipaserver/install/server/upgrade.py | 57 ++++++++++++++++++++++++++--------
|
|
|
ac7d03 |
ipaserver/rpcserver.py | 5 ++-
|
|
|
ac7d03 |
8 files changed, 103 insertions(+), 28 deletions(-)
|
|
|
ac7d03 |
create mode 100755 install/restart_scripts/renew_kdc_cert
|
|
|
ac7d03 |
|
|
|
ac7d03 |
diff --git a/install/restart_scripts/Makefile.am b/install/restart_scripts/Makefile.am
|
|
|
ac7d03 |
index 04881b406b6be92b46e630f30d724918506e2aa8..240cebdee8cae7a0c7bdf88f5300583b4232fc94 100644
|
|
|
ac7d03 |
--- a/install/restart_scripts/Makefile.am
|
|
|
ac7d03 |
+++ b/install/restart_scripts/Makefile.am
|
|
|
ac7d03 |
@@ -5,6 +5,7 @@ app_DATA = \
|
|
|
ac7d03 |
restart_dirsrv \
|
|
|
ac7d03 |
restart_httpd \
|
|
|
ac7d03 |
renew_ca_cert \
|
|
|
ac7d03 |
+ renew_kdc_cert \
|
|
|
ac7d03 |
renew_ra_cert \
|
|
|
ac7d03 |
stop_pkicad \
|
|
|
ac7d03 |
renew_ra_cert_pre \
|
|
|
ac7d03 |
diff --git a/install/restart_scripts/renew_kdc_cert b/install/restart_scripts/renew_kdc_cert
|
|
|
ac7d03 |
new file mode 100755
|
|
|
ac7d03 |
index 0000000000000000000000000000000000000000..9247920874fc9540ac3421dd59fd902cc195243f
|
|
|
ac7d03 |
--- /dev/null
|
|
|
ac7d03 |
+++ b/install/restart_scripts/renew_kdc_cert
|
|
|
ac7d03 |
@@ -0,0 +1,31 @@
|
|
|
ac7d03 |
+#!/usr/bin/python2 -E
|
|
|
ac7d03 |
+#
|
|
|
ac7d03 |
+# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
|
|
ac7d03 |
+#
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+import os
|
|
|
ac7d03 |
+import syslog
|
|
|
ac7d03 |
+import traceback
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+from ipaplatform import services
|
|
|
ac7d03 |
+from ipaplatform.paths import paths
|
|
|
ac7d03 |
+from ipaserver.install import certs
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+def main():
|
|
|
ac7d03 |
+ with certs.renewal_lock:
|
|
|
ac7d03 |
+ os.chmod(paths.KDC_CERT, 0o644)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ try:
|
|
|
ac7d03 |
+ if services.knownservices.krb5kdc.is_running():
|
|
|
ac7d03 |
+ syslog.syslog(syslog.LOG_NOTICE, 'restarting krb5kdc')
|
|
|
ac7d03 |
+ services.knownservices.krb5kdc.restart()
|
|
|
ac7d03 |
+ except Exception as e:
|
|
|
ac7d03 |
+ syslog.syslog(
|
|
|
ac7d03 |
+ syslog.LOG_ERR, "cannot restart krb5kdc: {}".format(e))
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+try:
|
|
|
ac7d03 |
+ main()
|
|
|
ac7d03 |
+except Exception:
|
|
|
ac7d03 |
+ syslog.syslog(syslog.LOG_ERR, traceback.format_exc())
|
|
|
ac7d03 |
diff --git a/install/share/kdc.conf.template b/install/share/kdc.conf.template
|
|
|
ac7d03 |
index ec53a1ff5f7110704143074bc7a5d1dfdc705344..306351b86111eb0e883b2398678f50b821e0ad7f 100644
|
|
|
ac7d03 |
--- a/install/share/kdc.conf.template
|
|
|
ac7d03 |
+++ b/install/share/kdc.conf.template
|
|
|
ac7d03 |
@@ -13,5 +13,7 @@
|
|
|
ac7d03 |
default_principal_flags = +preauth
|
|
|
ac7d03 |
; admin_keytab = $KRB5KDC_KADM5_KEYTAB
|
|
|
ac7d03 |
pkinit_identity = FILE:$KDC_CERT,$KDC_KEY
|
|
|
ac7d03 |
+ pkinit_anchors = FILE:$KDC_CERT
|
|
|
ac7d03 |
pkinit_anchors = FILE:$CACERT_PEM
|
|
|
ac7d03 |
+ pkinit_pool = FILE:$CA_BUNDLE_PEM
|
|
|
ac7d03 |
}
|
|
|
ac7d03 |
diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
|
|
|
ac7d03 |
index 7e8527e1fcb575844e8f4c90016435124b70e381..93da8422b6f503b8c44db678736d7f71f7d7567e 100644
|
|
|
ac7d03 |
--- a/ipaclient/install/ipa_certupdate.py
|
|
|
ac7d03 |
+++ b/ipaclient/install/ipa_certupdate.py
|
|
|
ac7d03 |
@@ -172,6 +172,7 @@ class CertUpdate(admintool.AdminTool):
|
|
|
ac7d03 |
certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent')
|
|
|
ac7d03 |
|
|
|
ac7d03 |
self.update_file(paths.CA_CRT, certs)
|
|
|
ac7d03 |
+ self.update_file(paths.CACERT_PEM, certs)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def update_file(self, filename, certs, mode=0o444):
|
|
|
ac7d03 |
certs = (c[0] for c in certs if c[2] is not False)
|
|
|
ac7d03 |
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
|
|
|
ac7d03 |
index fb6caee4d6b5fef27b53753b21ad83572da31ac4..73471f103eabfe39580c8fbd0665157f635fa5c5 100644
|
|
|
ac7d03 |
--- a/ipalib/install/kinit.py
|
|
|
ac7d03 |
+++ b/ipalib/install/kinit.py
|
|
|
ac7d03 |
@@ -96,7 +96,7 @@ def kinit_password(principal, password, ccache_name, config=None,
|
|
|
ac7d03 |
raise RuntimeError(result.error_output)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
|
|
|
ac7d03 |
-def kinit_armor(ccache_name, pkinit_anchor=None):
|
|
|
ac7d03 |
+def kinit_armor(ccache_name, pkinit_anchors=None):
|
|
|
ac7d03 |
"""
|
|
|
ac7d03 |
perform anonymous pkinit to obtain anonymous ticket to be used as armor
|
|
|
ac7d03 |
for FAST.
|
|
|
ac7d03 |
@@ -113,8 +113,9 @@ def kinit_armor(ccache_name, pkinit_anchor=None):
|
|
|
ac7d03 |
env = {'LC_ALL': 'C'}
|
|
|
ac7d03 |
args = [paths.KINIT, '-n', '-c', ccache_name]
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- if pkinit_anchor is not None:
|
|
|
ac7d03 |
- args.extend(['-X', 'X509_anchors=FILE:{}'.format(pkinit_anchor)])
|
|
|
ac7d03 |
+ if pkinit_anchors is not None:
|
|
|
ac7d03 |
+ for pkinit_anchor in pkinit_anchors:
|
|
|
ac7d03 |
+ args.extend(['-X', 'X509_anchors=FILE:{}'.format(pkinit_anchor)])
|
|
|
ac7d03 |
|
|
|
ac7d03 |
# this workaround enables us to capture stderr and put it
|
|
|
ac7d03 |
# into the raised exception in case of unsuccessful authentication
|
|
|
ac7d03 |
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
|
|
|
ac7d03 |
index e52577bbaa15064946f9a3c9720aa40ffc3251aa..1692e0b2badb23c18386346a552c83881018cf60 100644
|
|
|
ac7d03 |
--- a/ipaserver/install/krbinstance.py
|
|
|
ac7d03 |
+++ b/ipaserver/install/krbinstance.py
|
|
|
ac7d03 |
@@ -20,7 +20,6 @@
|
|
|
ac7d03 |
from __future__ import absolute_import
|
|
|
ac7d03 |
from __future__ import print_function
|
|
|
ac7d03 |
|
|
|
ac7d03 |
-import shutil
|
|
|
ac7d03 |
import os
|
|
|
ac7d03 |
import pwd
|
|
|
ac7d03 |
import socket
|
|
|
ac7d03 |
@@ -28,6 +27,8 @@ import dbus
|
|
|
ac7d03 |
|
|
|
ac7d03 |
import dns.name
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+from ipalib import x509
|
|
|
ac7d03 |
+from ipalib.install import certstore
|
|
|
ac7d03 |
from ipaserver.install import service
|
|
|
ac7d03 |
from ipaserver.install import installutils
|
|
|
ac7d03 |
from ipapython import ipaldap
|
|
|
ac7d03 |
@@ -430,7 +431,8 @@ class KrbInstance(service.Service):
|
|
|
ac7d03 |
ca=certmonger_ca,
|
|
|
ac7d03 |
dns=self.fqdn,
|
|
|
ac7d03 |
storage='FILE',
|
|
|
ac7d03 |
- profile=KDC_PROFILE)
|
|
|
ac7d03 |
+ profile=KDC_PROFILE,
|
|
|
ac7d03 |
+ post_command='renew_kdc_cert')
|
|
|
ac7d03 |
except dbus.DBusException as e:
|
|
|
ac7d03 |
# if the certificate is already tracked, ignore the error
|
|
|
ac7d03 |
name = e.get_dbus_name()
|
|
|
ac7d03 |
@@ -448,17 +450,23 @@ class KrbInstance(service.Service):
|
|
|
ac7d03 |
service.set_service_entry_config(
|
|
|
ac7d03 |
'KDC', self.fqdn, [PKINIT_ENABLED], self.suffix)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ def _install_pkinit_ca_bundle(self):
|
|
|
ac7d03 |
+ ca_certs = certstore.get_ca_certs(self.api.Backend.ldap2,
|
|
|
ac7d03 |
+ self.api.env.basedn,
|
|
|
ac7d03 |
+ self.api.env.realm,
|
|
|
ac7d03 |
+ False)
|
|
|
ac7d03 |
+ ca_certs = [c for c, _n, t, _u in ca_certs if t is not False]
|
|
|
ac7d03 |
+ x509.write_certificate_list(ca_certs, paths.CACERT_PEM)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
def issue_selfsigned_pkinit_certs(self):
|
|
|
ac7d03 |
self._call_certmonger(certmonger_ca="SelfSign")
|
|
|
ac7d03 |
- # for self-signed certificate, the certificate is its own CA, copy it
|
|
|
ac7d03 |
- # as CA cert
|
|
|
ac7d03 |
- shutil.copyfile(paths.KDC_CERT, paths.CACERT_PEM)
|
|
|
ac7d03 |
+ with open(paths.CACERT_PEM, 'w'):
|
|
|
ac7d03 |
+ pass
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def issue_ipa_ca_signed_pkinit_certs(self):
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
self._call_certmonger()
|
|
|
ac7d03 |
- # copy IPA CA bundle to the KDC's CA cert bundle
|
|
|
ac7d03 |
- shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM)
|
|
|
ac7d03 |
+ self._install_pkinit_ca_bundle()
|
|
|
ac7d03 |
self.pkinit_enable()
|
|
|
ac7d03 |
except RuntimeError as e:
|
|
|
ac7d03 |
root_logger.error("PKINIT certificate request failed: %s", e)
|
|
|
ac7d03 |
@@ -473,10 +481,7 @@ class KrbInstance(service.Service):
|
|
|
ac7d03 |
certs.install_key_from_p12(self.pkcs12_info[0],
|
|
|
ac7d03 |
self.pkcs12_info[1],
|
|
|
ac7d03 |
paths.KDC_KEY)
|
|
|
ac7d03 |
- # copy IPA CA bundle to the KDC's CA cert bundle
|
|
|
ac7d03 |
- # NOTE: this may not be the same set of CA certificates trusted by
|
|
|
ac7d03 |
- # externally provided PKINIT cert.
|
|
|
ac7d03 |
- shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM)
|
|
|
ac7d03 |
+ self._install_pkinit_ca_bundle()
|
|
|
ac7d03 |
self.pkinit_enable()
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def setup_pkinit(self):
|
|
|
ac7d03 |
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
|
|
|
ac7d03 |
index 648dc1f29c44f89d9fbceb7b50373d93c88b5c1a..db86353165809c57d1ac27bf762393721231fefd 100644
|
|
|
ac7d03 |
--- a/ipaserver/install/server/upgrade.py
|
|
|
ac7d03 |
+++ b/ipaserver/install/server/upgrade.py
|
|
|
ac7d03 |
@@ -11,6 +11,7 @@ import pwd
|
|
|
ac7d03 |
import fileinput
|
|
|
ac7d03 |
import sys
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+from augeas import Augeas
|
|
|
ac7d03 |
import dns.exception
|
|
|
ac7d03 |
|
|
|
ac7d03 |
import six
|
|
|
ac7d03 |
@@ -1527,19 +1528,49 @@ def setup_pkinit(krb):
|
|
|
ac7d03 |
else:
|
|
|
ac7d03 |
krb.issue_selfsigned_pkinit_certs()
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- # reconfigure KDC just in case in order to handle potentially broken
|
|
|
ac7d03 |
- # 4.5.0 -> 4.5.1 upgrade path
|
|
|
ac7d03 |
- replacevars = dict()
|
|
|
ac7d03 |
- replacevars['pkinit_identity'] = 'FILE:{},{}'.format(
|
|
|
ac7d03 |
- paths.KDC_CERT,paths.KDC_KEY)
|
|
|
ac7d03 |
- appendvars = {}
|
|
|
ac7d03 |
- ipautil.backup_config_and_replace_variables(
|
|
|
ac7d03 |
- krb.fstore, paths.KRB5KDC_KDC_CONF, replacevars=replacevars,
|
|
|
ac7d03 |
- appendvars=appendvars)
|
|
|
ac7d03 |
- tasks.restore_context(paths.KRB5KDC_KDC_CONF)
|
|
|
ac7d03 |
- if krb.is_running():
|
|
|
ac7d03 |
- krb.stop()
|
|
|
ac7d03 |
- krb.start()
|
|
|
ac7d03 |
+ aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD,
|
|
|
ac7d03 |
+ loadpath=paths.USR_SHARE_IPA_DIR)
|
|
|
ac7d03 |
+ try:
|
|
|
ac7d03 |
+ aug.transform('IPAKrb5', paths.KRB5KDC_KDC_CONF)
|
|
|
ac7d03 |
+ aug.load()
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ path = '/files{}/realms/{}'.format(paths.KRB5KDC_KDC_CONF, krb.realm)
|
|
|
ac7d03 |
+ modified = False
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ value = 'FILE:{},{}'.format(paths.KDC_CERT, paths.KDC_KEY)
|
|
|
ac7d03 |
+ expr = '{}[count(pkinit_identity)=1][pkinit_identity="{}"]'.format(
|
|
|
ac7d03 |
+ path, value)
|
|
|
ac7d03 |
+ if not aug.match(expr):
|
|
|
ac7d03 |
+ aug.remove('{}/pkinit_identity'.format(path))
|
|
|
ac7d03 |
+ aug.set('{}/pkinit_identity'.format(path), value)
|
|
|
ac7d03 |
+ modified = True
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ for value in ['FILE:{}'.format(paths.KDC_CERT),
|
|
|
ac7d03 |
+ 'FILE:{}'.format(paths.CACERT_PEM)]:
|
|
|
ac7d03 |
+ expr = '{}/pkinit_anchors[.="{}"]'.format(path, value)
|
|
|
ac7d03 |
+ if not aug.match(expr):
|
|
|
ac7d03 |
+ aug.set('{}/pkinit_anchors[last()+1]'.format(path), value)
|
|
|
ac7d03 |
+ modified = True
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ value = 'FILE:{}'.format(paths.CA_BUNDLE_PEM)
|
|
|
ac7d03 |
+ expr = '{}/pkinit_pool[.="{}"]'.format(path, value)
|
|
|
ac7d03 |
+ if not aug.match(expr):
|
|
|
ac7d03 |
+ aug.set('{}/pkinit_pool[last()+1]'.format(path), value)
|
|
|
ac7d03 |
+ modified = True
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ if modified:
|
|
|
ac7d03 |
+ try:
|
|
|
ac7d03 |
+ aug.save()
|
|
|
ac7d03 |
+ except IOError:
|
|
|
ac7d03 |
+ for error_path in aug.match('/augeas//error'):
|
|
|
ac7d03 |
+ root_logger.error('augeas: %s', aug.get(error_path))
|
|
|
ac7d03 |
+ raise
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ if krb.is_running():
|
|
|
ac7d03 |
+ krb.stop()
|
|
|
ac7d03 |
+ krb.start()
|
|
|
ac7d03 |
+ finally:
|
|
|
ac7d03 |
+ aug.close()
|
|
|
ac7d03 |
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def disable_httpd_system_trust(http):
|
|
|
ac7d03 |
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
|
|
|
ac7d03 |
index 996a3d29884ca0180c39841f6986abf9b23ff13a..4cde2815a0fe9332d67c84b531f573ff88b1a302 100644
|
|
|
ac7d03 |
--- a/ipaserver/rpcserver.py
|
|
|
ac7d03 |
+++ b/ipaserver/rpcserver.py
|
|
|
ac7d03 |
@@ -945,7 +945,10 @@ class login_password(Backend, KerberosSession):
|
|
|
ac7d03 |
self.debug('Obtaining armor in ccache %s', armor_path)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
- kinit_armor(armor_path, pkinit_anchor=paths.CACERT_PEM)
|
|
|
ac7d03 |
+ kinit_armor(
|
|
|
ac7d03 |
+ armor_path,
|
|
|
ac7d03 |
+ pkinit_anchors=[paths.KDC_CERT, paths.KDC_CA_BUNDLE_PEM],
|
|
|
ac7d03 |
+ )
|
|
|
ac7d03 |
except RuntimeError as e:
|
|
|
ac7d03 |
self.error("Failed to obtain armor cache")
|
|
|
ac7d03 |
# We try to continue w/o armor, 2FA will be impacted
|
|
|
ac7d03 |
--
|
|
|
ac7d03 |
2.9.4
|
|
|
ac7d03 |
|