Turn Kerberos-related properties to Service class members

The Service class now accepts keytab path and service name part of Kerberos
principal as members. Kerberos principal is turned into a property computed
from service prefix, FQDN and realm. the handling of Kerberos principals and
keytabs in service installers was changed to use class members instead of
copy-pasted constants. This shall aid in the future refactoring of
principal/keytab handling code.

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

Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Martin Babinsky 2016-11-03 17:54:14 +01:00 committed by Jan Cholasta
parent 81bf72dc35
commit 32599987fd
9 changed files with 95 additions and 74 deletions

View File

@ -136,7 +136,8 @@ class ADTRUSTInstance(service.Service):
self.host_netbios_name = None
super(ADTRUSTInstance, self).__init__(
"smb", service_desc="CIFS", fstore=fstore)
"smb", service_desc="CIFS", fstore=fstore, service_prefix=u'cifs',
keytab=paths.SAMBA_KEYTAB)
self.__setup_default_attributes()
@ -148,7 +149,6 @@ class ADTRUSTInstance(service.Service):
# Constants
self.smb_conf = paths.SMB_CONF
self.samba_keytab = paths.SAMBA_KEYTAB
self.cifs_hosts = []
# Values obtained from API.env
@ -156,7 +156,6 @@ class ADTRUSTInstance(service.Service):
self.host_netbios_name = make_netbios_name(self.fqdn)
self.realm = self.realm or api.env.realm
self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
self.suffix = ipautil.realm_to_suffix(self.realm)
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
installutils.realm_to_serverid(self.realm)
@ -173,7 +172,7 @@ class ADTRUSTInstance(service.Service):
api.env.container_cifsdomains,
self.suffix)
self.cifs_agent = DN(('krbprincipalname', self.cifs_principal.lower()),
self.cifs_agent = DN(('krbprincipalname', self.principal.lower()),
api.env.container_service,
self.suffix)
self.host_princ = DN(('fqdn', self.fqdn),
@ -494,8 +493,8 @@ class ADTRUSTInstance(service.Service):
try:
current = self.admin_conn.get_entry(targets_dn)
members = current.get('memberPrincipal', [])
if not(self.cifs_principal in members):
current["memberPrincipal"] = members + [self.cifs_principal]
if not(self.principal in members):
current["memberPrincipal"] = members + [self.principal]
self.admin_conn.update_entry(current)
else:
self.print_msg('cifs principal already targeted, nothing to do.')
@ -530,7 +529,7 @@ class ADTRUSTInstance(service.Service):
def __setup_principal(self):
try:
api.Command.service_add(unicode(self.cifs_principal))
api.Command.service_add(unicode(self.principal))
except errors.DuplicateEntry:
# CIFS principal already exists, it is not the first time
# adtrustinstance is managed
@ -544,21 +543,21 @@ class ADTRUSTInstance(service.Service):
try:
ipautil.run(["ipa-getkeytab", "--server", self.fqdn,
"--principal", self.cifs_principal,
"-k", self.samba_keytab])
"--principal", self.principal,
"-k", self.keytab])
except ipautil.CalledProcessError:
root_logger.critical("Failed to add key for %s"
% self.cifs_principal)
% self.principal)
def clean_samba_keytab(self):
if os.path.exists(self.samba_keytab):
if os.path.exists(self.keytab):
try:
ipautil.run(["ipa-rmkeytab", "--principal", self.cifs_principal,
"-k", self.samba_keytab])
ipautil.run(["ipa-rmkeytab", "--principal", self.principal,
"-k", self.keytab])
except ipautil.CalledProcessError as e:
if e.returncode != 5:
root_logger.critical("Failed to remove old key for %s"
% self.cifs_principal)
% self.principal)
def srv_rec(self, host, port, prio):
return "%(prio)d 100 %(port)d %(host)s" % dict(host=host,prio=prio,port=port)

View File

@ -620,7 +620,9 @@ class BindInstance(service.Service):
service_desc="DNS",
fstore=fstore,
api=api,
service_user=constants.NAMED_USER
service_user=constants.NAMED_USER,
service_prefix=u'DNS',
keytab=paths.NAMED_KEYTAB
)
self.dns_backup = DnsBackup(self)
self.domain = None
@ -778,7 +780,7 @@ class BindInstance(service.Service):
BINDKEYS_FILE=paths.NAMED_BINDKEYS_FILE,
MANAGED_KEYS_DIR=paths.NAMED_MANAGED_KEYS_DIR,
ROOT_KEY=paths.NAMED_ROOT_KEY,
NAMED_KEYTAB=paths.NAMED_KEYTAB,
NAMED_KEYTAB=self.keytab,
RFC1912_ZONES=paths.NAMED_RFC1912_ZONES,
NAMED_PID=paths.NAMED_PID,
NAMED_VAR_DIR=paths.NAMED_VAR_DIR,
@ -875,24 +877,23 @@ class BindInstance(service.Service):
self.__add_master_records(fqdn, addrs)
def __setup_principal(self):
dns_principal = "DNS/" + self.fqdn + "@" + self.realm
installutils.kadmin_addprinc(dns_principal)
installutils.kadmin_addprinc(self.principal)
# Store the keytab on disk
self.fstore.backup_file(paths.NAMED_KEYTAB)
installutils.create_keytab(paths.NAMED_KEYTAB, dns_principal)
p = self.move_service(dns_principal)
self.fstore.backup_file(self.keytab)
installutils.create_keytab(self.keytab, self.principal)
p = self.move_service(self.principal)
if p is None:
# the service has already been moved, perhaps we're doing a DNS reinstall
dns_principal = DN(('krbprincipalname', dns_principal),
dns_principal = DN(('krbprincipalname', self.principal),
('cn', 'services'), ('cn', 'accounts'), self.suffix)
else:
dns_principal = p
# Make sure access is strictly reserved to the named user
pent = pwd.getpwnam(self.service_user)
os.chown(paths.NAMED_KEYTAB, pent.pw_uid, pent.pw_gid)
os.chmod(paths.NAMED_KEYTAB, 0o400)
os.chown(self.keytab, pent.pw_uid, pent.pw_gid)
os.chmod(self.keytab, 0o400)
# modify the principal so that it is marked as an ipa service so that
# it can host the memberof attribute, then also add it to the
@ -1188,5 +1189,5 @@ class BindInstance(service.Service):
if named_regular_running:
self.named_regular.start()
installutils.remove_keytab(paths.NAMED_KEYTAB)
installutils.remove_keytab(self.keytab)
installutils.remove_ccache(run_as=self.service_user)

View File

@ -302,6 +302,7 @@ class CAInstance(DogtagInstance):
subsystem="CA",
service_desc="certificate server",
host_name=host_name,
service_prefix=ipalib.constants.PKI_GSSAPI_SERVICE_NAME,
)
# for external CAs
@ -323,6 +324,8 @@ class CAInstance(DogtagInstance):
self.requestId = None
self.log = log_mgr.get_logger(self)
self.no_db_setup = False
self.keytab = os.path.join(
paths.PKI_TOMCAT, self.service_prefix + '.keytab')
def configure_instance(self, host_name, dm_password, admin_password,
pkcs12_info=None, master_host=None, csr_file=None,
@ -1229,23 +1232,19 @@ class CAInstance(DogtagInstance):
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(self.service_user)
root_logger.info('Creating principal')
installutils.kadmin_addprinc(principal)
installutils.kadmin_addprinc(self.principal)
self.suffix = ipautil.realm_to_suffix(self.realm)
self.move_service(principal)
self.move_service(self.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)
installutils.create_keytab(self.keytab, self.principal)
os.chmod(self.keytab, 0o600)
os.chown(self.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(self.service_user)
root_logger.info('Creating Custodia keys')
@ -1261,9 +1260,9 @@ class CAInstance(DogtagInstance):
objectclass=['top', 'nsContainer'],
cn=['dogtag'],
)
keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys')
keyfile = os.path.join(paths.PKI_TOMCAT, self.service_prefix + '.keys')
keystore = IPAKEMKeys({'server_keys': keyfile})
keystore.generate_keys(service)
keystore.generate_keys(self.service_prefix)
os.chmod(keyfile, 0o600)
os.chown(keyfile, pent.pw_uid, pent.pw_gid)

View File

@ -64,7 +64,9 @@ class DNSKeySyncInstance(service.Service):
super(DNSKeySyncInstance, self).__init__(
"ipa-dnskeysyncd",
service_desc="DNS key synchronization service",
fstore=fstore
fstore=fstore,
service_prefix=u'ipa-dnskeysync',
keytab=paths.IPA_DNSKEYSYNCD_KEYTAB
)
self.logger = logger
self.extra_config = [u'dnssecVersion 1', ] # DNSSEC enabled
@ -406,24 +408,23 @@ class DNSKeySyncInstance(service.Service):
def __setup_principal(self):
assert self.ods_gid is not None
installutils.remove_keytab(paths.IPA_DNSKEYSYNCD_KEYTAB)
dnssynckey_principal = "ipa-dnskeysyncd/" + self.fqdn + "@" + self.realm
installutils.kadmin_addprinc(dnssynckey_principal)
installutils.remove_keytab(self.keytab)
installutils.kadmin_addprinc(self.principal)
# Store the keytab on disk
installutils.create_keytab(paths.IPA_DNSKEYSYNCD_KEYTAB, dnssynckey_principal)
p = self.move_service(dnssynckey_principal)
installutils.create_keytab(self.keytab, self.principal)
p = self.move_service(self.principal)
if p is None:
# the service has already been moved, perhaps we're doing a DNS reinstall
dnssynckey_principal_dn = DN(
('krbprincipalname', dnssynckey_principal),
('krbprincipalname', self.principal),
('cn', 'services'), ('cn', 'accounts'), self.suffix)
else:
dnssynckey_principal_dn = p
# Make sure access is strictly reserved to the named user
os.chown(paths.IPA_DNSKEYSYNCD_KEYTAB, 0, self.ods_gid)
os.chmod(paths.IPA_DNSKEYSYNCD_KEYTAB, 0o440)
os.chown(self.keytab, 0, self.ods_gid)
os.chmod(self.keytab, 0o440)
dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'),
('cn', 'pbac'), self.suffix)
@ -487,4 +488,4 @@ class DNSKeySyncInstance(service.Service):
except Exception:
pass
installutils.remove_keytab(paths.IPA_DNSKEYSYNCD_KEYTAB)
installutils.remove_keytab(self.keytab)

View File

@ -108,14 +108,15 @@ class DogtagInstance(service.Service):
server_cert_name = None
def __init__(self, realm, subsystem, service_desc, host_name=None,
nss_db=paths.PKI_TOMCAT_ALIAS_DIR):
nss_db=paths.PKI_TOMCAT_ALIAS_DIR, service_prefix=None):
"""Initializer"""
super(DogtagInstance, self).__init__(
'pki-tomcatd',
service_desc=service_desc,
realm_name=realm,
service_user=constants.PKI_USER
service_user=constants.PKI_USER,
service_prefix=service_prefix
)
self.admin_password = None

View File

@ -227,6 +227,8 @@ class DsInstance(service.Service):
"dirsrv",
service_desc="directory server",
fstore=fstore,
service_prefix=u'ldap',
keytab=paths.DS_KEYTAB,
service_user=DS_USER,
realm_name=realm_name
)
@ -308,7 +310,6 @@ class DsInstance(service.Service):
self.fqdn = fqdn
self.dm_password = dm_password
self.domain = domain_name
self.principal = "ldap/%s@%s" % (self.fqdn, self.realm)
self.subject_base = subject_base
self.idstart = idstart
self.idmax = idmax
@ -1225,26 +1226,26 @@ class DsInstance(service.Service):
def __get_ds_keytab(self):
self.fstore.backup_file(paths.DS_KEYTAB)
self.fstore.backup_file(self.keytab)
try:
os.unlink(paths.DS_KEYTAB)
os.unlink(self.keytab)
except OSError:
pass
installutils.install_service_keytab(self.api,
self.principal,
self.master_fqdn,
paths.DS_KEYTAB,
self.keytab,
force_service_add=True)
# Configure DS to use the keytab
vardict = {"KRB5_KTNAME": paths.DS_KEYTAB}
vardict = {"KRB5_KTNAME": self.keytab}
ipautil.config_replace_variables(paths.SYSCONFIG_DIRSRV,
replacevars=vardict)
# Keytab must be owned by DS itself
pent = pwd.getpwnam(self.service_user)
os.chown(paths.DS_KEYTAB, pent.pw_uid, pent.pw_gid)
os.chown(self.keytab, pent.pw_uid, pent.pw_gid)
def __get_ds_cert(self):
subject = self.subject_base or DN(('O', self.realm))

View File

@ -124,7 +124,9 @@ class HTTPInstance(service.Service):
"httpd",
service_desc="the web interface",
fstore=fstore,
service_user=HTTPD_USER)
service_prefix=u'HTTP',
service_user=HTTPD_USER,
keytab=paths.IPA_KEYTAB)
self.cert_nickname = cert_nickname
self.ca_is_configured = True
@ -139,7 +141,6 @@ class HTTPInstance(service.Service):
self.domain = domain_name
self.suffix = ipautil.realm_to_suffix(self.realm)
self.pkcs12_info = pkcs12_info
self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm)
self.dercert = None
self.subject_base = subject_base
self.sub_dict = dict(
@ -202,9 +203,9 @@ class HTTPInstance(service.Service):
def __create_http_keytab(self):
if not self.promote:
installutils.remove_keytab(paths.IPA_KEYTAB)
installutils.remove_keytab(self.keytab)
installutils.kadmin_addprinc(self.principal)
installutils.create_keytab(paths.IPA_KEYTAB, self.principal)
installutils.create_keytab(self.keytab, self.principal)
self.move_service(self.principal)
pent = pwd.getpwnam(self.service_user)
@ -527,7 +528,7 @@ class HTTPInstance(service.Service):
except ValueError as error:
root_logger.debug(error)
installutils.remove_keytab(paths.IPA_KEYTAB)
installutils.remove_keytab(self.keytab)
installutils.remove_ccache(ccache_path=paths.KRB5CC_HTTPD,
run_as=self.service_user)

View File

@ -24,7 +24,9 @@ class ODSExporterInstance(service.Service):
super(ODSExporterInstance, self).__init__(
"ipa-ods-exporter",
service_desc="IPA OpenDNSSEC exporter daemon",
fstore=fstore
fstore=fstore,
keytab=paths.IPA_ODS_EXPORTER_KEYTAB,
service_prefix=u'ipa-ods-exporter'
)
self.ods_uid = None
self.ods_gid = None
@ -81,29 +83,29 @@ class ODSExporterInstance(service.Service):
def __setup_principal(self):
assert self.ods_uid is not None
for f in [paths.IPA_ODS_EXPORTER_CCACHE, paths.IPA_ODS_EXPORTER_KEYTAB]:
for f in [paths.IPA_ODS_EXPORTER_CCACHE, self.keytab]:
try:
os.remove(f)
except OSError:
pass
dns_exporter_principal = "ipa-ods-exporter/" + self.fqdn + "@" + self.realm
installutils.kadmin_addprinc(dns_exporter_principal)
installutils.kadmin_addprinc(self.principal)
# Store the keytab on disk
installutils.create_keytab(paths.IPA_ODS_EXPORTER_KEYTAB, dns_exporter_principal)
p = self.move_service(dns_exporter_principal)
installutils.create_keytab(paths.IPA_ODS_EXPORTER_KEYTAB,
self.principal)
p = self.move_service(self.principal)
if p is None:
# the service has already been moved, perhaps we're doing a DNS reinstall
dns_exporter_principal_dn = DN(
('krbprincipalname', dns_exporter_principal),
('krbprincipalname', self.principal),
('cn', 'services'), ('cn', 'accounts'), self.suffix)
else:
dns_exporter_principal_dn = p
# Make sure access is strictly reserved to the ods user
os.chmod(paths.IPA_ODS_EXPORTER_KEYTAB, 0o440)
os.chown(paths.IPA_ODS_EXPORTER_KEYTAB, 0, self.ods_gid)
os.chmod(self.keytab, 0o440)
os.chown(self.keytab, 0, self.ods_gid)
dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'),
('cn', 'pbac'), self.suffix)
@ -146,10 +148,8 @@ class ODSExporterInstance(service.Service):
self.start()
def remove_service(self):
dns_exporter_principal = ("ipa-ods-exporter/%s@%s" % (self.fqdn,
self.realm))
try:
api.Command.service_del(dns_exporter_principal)
api.Command.service_del(self.principal)
except errors.NotFound:
pass
@ -181,5 +181,5 @@ class ODSExporterInstance(service.Service):
if signerd_running:
signerd_service.start()
installutils.remove_keytab(paths.IPA_ODS_EXPORTER_KEYTAB)
installutils.remove_keytab(self.keytab)
installutils.remove_ccache(ccache_path=paths.IPA_ODS_EXPORTER_CCACHE)

View File

@ -24,14 +24,20 @@ import datetime
import traceback
import tempfile
import six
from ipapython import ipautil, sysrestore
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
from ipapython import kerberos
from ipalib import api, errors, certstore
from ipaplatform import services
from ipaplatform.paths import paths
if six.PY3:
unicode = str
# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple
# the first value is the *nix service name, the second the start order.
SERVICE_LIST = {
@ -132,7 +138,8 @@ def find_providing_server(svcname, conn, host_name=None, api=api):
class Service(object):
def __init__(self, service_name, service_desc=None, sstore=None,
fstore=None, api=api, realm_name=None,
service_user=None):
service_user=None, service_prefix=None,
keytab=None):
self.service_name = service_name
self.service_desc = service_desc
self.service = services.service(service_name)
@ -153,7 +160,8 @@ class Service(object):
self.realm = realm_name
self.suffix = DN()
self.principal = None
self.service_prefix = service_prefix
self.keytab = keytab
self.dercert = None
self.api = api
self.service_user = service_user
@ -165,6 +173,16 @@ class Service(object):
"""
return api.Backend.ldap2
@property
def principal(self):
if any(attr is None for attr in (self.realm, self.fqdn,
self.service_prefix)):
return
return unicode(
kerberos.Principal(
(self.service_prefix, self.fqdn), realm=self.realm))
def _ldap_mod(self, ldif, sub_dict=None, raise_on_err=True,
ldap_uri=None, dm_password=None):
pw_name = None