summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorChristian Heimes <cheimes@redhat.com>2015-06-23 17:01:00 +0200
committerPetr Vobornik <pvoborni@redhat.com>2015-06-24 10:43:58 +0200
commit495da412f155603c02907187c21dd4511281df2c (patch)
tree8bc25d341bfdfb48673fbc24ba3f538ef87b6d41 /install
parent49d708f00fd13903dbd96193aac2c608e3512398 (diff)
downloadfreeipa-495da412f155603c02907187c21dd4511281df2c.tar.gz
freeipa-495da412f155603c02907187c21dd4511281df2c.tar.xz
freeipa-495da412f155603c02907187c21dd4511281df2c.zip
Provide Kerberos over HTTP (MS-KKDCP)
Add integration of python-kdcproxy into FreeIPA to support the MS Kerberos KDC proxy protocol (MS-KKDCP), to allow KDC and KPASSWD client requests over HTTP and HTTPS. - freeipa-server now depends on python-kdcproxy >= 0.3. All kdcproxy dependencies are already satisfied. - The service's state is configured in cn=KDC,cn=$FQDN,cn=masters,cn=ipa, cn=etc,$SUFFIX. It's enabled, when ipaConfigString=kdcProxyEnabled is present. - The installers and update create a new Apache config file /etc/ipa/kdcproxy/ipa-kdc-proxy.conf that mounts a WSGI app on /KdcProxy. The app is run inside its own WSGI daemon group with a different uid and gid than the webui. - A ExecStartPre script in httpd.service symlinks the config file to /etc/httpd/conf.d/ iff ipaConfigString=kdcProxyEnabled is present. - The httpd.service also sets KDCPROXY_CONFIG=/etc/ipa/kdcproxy.conf, so that an existing config is not used. SetEnv from Apache config does not work here, because it doesn't set an OS env var. - python-kdcproxy is configured to *not* use DNS SRV lookups. The location of KDC and KPASSWD servers are read from /etc/krb5.conf. - The state of the service can be modified with two ldif files for ipa-ldap-updater. No CLI script is offered yet. https://www.freeipa.org/page/V4/KDC_Proxy https://fedorahosted.org/freeipa/ticket/4801 Reviewed-By: Nathaniel McCallum <npmccallum@redhat.com> Reviewed-By: Simo Sorce <ssorce@redhat.com>
Diffstat (limited to 'install')
-rw-r--r--install/conf/Makefile.am1
-rw-r--r--install/conf/ipa-kdc-proxy.conf.template30
-rw-r--r--install/conf/ipa.conf6
-rw-r--r--install/share/Makefile.am3
-rw-r--r--install/share/kdcproxy-disable.uldif3
-rw-r--r--install/share/kdcproxy-enable.uldif6
-rw-r--r--install/share/kdcproxy.conf4
-rw-r--r--install/tools/Makefile.am5
-rwxr-xr-xinstall/tools/ipa-httpd-kdcproxy180
9 files changed, 235 insertions, 3 deletions
diff --git a/install/conf/Makefile.am b/install/conf/Makefile.am
index 65e25bc94..5daac776f 100644
--- a/install/conf/Makefile.am
+++ b/install/conf/Makefile.am
@@ -3,6 +3,7 @@ NULL =
appdir = $(IPA_DATA_DIR)
app_DATA = \
ipa.conf \
+ ipa-kdc-proxy.conf.template \
ipa-pki-proxy.conf \
ipa-rewrite.conf \
$(NULL)
diff --git a/install/conf/ipa-kdc-proxy.conf.template b/install/conf/ipa-kdc-proxy.conf.template
new file mode 100644
index 000000000..9290cebba
--- /dev/null
+++ b/install/conf/ipa-kdc-proxy.conf.template
@@ -0,0 +1,30 @@
+# Kerberos over HTTP / MS-KKDCP support (Kerberos KDC Proxy)
+#
+# The symlink from /etc/ipa/kdcproxy/ to /etc/httpd/conf.d/ is maintained
+# by the ExecStartPre script /usr/libexec/ipa/ipa-httpd-kdcproxy in
+# httpd.service. The service also sets the environment variable
+# KDCPROXY_CONFIG to $KDCPROXY_CONFIG.
+#
+# Disable KDC Proxy on the current host:
+# # ipa-ldap-updater /usr/share/ipa/kdcproxy-disable.uldif
+# # systemctl restart httpd.service
+#
+# Enable KDC Proxy on the current host:
+# # ipa-ldap-updater /usr/share/ipa/kdcproxy-enable.uldif
+# # systemctl restart httpd.service
+#
+
+WSGIDaemonProcess kdcproxy processes=2 threads=15 maximum-requests=5000 \
+ user=kdcproxy group=kdcproxy display-name=%{GROUP}
+WSGIImportScript /usr/lib/python2.7/site-packages/kdcproxy/__init__.py \
+ process-group=kdcproxy application-group=kdcproxy
+WSGIScriptAlias /KdcProxy /usr/lib/python2.7/site-packages/kdcproxy/__init__.py
+WSGIScriptReloading Off
+
+<Location "/KdcProxy">
+ Satisfy Any
+ Order Deny,Allow
+ Allow from all
+ WSGIProcessGroup kdcproxy
+ WSGIApplicationGroup kdcproxy
+</Location>
diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf
index 57de2f1a9..e2b602c85 100644
--- a/install/conf/ipa.conf
+++ b/install/conf/ipa.conf
@@ -41,9 +41,7 @@ WSGISocketPrefix /run/httpd/wsgi
# Configure mod_wsgi handler for /ipa
-WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500
-WSGIProcessGroup ipa
-WSGIApplicationGroup ipa
+WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500 display-name=%{GROUP}
WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa
WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py
WSGIScriptReloading Off
@@ -70,6 +68,8 @@ WSGIScriptReloading Off
GssapiUseS4U2Proxy on
Require valid-user
ErrorDocument 401 /ipa/errors/unauthorized.html
+ WSGIProcessGroup ipa
+ WSGIApplicationGroup ipa
</Location>
# Turn off Apache authentication for sessions
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index 53f0ecf01..80e959a75 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -84,6 +84,9 @@ app_DATA = \
sasl-mapping-fallback.ldif \
schema-update.ldif \
vault.update \
+ kdcproxy.conf \
+ kdcproxy-enable.uldif \
+ kdcproxy-disable.uldif \
$(NULL)
EXTRA_DIST = \
diff --git a/install/share/kdcproxy-disable.uldif b/install/share/kdcproxy-disable.uldif
new file mode 100644
index 000000000..bfc0b72c1
--- /dev/null
+++ b/install/share/kdcproxy-disable.uldif
@@ -0,0 +1,3 @@
+# Disable MS-KKDCP protocol for the current host
+dn: cn=KDC,cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX
+remove:ipaConfigString:kdcProxyEnabled
diff --git a/install/share/kdcproxy-enable.uldif b/install/share/kdcproxy-enable.uldif
new file mode 100644
index 000000000..92297152f
--- /dev/null
+++ b/install/share/kdcproxy-enable.uldif
@@ -0,0 +1,6 @@
+# Enable MS-KKDCP protocol for the current host
+dn: cn=KDC,cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX
+default:objectClass: nsContainer
+default:objectClass: ipaConfigObject
+default:cn: KDC
+add: ipaConfigString: kdcProxyEnabled
diff --git a/install/share/kdcproxy.conf b/install/share/kdcproxy.conf
new file mode 100644
index 000000000..530703d4a
--- /dev/null
+++ b/install/share/kdcproxy.conf
@@ -0,0 +1,4 @@
+[global]
+configs = mit
+use_dns = false
+
diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
index e5d45c479..147ce33a9 100644
--- a/install/tools/Makefile.am
+++ b/install/tools/Makefile.am
@@ -35,6 +35,11 @@ EXTRA_DIST = \
$(sbin_SCRIPTS) \
$(NULL)
+appdir = $(libexecdir)/ipa/
+app_SCRIPTS = \
+ ipa-httpd-kdcproxy \
+ $(NULL)
+
MAINTAINERCLEANFILES = \
*~ \
Makefile.in
diff --git a/install/tools/ipa-httpd-kdcproxy b/install/tools/ipa-httpd-kdcproxy
new file mode 100755
index 000000000..c71f9cccf
--- /dev/null
+++ b/install/tools/ipa-httpd-kdcproxy
@@ -0,0 +1,180 @@
+#!/usr/bin/python2
+# Authors:
+# Christian Heimes <cheimes@redhat.com>
+#
+# Copyright (C) 2015 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/>.
+#
+"""ipa-httpd-kdproxy
+
+This script creates or removes the symlink from /etc/ipa/ipa-kdc-proxy.conf
+to /etc/httpd/conf.d/. It's called from ExecStartPre hook in httpd.service.
+"""
+import os
+import sys
+
+from ipalib import api, errors
+from ipapython.ipa_log_manager import standard_logging_setup
+from ipapython.ipaldap import IPAdmin
+from ipapython.dn import DN
+from ipaplatform.paths import paths
+
+
+DEBUG = False
+TIME_LIMIT = 2
+
+
+class CheckError(Exception):
+ """An unrecoverable error has occured"""
+
+
+class KDCProxyConfig(object):
+ ipaconfig_flag = 'ipaKDCProxyEnabled'
+
+ def __init__(self, time_limit=TIME_LIMIT):
+ self.time_limit = time_limit
+ self.con = None
+ self.log = api.log
+ self.ldap_uri = api.env.ldap_uri
+ self.kdc_dn = DN(('cn', 'KDC'), ('cn', api.env.host),
+ ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
+ api.env.basedn)
+ self.conf = paths.HTTPD_IPA_KDCPROXY_CONF
+ self.conflink = paths.HTTPD_IPA_KDCPROXY_CONF_SYMLINK
+
+ def _ldap_con(self):
+ """Establish LDAP connection"""
+ self.log.debug('ldap_uri: %s', self.ldap_uri)
+ try:
+ self.con = IPAdmin(ldap_uri=self.ldap_uri)
+ # EXTERNAL bind as root user
+ self.con.ldapi = True
+ self.con.do_bind(timeout=self.time_limit)
+ except errors.NetworkError as e:
+ msg = 'Failed to get setting from dirsrv: %s' % e
+ self.log.exception(msg)
+ raise CheckError(msg)
+ except Exception as e:
+ msg = ('Unknown error while retrieving setting from %s: %s' %
+ (self.ldap_uri, e))
+ self.log.exception(msg)
+ raise CheckError(msg)
+
+ def _find_entry(self, dn, attrs, filter, scope=IPAdmin.SCOPE_BASE):
+ """Find an LDAP entry, handles NotFound and Limit"""
+ try:
+ entries, truncated = self.con.find_entries(
+ filter, attrs, dn, scope, time_limit=self.time_limit)
+ if truncated:
+ raise errors.LimitsExceeded()
+ except errors.NotFound:
+ self.log.debug('Entry not found: %s', dn)
+ return None
+ except Exception as e:
+ msg = ('Unknown error while retrieving setting from %s: %s' %
+ (self.ldap_uri, e))
+ self.log.exception(msg)
+ raise CheckError(msg)
+ return entries[0]
+
+ def is_host_enabled(self):
+ """Check replica specific flag"""
+ self.log.debug('Read settings from dn: %s', self.kdc_dn)
+ srcfilter = self.con.make_filter(
+ {'ipaConfigString': u'kdcProxyEnabled'}
+ )
+ entry = self._find_entry(self.kdc_dn, ['cn'], srcfilter)
+ self.log.debug('%s ipaConfigString: %s', self.kdc_dn, entry)
+ return entry is not None
+
+ def validate_symlink(self):
+ """Validate symlink in Apache conf.d"""
+ if not os.path.exists(self.conflink):
+ return False
+ if not os.path.islink(self.conflink):
+ raise CheckError("'%s' already exists, but it is not a symlink" %
+ self.conflink)
+ dest = os.readlink(self.conflink)
+ if dest != self.conf:
+ raise CheckError("'%s' points to '%s', expected '%s'"
+ % (self.conflink, dest, self.conf))
+ return True
+
+ def create_symlink(self):
+ """Create symlink to enable KDC proxy support"""
+ try:
+ valid = self.validate_symlink()
+ except CheckError as e:
+ self.log.warn("Cannot enable KDC proxy: %s " % e)
+ return False
+
+ if valid:
+ self.log.debug("Symlink exists and is valid")
+ return True
+
+ if not os.path.isfile(self.conf):
+ self.log.warn("'%s' does not exist", self.conf)
+ return False
+
+ # create the symbolic link
+ self.log.debug("Creating symlink from '%s' to '%s'",
+ self.conf, self.conflink)
+ os.symlink(self.conf, self.conflink)
+ return True
+
+ def remove_symlink(self):
+ """Delete symlink to disable KDC proxy support"""
+ try:
+ valid = self.validate_symlink()
+ except CheckError as e:
+ self.log.warn("Cannot disable KDC proxy: %s " % e)
+ return False
+
+ if valid:
+ self.log.debug("Removing symlink '%s'", self.conflink)
+ os.unlink(self.conflink)
+ else:
+ self.log.debug("Symlink '%s' has already been removed.",
+ self.conflink)
+
+ return True
+
+ def __enter__(self):
+ self._ldap_con()
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if self.con is not None:
+ self.con.unbind()
+ self.con = None
+
+
+def main(debug=DEBUG, time_limit=TIME_LIMIT):
+ # initialize API without file logging
+ if not api.isdone('bootstrap'):
+ api.bootstrap(context='kdcproxyshim', log=None, debug=debug)
+ standard_logging_setup(verbose=True, debug=debug)
+
+ with KDCProxyConfig(time_limit) as cfg:
+ if cfg.is_host_enabled():
+ if cfg.create_symlink():
+ api.log.info('KDC proxy enabled')
+ else:
+ if cfg.remove_symlink():
+ api.log.info('KDC proxy disabled')
+
+if __name__ == '__main__':
+ main()