From: Simo Sorce Date: Tue, 29 Apr 2014 21:24:29 +0000 (-0400) Subject: Add IPA helper for server install X-Git-Tag: v0.2.2~2 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=33d8af8c15d28a32c42f056546cf391b2cffa803 Add IPA helper for server install The IPa helper chcks a krb keytab is available for the local HTTPD service at the standard ipa location, and if not available, tries to register the sevice and retrieve one from the IPA server. At the end of the process forces the activation of the krb plugin as well as the fallback to pam for authentication. Signed-off-by: Simo Sorce --- diff --git a/contrib/fedora/ipsilon.spec b/contrib/fedora/ipsilon.spec index f86e4de..f5e1931 100644 --- a/contrib/fedora/ipsilon.spec +++ b/contrib/fedora/ipsilon.spec @@ -98,6 +98,7 @@ semanage fcontext -d -t httpd_var_lib_t '%{_sharedstatedir}/ipsilon(/.*)?' 2>/de %{python2_sitelib}/ipsilon-*.egg-info %{python2_sitelib}/ipsilon/__init__.py* %{python2_sitelib}/ipsilon/tools/* +%{python2_sitelib}/ipsilon/helpers/* %{_datadir}/ipsilon/templates/install/saml2/sp.conf %{_datadir}/ipsilon/ui/saml2sp/* %{_bindir}/ipsilon-client-install diff --git a/ipsilon/helpers/ipa.py b/ipsilon/helpers/ipa.py new file mode 100755 index 0000000..df6717f --- /dev/null +++ b/ipsilon/helpers/ipa.py @@ -0,0 +1,170 @@ +#!/usr/bin/python +# +# Copyright (C) 2014 Simo Sorce +# +# 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 . + +import logging +import pwd +import os +import socket +import subprocess +import sys + + +IPA_CONFIG_FILE = '/etc/ipa/default.conf' +HTTPD_IPA_KEYTAB = '/etc/httpd/conf/ipa.keytab' +IPA_COMMAND = '/usr/bin/ipa' +IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab' +HTTPD_USER = 'apache' + +NO_CREDS_FOR_KEYTAB = """ +Valid IPA admin credentials are required to get a keytab. +Please kinit with a pivileged user like 'admin' and retry. +""" + +FAILED_TO_GET_KEYTAB = """ +A pre-existing keytab was not found and it was not possible to +successfully retrieve a new keytab for the IPA server. Please +manually provide a keytab or resolve the error that cause this +failure (see logs) and retry. +""" + + +class Installer(object): + + def __init__(self): + self.name = 'ipa' + self.ptype = 'helper' + self.logger = None + self.realm = None + self.domain = None + self.server = None + + def install_args(self, group): + group.add_argument('--ipa', choices=['yes', 'no', 'auto'], + default='auto', + help='Helper for IPA joined machines') + + def conf_init(self, opts): + logger = self.logger + # Do a simple check to see if machine is ipa joined + if not os.path.exists(IPA_CONFIG_FILE): + logger.info('No IPA configuration file. Skipping ipa helper...') + if opts['ipa'] == 'yes': + raise Exception('No IPA installation found!') + return + + # Get config vars from ipa file + try: + from ipapython import config as ipaconfig + + ipaconfig.init_config() + self.realm = ipaconfig.config.get_realm() + self.domain = ipaconfig.config.get_domain() + self.server = ipaconfig.config.get_server() + + except Exception, e: # pylint: disable=broad-except + logger.info('IPA tools installation found: [%s]', str(e)) + if opts['ipa'] == 'yes': + raise Exception('No IPA installation found!') + return + + def get_keytab(self, opts): + logger = self.logger + # Check if we have need ipa tools + if not os.path.exists(IPA_GETKEYTAB): + logger.info('ipa-getkeytab missing. Will skip keytab creation.') + if opts['ipa'] == 'yes': + raise Exception('No IPA tools found!') + + # Check if we already have a keytab for HTTP + if 'krb_httpd_keytab' in opts: + if os.path.exists(opts['krb_httpd_keytab']): + return + + if os.path.exists(HTTPD_IPA_KEYTAB): + opts['krb_httpd_keytab'] = HTTPD_IPA_KEYTAB + return + + us = socket.gethostname() + princ = 'HTTP/%s@%s' % (us, self.realm) + + # Check we have credentials to access server (for keytab) + from ipapython import ipaldap + from ipalib import errors as ipaerrors + + for srv in self.server: + try: + server = srv + c = ipaldap.IPAdmin(host=server) + c.do_sasl_gssapi_bind() + del c + break + except ipaerrors.ACIError, e: + # usually this error is returned when we have no + # good credentials, ask the user to kinit and retry + print >> sys.stderr, NO_CREDS_FOR_KEYTAB + logger.error('Invalid credentials: [%s]', repr(e)) + raise Exception('Invalid credentials: [%s]', str(e)) + except Exception, e: # pylint: disable=broad-except + # for other exceptions let's try to fail later + pass + + try: + subprocess.check_output([IPA_COMMAND, 'service-add', princ], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError, e: + # hopefully this means the service already exists + # otherwise we'll fail later again + logger.info('Error trying to create HTTP service:') + logger.info('Cmd> %s\n%s', e.cmd, e.output) + + try: + subprocess.check_output([IPA_GETKEYTAB, + '-s', server, '-p', princ, + '-k', opts['krb_httpd_keytab']], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError, e: + # unfortunately this one is fatal + print >> sys.stderr, FAILED_TO_GET_KEYTAB + logger.info('Error trying to get HTTP keytab:') + logger.info('Cmd> %s\n%s', e.cmd, e.output) + raise Exception('Missing keytab: [%s]' % str(e)) + + # Fixup permissions so only the ipsilon user can read these files + pw = pwd.getpwnam(HTTPD_USER) + os.chown(opts['krb_httpd_keytab'], pw.pw_uid, pw.pw_gid) + + def configure_server(self, opts): + if opts['ipa'] != 'yes' and opts['ipa'] != 'auto': + return + + self.logger = logging.getLogger() + + self.conf_init(opts) + + self.get_keytab(opts) + + # Forcibly use krb then pam modules + if not 'lm_order' in opts: + opts['lm_order'] = [] + opts['krb'] = 'yes' + if 'krb' not in opts['lm_order']: + opts['lm_order'].insert(0, 'krb') + opts['pam'] = 'yes' + if 'pam' not in opts['lm_order']: + opts['lm_order'].append('pam') diff --git a/setup.py b/setup.py index 4b4406b..4bf2a41 100755 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ setup( license = 'GPLv3+', packages = ['ipsilon', 'ipsilon.admin', 'ipsilon.login', 'ipsilon.util', 'ipsilon.providers', 'ipsilon.providers.saml2', - 'ipsilon.tools'], + 'ipsilon.tools', 'ipsilon.helpers'], data_files = [('share/man/man7', ["man/ipsilon.7"]), ('share/doc/ipsilon', ['COPYING']), ('share/doc/ipsilon/examples', ['examples/ipsilon.conf',