Skip to content

Instantly share code, notes, and snippets.

@abbra
Created August 23, 2019 13:23
Show Gist options
  • Save abbra/33f5ac59c5cae750ecdb3974978d9cec to your computer and use it in GitHub Desktop.
Save abbra/33f5ac59c5cae750ecdb3974978d9cec to your computer and use it in GitHub Desktop.
Verifying DNA and ID ranges in FreeIPA
from ipaserver.install import replication
def check_ids_in_modified_range(ldap, old_base, old_size, new_base, new_size):
from ipalib import errors
if new_base is None and new_size is None:
# nothing to check
return (0, [])
if new_base is None:
new_base = old_base
if new_size is None:
new_size = old_size
old_interval = (old_base, old_base + old_size - 1)
new_interval = (new_base, new_base + new_size - 1)
checked_intervals = []
low_diff = new_interval[0] - old_interval[0]
if low_diff > 0:
checked_intervals.append((old_interval[0],
min(old_interval[1], new_interval[0] - 1)))
high_diff = old_interval[1] - new_interval[1]
if high_diff > 0:
checked_intervals.append((max(old_interval[0], new_interval[1] + 1),
old_interval[1]))
if not checked_intervals:
# range is equal or covers the entire old range, nothing to check
return (0, [])
id_filter_base = ["(objectclass=posixAccount)",
"(objectclass=posixGroup)",
"(objectclass=ipaIDObject)"]
id_filter_ids = []
for id_low, id_high in checked_intervals:
id_filter_ids.append("(&(uidNumber>=%(low)d)(uidNumber<=%(high)d))"
% dict(low=id_low, high=id_high))
id_filter_ids.append("(&(gidNumber>=%(low)d)(gidNumber<=%(high)d))"
% dict(low=id_low, high=id_high))
id_filter = ldap.combine_filters(
[ldap.combine_filters(id_filter_base, "|"),
ldap.combine_filters(id_filter_ids, "|")],
"&")
try:
num, entries = ldap.search(filter=id_filter,
attrs_list=['uidNumber', 'gidNumber', 'dn', 'objectclass',
'ipaNTSecurityIdentifier'],
base_dn=api.env.container_accounts + api.env.basedn)
except errors.NotFound:
# no objects in this range found, allow the command
return (0, [])
return num, entries
r = replication.ReplicationManager(api.env.realm, api.env.host, starttls=True, port=389)
r_next, r_max = r.get_DNA_range(api.env.host)
ldap = api.Backend.ldap2
add_new_idrange = True
idranges = api.Command.idrange_find(iparangetype=u'ipa-local')['result']
for idrange in idranges:
ipabaseid = int(idrange.get(u'ipabaseid', ['0'])[0])
ipaidrangesize = int(idrange.get(u'ipaidrangesize', ['0'])[0])
rangename = idrange.get(u'cn')[0]
# Check whether this range corresponds to our DNA range already
if r_next >= ipabaseid and r_max <= ipabaseid + ipaidrangesize - 1:
print("Range '{}' ({}-{}) fits "
"DNA range ({}-{})".format(
rangename, ipabaseid, ipabaseid + ipaidrangesize - 1, r_next, r_max))
add_new_idrange = False
continue
num, entries = check_ids_in_modified_range(ldap, ipabaseid, ipaidrangesize, 0, 0)
if num == 0:
print("Range '{}' has no allocated entries and can be removed".format(rangename))
continue
print("Range '{}' has IDs in following entries:".format(rangename))
for e in entries:
attrs = []
for a in (u'uidnumber', u'gidnumber', u'ipantsecurityidentifier'):
v = e.get(a)
if v:
attrs.append("{}: {}".format(a, ",".join(v)))
print("\t{} [{}]".format(e.dn, ", ".join(attrs)))
if add_new_idrange:
print("A new ID range needs to be created for DNA range {}-{}".format(r_next, r_max))
@abbra
Copy link
Author

abbra commented Aug 23, 2019

When FreeIPA replica is installed, DNA range is not allocated to it automatically. The range is only cut from the master's DNA range when a replica really needs to get the IDs allocated. E.g. when a user or a group is being created. When this new DNA range appears on replica side, we ideally need to allocate ID range with the same parameters to be able to issue SIDs for the objects which received IDs from DNA plugin. But that is not happening, so admins need to allocate ID ranges manually.

When such situation arises, it is good to see what DNA ranges aren't mapped to ID ranges yet and which objects are there in additional ID ranges already.

Basic deployment use:

# kinit admin
# ipa -e in_server=True console sync-ranges.py
Range 'IPAEXAMPLE.TEST_id_range' (919600000-919799999) fits DNA range (919600002-919799999)

If several ID ranges were added:

# ipa idrange-add IPAEXAMPLE.TEST_new_idrange --base-id=1936000000 --range-size=200000 --type=ipa-local  --rid-base=750000 --secondary-rid-base=950000
----------------------------------------
Added ID range "IPAEXAMPLE.TEST_new_idrange"
----------------------------------------
  Range name: IPAEXAMPLE.TEST_new_idrange
  First Posix ID of the range: 1936000000
  Number of IDs in the range: 200000
  First RID of the corresponding RID range: 750000
  First RID of the secondary RID range: 950000
  Range type: local domain range

# ipa idrange-add IPAEXAMPLE.TEST_additional_idrange --base-id=1736000000 --range-size=200000 --type=ipa-local  --rid-base=220000 --secondary-rid-base=510000
-----------------------------------------------
Added ID range "IPAEXAMPLE.TEST_additional_idrange"
-----------------------------------------------
  Range name: IPAEXAMPLE.TEST_additional_idrange
  First Posix ID of the range: 1736000000
  Number of IDs in the range: 200000
  First RID of the corresponding RID range: 220000
  First RID of the secondary RID range: 510000
  Range type: local domain range

And users created utilizing on of those ranges:

# ipa user-add some-user --uid 1936000000
First name: Some
Last name: User
----------------------
Added user "some-user"
----------------------
  User login: some-user
  First name: Some
  Last name: User
  Full name: Some User
  Display name: Some User
  Initials: SU
  Home directory: /home/some-user
  GECOS: Some User
  Login shell: /bin/sh
  Principal name: some-user@IPAEXAMPLE.TEST
  Principal alias: some-user@IPAEXAMPLE.TEST
  Email address: some-user@ipaexample.test
  UID: 1936000000
  GID: 1936000000
  Password: False
  Member of groups: ipausers
  Kerberos keys available: False

Then running the script will produce information like this:

# ipa -e in_server=True console sync-ranges.py
Range 'IPAEXAMPLE.TEST_id_range' (919600000-919799999) fits DNA range (919600002-919799999)
Range 'IPAEXAMPLE.TEST_additional_idrange' has no allocated entries and can be removed
Range 'IPAEXAMPLE.TEST_new_idrange' has IDs in following entries:
	uid=some-user,cn=users,cn=accounts,dc=ipaexample,dc=test [uidnumber: 1936000000, gidnumber: 1936000000]
	cn=some-user,cn=groups,cn=accounts,dc=ipaexample,dc=test [gidnumber: 1936000000]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment