Hello all -

I've been using IdM and was tasked by my management with generating two
system reports:

- List of what users have access to what services on each system
- List of sudo rules for each system

I did a lot of research but couldn't find a simple way to do this so I
created scripts using ldapsearch calls that created the reports I needed.

I'm sending these out to the community for comment and for anyone that has
similar requirements.

I've pasted the scripts below. If there are any issues with formatting, you
can download the scripts from my Github (github
com/jerelgilmer/freeipa-scripts)

Jerel Gilmer

----------> server-access-report.py
#!/usr/bin/python
'''
 2016 - March - 2
 Author: Jerel Gilmer
'''

import os
import sys
import ldap

def print_usage():
 print "Usage: server-access-report.py <hostname>"
 print "This script generates the list of allowed users for each service
defined in applicable HBAC rules.\n"
 print "<hostname> - System hostname; This can be the short name\n"
 print "For report of all systems, use \'.\'\n"
 print "Make sure to set the below variables in the script:"
 print "\tDOMAIN: Domain component"
 print "\tLDAP_SERVER: LDAP server to be queried"
 print "\tLDAP_USER: LDAP user to query server; preferable a read-only
account"
 print "\tLDAP_PW: LDAP user's password\n"
 sys.exit(1)

try:
 server = str(sys.argv[1])
except:
 print_usage()

## LDAP Connection Info and bind to the LDAP server
## Uncomment and set these variables to the appropriate values
## Below are examples
#DOMAIN = "dc=sub,dc=example,dc=com"
#LDAP_SERVER = "ldap://ipaserver1.sub.example.com";
#LDAP_USER = "uid=user1,cn=users,cn=compat," + DOMAIN
#LDAP_PW = "Password123"

try:
 DOMAIN
 LDAP_SERVER
 LDAP_USER
 LDAP_PW
except:
 print_usage()

l = ldap.initialize(LDAP_SERVER)

l.simple_bind_s(LDAP_USER,LDAP_PW)

## LDAP Search Variables
## Base DN for LDAP Searches
baseComputerDN = "cn=computers,cn=accounts," + DOMAIN
baseGroupDN =  "cn=groups,cn=accounts," + DOMAIN
baseUserDN = "cn=users,cn=accounts," + DOMAIN
baseHBACDN = "cn=hbac," + DOMAIN
baseHBACServicesDN = "cn=hbacservices,cn=hbac," + DOMAIN
baseHBACServiceGroupsDN = "cn=hbacservicegroups,cn=hbac," + DOMAIN

## Default LDAP SCOPE
scope = ldap.SCOPE_SUBTREE

## Filter for LDAP Searches
compFilter = "(&(objectclass=ipahost)(fqdn=*" + server + "*))"
hbacFilter = "(objectclass=ipahbacrule)"
userFilter = "(objectclass=person)"
groupFilter = "(objectclass=ipausergroup)"
hbacServiceFilter = "(objectclass=ipahbacservice)"
hbacServiceGroupsFilter = "(objectclass=ipahbacservicegroup)"

## Attributes from LDAP Searches
compAttributes =  ['memberOf', 'fqdn']
hbacAttributes = ['memberUser', 'memberService', 'serviceCategory']
userAttributes = ['uid']
groupAttributes = ['member']
hbacServiceAttributes = ['cn' , 'ipaUniqueID']
hbacServiceGroupsAttributes = ['cn' , 'member']

## Perform LDAP searches and store results into array
ALL_HOSTS = l.search_s(baseComputerDN, scope, compFilter, compAttributes)

ALL_USERS = l.search_s(baseUserDN, scope, userFilter, userAttributes)

ALL_GROUPS = l.search_s(baseGroupDN, scope, groupFilter, groupAttributes)

ALL_HBACRULES = l.search_s(baseHBACDN, scope, hbacFilter, hbacAttributes)

ALL_HBACSERVICES = l.search_s(baseHBACServicesDN, scope, hbacServiceFilter,
hbacServiceAttributes)

ALL_HBACSERVICEGROUPS = l.search_s(baseHBACServiceGroupsDN, scope,
hbacServiceGroupsFilter, hbacServiceGroupsAttributes)

# HBAC rules that apply to all servers
hbacAllServersFilter = "(&(objectclass=ipahbacrule)(hostCategory=all))"
HBACRULE_ALL_SERVERS = l.search_s(baseHBACDN, scope, hbacAllServersFilter,
hbacAttributes)

ALL_HOSTS.sort()

def findUID(user):
 uid = filter(lambda x: user in x, ALL_USERS)
 return uid[0][1]['uid'][0]

def findGroupMembers(groupname):
 if "cn=groups,cn" not in groupname:
  pass
 group = filter(lambda x: groupname in x, ALL_GROUPS)
 try:
  groupmembers = group[0][1]['member']
 except:
  groupmembers = ""
 for user in groupmembers:
  if "cn=groups,cn" in user:
   for i in findGroupMembers(user):
    yield i
  else:
   yield (findUID(user))

def findServiceName(service_name):
 s = filter(lambda x: service_name in x, ALL_HBACSERVICES)
 return s[0][1]['cn'][0]

def findServiceGroupMembers(service_group):
 allServices = []
 serviceGroup = filter(lambda x: service_group in x, ALL_HBACSERVICEGROUPS)
 serviceGroupMembers = serviceGroup[0][1]['member']
 for i in serviceGroupMembers:
  allServices.append(findServiceName(i))
 formattedAllServices = ', '.join(allServices)
 return formattedAllServices

def accessToAllSystems():
 allSystemsHBACRules = {}

 for hbacname in HBACRULE_ALL_SERVERS:
  hbacrule = filter(lambda x: hbacname[0] in x, ALL_HBACRULES)

  for hbacuser in hbacrule:
   services = []
   allowedUsers = []
   users = []
   groups = []

   try:
    users = filter(lambda x: "cn=users,cn" in x, hbacuser[1]['memberUser'])
   except:
    users = []

   try:
    groups = filter(lambda x: "cn=groups,cn" in x,
hbacuser[1]['memberUser'])
   except:
    groups = []

   try:
    hbacservice = hbacuser[1]['memberService']
    for i in hbacservice:
     if "hbacservicegroups,cn" in i:
      services.append(findServiceGroupMembers(i))
     else:
      services.append(findServiceName(i))
   except:
    try:
     services = hbacuser[1]['serviceCategory'][0]
    except:
     services = ['None']

   for i in users:
    allowedUsers.append(findUID(i))

   for i in groups:
    allowedUsers += (findGroupMembers(i))

  allSystemsHBACRules[hbacrule[0][0]] = {'services': services,
'allowedUsers': allowedUsers}

 return allSystemsHBACRules

def mergeD(results,services):
 for k in results:
  if services == results[k]['services']:
   return "MATCH!!", k

def nestedL(l):
 if isinstance(l, str):
  yield l
 for k in l:
  if isinstance(k, list):
   for i in k:
    yield i
  if isinstance(k, str):
   yield k

def main():
 for entry in ALL_HOSTS:
  systemWide = {}
  HBACAllowedList = {}
  results = {}
  x = 1

  fqdn = entry[1]['fqdn'][0]

  print "HOSTNAME = ", fqdn
  try:
   membership = filter(lambda x: "hbac,dc" in x, entry[1]['memberOf'])
  except:
   membership = []

  for hbacname in membership:
   hbacrule = filter(lambda x: hbacname in x, ALL_HBACRULES)
   for hbacuser in hbacrule:
    allowedUsers = []
    allowedUsersLst = []
    users = []
    groups = []
    services = []
    try:
     hbacservice = hbacuser[1]['memberService']
     for i in hbacservice:
      if "hbacservicegroups,cn" in i:
       services.append(findServiceGroupMembers(i))
      else:
       services.append(findServiceName(i))
    except:
     try:
      services = hbacuser[1]['serviceCategory'][0]
     except:
      services = []
    try:
     users = filter(lambda x: "cn=users,cn" in x, hbacuser[1]['memberUser'])
    except:
     users = []

    try:
     groups = filter(lambda x: "cn=groups,cn" in x,
hbacuser[1]['memberUser'])
    except:
     groups = []

    for i in users:
     allowedUsers.append(findUID(i))

    for i in groups:
     allowedUsers += findGroupMembers(i)

    HBACAllowedList[hbacrule[0][0]] = {'services': services,
'allowedUsers': allowedUsers}

  systemWide = accessToAllSystems()
  HBACAllowedList.update(accessToAllSystems())

  for key, value in HBACAllowedList.iteritems():

   if isinstance(value['services'], list):
    services = ', '.join(value['services'])
   else:
    services = value['services']

   allowedUsers = value['allowedUsers']

   try:
    mark, key = mergeD(results,services)
   except:
    mark, key = (None, None)

   if mark == "MATCH!!":
    results[key]['allowedUsers'].append(allowedUsers)
   else:
    results[x] = {'services': services, 'allowedUsers': allowedUsers}
    x = x + 1

  for i in results:
   results_services = results[i]['services']

   results_allowedUsers = list(nestedL(results[i]['allowedUsers']))
   results_allowedUsersSet = set(results_allowedUsers)
   results_allowedUsersLst = list(results_allowedUsersSet)
   results_allowedUsersLst.sort()
   formatted_allowedUsers = ' '.join(results_allowedUsersLst)

   if not results_services:
    results_services = 'empty'
   if not formatted_allowedUsers:
    formatted_allowedUsers = 'empty'
   print "SERVICES = ", results_services
   print "ALLOWED USERS = ", formatted_allowedUsers, "\n"

main()

--------------------------------------------------

-------------------> sudo-report.py
#!/usr/bin/python
'''
 2016 - March - 2
 Author: Jerel Gilmer
'''

import os
import sys
import ldap

def print_usage():
 print "Usage: server-access-report.py <hostname>"
 print "This script generates the list of sudo rules for each server.\n"
 print "<hostname> - System hostname; This can be the short name\n"
 print "For report of all systems, use \'.\'\n"
 print "Make sure to set the below variables in the script:"
 print "\tDOMAIN: Domain component"
 print "\tLDAP_SERVER: LDAP server to be queried"
 print "\tLDAP_USER: LDAP user to query server; preferable a read-only
account"
 print "\tLDAP_PW: LDAP user's password\n"
 sys.exit(1)

try:
 server = str(sys.argv[1])
except:
 print_usage()

## LDAP Connection Info and bind to the LDAP server
## Uncomment and set these variables to the appropriate values
## Below are examples
#DOMAIN = "dc=sub,dc=example,dc=com"
#LDAP_SERVER = "ldap://ipaserver1";
#LDAP_USER = "uid=user1,cn=users,cn=compat," + DOMAIN
#LDAP_PW = "Password123"

try:
 DOMAIN
 LDAP_SERVER
 LDAP_USER
 LDAP_PW
except:
 print_usage()

l = ldap.initialize(LDAP_SERVER)

l.simple_bind_s(LDAP_USER,LDAP_PW)

## LDAP Search Variables
## Base DN for LDAP Searches
baseComputerDN = "cn=computers,cn=accounts," + DOMAIN
baseGroupDN =  "cn=groups,cn=accounts," + DOMAIN
baseUserDN = "cn=users,cn=accounts," + DOMAIN
baseSudoDN = "cn=sudorules,cn=sudo," + DOMAIN
baseSudoCmdDN = "cn=sudocmds,cn=sudo," + DOMAIN
baseSudoCmdGroupDN = "cn=sudocmdgroups,cn=sudo," + DOMAIN

## Default LDAP SCOPE
scope = ldap.SCOPE_SUBTREE

## Filter for LDAP Searches
compFilter = "(&(objectclass=ipahost)(fqdn=*" + server + "*))"
userFilter = "(objectclass=person)"
groupFilter = "(objectclass=ipausergroup)"
sudoFilter = "objectclass=ipasudorule"
sudoCmdFilter = "objectclass=ipasudocmd"
sudoCmdGroupFilter = "objectclass=ipasudocmdgrp"

## Attributes from LDAP Searches
compAttributes =  ['memberOf', 'fqdn']
userAttributes = ['uid']
groupAttributes = ['member']
sudoAttributes = ['memberUser', 'ipaSudoOpt', 'memberAllowCmd',
'hostCategory', 'cmdCategory']
sudoCmdAttributes = ['sudoCmd']
sudoCmdGroupAttributes = ['member']

## Perform LDAP searches and store results into array
ALL_HOSTS = l.search_s(baseComputerDN, scope, compFilter, compAttributes)

ALL_USERS = l.search_s(baseUserDN, scope, userFilter, userAttributes)

ALL_GROUPS = l.search_s(baseGroupDN, scope, groupFilter, groupAttributes)

ALL_SUDORULES = l.search_s(baseSudoDN, scope, sudoFilter, sudoAttributes)

ALL_SUDOCMDS = l.search_s(baseSudoCmdDN, scope, sudoCmdFilter,
sudoCmdAttributes)

ALL_SUDOCMDGROUPS = l.search_s(baseSudoCmdGroupDN, scope,
sudoCmdGroupFilter, sudoCmdGroupAttributes)

# Sudo rules that apply to all servers
sudoAllServersFilter = "(&(objectclass=ipasudorule)(hostCategory=all))"
SUDORULE_ALL_SERVERS = l.search_s(baseSudoDN, scope, sudoAllServersFilter,
sudoAttributes)

ALL_HOSTS.sort()

def findUID(user):
 uid = filter(lambda x: user in x, ALL_USERS)
 return uid[0][1]['uid'][0]

def findGroupMembers(groupname):
 if "cn=groups,cn" not in groupname:
  pass
 group = filter(lambda x: groupname in x, ALL_GROUPS)
 try:
  groupmembers = group[0][1]['member']
 except:
  groupmembers = ""
 for user in groupmembers:
  if "cn=groups,cn" in user:
   for i in findGroupMembers(user):
    yield i
  else:
   yield (findUID(user))

def findSudoCmds(sudo_cmd):
 s = filter(lambda x: sudo_cmd in x, ALL_SUDOCMDS)
 return s[0][1]['sudoCmd'][0]

def findSudoCmdGroupMembers(sudo_cmd_group):
 allSudoCmds = []
 sudoGroup = filter(lambda x: sudo_cmd_group in x, ALL_SUDOCMDGROUPS)
 sudoGroupMembers = sudoGroup[0][1]['member']
 for i in sudoGroupMembers:
  allSudoCmds.append(findSudoCmds(i))
 formattedAllSudoCmds = ', '.join(allSudoCmds)
 return formattedAllSudoCmds

def sudoOnAllSystems():
 allSystemsSudoRules = {}

 for sudoname in SUDORULE_ALL_SERVERS:
  sudorule = filter(lambda x: sudoname[0] in x, ALL_SUDORULES)

  for sudouser in sudorule:
   sudocmds = []
   allowedUsers = []
   allowedSudoCmd = []
   users = []
   groups = []

   try:
    sudoOptions = ['ipaSudoOpt']
   except:
    sudoOptions = []

   try:
    sudocmds = sudouser[1]['memberAllowCmd']
    for i in sudocmds:
     if "cn=sudocmdgroups,cn" in i:
      allowedSudoCmd.append(findSudoCmdGroupMembers(i))
     else:
      allowedSudoCmd.append(findSudoCmds(i))
   except:
    try:
     if sudouser[1]['cmdCategory']:
      allowedSudoCmd = sudouser[1]['cmdCategory'][0]
    except:
     allowedSudoCmd = ['None']

   try:
    sudocmdgroup = filter(lambda x: "cn=sudocmdgroups" in x,
sudouser[1]['memberAllowCmd'])
   except:
    sudocmdgroup = ''

   try:
    users = filter(lambda x: "cn=users,cn" in x, sudouser[1]['memberUser'])
   except:
    users = []

   try:
    groups = filter(lambda x: "cn=groups,cn" in x,
sudouser[1]['memberUser'])
   except:
    groups = []

   for i in users:
    allowedUsers.append(findUID(i))

   for i in groups:
    allowedUsers += (findGroupMembers(i))

  allSystemsSudoRules[sudorule[0][0]] = {'sudoCommands': allowedSudoCmd,
'allowedUsers': allowedUsers}

 return allSystemsSudoRules

def mergeD(results,allowedSudoCmd):
 for k in results:
  if allowedSudoCmd == results[k]['sudoCommands']:
   return "MATCH!!", k

def nestedL(l):
 if isinstance(l, str):
  yield l
 for k in l:
  if isinstance(k, list):
   for i in k:
    yield i
  if isinstance(k, str):
   yield k

def main():
 for entry in ALL_HOSTS:
  SudoAllowedList = {}
  results = {}
  x = 1

  fqdn = entry[1]['fqdn'][0]

  print "HOSTNAME = ", fqdn

  try:
   membership = filter(lambda x: "sudo,dc" in x, entry[1]['memberOf'])
  except:
   membership = []

  for sudoname in membership:
   sudorule = filter(lambda x: sudoname in x, ALL_SUDORULES)
   for sudouser in sudorule:
    allowedUsers = []
    allowedUsersLst = []
    allowedSudoLst = []
    allowedSudoCmd = []
    users = []
    groups = []

    try:
     sudoOptions = ['ipaSudoOpt']
    except:
     sudoOptions = []

    try:
     sudocmds = sudouser[1]['memberAllowCmd']
     for i in sudocmds:
      if "cn=sudocmdgroups,cn" in i:
       allowedSudoCmd.append(findSudoCmdGroupMembers(i))
      else:
       allowedSudoCmd.append(findSudoCmds(i))
    except:
     try:
      if sudouser[1]['cmdCategory']:
       allowedSudoCmd = sudouser[1]['cmdCategory'][0]
     except:
      allowedSudoCmd = ['None']

    try:
     users = filter(lambda x: "cn=users,cn" in x, sudouser[1]['memberUser'])
    except:
     users = []

    try:
     groups = filter(lambda x: "cn=groups,cn" in x,
sudouser[1]['memberUser'])
    except:
     groups = []

    for i in users:
     allowedUsers.append(findUID(i))

    for i in groups:
     allowedUsers += findGroupMembers(i)

    SudoAllowedList[sudorule[0][0]] = {'sudoCommands': allowedSudoCmd,
'allowedUsers': allowedUsers}

  systemWide = sudoOnAllSystems()
  SudoAllowedList.update(systemWide)

  for key, value in SudoAllowedList.iteritems():

   if isinstance(value['sudoCommands'], list):
    allowedSudoCmd = ', '.join(value['sudoCommands'])
   else:
    allowedSudoCmd = value['sudoCommands']

   allowedUsers = value['allowedUsers']

   try:
    mark, key = mergeD(results,allowedSudoCmd)
   except:
    mark, key = (None, None)

   if mark == "MATCH!!":
    results[key]['allowedUsers'].append(allowedUsers)
   else:
    results[x] = {'sudoCommands': allowedSudoCmd, 'allowedUsers':
allowedUsers}
    x = x + 1

  for i in results:
   results_allowedSudoCmd = results[i]['sudoCommands']

   results_allowedUsers = list(nestedL(results[i]['allowedUsers']))
   results_allowedUsersSet = set(results_allowedUsers)
   results_allowedUsersLst = list(results_allowedUsersSet)
   results_allowedUsersLst.sort()
   formatted_allowedUsers = ' '.join(results_allowedUsersLst)

   if not results_allowedSudoCmd:
    results_services = 'empty'
   if not formatted_allowedUsers:
    formatted_allowedUsers = 'empty'
   print "SUDO COMMANDS = ", results_allowedSudoCmd
   print "ALLOWED USERS = ", formatted_allowedUsers, "\n"

main()

------------------------------------------------
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to