To get a user's nested group membership in the LDAP-Group attribute, you need to use the membership_filter configuration item, rather than membership_attribute, using the appropriate Active Directory extended match filter: membership_filter = "(member:1.2.840.113556.1.4.1941:=%{control:${..user_dn}})" This causes FreeRADIUS to perform a second query to find groups which a user is a member of, rather than reading the memberOf attribute from the user's object (which doesn't include nested groups). There is a caveat (down to Active Directory behaviour), the user's primary group is not returned with either technique, and equally, nested groups which the user's primary group is a member of will not be returned. That's just how Active Directory chooses to present group membership in LDAP queries. As for categorising your clients, you can add other values to the client definition e.g. client switches { ipaddr = 10.0.1.0/24 secret = XXX sensitive = yes } Then you can refer to %{client:sensitive} in your policy On 21/04/2022 23:53, Braden McGrath via Freeradius-Users wrote:
FR users & maintainers,
I have a functional FreeRADIUS installation (3.0.20 - I know it's slightly old, it's from the Ubuntu repo - on Ubuntu 20.04LTS), being used for management access and authorization on varied network equipment at an ISP (not everything supports TACACS so we're using RADIUS).
When I first setup this system, Alan and other members of this group gave me a bunch of help and I threw together a policy.d file (called "group_authz") that is querying for LDAP group membership, and then altering the replies back to the various NASes with specific attributes to grant read-only or read-write permissions on the devices. I was originally told by my boss that a universal read-only and read-write group would be sufficient, so it was pretty easy to check for membership in one of those two groups and then just send back specific attributes depending on %{client:nas_type}.
Of course, now the goalposts have shifted. I've been told that we need "tiered" access. Some users (tier 2 NOC team) should get R/W to most of the network, but should *not* have any access at all to some of the more sensitive gear (core/datacenter network stuff). Others (tier 1 NOC team) should get only R/O to the same chunk of network, but not the sensitive stuff. We still need a "full R/W" (tier3/architects) and "full R/O" (probably won't get used much, but just in case) as well.
I'm now trying to figure out the "best" / most elegant way to handle this new requirement. I'm thinking that it would be helpful to use group nesting to make things more simple on the LDAP side, but I don't know if LDAP-Group[*] will catch nested membership (user is a member of group X, which is a member of group Y - does LDAP-Group show group Y)? I'll also need to define the "sensitive" gear somehow (either via NAS name or IP address as defined in clients.conf) and return a reject for those cases...
Below is the entirety of my "group_authz" file from policy.d/ so you know what I'm doing now. I am far from a developer, so I'm open to any and all ideas to improve this (in case I've done something stupid), as well as meet my new "tiered" requirements.
Thanks all! Braden McGrath braden@big-geek.net
group_authz { if (&LDAP-Group[*] == "cn=network-fulladmin,${modules.ldap.group.base_dn}") { switch "%{client:nas_type}" { case mikrotik { # For Mikrotik routers update reply { &Mikrotik-Group := "full" } return }
case dell_os10 { # For Dell OS10 switches update reply { &Cisco-AVPair += 'shell:roles="sysadmin"' } return }
case juniper { # For Juniper / JunOS devices update reply { &Juniper-Local-User-Name := "SUPER" } return }
case cisco { update reply { &Cisco-AVPair += "shell:priv-lvl=15" # &Service-Type := "Administrative-User" } return }
case awplus { # AlliedWare Plus - Allied Telesis switches (and others) # https://www.alliedtelesis.com/sites/default/files/documents/configuration-gu... # NOTE: AWPlus treats any Service-Type other than "Administrative-User" or "NAS-Prompt-User" as ACCESS-REJECT update reply { &Service-Type := "Administrative-User" } return }
case { # default case - shouldn't ever match! update reply { &Reply-Message := "Could not find NAS_Type - check clients.conf?" } reject } } # debug_reply return } elsif (&LDAP-Group[*] == "cn=network-readonly,${modules.ldap.group.base_dn}") { switch "%{client:nas_type}" { case mikrotik { # Obviously, this group gets read access... update reply { &Mikrotik-Group := "read" } return } case dell_os10 { # On the Dells, this allows normal "op" actions but can't read/dump config update reply { &Cisco-AVPair += 'shell:roles="netoperator"' } return } case juniper { # true read-only for now, can use "OPR" if we want to allow clearing counters / etc update reply { &Juniper-Local-User-Name := "RO" } return }
case cisco { update reply { # priv-lvl=1 is basic RO / not-enabled on Cisco, not "7" like Allied Telesis &Cisco-AVPair += "shell:priv-lvl=1" #&Service-Type := "NAS-Prompt-User" } return }
case awplus { # this should be readonly/show commands for Allied Telesis # Definitely need both of these for priv7 level, drop the AVPair for just priv1 update reply { &Cisco-AVPair += "shell:priv-lvl=7" &Service-Type := "NAS-Prompt-User" } return }
case { # default case, shouldn't ever match update reply { &Reply-Message := "Could not find NAS_Type - check clients.conf?" } reject } } return } else { update reply { &Reply-Message := "User not authorized - check directory/LDAP group membership" } reject } } - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
-- Nick Porter Porter Computing Ltd Registered in England No 12659380