User Tools

Site Tools


samba:freeradius-ad

Setting up Freeradius and Samba AD for WPA2 WiFi Auth

There are several steps to make this work, this is not a pure Samba article, but I think it's good to have it here in my notebook for my reference. Radius is quite a complex system, took me a while to make things work. Most of this has been possible with the help of Kees Van Vloten and his Freeradius Enterprise WiFi notes. They are presented here in a different fashion.

Steps to follow:

  • You already have a Samba member server joined to the domain. See Setting up a Member Server
  • You have created an AD permission group (named 'MAD\wifi' in our example) that contains all windows machines allowed to connect to wifi.
  • Configure Samba to allow ntlm_auth to use mschapv2 and ntlmv2
  • Create a PKI infrastructure to generate and maintain certificates
  • Install and configure Freeradius on a member server.
  • Install CA certificate in Windows clients

Configure Samba to allow ntlm_auth to use mschapv2 and ntlmv2

This one is pretty straight forward. Add the following line to /etc/samba/smb.conf in *all* your DCs

ntlm auth = mschapv2-and-ntlmv2-only

Save and restart samba AD DC

/etc/init.d/samba-ad-dc restart

Install EasyRSA to manage your PKI

EasyRSA is part of OpenVPN group and allows to very easily manage a simple (internal only) Public key infrastructure. See EasyRSA.

You do not need root privileges to run EasyRSA. This is a very simple collection of programs, it can be run in any machine, any server, it has no dependencies with Samba or Freeradius.

git clone https://github.com/OpenVPN/easy-rsa
cd ~/easy-rsa/easyrsa3
cp vars.example vars

Edit ./vars file and have:

set_var EASYRSA_REQ_COUNTRY     "ES"
set_var EASYRSA_REQ_PROVINCE    "Madrid"
set_var EASYRSA_REQ_CITY        "Madrid"
set_var EASYRSA_REQ_ORG         "Caponato Enterprises"
set_var EASYRSA_REQ_EMAIL       "capo@caponato.es"
set_var EASYRSA_REQ_OU          "ITS"

In order to have a location for a CDP - Certificate Revocation List Distribution Point for your internal Certification Authority - edit ./x509-types/COMMON and:

authorityInfoAccess = caIssuers;URI:http://pki.caponato.es/pki/ca.crt
crlDistributionPoints = URI:http://pki.caponato.es/cdp/crl.pem

You need to set up a basic webserver, create a virtual host (in our example pki) and upload those files (ca.crt and crl.pem) when they are issued. Setting up the webserver is beyond the scope on this article.

See for better and longer explanations:

I named my radius server “radius-1”

cd ~/easy-rsa/easyrsa3
./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-req radius-1 nopass
./easyrsa sign-req server radius-1
./easyrsa gen-crl

Upload your CA and CRL to your PKI webserver Please not your destination directories in the web server will be different :

Please note, if you revoke any certificate, you must copy generate the nee CRL file, and re-distribute it to your pki webserver, create your CA / CRL combo file and redistribute. See hereunder.

cd ~/easy-rsa/easyrsa3
rsync ./pki/ca.crt pki:/var/www/html/pki/
rsync ./pki/crl.pem  pki:/var/www/html/cdp/

Copy your newly generated certificates to your radius server: Private key, Public key, CA cert, and CRL certificates :

cd ~/easy-rsa/easyrsa3
rsync -av ./pki/private/radius-1.key radius-1:/etc/ssl/private/ 
rsync -av ./pki/issued/radius-1.crt radius-1:/etc/ssl/certs/
rsync -av ./pki/ca.crt radius-1:/etc/ssl/certs/ca-caponato.pem
rsync -av ./pki/crl.pem  radius-1:/etc/ssl/certs/crl-caponato.pem
# Pleaase note CA and and CRL certificates have been renamed for clarity
# Please note CA cert extension has been changed to pem - equivalent to crt

Log on to your radius-1 server and set up permissions for certificates correctly:

chmod 640 /etc/ssl/private/radius-1.key
chgrp ssl-cert /etc/ssl/private/radius-1.key
chmod 644 /etc/ssl/certs/radius-1.crt
chmod 644 /etc/ssl/certs/ca-caponato.pem
chmod 644 /etc/ssl/certs/crl-caponato.pem

Your certificates are all set and ready for Freeradius!

Install and configure Freeradius on a member server.

Install freeradius, and add freerad user to Winbind and SSL groups:

apt-get install freeradius freeradius-common freeradius-utils makepasswd
usermod -a -G winbindd_priv,ssl-cert freerad

Configuration steps:

Create a combined CA and CRL certificate:

cat /etc/ssl/certs/ca-caponato.pem /etc/ssl/certs/crl-caponato.pem > /etc/freeradius/3.0/ca_and_crl.pem  

Add this line to the top of /etc/freeradius/3.0/users with:

DEFAULT Auth-Type = ntlm_auth

Add this to /etc/freeradius/3.0/clients.conf:

# For each access-point add:
client <AP_HOSTNAME> {
       ipaddr = <AP_IPADDRESS>
       netmask = 32
       secret = <AP_SECRET>
       shortname = <AP_HOSTNAME>
}

Or, if you have a subnet with all APs in it - like my setup - you can do:

# For all access-points add:
client unifi-ap {
       ipaddr = 192.168.254.0/24
       secret = radius-24
       shortname = unifi-ap
}

Remove default configurations :

rm /etc/freeradius/3.0/sites-enabled/default
rm /etc/freeradius/3.0/sites-enabled/inner-tunnel

Replace /etc/freeradius/3.0/proxy.conf with the following, make sure you update your domain name at the end of the file, in my case “realm mad.caponato.es” in lowercase:

proxy server {
        default_fallback = no
}
home_server localhost {
        type = auth
        ipaddr = 127.0.0.1
        port = 1812
        secret = testing123
        response_window = 20
        zombie_period = 40
        revive_interval = 120
        status_check = status-server
        check_interval = 30
        check_timeout = 4
        num_answers_to_alive = 3
        max_outstanding = 65536
        coa {
                irt = 2
                mrt = 16
                mrc = 5
                mrd = 30
        }
        limit {
              max_connections = 16
              max_requests = 0
              lifetime = 0
              idle_timeout = 0
        }
}
home_server_pool samba_auth_failover {
        type = fail-over
        home_server = localhost
}
realm mad.caponato.es {
        auth_pool = samba_auth_failover
}
realm LOCAL {
}

Create /etc/freeradius/3.0/sites-available/samba_default

######################################################################
#
#   As of 2.0.0, FreeRADIUS supports virtual hosts using the
#   "server" section, and configuration directives.
#
#   Virtual hosts should be put into the "sites-available"
#   directory.  Soft links should be created in the "sites-enabled"
#   directory to these files.  This is done in a normal installation. 
#
#   If you are using 802.1X (EAP) authentication, please see also
#   the "inner-tunnel" virtual server.  You will likely have to edit
#   that, too, for authentication to work.
#
######################################################################

server default {
    listen {
        type = auth
        ipaddr = *
        port = 1812
        limit {
              max_connections = 16
              lifetime = 0
              idle_timeout = 30
        }
    }
    listen {
        ipaddr = *
        port = 1813
        type = acct
        limit {
              max_connections = 16
              lifetime = 0
              idle_timeout = 30
        }
    }
    authorize {
        filter_username
        preprocess
        eap {
            ok = return
            #updated = return
        }
        expiration
        logintime
    }
    authenticate {
        eap
    }
    preacct {
        preprocess
        acct_unique
    }
    accounting {
        detail
        attr_filter.accounting_response
    }
    post-auth {
        update {
            &reply: += &session-state:
        }
        # For Exec-Program and Exec-Program-Wait
        exec
        #  Remove reply message if the response contains an EAP-Message
        remove_reply_message_if_eap
        Post-Auth-Type REJECT {
            attr_filter.access_reject
            # Insert EAP-Failure message if the request was rejected by policy instead of because of an authentication failure
            eap
            #  Remove reply message if the response contains an EAP-Message
            remove_reply_message_if_eap
        }
    }
    post-proxy {
        #  You MUST also use the 'nostrip' option in the 'realm' configuration.  Otherwise, the User-Name attribute
        #  in the proxied request will not match the user name  hidden inside of the EAP packet, and the end server will
        #  reject the EAP request.
        eap
    }
}

Create /etc/freeradius/3.0/sites-available/samba_inner-tunnel

######################################################################
#
# This is a virtual server that handles *only* inner tunnel
# requests for EAP-TTLS and PEAP types.
#
######################################################################

server inner-tunnel {
    listen {
           ipaddr = 127.0.0.1
           port = 18120
           type = auth
    }
    authorize {
        filter_username
        mschap
        update control {
            &Proxy-To-Realm := LOCAL
        }
        eap {
            ok = return
        }
        expiration
        logintime
    }
    authenticate {
        ntlm_auth
        Auth-Type MS-CHAP {
            mschap
        }
        mschap
        eap
    }
    session {
        radutmp
    }
    post-auth {
        #  Instead of "use_tunneled_reply", change this "if (0)" to an "if (1)".
        if (0) {
            #  These attributes are for the inner-tunnel only, and MUST NOT be copied to the outer reply.
            update reply {
                User-Name !* ANY
                Message-Authenticator !* ANY
                EAP-Message !* ANY
                Proxy-State !* ANY
                MS-MPPE-Encryption-Types !* ANY
                MS-MPPE-Encryption-Policy !* ANY
                MS-MPPE-Send-Key !* ANY
                MS-MPPE-Recv-Key !* ANY
            }
            #  Copy the inner reply attributes to the outer session-state list.  The post-auth policy will take
            #  care of copying the outer session-state list to the outer reply.
            update {
                &outer.session-state: += &reply:
            }
        }
        Post-Auth-Type REJECT {
            attr_filter.access_reject
            update outer.session-state {
                &Module-Failure-Message := &request:Module-Failure-Message
            }
        }
    }
    post-proxy {
        eap
    }
}

Replace /etc/freeradius/3.0/mods-available/eap with (Please note the correct certificate paths from the steps above in 'Creating PKI infrastructure' ):

eap {
        default_eap_type = mschapv2
        timer_expire = 60
        ignore_unknown_eap_types = no
        cisco_accounting_username_bug = no
        max_sessions = ${max_requests}
        tls-config tls-common {
                # private_key_password = whatever (no password in our key file)
                # Please make sure paths are correct for certificates
                private_key_file = /etc/ssl/private/radius-1.key
                certificate_file = /etc/ssl/certs/radius-1.crt
                ca_file = /etc/freeradius/3.0/ca_and_crl.pem
                ca_path = ${cadir}
                check_crl = yes
                cipher_list = "DEFAULT"
                cipher_server_preference = no
                tls_min_version = "1.2"
                tls_max_version = "1.3"
                ecdh_curve = "prime256v1"
                cache {
                        enable = no
                        store {
                                Tunnel-Private-Group-Id
                        }
                }
                verify {
                }
        }
        tls {
                tls = tls-common
        }
        peap {
                tls = tls-common
                default_eap_type = mschapv2
                copy_request_to_tunnel = no
                use_tunneled_reply = no
                virtual_server = "inner-tunnel"
        }
        mschapv2 {
        }
}

Replace /etc/freeradius/3.0/mods-available/mschap with:

Please note, in this notebook we are using domain MAD, and the permission group for computers allowed to connect is 'MAD\wifi'

# Microsoft CHAP authentication
#
#  This module supports MS-CHAP and MS-CHAPv2 authentication.
#  It also enforces the SMB-Account-Ctrl attribute.
#
mschap {
    use_mppe = yes
    with_ntdomain_hack = yes
    require_encryption = yes
    require_strong = yes
    ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key \
	--allow-mschapv2 \
              --domain=MAD \
              --require-membership-of=MAD\wifi \
              --username=%{%{mschap:User-Name}:-00} \
              --challenge=%{%{mschap:Challenge}:-00} \
              --nt-response=%{%{mschap:NT-Response}:-00}"

    pool {
        start = ${thread[pool].start_servers}
        min = ${thread[pool].min_spare_servers}
        max = ${thread[pool].max_servers}
        spare = ${thread[pool].max_spare_servers}
        uses = 0
        retry_delay = 30
        lifetime = 86400
        cleanup_interval = 300
        idle_timeout = 600
    }
    passchange {
    }
}

Replace /etc/freeradius/3.0/mods-available/ntlm_auth with:

Again please note, in this notebook we are using domain MAD, and the permission group for computers allowed to connect is 'MAD\wifi'

exec ntlm_auth {
        wait = yes
        shell_escape = yes
        program = "/usr/bin/ntlm_auth --allow-mschapv2 --request-nt-key \
                   --domain=MAD \
                   --require-membership-of=MAD\wifi \
                   --username=%{mschap:User-Name} --password=%{User-Password}"
}

Enable sites and modules:

ln -s /etc/freeradius/3.0/sites-available/samba_default /etc/freeradius/3.0/sites-enabled/samba_default
ln -s /etc/freeradius/3.0/sites-available/samba_inner-tunnel /etc/freeradius/3.0/sites-enabled/samba_inner-tunnel
ln -s /etc/freeradius/3.0/mods-available/eap /etc/freeradius/3.0/mods-enabled/eap
ln -s /etc/freeradius/3.0/mods-available/mschap /etc/freeradius/3.0/mods-enabled/mschap
ln -s /etc/freeradius/3.0/mods-available/ntlm_auth /etc/freeradius/3.0/mods-enabled/ntlm_auth

Enable and start Freeradius

systemctl enable freeradius
systemctl start freeradius

Caponato's Samba notebook. Start here or else Main menu

samba/freeradius-ad.txt · Last modified: 2024/03/09 23:19 by caponato