Projects/Policy refcount elimination
This project corresponds to [krbdev.mit.edu #7385], which proposes to eliminate the use of the policy reference count field.
Contents
Background
Policy objects in the Kerberos database contain a policy_refcnt field, which is intended to reflect the number of principals associated with that policy. libkadm5srv maintains the policy_refcnt field in its principal operations (so modifying a principal can also result in modifying its old or new policy reference), and refuses to delete a policy with a non-zero policy_refcnt value.
The policy reference count field creates a number of problems:
- If the database is modified by any agent other than kadmin (e.g. through LDAP operations for an LDAP KDB, or through an application using libkdb5 for any type of KDB), the policy field may not be maintained.
- The LDAP KDB schema does not contain a field for the policy reference count, presumably out of concern that it might become out of date. Instead, prior to [krbdev.mit.edu #6799], every policy fetch operation performed a search for all principals referencing the policy. This created a terrible performance problem--especially since fetching a principal currently requires fetching its associated policy object. After [krbdev.mit.edu #6799], LDAP populates the refcnt_policy field with 0 and checks for references from principals when deleting a policy, but this creates a layering inconsistency between the LDAP KDB and other KDB types.
- Historically, there have been bugs such as [krbdev.mit.edu #7384] allowing policy reference counts to become out of sync on slaves, and there are probably still bugs of that nature. If a slave is promoted to a master with inconsistent reference counts, the new master could incorrectly forbid or allow a policy deletion operation.
- [krbdev.mit.edu #7522] proposes to propagate policy changes over iprop (which currently has no way to marshal them) by forcing a full propagation whenever a policy changes. Frequent changes to policy reference counts would render this prohibitively expensive. Ignoring policy changes which only change the policy_refcnt field would allow reference count fields to become inconsistent on slaves.
- Policy deletion is a rare operation. Fundamentally, it does not make sense to impose an extra burden on principal modifications for the sake of such a rare operation.
Alternatives for policy deletion
Here are four options for handling policy deletion without using the reference count:
1. Disallow policy deletion altogether. A typical KDB does not have many policy objects, so the total space occupied by policies is quite small, and there is no efficiency reason to delete them. However, administrators might find it annoying not to be able to delete a policy name which contains a typo.
2. At deletion time, iterate over all principals. If any principals reference the policy, disallow the deletion.
3. At deletion time, iterate over all principals. If any principals reference the policy, null out their policy references.
4. Delete the policy even though it might be referenced by principals. If a principals references a nonexistent policy, treat it as if the principal had no policy reference. If a policy with the same name is recreated, principals referencing that policy name will become associated with the new policy. Put another way, principals could be thought of as referencing policy names (which might or might not exist as policy objects), rather than directly referencing policy objects.
This project proposes to implement option #4.
Code changes
The following units of code are affected by this project:
- kadm5_policy_ent_rec, osa_policy_ent_rec: add comments indicating that policy_refcnt is no longer maintained or used.
- kadm5_create_principal_3, kadm5_modify_principal, kadm5_delete_principal: stop maintaining policy_refcnt fields of policies referenced by the old or new principal entries. Stop returning an error if the new principal entry references a nonexistent policy (also in apply_keysalt_policy).
- kadm5_chpass_principal_3, kadm5_randkey_principal_3, kadm5_setv4key_principal, kadm5_setkey_principal_3: Stop erroring out if the entry references a nonexistent policy.
- kadm5_create_policy_internal, kadm5_modify_policy_internal: stop checking mask & KADM5_REF_COUNT and setting pent.policy_refcnt. These functions can be folded into their callers (kadm5_create_policy and kadm5_modify_policy respectively).
- kadm5_delete_policy: stop checking policy_refcnt.
- kadm5_get_policy: set entry->policy_refcnt to 0 instead of propagating it from the KDB entry.
- dump_k5beta7_policy, dump_r1_8_policy, dump_r1_11_policy: dump 0 instead of the policy_refcnt value from entry.
- process_k5beta7_policy, process_r1_8_policy, process_r1_11_policy: ignore the policy_refcnt values read from the dump instead of storing them into the entry.
- kadmin_addprinc, kadmin_modprinc: If the principal's policy reference is being set, check if the policy exists and warn if it does not.
- kadmin_getpol: Don't output policy_refcnt in long-form output, but annotate the policy name if it does not exist. In terse output, output 0 in place of policy_refcnt.
- populate_krb5_db_entry (in LDAP KDB module): don't return an error if the entry's policy cannot be found.
- krb5_ldap_delete_password_policy: stop checking the reference count.
Testing
The kadm5 dejagnu test suite will need to be modified to allow the new semantics. t_kdb.py may need adjusting as well.
The Python scripts t_lockout.py, t_pwhist.py, and t_allowed_keysalts.py will be consolidated into a new script t_policy.py. Tests will be added to this script for:
- Creation of a principal with a nonexistent policy
- Modification of a principal to refer to a nonexistent policy
- Deleting a policy referenced by a principal
- Fetching a principal (with getprinc) referencing a nonexistent policy
- Authenticating (with preauth) against a principal referencing a nonexistent policy
- Creating the policy (formerly nonexistent) referenced by a principal, and checking that it is now enforced
Commits
090f561c631db7e4970b71cbe1426d636c39c77a Stop loading policy for pw_expiration in LDAP 0780e46fc13dbafa177525164997cd204cc50b51 Allow principals to refer to nonexistent policies c50c0318397cc41d559763bef693da78ad642c6b Consolidate policy tests into t_policy.py 2ca2166dbeb374a06d4dc92c9bb93c24133b916d Test more policy features ecb9c348dd3e82aa8e68a466d89150dc0df3d46c Fold kadm5 internal policy functions into callers
Release notes
Administrator experience:
- Principal entries may now refer to the names of policies which do not exist as policy objects in the database. Policy objects may now be deleted whether or not principals reference their names. A principal which references a nonexistent policy name will behave as if it does not reference a policy.