Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
technical:fr-ldap [2026/07/23 09:38] systemtechnical:fr-ldap [2026/07/26 18:39] (current) – [Configure OpenLDAP for ldaps] system
Line 138: Line 138:
 modifyTimestamp: 20260722184313Z modifyTimestamp: 20260722184313Z
 </code> </code>
 +  * Now that we have a working LDAP setup we can configure FreeRADIUS to work with this LDAP server.
 +  * 
 +===== FreeRADIUS + LDAP =====
 +  * We assume the following:
 +    * You have installed the OpenLDAP server on the same host that FreeRADIUS is installed on.
 +    * You have a clean install of FreeRADIUS. (default config)
 +<alert type="info">
 +  * If you have installed RADIUSdesk on the host it will have a modified FreeRADIUS config.
 +  * You can however activate the default config again with the following steps
 +<code bash>
 +sudo su
 +service freeradius stop
 +cd /etc
 +mv /etc/freeradius /etc/freeradius.rd
 +cp -r /etc/freeradius.orig /etc/freeradius
 +chown -R freerad:freerad /etc/freeradius
 +
 +</code>
 +</alert>
 +
 +==== Enable the FreeRADIUS LDAP Module ====
 +  * FreeRADIUS keeps available modules in one directory and active ones in another. 
 +  * Enable the LDAP module by creating a symbolic link.
 +<code bash>
 +sudo su
 +# Navigate to the enabled modules directory
 +cd /etc/freeradius/3.0/mods-enabled/
 +
 +# Link the LDAP configuration module
 +sudo ln -s ../mods-available/ldap .
 +</code>
 +====  Map FreeRADIUS to OpenLDAP ====
 +  * Edit the module configuration file to point FreeRADIUS to your local OpenLDAP instance.
 +  * Edit ///etc/freeradius/3.0/mods-available/ldap// and update these core lines:
 +<code bash>
 +ldap {
 +    # LDAP server connection parameters
 +    server = "localhost"
 +    port = 389
 +
 +    # Identity used to search the directory
 +    identity = "cn=admin,dc=radiusdesk,dc=com"
 +    password = testing123
 +
 +    # Base DN where user lookups will begin
 +    base_dn = "dc=radiusdesk,dc=com"
 +
 +    # User lookup mapping filter
 +    update {
 +        control:Password-With-Header += 'userPassword'
 +    }
 +
 +    user {
 +        base_dn = "ou=people,dc=radiusdesk,dc=com"
 +        filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
 +    }
 +}
 +</code>
 +
 +==== Check the Default Virtual Server ====
 +  * You must instruct FreeRADIUS to check the LDAP backend during incoming connection requests.
 +  * Open /etc/freeradius/3.0/sites-enabled/default and confirm the following is in the authorize block
 +<code bash>
 +#
 +#  The ldap module reads passwords from the LDAP database.
 +-ldap
 +</code>
 +  * The **-** prefix to **ldap** means it will silently be ignored when the LDAP module is not enabled.
 +
 +
 +==== Test it out ====
 +  * Test the RADIUS authentication to confirm if it is working as intended
 +  * Start FreeRADIUS in debug mode
 +<code bash>
 +sudo systemctl stop freeradius
 +sudo freeradius -X
 +</code>
 +  * Use the radtest program to do a test authentication.
 +<code bash>
 +radtest testuser mysecretpassword localhost 1812 testing123
 +#This is the return on my setup
 +Sent Access-Request Id 249 from 0.0.0.0:56819 to 127.0.0.1:1812 length 78
 + User-Name = "testuser"
 + User-Password = "mysecretpassword"
 + NAS-IP-Address = 127.0.1.1
 + NAS-Port = 1812
 + Message-Authenticator = 0x00
 + Cleartext-Password = "mysecretpassword"
 +Received Access-Accept Id 249 from 127.0.0.1:1812 to 127.0.0.1:56819 length 38
 + Message-Authenticator = 0x216fe46614354e897d645ce27ec9e0d8
 +</code>
 +  * Lets look at the LDAP module's debug output in FreeRADIUS
 +<code bash>
 +rlm_ldap (ldap): Reserved connection (1)
 +(2) ldap: EXPAND (uid=%{%{Stripped-User-Name}:-%{User-Name}})
 +(2) ldap:    --> (uid=testuser)
 +(2) ldap: Performing search in "ou=people,dc=radiusdesk,dc=com" with filter "(uid=testuser)", scope "sub"
 +(2) ldap: Waiting for search result...
 +(2) ldap: User object found at DN "uid=testuser,ou=people,dc=radiusdesk,dc=com"
 +(2) ldap: Processing user attributes
 +(2) ldap: control:Password-With-Header += 'mysecretpassword'
 +rlm_ldap (ldap): Released connection (1)
 +Need 1 more connections to reach min connections (3)
 +Need more connections to reach 10 spares
 +rlm_ldap (ldap): Opening additional connection (7), 1 of 30 pending slots used
 +rlm_ldap (ldap): Connecting to ldap://localhost:389
 +rlm_ldap (ldap): Waiting for bind result...
 +rlm_ldap (ldap): Bind successful
 +(2)     [ldap] = updated
 +(2)     [expiration] = noop
 +(2)     [logintime] = noop
 +(2) pap: No {...} in Password-With-Header, re-writing to Cleartext-Password
 +(2) pap: Removing &control:Password-With-Header
 +(2)     [pap] = updated
 +(2)   } # authorize = updated
 +(2) Found Auth-Type = PAP
 +
 +</code>
 +  * Based on the debug output we can see the following happens when the ldap module is angaged
 +    * The LDAP module does a search for the user.
 +    * When the LDAP server replies with a result the LDAP module looks for the **userPassword** LDAP reply attribute.
 +    * This is the clear-text password of the user and **not all LDAP servers provides it**.
 +    * OpenLDAP does provide it (control:Password-With-Header += 'mysecretpassword')
 +    * It then tries an LDAP bind as the user to confirm the password is working.
 +    * If this worked it sets the Cleartext-Password so we can do PAP authentication. (Auth-Type = PAP)
 +  * Not all LDAP authentications works like this since not all LDAP servers will return the user's password in cleartext.
 +  * We will cover those later in the document.
 +
 +====== FreeRADIUS with Secure LDAP ======
 +  * When you plan to use any external LDAP server with FreeRADIUS they will typically be forcing you to connect securely via SSL/TLS on port 636.
 +  * In this section we will:
 +    * Create a PKI. This includes creating a CA with cert and key for slapd (OpenLDAP)
 +    * Configure OpenLDAP to also support **ldaps**.
 +    * Configure FreeRADIUS to communicate via ldaps with slapd (OpenLDAP).
 + 
 +===== Create PKI =====
 +==== Create the CA ====
 +  * Create a working directory
 +<code bash>
 +mkdir -p ~/pki
 +cd ~/pki
 +</code>
 +  * Generate the CA key
 +<code bash>
 +openssl genpkey -algorithm RSA -out ca.key -pkeyopt rsa_keygen_bits:4096
 +</code>
 +  * Create the CA certificate
 +<code bash>
 +openssl req -new -x509 -days 3650 -key ca.key -sha256 -out ca.crt
 +#### This is what we filled in ####
 +You are about to be asked to enter information that will be incorporated
 +into your certificate request.
 +What you are about to enter is what is called a Distinguished Name or a DN.
 +There are quite a few fields but you can leave some blank
 +For some fields there will be a default value,
 +If you enter '.', the field will be left blank.
 +-----
 +Country Name (2 letter code) [AU]:ZA
 +State or Province Name (full name) [Some-State]:Gauteng
 +Locality Name (eg, city) []:Johannesburg
 +Organization Name (eg, company) [Internet Widgits Pty Ltd]:RADIUSdesk.com
 +Organizational Unit Name (eg, section) []:PKI
 +Common Name (e.g. server FQDN or YOUR name) []:RADIUSdesk Internal Root CA
 +Email Address []:dirk@gmail.com
 +</code>
 +  * Keep **ca.key** secret.
 +
 +==== Generate the LDAP server key ====
 +  * Issue the following command:
 +<code bash>
 +openssl genpkey -algorithm RSA -out ldap.key -pkeyopt rsa_keygen_bits:4096
 +</code>
 +==== Create an OpenSSL configuration ====
 +  * Create ldap.conf. Use the following as reference.
 +<code>
 +[req]
 +default_bits = 4096
 +prompt = no
 +distinguished_name = dn
 +req_extensions = req_ext
 +
 +[dn]
 +CN = ldap.radiusdesk.com
 +
 +[req_ext]
 +subjectAltName = @alt_names
 +
 +[alt_names]
 +DNS.1 = ldap.radiusdesk.com
 +DNS.2 = ldap
 +IP.1  = 127.0.0.1
 +</code>
 +  * **Please Note**: The subjectAltName (SAN) is important. Modern TLS ignores the Common Name.
 +
 +==== Create the CSR ====
 +  * The following command will create the sign request:
 +<code bash>
 +openssl req -new -key ldap.key -out ldap.csr -config ldap.cnf
 +</code>
 +
 +==== Sign the request ====
 +  * The following command will use the sign request to create a certificate:
 +<code bash>
 +openssl x509 -req -in ldap.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out ldap.crt -days 825 -sha256 -copy_extensions copy
 +</code> 
 +  * Now you have the following files:
 +    * **ca.crt** - The CA public file
 +    * **ca.key** - The CA private file
 +    * **ldap.key** - The LDAP private file
 +    * **ldap.crt**  - The LDAP public file
 +
 +  * Everything is now in place in terms of our PKI for us to configure slapd (OpenLDAP) to support ldaps.
 +
 +===== Configure OpenLDAP for ldaps =====
 +  * Issue the following commands
 +<code bash>
 +sudo mkdir /etc/ldap/tls
 +#Copy the following files over
 +sudo cp ca.crt ldap.key ldap.crt /etc/ldap/tls
 +#Change their permissions
 +sudo chown openldap:openldap /etc/ldap/tls/*
 +sudo chmod 600 /etc/ldap/tls/ldap.key
 +sudo chmod 644 /etc/ldap/tls/*.crt
 +</code>
 +  * Configure slapd to use those files.
 +  * Create **tls.ldif** with the following contents
 +<code>
 +dn: cn=config
 +changetype: modify
 +replace: olcTLSCertificateFile
 +olcTLSCertificateFile: /etc/ldap/tls/ldap.crt
 +-
 +replace: olcTLSCertificateKeyFile
 +olcTLSCertificateKeyFile: /etc/ldap/tls/ldap.key
 +-
 +replace: olcTLSCACertificateFile
 +olcTLSCACertificateFile: /etc/ldap/tls/ca.crt
 +</code>
 +  * Apply it to the directory with the following commnand:
 +<code>
 +sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f tls.ldif
 +</code>
 +  * Enable LDAPS by editing **/etc/default/slapd**.
 +  * Look for the following section and change accordingly:
 +<code bash>
 +# slapd normally serves ldap only on all TCP-ports 389. slapd can also
 +# service requests on TCP-port 636 (ldaps) and requests via unix
 +# sockets.
 +# Example usage:
 +# SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"
 +#SLAPD_SERVICES="ldap:/// ldapi:///"
 +SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
 +</code bash>
 +  * Restart **slapd**.
 +<code>
 +sudo systemctl restart slapd
 +</code>
 +  * Confirm that it is now listening on port 636 also:
 +<code bash>
 +sudo ss -lnpt | grep 636
 +LISTEN 0      2048         0.0.0.0:636        0.0.0.0:   users:(("slapd",pid=698775,fd=11))                       
 +LISTEN 0      2048            [::]:636           [::]:   users:(("slapd",pid=698775,fd=12))      
 +</code>
 +  * To make the cert's FQDN work smooth add it to the /etc/hosts file (ldap.radiusdesk.com in our case).
 +<code>
 +127.0.0.1 localhost
 +127.0.1.1 xubuntu-24-4
 +127.0.0.1 ldap.radiusdesk.com
 +
 +# The following lines are desirable for IPv6 capable hosts
 +::1     ip6-localhost ip6-loopback
 +fe00::0 ip6-localnet
 +ff00::0 ip6-mcastprefix
 +ff02::1 ip6-allnodes
 +ff02::2 ip6-allrouters
 +</code>
 +  * Test the certificate with the following command:
 +<code>
 +openssl s_client -connect ldap.radiusdesk.com:636 -CAfile ca.crt
 +
 +#IT should end with something like this:
 +---
 +SSL handshake has read 3905 bytes and written 401 bytes
 +Verification: OK
 +---
 +New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
 +Server public key is 4096 bit
 +Secure Renegotiation IS NOT supported
 +Compression: NONE
 +Expansion: NONE
 +No ALPN negotiated
 +Early data was not sent
 +Verify return code: 0 (ok)
 +
 +</code>
 +  * You can now test with the ldapsearch utility. 
 +<WRAP center round important>
 +Important is to specify the CA cert (LDAPTLS_CACERT) that ldapsearch needs to use else if **will fail**.
 +</WRAP>
 +
 +<code>
 +LDAPTLS_CACERT=/etc/ldap/tls/ca.crt ldapsearch -H ldaps://ldap.radiusdesk.com -x -D "cn=admin,dc=radiusdesk,dc=com" -w testing123 -b dc=radiusdesk,dc=com
 +</code>
 +<WRAP center round tip>
 +  * If you want this CA to be part of the list of trusted CA's on the system you can do the following:
 +<code bash>
 +sudo cp /etc/ldap/tls/ca.crt /usr/local/share/ca-certificates/radiusdesk-ca.crt
 +sudo update-ca-certificates
 +#This is the output on our system
 +Updating certificates in /etc/ssl/certs...
 +rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
 +1 added, 0 removed; done.
 +Running hooks in /etc/ca-certificates/update.d...
 +Processing triggers for ca-certificates-java (20240118) ...
 +Adding debian:radiusdesk-ca.pem
 +done.
 +done.
 +#Now we can just use plain ldapsearch
 +ldapsearch -H ldaps://ldap.radiusdesk.com -x -D "cn=admin,dc=radiusdesk,dc=com" -w testing123 -b dc=radiusdesk,dc=com
 +</code>
 +</WRAP>
 +==== What does update-ca-certificates do? ====
 +I like to know how things work. If you also like to know how things work the following insert is for you :-)
 +  * The primary master CA file that is updated and can be used on Ubuntu is  **/etc/ssl/certs/ca-certificates.crt**
 +  * This command rebuilds the system's trusted certificate store by consolidating certificates from a few key locations:
 +    * **System Certificates:** The command reads the configuration file **/etc/ca-certificates.conf** to determine which certificates from **/usr/share/ca-certificates/** should be trusted.
 +    * **Local Certificates:** It automatically trusts all .crt files found in /usr/local/share/ca-certificates/. This is the place where we add our internal CA certificate.
 +  * **Output:** It then generates the single, concatenated bundle file at **/etc/ssl/certs/ca-certificates.crt**. This file is the master list used by many applications (like OpenSSL) to verify SSL/TLS connections.
 +
 +
 +
 +
 +
 +==== Update FreeRADIUS for ldaps:// ====
 +  * Do the following steps.
 +<code bash>
 +sudo su
 +#Copy the OpenLDAP's CA to FreeRADIUS
 +cp /etc/ldap/tls/ca /etc/freeradius/3.0/certs/ca.crt
 +</code>
 +  * Edit **/etc/freeradius/3.0/mods-enabled/ldap**
 +<code bash>
 +#Look for these items...
 +#server = 'localhost'
 +#---This has to match the cert' ubjectAltName (SAN)--- 
 +server = 'ldap.radiusdesk.com'
 +#       server = 'ldap.rrdns.example.org'
 +#       server = 'ldap.rrdns.example.org'
 +
 +#  Port to connect on, defaults to 389, will be ignored for LDAP URIs.
 +##port = 389
 +#--We specify the ldaps port--
 +port = 636
 +
 +#--- Then loop for the tls section
 +tls {
 +        # Set this to 'yes' to use TLS encrypted connections
 +        # to the LDAP database by using the StartTLS extended
 +        # operation.
 +        #
 +        # The StartTLS operation is supposed to be
 +        # used with normal ldap connections instead of
 +        # using ldaps (port 636) connections
 +        
 +        #--- Disable start_tls since we are forcing ssl/tls ---
 +        
 +        #start_tls = yes
 +
 +#               ca_file = ${certdir}/cacert.pem
 +
 +       #--- The CA file from OpenLDAP--
 +       
 +        ca_file = /etc/freeradius/3.0/certs/ca.crt
 +
 +#               ca_path = ${certdir}
 +#               certificate_file = /path/to/radius.crt
 +#               private_key_file = /path/to/radius.key
 +#               random_file = /dev/urandom
 +
 +        #  Certificate Verification requirements.  Can be:
 +        #    'never' (do not even bother trying)
 +        #    'allow' (try, but don't fail if the certificate
 +        #               cannot be verified)
 +        #    'demand' (fail if the certificate does not verify)
 +        #    'hard'  (similar to 'demand' but fails if TLS
 +        #             cannot negotiate)
 +        #
 +        #  The default is libldap's default, which varies based
 +        #  on the contents of ldap.conf.
 +
 +        #---Enforce FreeRADIUS to check the validity of the certificate ---
 +        
 +        require_cert    = 'demand'
 +
 +        #
 +        #  Check the CRL, as with the EAP module.
 +        #
 +</code>
 +  * After you made these changes, restart FreeRADIUS in debug mode and to a test authentication to confirm that it is now using ldaps (port 636)
 +  * See the results from out setup below:
 +<code bash>
 +rlm_ldap (ldap): Reserved connection (3)
 +(3) ldap: EXPAND (uid=%{%{Stripped-User-Name}:-%{User-Name}})
 +(3) ldap:    --> (uid=testuser)
 +(3) ldap: Performing search in "ou=people,dc=radiusdesk,dc=com" with filter "(uid=testuser)", scope "sub"
 +(3) ldap: Waiting for search result...
 +(3) ldap: User object found at DN "uid=testuser,ou=people,dc=radiusdesk,dc=com"
 +(3) ldap: Processing user attributes
 +(3) ldap: control:Password-With-Header += 'mysecretpassword'
 +rlm_ldap (ldap): Released connection (3)
 +Need more connections to reach 10 spares
 +rlm_ldap (ldap): Opening additional connection (7), 1 of 25 pending slots used
 +rlm_ldap (ldap): Connecting to ldap://ldap.radiusdesk.com:636
 +rlm_ldap (ldap): Waiting for bind result...
 +rlm_ldap (ldap): Bind successful
 +
 +</code>
 +
 +
 +
 +
 +
  
  
  
  
  • technical/fr-ldap.1784792338.txt.gz
  • Last modified: 2026/07/23 09:38
  • by system