summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/share/kdc.conf.template2
-rw-r--r--install/share/profiles/KDCs_PKINIT_Certs.cfg109
-rw-r--r--install/share/profiles/Makefile.am1
-rw-r--r--ipaclient/install/client.py2
-rw-r--r--ipalib/install/certmonger.py43
-rw-r--r--ipaplatform/base/paths.py3
-rw-r--r--ipapython/dogtag.py4
-rw-r--r--ipaserver/install/cainstance.py2
-rw-r--r--ipaserver/install/certs.py10
-rw-r--r--ipaserver/install/dsinstance.py2
-rw-r--r--ipaserver/install/httpinstance.py2
-rw-r--r--ipaserver/install/krbinstance.py62
-rw-r--r--ipaserver/install/server/__init__.py4
-rw-r--r--ipaserver/install/server/install.py21
-rw-r--r--ipaserver/install/server/replicainstall.py4
-rw-r--r--ipaserver/install/server/upgrade.py35
-rw-r--r--ipaserver/plugins/cert.py86
-rw-r--r--ipaserver/plugins/dogtag.py2
18 files changed, 325 insertions, 69 deletions
diff --git a/install/share/kdc.conf.template b/install/share/kdc.conf.template
index 296b75b4c..ec53a1ff5 100644
--- a/install/share/kdc.conf.template
+++ b/install/share/kdc.conf.template
@@ -12,6 +12,6 @@
dict_file = $DICT_WORDS
default_principal_flags = +preauth
; admin_keytab = $KRB5KDC_KADM5_KEYTAB
- pkinit_identity = FILE:$KDC_PEM
+ pkinit_identity = FILE:$KDC_CERT,$KDC_KEY
pkinit_anchors = FILE:$CACERT_PEM
}
diff --git a/install/share/profiles/KDCs_PKINIT_Certs.cfg b/install/share/profiles/KDCs_PKINIT_Certs.cfg
new file mode 100644
index 000000000..c5e412b00
--- /dev/null
+++ b/install/share/profiles/KDCs_PKINIT_Certs.cfg
@@ -0,0 +1,109 @@
+profileId=KDCs_PKINIT_Certs
+classId=caEnrollImpl
+desc=This certificate profile is for enrolling server certificates with IPA-RA agent authentication.
+visible=false
+enable=true
+enableBy=admin
+auth.instance_id=raCertAuth
+name=IPA-RA Agent-Authenticated Server Certificate Enrollment
+input.list=i1,i2
+input.i1.class_id=certReqInputImpl
+input.i2.class_id=submitterInfoInputImpl
+output.list=o1
+output.o1.class_id=certOutputImpl
+policyset.list=serverCertSet
+policyset.serverCertSet.list=1,2,3,4,5,6,7,8,9,10,11
+policyset.serverCertSet.1.constraint.class_id=subjectNameConstraintImpl
+policyset.serverCertSet.1.constraint.name=Subject Name Constraint
+policyset.serverCertSet.1.constraint.params.pattern=CN=[^,]+,.+
+policyset.serverCertSet.1.constraint.params.accept=true
+policyset.serverCertSet.1.default.class_id=subjectNameDefaultImpl
+policyset.serverCertSet.1.default.name=Subject Name Default
+policyset.serverCertSet.1.default.params.name=CN=$$request.req_subject_name.cn$$, $SUBJECT_DN_O
+policyset.serverCertSet.2.constraint.class_id=validityConstraintImpl
+policyset.serverCertSet.2.constraint.name=Validity Constraint
+policyset.serverCertSet.2.constraint.params.range=740
+policyset.serverCertSet.2.constraint.params.notBeforeCheck=false
+policyset.serverCertSet.2.constraint.params.notAfterCheck=false
+policyset.serverCertSet.2.default.class_id=validityDefaultImpl
+policyset.serverCertSet.2.default.name=Validity Default
+policyset.serverCertSet.2.default.params.range=731
+policyset.serverCertSet.2.default.params.startTime=0
+policyset.serverCertSet.3.constraint.class_id=keyConstraintImpl
+policyset.serverCertSet.3.constraint.name=Key Constraint
+policyset.serverCertSet.3.constraint.params.keyType=RSA
+policyset.serverCertSet.3.constraint.params.keyParameters=2048,3072,4096
+policyset.serverCertSet.3.default.class_id=userKeyDefaultImpl
+policyset.serverCertSet.3.default.name=Key Default
+policyset.serverCertSet.4.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.4.constraint.name=No Constraint
+policyset.serverCertSet.4.default.class_id=authorityKeyIdentifierExtDefaultImpl
+policyset.serverCertSet.4.default.name=Authority Key Identifier Default
+policyset.serverCertSet.5.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.5.constraint.name=No Constraint
+policyset.serverCertSet.5.default.class_id=authInfoAccessExtDefaultImpl
+policyset.serverCertSet.5.default.name=AIA Extension Default
+policyset.serverCertSet.5.default.params.authInfoAccessADEnable_0=true
+policyset.serverCertSet.5.default.params.authInfoAccessADLocationType_0=URIName
+policyset.serverCertSet.5.default.params.authInfoAccessADLocation_0=http://$IPA_CA_RECORD.$DOMAIN/ca/ocsp
+policyset.serverCertSet.5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+policyset.serverCertSet.5.default.params.authInfoAccessCritical=false
+policyset.serverCertSet.5.default.params.authInfoAccessNumADs=1
+policyset.serverCertSet.6.constraint.class_id=keyUsageExtConstraintImpl
+policyset.serverCertSet.6.constraint.name=Key Usage Extension Constraint
+policyset.serverCertSet.6.constraint.params.keyUsageCritical=true
+policyset.serverCertSet.6.constraint.params.keyUsageDigitalSignature=true
+policyset.serverCertSet.6.constraint.params.keyUsageNonRepudiation=true
+policyset.serverCertSet.6.constraint.params.keyUsageDataEncipherment=true
+policyset.serverCertSet.6.constraint.params.keyUsageKeyEncipherment=true
+policyset.serverCertSet.6.constraint.params.keyUsageKeyAgreement=false
+policyset.serverCertSet.6.constraint.params.keyUsageKeyCertSign=false
+policyset.serverCertSet.6.constraint.params.keyUsageCrlSign=false
+policyset.serverCertSet.6.constraint.params.keyUsageEncipherOnly=false
+policyset.serverCertSet.6.constraint.params.keyUsageDecipherOnly=false
+policyset.serverCertSet.6.default.class_id=keyUsageExtDefaultImpl
+policyset.serverCertSet.6.default.name=Key Usage Default
+policyset.serverCertSet.6.default.params.keyUsageCritical=true
+policyset.serverCertSet.6.default.params.keyUsageDigitalSignature=true
+policyset.serverCertSet.6.default.params.keyUsageNonRepudiation=true
+policyset.serverCertSet.6.default.params.keyUsageDataEncipherment=true
+policyset.serverCertSet.6.default.params.keyUsageKeyEncipherment=true
+policyset.serverCertSet.6.default.params.keyUsageKeyAgreement=false
+policyset.serverCertSet.6.default.params.keyUsageKeyCertSign=false
+policyset.serverCertSet.6.default.params.keyUsageCrlSign=false
+policyset.serverCertSet.6.default.params.keyUsageEncipherOnly=false
+policyset.serverCertSet.6.default.params.keyUsageDecipherOnly=false
+policyset.serverCertSet.7.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.7.constraint.name=No Constraint
+policyset.serverCertSet.7.default.class_id=extendedKeyUsageExtDefaultImpl
+policyset.serverCertSet.7.default.name=Extended Key Usage Extension Default
+policyset.serverCertSet.7.default.params.exKeyUsageCritical=false
+policyset.serverCertSet.7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1,1.3.6.1.5.2.3.5
+policyset.serverCertSet.8.constraint.class_id=signingAlgConstraintImpl
+policyset.serverCertSet.8.constraint.name=No Constraint
+policyset.serverCertSet.8.constraint.params.signingAlgsAllowed=SHA1withRSA,SHA256withRSA,SHA512withRSA,SHA1withDSA,SHA1withEC,SHA256withEC,SHA384withEC,SHA512withEC
+policyset.serverCertSet.8.default.class_id=signingAlgDefaultImpl
+policyset.serverCertSet.8.default.name=Signing Alg
+policyset.serverCertSet.8.default.params.signingAlg=-
+policyset.serverCertSet.9.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.9.constraint.name=No Constraint
+policyset.serverCertSet.9.default.class_id=crlDistributionPointsExtDefaultImpl
+policyset.serverCertSet.9.default.name=CRL Distribution Points Extension Default
+policyset.serverCertSet.9.default.params.crlDistPointsCritical=false
+policyset.serverCertSet.9.default.params.crlDistPointsNum=1
+policyset.serverCertSet.9.default.params.crlDistPointsEnable_0=true
+policyset.serverCertSet.9.default.params.crlDistPointsIssuerName_0=$CRL_ISSUER
+policyset.serverCertSet.9.default.params.crlDistPointsIssuerType_0=DirectoryName
+policyset.serverCertSet.9.default.params.crlDistPointsPointName_0=http://$IPA_CA_RECORD.$DOMAIN/ipa/crl/MasterCRL.bin
+policyset.serverCertSet.9.default.params.crlDistPointsPointType_0=URIName
+policyset.serverCertSet.9.default.params.crlDistPointsReasons_0=
+policyset.serverCertSet.10.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.10.constraint.name=No Constraint
+policyset.serverCertSet.10.default.class_id=subjectKeyIdentifierExtDefaultImpl
+policyset.serverCertSet.10.default.name=Subject Key Identifier Extension Default
+policyset.serverCertSet.10.default.params.critical=false
+policyset.serverCertSet.11.constraint.class_id=noConstraintImpl
+policyset.serverCertSet.11.constraint.name=No Constraint
+policyset.serverCertSet.11.default.class_id=userExtensionDefaultImpl
+policyset.serverCertSet.11.default.name=User Supplied Extension Default
+policyset.serverCertSet.11.default.params.userExtOID=2.5.29.17
diff --git a/install/share/profiles/Makefile.am b/install/share/profiles/Makefile.am
index d1c1bac96..640ca0a4a 100644
--- a/install/share/profiles/Makefile.am
+++ b/install/share/profiles/Makefile.am
@@ -4,6 +4,7 @@ appdir = $(IPA_DATA_DIR)/profiles
app_DATA = \
caIPAserviceCert.cfg \
IECUserRoles.cfg \
+ KDCs_PKINIT_Certs.cfg \
$(NULL)
EXTRA_DIST = \
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
index 0eec5bdba..ae96bc191 100644
--- a/ipaclient/install/client.py
+++ b/ipaclient/install/client.py
@@ -779,7 +779,7 @@ def configure_certmonger(
passwd_fname = os.path.join(paths.IPA_NSSDB_DIR, 'pwdfile.txt')
try:
certmonger.request_cert(
- nssdb=paths.IPA_NSSDB_DIR,
+ certpath=paths.IPA_NSSDB_DIR,
nickname='Local IPA host', subject=subject, dns=[hostname],
principal=principal, passwd_fname=passwd_fname)
except Exception as ex:
diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py
index c79cf9383..951ca9ab8 100644
--- a/ipalib/install/certmonger.py
+++ b/ipalib/install/certmonger.py
@@ -299,17 +299,17 @@ def add_subject(request_id, subject):
def request_and_wait_for_cert(
- nssdb, nickname, subject, principal, passwd_fname=None,
+ certpath, nickname, subject, principal, passwd_fname=None,
dns=None, ca='IPA', profile=None,
- pre_command=None, post_command=None):
+ pre_command=None, post_command=None, storage='NSSDB'):
"""
Execute certmonger to request a server certificate.
The method also waits for the certificate to be available.
"""
- reqId = request_cert(nssdb, nickname, subject, principal,
+ reqId = request_cert(certpath, nickname, subject, principal,
passwd_fname, dns, ca, profile,
- pre_command, post_command)
+ pre_command, post_command, storage)
state = wait_for_request(reqId, api.env.startup_timeout)
ca_error = get_request_value(reqId, 'ca-error')
if state != 'MONITORING' or ca_error:
@@ -318,23 +318,29 @@ def request_and_wait_for_cert(
def request_cert(
- nssdb, nickname, subject, principal, passwd_fname=None,
- dns=None, ca='IPA', profile=None, pre_command=None, post_command=None):
+ certpath, nickname, subject, principal, passwd_fname=None,
+ dns=None, ca='IPA', profile=None,
+ pre_command=None, post_command=None, storage='NSSDB'):
"""
Execute certmonger to request a server certificate.
``dns``
A sequence of DNS names to appear in SAN request extension.
"""
+ if storage == 'FILE':
+ certfile, keyfile = certpath
+ else:
+ certfile = certpath
+ keyfile = certpath
+
cm = _certmonger()
ca_path = cm.obj_if.find_ca_by_nickname(ca)
if not ca_path:
raise RuntimeError('{} CA not found'.format(ca))
- request_parameters = dict(KEY_STORAGE='NSSDB', CERT_STORAGE='NSSDB',
- CERT_LOCATION=nssdb, CERT_NICKNAME=nickname,
- KEY_LOCATION=nssdb, KEY_NICKNAME=nickname,
- SUBJECT=subject,
- CA=ca_path)
+ request_parameters = dict(KEY_STORAGE=storage, CERT_STORAGE=storage,
+ CERT_LOCATION=certfile, CERT_NICKNAME=nickname,
+ KEY_LOCATION=keyfile, KEY_NICKNAME=nickname,
+ SUBJECT=subject, CA=ca_path)
if principal:
request_parameters['PRINCIPAL'] = [principal]
if dns is not None and len(dns) > 0:
@@ -409,20 +415,27 @@ def start_tracking(nickname, secdir, password_file=None, command=None):
return request.prop_if.Get(DBUS_CM_REQUEST_IF, 'nickname')
-def stop_tracking(secdir, request_id=None, nickname=None):
+def stop_tracking(secdir=None, request_id=None, nickname=None, certfile=None):
"""
Stop tracking the current request using either the request_id or nickname.
Returns True or False
"""
- if request_id is None and nickname is None:
- raise RuntimeError('Both request_id and nickname are missing.')
+ if request_id is None and nickname is None and certfile is None:
+ raise RuntimeError('One of request_id, nickname and certfile is'
+ ' required.')
+ if secdir is not None and certfile is not None:
+ raise RuntimeError("Can't specify both secdir and certfile.")
- criteria = {'cert-database': secdir}
+ criteria = dict()
+ if secdir:
+ criteria['cert-database'] = secdir
if request_id:
criteria['nickname'] = request_id
if nickname:
criteria['cert-nickname'] = nickname
+ if certfile:
+ criteria['cert-file'] = certfile
try:
request = _get_request(criteria)
except RuntimeError as e:
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index f85a2aa12..896fa9d98 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -240,7 +240,8 @@ class BasePathNamespace(object):
KRB5KDC_KADM5_ACL = "/var/kerberos/krb5kdc/kadm5.acl"
KRB5KDC_KADM5_KEYTAB = "/var/kerberos/krb5kdc/kadm5.keytab"
KRB5KDC_KDC_CONF = "/var/kerberos/krb5kdc/kdc.conf"
- KDC_PEM = "/var/kerberos/krb5kdc/kdc.pem"
+ KDC_CERT = "/var/kerberos/krb5kdc/kdc.crt"
+ KDC_KEY = "/var/kerberos/krb5kdc/kdc.key"
VAR_LIB = "/var/lib"
AUTHCONFIG_LAST = "/var/lib/authconfig/last"
VAR_LIB_CERTMONGER_DIR = "/var/lib/certmonger"
diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
index f4f1955eb..eb1f73eee 100644
--- a/ipapython/dogtag.py
+++ b/ipapython/dogtag.py
@@ -48,9 +48,13 @@ Profile = collections.namedtuple('Profile', ['profile_id', 'description', 'store
INCLUDED_PROFILES = {
Profile(u'caIPAserviceCert', u'Standard profile for network services', True),
Profile(u'IECUserRoles', u'User profile that includes IECUserRoles extension from request', True),
+ Profile(u'KDCs_PKINIT_Certs',
+ u'Profile for PKINIT support by KDCs',
+ False),
}
DEFAULT_PROFILE = u'caIPAserviceCert'
+KDC_PROFILE = u'KDCs_PKINIT_Certs'
def error_from_xml(doc, message_template):
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 29acd7e27..c7e81f085 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -817,7 +817,7 @@ class CAInstance(DogtagInstance):
# The certificate must be requested using caServerCert profile
# because this profile does not require agent authentication
reqId = certmonger.request_and_wait_for_cert(
- nssdb=self.ra_agent_db,
+ certpath=self.ra_agent_db,
nickname='ipaCert',
principal='host/%s' % self.fqdn,
passwd_fname=self.ra_agent_pwd,
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 45602baa6..02b03d48b 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -633,7 +633,13 @@ class CertDB(object):
def install_pem_from_p12(self, p12_fname, p12_passwd, pem_fname):
pwd = ipautil.write_tmp_file(p12_passwd)
- ipautil.run([paths.OPENSSL, "pkcs12", "-nodes",
+ ipautil.run([paths.OPENSSL, "pkcs12", "-nokeys",
+ "-in", p12_fname, "-out", pem_fname,
+ "-passin", "file:" + pwd.name])
+
+ def install_key_from_p12(self, p12_fname, p12_passwd, pem_fname):
+ pwd = ipautil.write_tmp_file(p12_passwd)
+ ipautil.run([paths.OPENSSL, "pkcs12", "-nodes", "-nocerts",
"-in", p12_fname, "-out", pem_fname,
"-passin", "file:" + pwd.name])
@@ -647,7 +653,7 @@ class CertDB(object):
def request_service_cert(self, nickname, principal, host, pwdconf=False):
if pwdconf:
self.create_password_conf()
- certmonger.request_and_wait_for_cert(nssdb=self.secdir,
+ certmonger.request_and_wait_for_cert(certpath=self.secdir,
nickname=nickname,
principal=principal,
subject=host,
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 1be5ac73c..bcfcb0500 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -816,7 +816,7 @@ class DsInstance(service.Service):
try:
cmd = 'restart_dirsrv %s' % self.serverid
certmonger.request_and_wait_for_cert(
- nssdb=dirname,
+ certpath=dirname,
nickname=self.nickname,
principal=self.principal,
passwd_fname=dsdb.passwd_fname,
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 15c310780..b7ce857ed 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -376,7 +376,7 @@ class HTTPInstance(service.Service):
try:
certmonger.request_and_wait_for_cert(
- nssdb=db.secdir,
+ certpath=db.secdir,
nickname=self.cert_nickname,
principal=self.principal,
passwd_fname=db.passwd_fname,
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 8de92f764..b52b0c3f9 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -24,6 +24,7 @@ import shutil
import os
import pwd
import socket
+import dbus
import dns.name
@@ -32,6 +33,7 @@ from ipaserver.install import installutils
from ipapython import ipautil
from ipapython import kernel_keyring
from ipalib import api
+from ipalib.install import certmonger
from ipapython.ipa_log_manager import root_logger
from ipapython.dn import DN
@@ -153,12 +155,14 @@ class KrbInstance(service.Service):
self.step("creating a keytab for the directory", self.__create_ds_keytab)
self.step("creating a keytab for the machine", self.__create_host_keytab)
self.step("adding the password extension to the directory", self.__add_pwd_extop_module)
- if setup_pkinit:
- self.step("creating X509 Certificate for PKINIT", self.__setup_pkinit)
- self.step("creating principal for anonymous PKINIT", self.__add_anonymous_pkinit_principal)
+ self.step("creating anonymous principal", self.add_anonymous_principal)
self.__common_post_setup()
+ if setup_pkinit:
+ self.step("installing X509 Certificate for PKINIT",
+ self.setup_pkinit)
+
self.start_creation(runtime=30)
self.kpasswd = KpasswdInstance()
@@ -179,7 +183,8 @@ class KrbInstance(service.Service):
self.step("configuring KDC", self.__configure_instance)
self.step("adding the password extension to the directory", self.__add_pwd_extop_module)
if setup_pkinit:
- self.step("installing X509 Certificate for PKINIT", self.__setup_pkinit)
+ self.step("installing X509 Certificate for PKINIT",
+ self.setup_pkinit)
self.__common_post_setup()
@@ -214,7 +219,8 @@ class KrbInstance(service.Service):
KRB5KDC_KADM5_ACL=paths.KRB5KDC_KADM5_ACL,
DICT_WORDS=paths.DICT_WORDS,
KRB5KDC_KADM5_KEYTAB=paths.KRB5KDC_KADM5_KEYTAB,
- KDC_PEM=paths.KDC_PEM,
+ KDC_CERT=paths.KDC_CERT,
+ KDC_KEY=paths.KDC_KEY,
CACERT_PEM=paths.CACERT_PEM)
# IPA server/KDC is not a subdomain of default domain
@@ -338,31 +344,50 @@ class KrbInstance(service.Service):
self.move_service_to_host(host_principal)
- def __setup_pkinit(self):
+ def setup_pkinit(self):
ca_db = certs.CertDB(self.realm, host_name=self.fqdn,
subject_base=self.subject_base)
if self.pkcs12_info:
ca_db.install_pem_from_p12(self.pkcs12_info[0],
self.pkcs12_info[1],
- paths.KDC_PEM)
+ paths.KDC_CERT)
+ ca_db.install_key_from_p12(self.pkcs12_info[0],
+ self.pkcs12_info[1],
+ paths.KDC_KEY)
else:
- raise RuntimeError("PKI not supported yet\n")
+ subject = str(DN(('cn', self.fqdn), self.subject_base))
+ krbtgt = "krbtgt/" + self.realm + "@" + self.realm
+ certpath = (paths.KDC_CERT, paths.KDC_KEY)
+ try:
+ reqid = certmonger.request_cert(certpath, u'KDC-Cert',
+ subject, krbtgt,
+ dns=self.fqdn, storage='FILE',
+ profile='KDCs_PKINIT_Certs')
+ except dbus.DBusException as e:
+ # if the certificate is already tracked, ignore the error
+ name = e.get_dbus_name()
+ if name != 'org.fedorahosted.certmonger.duplicate':
+ root_logger.error("Failed to initiate the request: %s", e)
+ return
+
+ try:
+ certmonger.wait_for_request(reqid)
+ except RuntimeError as e:
+ root_logger.error("Failed to wait for request: %s", e)
# Finally copy the cacert in the krb directory so we don't
# have any selinux issues with the file context
shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM)
- def __add_anonymous_pkinit_principal(self):
+ def get_anonymous_principal_name(self):
princ = "WELLKNOWN/ANONYMOUS"
- princ_realm = "%s@%s" % (princ, self.realm)
+ return "%s@%s" % (princ, self.realm)
+ def add_anonymous_principal(self):
# Create the special anonymous principal
+ princ_realm = self.get_anonymous_principal_name()
installutils.kadmin_addprinc(princ_realm)
- dn = DN(('krbprincipalname', princ_realm), self.get_realm_suffix())
- entry = api.Backend.ldap2.get_entry(dn)
- entry['nsAccountlock'] = ['TRUE']
- api.Backend.ldap2.update_entry(entry)
def __convert_to_gssapi_replication(self):
repl = replication.ReplicationManager(self.realm,
@@ -372,6 +397,9 @@ class KrbInstance(service.Service):
r_binddn=DN(('cn', 'Directory Manager')),
r_bindpw=self.dm_password)
+ def stop_tracking_certs(self):
+ certmonger.stop_tracking(certfile=paths.KDC_CERT)
+
def uninstall(self):
if self.is_configured():
self.print_msg("Unconfiguring %s" % self.service_name)
@@ -394,6 +422,12 @@ class KrbInstance(service.Service):
if enabled:
self.enable()
+ # stop tracking and remove certificates
+ self.stop_tracking_certs()
+ installutils.remove_file(paths.CACERT_PEM)
+ installutils.remove_file(paths.KDC_CERT)
+ installutils.remove_file(paths.KDC_KEY)
+
if running:
self.restart()
diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
index 0237702cc..28cdd066a 100644
--- a/ipaserver/install/server/__init__.py
+++ b/ipaserver/install/server/__init__.py
@@ -501,8 +501,8 @@ class ServerInstallInterface(client.ClientInstallInterface,
"You must specify at least one of --forwarder, "
"--auto-forwarders, or --no-forwarders options")
- # Automatically disable pkinit w/ dogtag until that is supported
- self.no_pkinit = True
+ # Automatically enable pkinit w/ dogtag
+ self.no_pkinit = not self.setup_ca
ServerMasterInstallInterface = installs_master(ServerInstallInterface)
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index f81c202cc..b5b9cb48a 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -521,6 +521,11 @@ def install_check(installer):
dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)
if options.pkinit_cert_files:
+ if not options.no_pkinit:
+ raise ScriptError("Cannot create KDC PKINIT certificate and use "
+ "provided external PKINIT certificate at the "
+ "same time. Please choose one of them.")
+
if options.pkinit_pin is None:
options.pkinit_pin = read_password(
"Enter Kerberos KDC private key unlock",
@@ -792,17 +797,11 @@ def install(installer):
ds.enable_ssl()
krb = krbinstance.KrbInstance(fstore)
- if options.pkinit_cert_files:
- krb.create_instance(realm_name, host_name, domain_name,
- dm_password, master_password,
- setup_pkinit=not options.no_pkinit,
- pkcs12_info=pkinit_pkcs12_info,
- subject_base=options.subject)
- else:
- krb.create_instance(realm_name, host_name, domain_name,
- dm_password, master_password,
- setup_pkinit=not options.no_pkinit,
- subject_base=options.subject)
+ krb.create_instance(realm_name, host_name, domain_name,
+ dm_password, master_password,
+ setup_pkinit=not options.no_pkinit,
+ pkcs12_info=pkinit_pkcs12_info,
+ subject_base=options.subject)
# restart DS to enable ipa-pwd-extop plugin
print("Restarting directory server to enable password extension plugin")
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 06d209e23..b0cf28f0f 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -124,7 +124,9 @@ def install_krb(config, setup_pkinit=False, promote=False):
krb.create_replica(config.realm_name,
config.master_host_name, config.host_name,
config.domain_name, config.dirman_password,
- setup_pkinit, pkcs12_info, promote=promote)
+ setup_pkinit, pkcs12_info,
+ subject_base=config.subject_base,
+ promote=promote)
return krb
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 245450701..0ebe9af24 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -47,6 +47,7 @@ from ipaserver.install import sysupgrade
from ipaserver.install import dnskeysyncinstance
from ipaserver.install import krainstance
from ipaserver.install import dogtaginstance
+from ipaserver.install import krbinstance
from ipaserver.install.upgradeinstance import IPAUpgrade
from ipaserver.install.ldapupdate import BadSyntax
@@ -1492,6 +1493,20 @@ def add_default_caacl(ca):
sysupgrade.set_upgrade_state('caacl', 'add_default_caacl', True)
+def enable_anonymous_principal(krb):
+ princ_realm = krb.get_anonymous_principal_name()
+ dn = DN(('krbprincipalname', princ_realm), krb.get_realm_suffix())
+ try:
+ _ = api.Backend.ldap2.get_entry(dn) # pylint: disable=unused-variable
+ except ipalib.errors.NotFound:
+ krb.add_anonymous_principal()
+
+ try:
+ api.Backend.ldap2.set_entry_active(dn, True)
+ except ipalib.errors.AlreadyActive:
+ pass
+
+
def upgrade_configuration():
"""
Execute configuration upgrade of the IPA services
@@ -1735,6 +1750,26 @@ def upgrade_configuration():
set_sssd_domain_option('ipa_server_mode', 'True')
+ krb = krbinstance.KrbInstance(fstore)
+ krb.fqdn = fqdn
+ krb.realm = api.env.realm
+ krb.suffix = ipautil.realm_to_suffix(krb.realm)
+ krb.subject_base = subject_base
+ if not os.path.exists(paths.KDC_CERT):
+ krb.setup_pkinit()
+ replacevars = dict()
+ replacevars['pkinit_identity'] = 'FILE:{},{}'.format(
+ paths.KDC_CERT,paths.KDC_KEY)
+ appendvars = {}
+ ipautil.backup_config_and_replace_variables(
+ fstore, paths.KRB5KDC_KDC_CONF, replacevars=replacevars,
+ appendvars=appendvars)
+ tasks.restore_context(paths.KRB5KDC_KDC_CONF)
+ if krb.is_running():
+ krb.stop()
+ krb.start()
+ enable_anonymous_principal(krb)
+
if not ds_running:
ds.stop(ds_serverid)
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index e4efa7d37..81872cffd 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -144,11 +144,12 @@ http://www.ietf.org/rfc/rfc5280.txt
""")
-USER, HOST, SERVICE = range(3)
+USER, HOST, KRBTGT, SERVICE = range(4)
PRINCIPAL_TYPE_STRING_MAP = {
USER: _('user'),
HOST: _('host'),
+ KRBTGT: _('krbtgt'),
SERVICE: _('service'),
}
@@ -216,6 +217,13 @@ def caacl_check(principal_type, principal, ca, profile_id):
)
+def ca_kdc_check(ldap, hostname):
+ result = api.Command.config_show()['result']
+ if hostname not in result['ipa_master_server']:
+ raise errors.ACIError(info=_(
+ "Host '%(hostname)s' is not a KDC") % dict(hostname=hostname))
+
+
def validate_certificate(value):
return x509.validate_certificate(value, x509.DER)
@@ -533,6 +541,7 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
ca_enabled_check()
ldap = self.api.Backend.ldap2
+ realm = unicode(self.api.env.realm)
add = kw.get('add')
request_type = kw.get('request_type')
profile_id = kw.get('profile_id', self.Backend.ra.DEFAULT_PROFILE)
@@ -563,11 +572,16 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
principal_type = USER
elif principal.is_host:
principal_type = HOST
+ elif principal.service_name == 'krbtgt':
+ principal_type = KRBTGT
+ if profile_id != self.Backend.ra.KDC_PROFILE:
+ raise errors.ACIError(
+ info=_("krbtgt certs can use only the %s profile") % (
+ self.Backend.ra.KDC_PROFILE))
else:
principal_type = SERVICE
- bind_principal = kerberos.Principal(
- getattr(context, 'principal'))
+ bind_principal = kerberos.Principal(getattr(context, 'principal'))
bind_principal_string = unicode(bind_principal)
if bind_principal.is_user:
@@ -589,7 +603,10 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
bypass_caacl = False
if not bypass_caacl:
- caacl_check(principal_type, principal, ca, profile_id)
+ if principal_type == KRBTGT:
+ ca_kdc_check(ldap, bind_principal.hostname)
+ else:
+ caacl_check(principal_type, principal, ca, profile_id)
try:
csr_obj = pkcs10.load_certificate_request(csr)
@@ -616,6 +633,11 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
try:
if principal_type == SERVICE:
principal_obj = api.Command['service_show'](principal_string, all=True)
+ elif principal_type == KRBTGT:
+ # Allow only our own realm krbtgt for now, no trusted realm's.
+ if principal != kerberos.Principal((u'krbtgt', realm),
+ realm=realm):
+ raise errors.NotFound("Not our realm's krbtgt")
elif principal_type == HOST:
principal_obj = api.Command['host_show'](
principal.hostname, all=True)
@@ -635,8 +657,9 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
else:
raise errors.NotFound(
reason=_("The principal for this request doesn't exist."))
- principal_obj = principal_obj['result']
- dn = principal_obj['dn']
+ if principal_obj:
+ principal_obj = principal_obj['result']
+ dn = principal_obj['dn']
# Ensure that the DN in the CSR matches the principal
#
@@ -656,6 +679,13 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
"hostname in subject of request '%(cn)s' does not "
"match name or aliases of principal '%(principal)s'"
) % dict(cn=cn, principal=principal))
+ elif principal_type == KRBTGT and not bypass_caacl:
+ if cn.lower() != bind_principal.hostname.lower():
+ raise errors.ACIError(
+ info=_("hostname in subject of request '%(cn)s' "
+ "does not match principal hostname "
+ "'%(hostname)s'") % dict(
+ cn=cn, hostname=bind_principal.hostname))
elif principal_type == USER:
# check user name
if cn != principal.username:
@@ -677,10 +707,12 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
"any of user's email addresses")
)
- # We got this far so the principal entry exists, can we write it?
- if not ldap.can_write(dn, "usercertificate"):
- raise errors.ACIError(info=_("Insufficient 'write' privilege "
- "to the 'userCertificate' attribute of entry '%s'.") % dn)
+ if principal_type != KRBTGT:
+ # We got this far so the principal entry exists, can we write it?
+ if not ldap.can_write(dn, "usercertificate"):
+ raise errors.ACIError(
+ info=_("Insufficient 'write' privilege to the "
+ "'userCertificate' attribute of entry '%s'.") % dn)
# Validate the subject alt name, if any
generalnames = []
@@ -711,6 +743,9 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
if principal_type == HOST:
alt_principal_obj = api.Command['host_show'](
name, all=True)
+ elif principal_type == KRBTGT:
+ alt_principal = kerberos.Principal(
+ (u'host', name), principal.realm)
elif principal_type == SERVICE:
alt_principal_obj = api.Command['service_show'](
alt_principal, all=True)
@@ -722,17 +757,26 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
'subject alt name %s in certificate request does not '
'exist') % name)
- # we found an alternative principal;
- # now check write access and caacl
- altdn = alt_principal_obj['result']['dn']
- if not ldap.can_write(altdn, "usercertificate"):
- raise errors.ACIError(info=_(
- "Insufficient privilege to create a certificate "
- "with subject alt name '%s'.") % name)
+ if alt_principal_obj is not None:
+ # we found an alternative principal;
+ # now check write access and caacl
+ altdn = alt_principal_obj['result']['dn']
+ if not ldap.can_write(altdn, "usercertificate"):
+ raise errors.ACIError(info=_(
+ "Insufficient privilege to create a certificate "
+ "with subject alt name '%s'.") % name)
if not bypass_caacl:
- caacl_check(principal_type, alt_principal, ca, profile_id)
+ if principal_type == KRBTGT:
+ ca_kdc_check(ldap, alt_principal.hostname)
+ else:
+ caacl_check(principal_type, alt_principal, ca,
+ profile_id)
elif isinstance(gn, (x509.KRB5PrincipalName, x509.UPN)):
+ if principal_type == KRBTGT:
+ principal_obj = dict()
+ principal_obj['krbprincipalname'] = [
+ kerberos.Principal((u'krbtgt', realm), realm)]
if not _principal_name_matches_principal(
gn.name, principal_obj):
raise errors.ValidationError(
@@ -793,6 +837,9 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
api.Command['host_mod'](principal.hostname, **kwargs)
elif principal_type == USER:
api.Command['user_mod'](principal.username, **kwargs)
+ elif principal_type == KRBTGT:
+ self.log.error("Profiles used to store cert should't be "
+ "used for krbtgt certificates")
return dict(
result=result,
@@ -810,6 +857,9 @@ def _dns_name_matches_principal(name, principal, principal_obj):
:return: True if name matches, otherwise False
"""
+ if principal_obj is None:
+ return False
+
for alias in principal_obj.get('krbprincipalname', []):
# we can only compare them if both subject principal and
# the alias are service or host principals
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index b77b21aa2..73c14ed53 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -1225,6 +1225,8 @@ class RestClient(Backend):
profile_api.create_profile(...)
"""
+ DEFAULT_PROFILE = dogtag.DEFAULT_PROFILE
+ KDC_PROFILE = dogtag.KDC_PROFILE
path = None
@staticmethod