Subject: [Ietf-krb-wg] LDAP schema for kdc

From: Howard Chu <[email-masked]>
Date: Fri, 03 Jul 2009 17:10:07 -0700

With an eye toward getting a draft written soon, I've started an analysis of 
the existing MIT and Heimdal LDAP schemas, in the context of the kdc-model 
draft and LDAP Password Policy management.

For reference, here's a quick overview of the existing schemas:

Heimdal
All of the schema are defined under the 1.3.6.1.4.1.5322.10 OID arc. (PADL.10)

Attributes
krb5PrincipalName	caseExactIA5
krb5KeyVersionNumber	integer
krb5MaxLife		integer
krb5MaxRenew		integer
krb5KDCFlags		integer
krb5EncryptionType	integer
krb5ValidStart		generalizedTime
krb5ValidEnd		generalizedTime
krb5PasswordEnd		generalizedTime
krb5Key			ASN.1 structure
krb5PrincipalRealm	DN
krb5RealmName		octetString

ObjectClasses
krb5Principal	(krb5PrincipalName) (cn, krb5PrincipalRealm)
krb5KDCEntry	(krb5KeyVersionNumber) (krb5ValidStart, krb5ValidEnd,
		 krb5PasswordEnd, krb5MaxLife, krb5MaxRenew,
		 krb5KDCFlags, krb5EncryptionType, krb5Key)
krb5Realm	(krb5RealmName)

The schema is quite compact and addresses only a small subset of the proposed 
information model. But it also exposes a few gaps in the information model.

Model section	Schema Item
6.1.1.1		krb5PrincipalName	(this attribute is single-valued, so it is also the 
canonical name)

6.1.1.2		krb5ValidStart
6.1.1.3		krb5ValidEnd
(no analogue for .4 thru .10)
6.1.1.11	krb5MaxLife
6.1.1.12	krb5MaxRenew
6.1.1.13	krb5EncryptionType

6.1.3		krb5PrincipalRealm and krb5RealmName are not addressed by the 
information model.

6.2.1.1		krb5KeyversionNumber	(note that in Heimdal this is a required 
attribute, but 6.2 says keyset parameters MUST NOT be REQUIRED)
6.2.2		krb5Key is multivalued, but krb5KeyVersionNumber is single-valued, so 
this definition basically only supports 1 keySet
6.3		krb5Key		(in Heimdal the components of this blob are not exposed as 
individual LDAP attributes)
6.3.1.5		krb5PasswordEnd
6.3.1.6		(absent)
6.3.1.7		(absent)

6.4		krb5KDCFlags	the information model doesn't really address common KDC 
policies such as whether a principal may be a client or server, whether it may 
use forwardable tickets, etc.

MIT
Some of the schema are under the 1.2.840.113554 (MIT) arc, some under the
2.16.840.1.113719 (Novell) arc.

Attributes
krbPrincipalName	caseExactIA5
krbCanonicalName	caseExactIA5
krbPrincipalType	integer
krbUPEnabled		boolean
krbPrincipalExpiration	generalizedTime
krbTicketFlags		integer
krbMaxTicketLife	integer
krbMaxRenewableAge	integer
krbRealmReferences	DN
krbLDAPServers		LDAP URI (bastardized)
krbKdcServers		DN
krbPwdServers		DN
krbHostServer		caseExactIA5
krbSearchScope		integer LDAP search scope, 1=onelevel, 2=subtree
krbPrincipalReferences	DN
krbPrincipalNamingAttr	caseIgnore (LDAP attribute name)
krbAdmServers		DN
krbMaxPwdLife		integer
krbMinPwdLife		integer
krbPwdMinDiffChars	integer (character classes)
krbPwdMinLength		integer
krbPwdHistoryLength	integer
krbPwdPolicyReference	DN
krbPasswordExpiration	generalizedTime
krbPrincipalKey		ASN.1 structure
krbTicketPolicyReference	DN
krbSubtrees		DN
krbDefaultEncSaltTypes	caseIgnore
krbSupportedEncSaltTypes	caseIgnore
krbPwdHistory		ASN.1 structure
krbLastPwdChange	generalizedTime
krbMKey			ASN.1 structure
krbPrincipalAliases	caseExactIA5
krbLastSuccessfulAuth	generalizedTime
krbLastFailedAuth	generalizedTime
krbLoginFailedCount	integer
krbExtraData		blob (octetstring)
krbObjectReferences	DN
krbPrincContainerRef	DN

ObjectClasses
krbContainer		(cn)
krbRealmContainer	(cn) (krbMKey, krbUPEnabled, krbSubtrees,
			 krbSearchScope, krbLDAPServers,
			 krbSupportedEncSaltTypes, krbDefaultEncSaltTypes,
			 krbTicketPolicyReference, krbKdcServers,
			 krbPwdServers, krbAdmServers, krbPrincNamingAttr,
			 krbPwdPolicyReference, krbPrincContainerRef)
krbService		(cn) (krbHostServer, krbRealmReferences)
krbKdcService		sup krbService
krbPwdService		sup krbService
krbPrincipalAux		() (krbPrincipalName, krbCanonicalName, krbUPEnabled,
			 krbPrincipalKey, krbTicketPolicyReference,
			 krbPrincipalExpiration, krbPasswordExpiration,
			 krbPwdPolicyReference, krbPrincipalType,
			 krbPwdHistory, krbLastPwdChange, krbPrincipalAliases,
			 krbLastSuccessfulAuth, krbLastFailedAuth,
			 krbLoginFailedCount, krbExtraData)
krbPrincipal		(krbPrincipalName) (krbObjectReferences)
krbPrincRefAux		() (krbPrincipalReferences)
krbAdmService		sup krbService
krbPwdPolicy		(cn) (krbMaxPwdLife, krbMinPwdLife,
			 krbPwdMinDiffChars, krbPwdMinLength,
			 krbPwdHistoryLength)
krbTicketPolicyAux	() (krbTicketflags, krbMaxTicketLife,
			 krbMaxRenewableAge)
krbTicketPolicy		(cn)

This schema addresses much more of the information model, and also exposes 
areas the model does not address.

Model Section	Schema Item
6.1.1.1		krbPrincipalName, krbCanonicalName	(the definition is inconsistent 
with the model; a single name must be canonical but the schema says if the 
krbPrincipalName has multiple values and the krbCanonicalName attribute is 
absent, then all the values are canonical)
6.1.1.2		(absent)
6.1.1.3		krbPrincipalExpiration
6.1.1.4		(absent)
6.1.1.5		krbLoginFailedCount
6.1.1.6		krbLastFailedAuth
6.1.1.7		krbLastSuccessfulAuth
6.1.1.8		krbLastPwdChange
6.1.1.9		(absent, LDAP createTimeStamp may suffice)
6.1.1.10	(absent, LDAP modifyTimeStamp may suffice)
6.1.1.11	krbMaxTicketLife
6.1.1.12	krbMaxRenewableAge
6.1.1.13	(maybe krbDefaultEncSaltTypes and krbSupportedEncSaltTypes)

6.1.2		krbPwdPolicyReference, krbTicketPolicyReference
6.1.3		krbRealmReferences

6.2.1.1		embedded in krbPrincipalKey
6.2.2		krbPrincipalKey is multi-valued
6.3.1.1 thru 6.3.1.4 embedded in krbPrincipalKey
6.3.1.5		krbPasswordExpiration - note, while krbPrincipalKey is multivalued, 
this attribute is single-valued, so individual KeySets do not have individual 
expiration times.
6.3.1.6		(absent)
6.3.1.7		(absent)

6.4		krbTicketFlags, krbTicketPolicy
6.4.2.1		krbPwdMinDiffChars, krbPwdMinLength
6.4.2.2		krbPwdMaxLife, krbPwdMinLife, krbPwdHistoryLength

General Commentary

A significant portion of the model is concerned with password policies. Many 
of the same issues are being faced in LDAP and it would make sense to 
coordinate the effort there. Some of the elements that are currently included 
in the LDAP Password Policy draft are associated with the Kerberos principals 
here, as opposed to being specifically associated with the Password Policy 
sections of the Information Model. That tells me that the notion of what 
constitutes Password Policy is still ill-defined either here or in the LDAP work.

While I see the value of having multiple security associations per "user" I 
don't see the value of having multiple KeySets per principal. I.e., I may have 
a user hyc with principals hyc/PasswordAdmin@realm or hyc/SoftwareAdmin@realm 
but I only want one password for each instance. The requirement to support 
multiple KeySets per principal makes this aspect of the Information Model 
pretty unwieldy.

The Heimdal krb5KDCFlags and MIT krbTicketFlags attributes behave similarly, a 
bitmask of several flags expressed as a single integer. But while the flag 
values they represent have some overlap, they are not identical. For a uniform 
LDAP Schema For Kerberos it would be better to replace attributes of this 
nature with an enumeration of strings, e.g. "proxiable", "require-preauth", 
etc... Likewise for the MIT krbExtraData blob; whatever is inside this blob 
should be exposed as plainly defined attributes.

The Heimdal schema assumes one Kerberos Principal per LDAP Account object, 
where all of the associated Kerberos Principal data is simply added to the 
LDAP Account.

The MIT schema assumes the Kerberos Principal data resides separately from the 
LDAP Account entry, and defines a number of Reference attributes to point from 
one to the other. While this certainly enhances flexibility, it also greatly 
increases complexity for Kerberos and Directory administrators. I would omit 
all of this glue from a Standard LDAP Schema for Kerberos and leave it 
implementation-specific. In practice, experience through many years of 
production deployment shows that the Heimdal approach is sufficient and few 
sites will need or want to add the complexity of splitting the data.

Some minor nits with the MIT schema:
   the KrbPrincNamingAttr attribute ought to have used objectIdentifier syntax 
since its only valid values are meant to be LDAP Attributes.
   the krbHostServer uses caseExact matching but Internet hostnames are 
case-insensitive; probably this should have used caseIgnore

Most of the MIT password policy attributes are already provided in the LDAP 
Password Policy draft

http://tools.ietf.org/draft/draft-behera-ldap-password-policy/draft-behera-ldap-password-policy-09.txt

That draft is long expired, but it would be worthwhile to write a new draft 
adding missing items as identified here:

	krbPwdMindiffChars
	krbLastSuccessfulAuth

Also something should be done to harmonize failed login tracking; currently 
the MIT schema uses two different attributes krbLastFailedAuth and 
krbLoginFailedCount while LDAP ppolicy uses a single pwdFailureTime attribute 
that records the timestamps of each failure. For auditing purposes, IMO the 
LDAP approach is more informative, but it may be overkill since login failures 
will usually also be logged elsewhere in a system.

Other elements mentioned in the data model that aren't present in LDAP 
Password Policy:

	keyNotUsedBefore
	keyIsDisabled

LDAP Password Policy attributes that do correspond to the Kerberos Information 
Model:

Model Section		LDAP Password Policy
6.1.1.5,6.1.1.6		pwdFailureTime
6.1.1.8			pwdChangedTime
6.3.1.5			pwdMaxAge
6.4.2.1			pwdMinLength, pwdCheckQuality
6.4.2.2			pwdMinAge, pwdMustChange, pwdAllowUserChange,
			 pwdSafeModify

MIT Kerberos schema elements that overlap LDAP Password Policy:

MIT			LDAP
krbMaxPwdLife		pwdMaxAge
krbMinPwdLife		pwdMinAge
krbPwdMinLength		pwdMinLength
krbPwdHistoryLength	pwdInHistory
krbPwdPolicyReference	pwdPolicySubentry
krbPasswordExpiration	(redundant, use pwdChangedTime + pwdMaxAge)
krbPwdHistory		pwdHistory
krbLastPwdChange	pwdChangedTime
krbLastFailedAuth	pwdFailureTime
krbFailedLogincount	(pwdFailureTime)

Sorry for the length of this email but hopefully it illuminates areas where 
further design work is needed. As I receive feedback from this post I will 
start drafting a proposal for a new LDAP Schema for Kerberos.

-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/
_______________________________________________
ietf-krb-wg mailing list
[email-masked]
https://lists.anl.gov/mailman/listinfo/ietf-krb-wg

---

From: Howard Chu <[email-masked]>
Date: Fri, 03 Jul 2009 18:52:00 -0700

> krbLDAPServers		LDAP URI (bastardized)

I forgot to explain my problem with this attribute - the description says 
"holds data in the LDAP URI format" but the examples given are not actual 
URIs, e.g. "acme.com#636, 164.164.164.164#1636" - that's
actually the format used for the krbHostServer attribute.

> multiple KeySets per principal makes this aspect of the Information Model

It also makes auditing slightly hairier, because now your audit logs also need 
to identify which keyset was used to perform an authentication.

> http://tools.ietf.org/draft/draft-behera-ldap-password-policy/draft-behera-ldap-password-policy-09.txt

This draft should be taken into consideration as well:

http://tools.ietf.org/html/draft-zeilenga-ldap-passwords-00

It highlights several problems with the Behera draft. It also omits several 
features as a result; in practice many sites depend on those features so it 
seems that they should not be omitted.

> krbFailedLogincount	(pwdFailureTime)

IMO the best approach would be to drop the majority of Password Policy 
discussions from the Kerberos Model and simply refer to the LDAP Password 
Policy work. At the same time, we need to drive the LDAP Password Policy work 
forward to get out of Draft status and to an accepted RFC.

In the context of the Behera draft the only thing any Kerberos document would 
really need to specify is a Syntax for storing old keys in the pwdHistory 
attribute. This could be as simple as defining a syntax for the ASN.1 
structures that Heimdal and MIT both currently use for their krb5key / 
krbPrincipalKey attributes.

---

From: Ken Raeburn <[email-masked]>
Date: Sat, 4 Jul 2009 04:20:22 -0400

On Jul 3, 2009, at 20:10, Howard Chu wrote:
> 6.3.1.5		krbPasswordExpiration - note, while krbPrincipalKey is  
> multivalued, this attribute is single-valued, so individual KeySets  
> do not have individual expiration times.

I would assume -- but haven't verified -- that the expiration would  
apply to the current key version number, and refers to when the  
password needs changing.  So it wouldn't make sense for older keys, as  
they've already been replaced.

> While I see the value of having multiple security associations per  
> "user" I don't see the value of having multiple KeySets per  
> principal. I.e., I may have a user hyc with principals hyc/ 
> PasswordAdmin@realm or hyc/SoftwareAdmin@realm but I only want one  
> password for each instance. The requirement to support multiple  
> KeySets per principal makes this aspect of the Information Model  
> pretty unwieldy.

If the key for krbtgt/REALM (local or cross-realm) is changed, do you  
want to keep the old key around too, or immediately invalidate all the  
TGTs that have been issued in the past several hours?  Granted, there  
are use cases where you want the latter, but if changing the key is a  
part of a routine periodic security process, you'd generally want the  
old keys to keep working until the already-issued TGTs expire.

I'm trying to remember the result of some past discussion... I think  
you can have the KDC renew a ticket for a service that isn't a KDC  
service, so the KDC would need to know about the recently-replaced  
keys for services too.  If that were the case, then you could probably  
make an argument that only a service needs to keep track of its own  
recently-expired keys and they don't need to be in the KDC database,  
and it applies to the KDC services (particularly the local and all  
cross-realm krbtgt principals' keys) too; there's the little detail  
that the database is a convenient place for the KDC to keep/get those  
keys, but that by itself probably shouldn't be a driving force for the  
model.

For users, yeah, probably only one at a time makes sense, usually.   
(There's the annoying possibility that someone may ask for credentials  
with another user principal as the service, which if it's not disabled  
results in the credentials being encrypted with the second user's long- 
term key, but I don't think much software really supports being the  
receiving user in that sort of configuration, asking for your current  
and previous passwords, etc.)  But if your whole database is in LDAP,  
you've got service principals to deal with too.

> Also something should be done to harmonize failed login tracking;  
> currently the MIT schema uses two different attributes  
> krbLastFailedAuth and krbLoginFailedCount while LDAP ppolicy uses a  
> single pwdFailureTime attribute that records the timestamps of each  
> failure. For auditing purposes, IMO the LDAP approach is more  
> informative, but it may be overkill since login failures will  
> usually also be logged elsewhere in a system.

It sounds like the LDAP approach makes it easy to implement policies  
like "lock out any account with N failed-password attempts in the  
previous 24 hours" where the lockout is temporary and automatically  
removed based on the time.

> Sorry for the length of this email but hopefully it illuminates  
> areas where further design work is needed. As I receive feedback  
> from this post I will start drafting a proposal for a new LDAP  
> Schema for Kerberos.

I think it's great that you've done this analysis, and want to go back  
and look over your results more carefully later.

-- 
Ken Raeburn / [email-masked] / no longer at MIT Kerberos Consortium

---

From: "Henry B. Hotz" <[email-masked]>
Date: Tue, 14 Jul 2009 12:27:08 -0700

> you've got service principals to deal with too.

Another use case is if the KDC is directly supporting time- 
synchronized OTP's.  You will want to allow the current-time keyset,  
as well as some number of previous and next values since the user's  
"password" may be out-of-sync by some allowable amount.

Of course you probably wouldn't really store those keysets in LDAP,  
but construct them on-the-fly.  OTOH if you wanted to support them for  
non-Kerberos operations . . .

------------------------------------------------------
The opinions expressed in this message are mine,
not those of Caltech, JPL, NASA, or the US Government.
[email-masked], or [email-masked]

---

From: Howard Chu <[email-masked]>
Date: Tue, 14 Jul 2009 12:33:29 -0700

> non-Kerberos operations . . .

Thanks for those, obviously I hadn't considered that but it makes sense.

---

From: Howard Chu <[email-masked]>
Date: Wed, 29 Jul 2009 22:21:24 -0700

> they've already been replaced.

Thanks for the feedback, much appreciated.

> old keys to keep working until the already-issued TGTs expire.

In that case, it strikes me that you still need the keyVersionNumber for each 
old key that you keep around, if you're still going to allow them to be used 
for authentication. No?

> removed based on the time.

Yes, that's a feature of the current LDAP Password Policy draft. Another 
feature I'd like to standardize here is an increasing (e.g. exponential) delay 
for consecutive login failures, as opposed to a simple lockout.

> and look over your results more carefully later.

Thanks again.

For the sake of getting something we can poke at going, I'm going to continue 
to use a "krb5" prefix on elements of the new schema proposal.

---

From: "Henry B. Hotz" <[email-masked]>
Date: Thu, 30 Jul 2009 00:35:51 -0700

> old key that you keep around, if you're still going to allow them to  

Unless you stipulate that old keys are consecutively numbered (er,  
backwards that is ;-).  That would certainly cover the obvious use  
cases.

---

From: Howard Chu <[email-masked]>
Date: Thu, 30 Jul 2009 00:51:51 -0700

> backwards that is ;-).  That would certainly cover the obvious use

Since LDAP attributes are sets, and thus their values have no defined 
ordering, there is no such thing as "backwards" or "consecutive".