Secure
Let’s take a few steps to block casual access, stop using the admin account, and validate the certificates we’re using.
LDAP
Require Passwords
By default, the LDAP server allows anonymous connections to read all the user entry data. Let’s prevent that by disabling anonymous binds.
Before we make any changes, this anonymous bind and search will return all the entries.
ldapsearch -x -LLL -b dc=example,dc=org
Let’s create a LDIF config file to disable that, load it and test again
vi disable_anon_bind.ldif
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon
# Modify the config
ldapmodify -H ldapi:/// -Y EXTERNAL -f disable_anon_bind.ldif
# An anonymous bind will now fail
ldapsearch -x -LLL -b dc=example,dc=org
# An authenticated search will succeed
ldapsearch -x -LLL -W -D cn=admin,dc=example,dc=org -b dc=example,dc=org
Require Encryption
OpenLDAP accepts TLS connections, but it doesn’t require it. Now that we’re requiring passwords we should also require encryption. NOTE make sure systems talking to your LDAP server can use TLS and ignore/trust the Let’s Encrypt trust chain.
vi require-tls.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcSecurity
olcSecurity: tls=1
ldapmodify -H ldapi:// -Y EXTERNAL -f require-tls.ldif
See if it requires encryption.
# Test without -ZZ for no TLS
ldapsearch -x -LLL -W -D cn=admin,dc=example,dc=org -b dc=example,dc=org -h wifi.example.org
Enter LDAP Password:
ldap_bind: Confidentiality required (13)
additional info: TLS confidentiality required
Create Service Accounts
Services should have their own accounts, so let’s create one for FreeRADIUS and a theoretical Identity Management Service. These accounts bind directly so we’ll set their passwords traditionally.
vi service_accts.ldif
dn: cn=FreeRADIUS,dc=example,dc=org
objectClass: person
cn: FreeRADIUS
sn: Server
description: service
dn: cn=IDM,dc=example,dc=org
objectClass: person
cn: IDM
sn: Server
description: service
ldapadd -x -W -D cn=admin,dc=example,dc=org -f service_accts.ldif
ldappasswd -x -W -D cn=admin,dc=example,dc=org -S cn=FreeRADIUS,dc=example,dc=org
ldappasswd -x -W -D cn=admin,dc=example,dc=org -S cn=IDM,dc=example,dc=org
Add ACLs
The password attribute is protected by default. The FreeRADIUS account must read and the IDM account write it, so lets replace the ACL on that attribute.
vi FreeRADIUS-IDM-password.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by dn="cn=FreeRADIUS,dc=example,dc=org" read by dn="cn=IDM,dc=example,dc=org" write by * none
olcAccess: {1}to attrs=shadowLastChange by self write by * read
olcAccess: {2}to * by * read
The IDM account also gets the ability to manage the whole folder, so as to add and delete people.
vi IDM-Access.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {2}to dn.exact="ou=people,dc=example,dc=org" attrs=children by dn="cn=IDM,dc=example,dc=org" manage
olcAccess: {3}to dn.children="ou=people,dc=example,dc=org" by dn="cn=IDM,dc=example,dc=org" manage
ldapmodify -Y EXTERNAL -H ldapi:/// -f FreeRADIUS-IDM-password.ldif
ldapmodify -Y EXTERNAL -H ldapi:/// -f idm-access.ldif
The FreeRADIUS user should now be able to query a user and see their password value
ldapsearch -x -LLL -W -D cn=FreeRADIUS,dc=example,dc=org -b dc=example,dc=org
...
userPassword:: .....
If you mess something up and need to reset ACLs, or understand more about the rules, see the miscellany.
RADIUS
Use New Account
Now that you’ve created an account for FreeRADIUS, you should go back and update it’s connection and test that it still works.
vi /etc/freeradius/3.0/mods-available/ldap
identity = 'cn=FreeRADIUS,dc=example,dc=org'
password = somePasswordYouSet
Validate Certs
The server processes themselves are not validating the certs and that’s bad form. We’ve been skipping validation because in the past it was a hurdle. But Debian 12 and later include the ISRG Root X1 that Let’s Encrypt uses. Let’s test that now.
# And test with the CA option.
# You need to make sure the host name matches
echo 127.0.1.1 wifi.example.org >> /etc/hosts
ldapsearch -x -LLL -W -ZZ -D cn=admin,dc=example,dc=org -b dc=example,dc=org -h wifi.example.org
If this works as expected, you can attempt setting validate in the RADIUS settings.
vi /etc/freeradius/3.0/mods-available/ldap
start_tls = yes
ca_file = /etc/ssl/certs/ca-certificates.crt
require_cert = 'demand'
If these don’t work, you can compile a trust chain as described in the miscellany.
Troubleshooting
LDAP Error Messages
main: TLS init def ctx failed: -1
slapd can’t read the cert. Check the groups and unix permissions.
ldap_start_tls: Connect error (-11)
Check that the file you are specifying in ldapsearch, such LDAPTLS_CACERT=/root/r3-x1.pem, is actually available. Make sure you are using the -h and that the host you are connecting to matches the CN in the certificate. If it’s different, you’ll need to use a hosts file entry to trick the client
Nothing useful in logs
You can increase the log level from ‘stats’ to ‘args` with an ldapmodify. Just make sure to put it back when you’re done.
vi loglevel.ldif
dn: cn=config
changetype:modify
replace: olcLoglevel
#olcLoglevel: stats
olcLoglevel: args
ldapmodify -Y EXTERNAL -H ldapi:/// -b cn=config -D cn=config -s base -LLL -W -f loglevel.ldif
Next Steps
You’ve done a lot of work to get to this point where you can finally apply some Role Based Access Controls with Dynamic VLAN assignment.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.