ldap redundant-load-balance sanity check and questions
There was a thread a few days ago that caused me to relook at how to configure failover for multiple ldap backends. After a lot of reading, a lot more trial and error, I have an apparently functioning solution. Is there anything glaringly wrong with this configuration? Also, I didn't have any luck finding end to end examples so also hoping this will help if anyone else is trying to figure out a similar setup. First, my setup. I started with a fresh build, installed FR 3.2 from the networkradius repo. I added to radiusd.conf in the instantiate stanza: redundant-load-balance redundant_ldap { server1 server2 server3 } I edited mods-available/ldap: ldap server1 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap1.example.net' } ldap server2 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap2.example.net' } ldap server3 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap3.example.net' } To make ldap more readable and save typing, next made a file in mods-config/files/ldap_server_info containing all the ldap data, user, group, filters, etc that are static between all 3 nodes. port = [...] identity = [...] password = [...] base_dn = [...] update { control:Password-With-Header += 'userPassword' control:NT-Password := 'sambaNTPassword' } user_dn = "LDAP-UserDn" user { [...] } group { [...] } accounting { [...] } # Post-Auth can modify LDAP objects too post-auth { update { description := "Authenticated at %S" } } # LDAP connection-specific options. options { [...] } tls { [...] } pool { [...] } Then, in sites-available/default Under authenticate I uncommented and cahnged the Auth-Type LDAP call to Auth-Type LDAP { redundant_ldap { } } Under authorize is where I have a few questions. What I finally did that works: (question #1) redundant_ldap if ((ok || updated) && User-Password && !control:Auth-Type) { update control { &Auth-Type := LDAP } #update session-state { ## ignore these, they were iterations trying to figure out how to combine Ldap-Group related to question 2 # #&control:Ldap-Group += &control:Ldap-Group[*] # &Ldap-Group += &Ldap-Group[*] #} } Finally, under post-auth I have it return back some groups/etc for various devices. It finally clicked that I had to list each ldap server instance for Ldap-Group. I tried a few different stackoverflow inspired answers of updating a session-state or similar but wasn't able to get any of those to work. (question 2) if (server1-Ldap-Group == "group1") || (server2-Ldap-Group == "group1") || (server3-Ldap-Group == "group1") { update reply { [...] } } elsif (server1-Ldap-Group == "group2") || (server2-Ldap-Group == "group2") || (server3-Ldap-Group == "group2") { update reply { [...] } } elsif (server1-Ldap-Group == "group3") || (server2-Ldap-Group == "group3") || (server3-Ldap-Group == "group3") { update reply { [...] } } else { update reply { [...] } } My questions: Foremost, where I had to comment out the update control auth-type, what is that step? I know this is a pretty basic question but either I couldn't find in the docs (I'm sure it's there I just don't know what to look for), or didn't understand if I did find it, what is that update call actually doing? I tried a few different versions and when the config check ran cleanly I stopped messing with it. I get appropriate answers from radtest, I just am not sure what is happening. I actually had all of the update block commented out, so just "if (( ok... )) {}" with nothing between the braces and it works, which is the reason for the question. I assume this is an example as stated in the docs to not mess with auth-type but let the server "just figure it out", but wanted to make sure. Question 2 - is there a better way of handling multiple server[n]-Ldap-Group responses? I've tried to follow https://stackoverflow.com/questions/58187426/freeradius-problem-with-redunda... but wasn't exactly sure where those stanzas needed to go, or if rlb_ldap was a typo, or what. (P.S. as I type that, I realize where rlb_ldap came from, that is the instance name the question gave to the redundant-load-balance.) Either way, while server[n]-Ldap-Group works, it's cumbersome to expand with ansible so I'm hoping there's a more elegant way that I'm just not seeing. Thank you in advance! Brantley Padgett The question is not how far. The question is, do you possess the constitution, the depth of faith, to go as far as is needed? -Boondock Saints
On Oct 11, 2022, at 4:55 PM, Brantley Padgett via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
There was a thread a few days ago that caused me to relook at how to configure failover for multiple ldap backends. After a lot of reading, a lot more trial and error, I have an apparently functioning solution. Is there anything glaringly wrong with this configuration?
If it works...
Also, I didn't have any luck finding end to end examples so also hoping this will help if anyone else is trying to figure out a similar setup.
There are rarely documentation pages which describe everything people want to do. You really do have to put the pieces together yourself. It's usually nor hard, it just takes care and attention.
First, my setup. I started with a fresh build, installed FR 3.2 from the networkradius repo.
I added to radiusd.conf in the instantiate stanza: redundant-load-balance redundant_ldap { server1 server2 server3 }
That's good.
I edited mods-available/ldap:
ldap server1 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap1.example.net' } ldap server2 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap2.example.net' } ldap server3 { $INCLUDE ${modconfdir}/files/ldap_server_info server = 'ldap3.example.net' }
That's fine. I'd put those files somewhere else, as ${modconfdir}/files/ is intended for the "files" module. But it doesn't matter.
To make ldap more readable and save typing, next made a file in mods-config/files/ldap_server_info containing all the ldap data, user, group, filters, etc that are static between all 3 nodes.
That makes sense.
Then, in sites-available/default
Under authenticate I uncommented and cahnged the Auth-Type LDAP call to
Auth-Type LDAP { redundant_ldap { }
You don't need those brackets. Just do: Auth-Type LDAP { redundant_ldap }
Under authorize is where I have a few questions. What I finally did that works: (question #1)
redundant_ldap if ((ok || updated) && User-Password && !control:Auth-Type) { update control { &Auth-Type := LDAP
Yes. If you're using LDAP as an "oracle", you have to force Auth-Type = LDAP.
Finally, under post-auth I have it return back some groups/etc for various devices. It finally clicked that I had to list each ldap server instance for Ldap-Group
There is unfortunately no automatic failover with LDAP-Group. So yes, you have to check each LDAP server manually, by specifying the exact module: Server2-LDAP-Group, etc.
Foremost, where I had to comment out the update control auth-type, what is that step? I know this is a pretty basic question but either I couldn't find in the docs (I'm sure it's there I just don't know what to look for), or didn't understand if I did find it, what is that update call actually doing? I tried a few different versions and when the config check ran cleanly I stopped messing with it. I get appropriate answers from radtest, I just am not sure what is happening. I actually had all of the update block commented out, so just "if (( ok... )) {}" with nothing between the braces and it works, which is the reason for the question. I assume this is an example as stated in the docs to not mess with auth-type but let the server "just figure it out", but wanted to make sure.
Setting Auth-Type tells the server which "authenticate" sub-section to run. There are many different authentication methods, and there are many different ways to authenticate users. So it has to know somehow how the user us authenticated.
Question 2 - is there a better way of handling multiple server[n]-Ldap-Group responses?
Unfortunately, no. We're looking into fixing that for v4. Alan DeKok.
On 11/10/2022 23:47, Alan DeKok wrote:
On Oct 11, 2022, at 4:55 PM, Brantley Padgett via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote: Question 2 - is there a better way of handling multiple server[n]-Ldap-Group responses? Unfortunately, no. We're looking into fixing that for v4.
V3.2.x does allow you to set cache_attribue in the ldap module configuration. This is the attribute which cached group membership will be stored in when the ldap module is called in authorize (presuming appropriate settings are in place to cache group membership) If all the ldap instances are representing the same data, as would be normal in a redundant failover scenario, then it would be valid to set all instances to use the same attribute in which to cache the group membership e.g. cache_attribute = LDAP-Group Then, regardless of which ldap instance retrieves the group membership, it will be cached in the same attribute.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
-- Nick Porter
cache_attribute = LDAP-Group
I tried going that route but wasn't able to get the groups to return for the post-auth. Trying again just now, I added in the ldap_server_info common file: cacheable_name = 'yes' cache_attribute = 'LDAP-test' then in default I changed the first if test to be if (&LDAP-test == "group1") { #if (server1-Ldap-Group == "group1") || (server2-Ldap-Group == "group1") || (server3-Ldap-Group == "group1") { Running freeradius -Xx I see it adding the groups to "LDAP-test": Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Adding cacheable group object memberships Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "group1" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup2" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup" [...] Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Processing user attributes But it errors trying to return the cached name, or at least that's how I understood it: Wed Oct 12 08:34:26 2022 : Debug: (0) post-auth { Wed Oct 12 08:34:26 2022 : Debug: (0) if (&LDAP-test == "group1") { Wed Oct 12 08:34:26 2022 : ERROR: (0) Failed retrieving values required to evaluate condition I tried to follow the suggestions in this https://stackoverflow.com/questions/58187426/freeradius-problem-with-redunda... answer, but wasn't sure where the update call needed to go. I've tried putting in default, this for ldap in the authorize stanza: redundant_ldap if ((ok || updated) && User-Password && !control:Auth-Type) { update control { &Auth-Type := LDAP } update session-state { &LDAP-test += &LDAP-test[*] } } then under post auth: update { #&reply: += &session-state: &LDAP-test += &session-state:LDAP-test[*] } If I have just &session-state I see in the debug Wed Oct 12 08:58:26 2022 : Debug: (0) post-auth { Wed Oct 12 08:58:26 2022 : Debug: (0) update { Wed Oct 12 08:58:26 2022 : Debug: (0) No attributes updated for RHS &session-state:LDAP-test[*] Wed Oct 12 08:58:26 2022 : Debug: (0) } # update = noop which made me think I needed to add the name of the attribute, but then I get Wed Oct 12 09:04:24 2022 : Debug: (0) # Executing section post-auth from file /etc/freeradius/sites-enabled/default Wed Oct 12 09:04:24 2022 : Debug: (0) post-auth { Wed Oct 12 09:04:24 2022 : Debug: (0) update { Wed Oct 12 09:04:24 2022 : Debug: (0) No attributes updated for RHS &session-state:LDAP-test[*] Wed Oct 12 09:04:24 2022 : Debug: (0) } # update = noop but either way still get Wed Oct 12 09:04:24 2022 : Debug: (0) if (&LDAP-test == "group1") { Wed Oct 12 09:04:24 2022 : ERROR: (0) Failed retrieving values required to evaluate condition I'm sure Allan's answer and yours are the right way, I'm just not clear how to get there. Brantley Padgett The question is not how far. The question is, do you possess the constitution, the depth of faith, to go as far as is needed? -Boondock Saints On Wednesday, October 12, 2022, 04:23:15 AM CDT, Nick Porter <nick@portercomputing.co.uk> wrote: On 11/10/2022 23:47, Alan DeKok wrote:
On Oct 11, 2022, at 4:55 PM, Brantley Padgett via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote: Question 2 - is there a better way of handling multiple server[n]-Ldap-Group responses? Unfortunately, no. We're looking into fixing that for v4.
V3.2.x does allow you to set cache_attribue in the ldap module configuration. This is the attribute which cached group membership will be stored in when the ldap module is called in authorize (presuming appropriate settings are in place to cache group membership) If all the ldap instances are representing the same data, as would be normal in a redundant failover scenario, then it would be valid to set all instances to use the same attribute in which to cache the group membership e.g. cache_attribute = LDAP-Group Then, regardless of which ldap instance retrieves the group membership, it will be cached in the same attribute.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
-- Nick Porter - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Oct 12, 2022, at 10:11 AM, Brantley Padgett via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
I tried going that route but wasn't able to get the groups to return for the post-auth. Trying again just now, I added in the ldap_server_info common file:
I recommend a careful reading of the debug output/
cacheable_name = 'yes' cache_attribute = 'LDAP-test'
then in default I changed the first if test to be
if (&LDAP-test == "group1") {
Just the name, which means that by default it's looking in the "request" list.
Running freeradius -Xx I see it adding the groups to "LDAP-test":
Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Adding cacheable group object memberships Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "group1" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup2" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup"
These are being added to the "control" list. See "man unlang"
[...] Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Processing user attributes
But it errors trying to return the cached name, or at least that's how I understood it:
No, it errors *finding* the cached name. Details matter.
Wed Oct 12 08:34:26 2022 : Debug: (0) post-auth { Wed Oct 12 08:34:26 2022 : Debug: (0) if (&LDAP-test == "group1") { Wed Oct 12 08:34:26 2022 : ERROR: (0) Failed retrieving values required to evaluate condition
I tried to follow the suggestions in this https://stackoverflow.com/questions/58187426/freeradius-problem-with-redunda... answer, but wasn't sure where the update call needed to go.
I've tried putting in default, this for ldap in the authorize stanza: redundant_ldap if ((ok || updated) && User-Password && !control:Auth-Type) { update control { &Auth-Type := LDAP } update session-state { &LDAP-test += &LDAP-test[*]
Again &control:LDAP-Test versus &LDAP-Test. They're different. You can't just assume that the server does what you want, even when you tell it to do different things. Alan eEKok.
These are being added to the "control" list.
I did not realize that was significant, but it does make sense. Changing the if test to &control:LDAP-test still bypassed the if condition. I finally re-read Arran's last comment to his answer on that SO question. Changing the if condition to if (&control:LDAP-test[*] == "[groupname]") successfully pulls back the group membership. Again, thank you Alan, Nick and Arran! Brantley Padgett The question is not how far. The question is, do you possess the constitution, the depth of faith, to go as far as is needed? -Boondock Saints On Wednesday, October 12, 2022, 10:36:06 AM CDT, Alan DeKok <aland@deployingradius.com> wrote: On Oct 12, 2022, at 10:11 AM, Brantley Padgett via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
I tried going that route but wasn't able to get the groups to return for the post-auth. Trying again just now, I added in the ldap_server_info common file:
I recommend a careful reading of the debug output/
cacheable_name = 'yes' cache_attribute = 'LDAP-test'
then in default I changed the first if test to be
if (&LDAP-test == "group1") {
Just the name, which means that by default it's looking in the "request" list.
Running freeradius -Xx I see it adding the groups to "LDAP-test":
Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Adding cacheable group object memberships Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "group1" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup2" Wed Oct 12 08:34:26 2022 : Debug: (0) server2: &control:LDAP-test += "somegroup"
These are being added to the "control" list. See "man unlang"
[...] Wed Oct 12 08:34:26 2022 : Debug: (0) server2: Processing user attributes
But it errors trying to return the cached name, or at least that's how I understood it:
No, it errors *finding* the cached name. Details matter.
Wed Oct 12 08:34:26 2022 : Debug: (0) post-auth { Wed Oct 12 08:34:26 2022 : Debug: (0) if (&LDAP-test == "group1") { Wed Oct 12 08:34:26 2022 : ERROR: (0) Failed retrieving values required to evaluate condition
I tried to follow the suggestions in this https://stackoverflow.com/questions/58187426/freeradius-problem-with-redunda... answer, but wasn't sure where the update call needed to go.
I've tried putting in default, this for ldap in the authorize stanza: redundant_ldap if ((ok || updated) && User-Password && !control:Auth-Type) { update control { &Auth-Type := LDAP } update session-state { &LDAP-test += &LDAP-test[*]
Again &control:LDAP-Test versus &LDAP-Test. They're different. You can't just assume that the server does what you want, even when you tell it to do different things. Alan eEKok.
participants (3)
-
Alan DeKok -
Brantley Padgett -
Nick Porter