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