SMUS Wireless Configuration: Difference between revisions
(Created page with "== Introduction == == Prerequisites == == Software Used == == Hardware Used == == Firewall and NAT == == Freeradius Configuration == === Virtual Hosts === === Certificates...") |
|||
(30 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
== Introduction == | == Introduction == | ||
This page will discuss the backend for the SMUS wireless configuration. | |||
This document is made available under the [http://creativecommons.org/licenses/by-sa/2.5/ca/ Creative Commons Attribution ShareAlike 2.5 Canada] license. | |||
== Prerequisites == | == Prerequisites == | ||
Our requirements for wireless on campus are fairly complex. We decided on several prerequisites, for a variety of reasons. | |||
=== 802.1x === | |||
We wanted staff and students to be able to sign into the wireless system themselves without any help from the MIS department. Several implementations use a captive portal mechanism to do this, but that results in an SSID with no encryption. By using 802.1x, we can use WPA2-Enterprise encryption on the SSIDs, and staff and students can still configure the connection themselves. | |||
=== Active Directory Integration === | |||
Wherever possible, we have staff and students use their active directory credentials to log into whatever they're trying to access. We wanted this system to also use the active directory credentials. The AD server had preexisting groups we wanted to take advantage of as well, and we added more groups later to further separate out our users. | |||
=== Different Student and Staff IP addresses === | |||
Students on our campus are subject to bandwidth limitations and packet shaping. We do not want to apply these restrictions to staff members. Our packet shaper uses a simple IP range to track which machines to apply restrictions to, so we needed our students to be assigned a different set of IP addresses than our staff. | |||
=== VLANs for mobile labs === | |||
Our mobile laptop labs also need different IP ranges. As we have a senior and middle school, we apply different web filtering to each set of computers. We achieved this using VLAN assignments in freeradius after the machines logged in, based on a regular expression check on the computer name. | |||
=== Single simultaneous login for students === | |||
This is no longer a requirement for our system, so we have removed the sections containing simultaneous use from this document. See the document history from January 3 2012 or earlier to see how we did simultaneous use (although it wasn't fully working). | |||
=== Login times by grade === | |||
We apply different login hours by grade. Grade 12s can use the wireless longer into the evening than grade 11s, which can use it longer than grade 10s, etc. We accomplish this by assigning different VLANs per grade and boarder/day status. This results in different IP ranges that we can apply time-based firewalling on through our PFSense router. | |||
=== Guest logins === | |||
As there are frequently parents and other guests on campus, we wanted it to be fairly simple for them to get their wireless device onto our network. These devices are sometimes not as secure as other devices, so they are separated out onto their own network, and we check their computers for up-to-date antivirus protection through a captive portal before allowing them to login. Antivirus protection is not checked on smartphones and similar devices, only full computers. | |||
== Software Used == | == Software Used == | ||
We use a combination of Freeradius (to do radius authentication), and Samba (for active directory integration) on the backend. The wireless access points are configured using the Meraki cloud controller, although other wifi systems can also tap into the same radius configuration (we tested with Dlink access points as well). Whatever wifi system is selected must support 802.1x authentication through WPA2-Enterprise encryption. | |||
Bug-free support for the functions we're using arrived recently to Samba and Freeradius, and older versions definitely don't work properly. We are running Debian 6 with the stock versions of all packages. We were previously running Ubuntu 10.04 and the versions included there did not work. Freeradius 2.1.10 and Samba 3.5.6 are included with Debian 6, so those are the recommended versions. | |||
Our VLANs are routed through a PFSense 2.0.1 virtual machine. This VM can apply firewalls to any combination of subnet connections, and has good performance for the throughput we need. It also supports time-based firewalling so we can block access to the Internet at specific times per VLAN. Routing and firewalling can also be done through a dedicated router. | |||
== Hardware Used == | == Hardware Used == | ||
== | Our radius server runs as a VMWare ESXi 5.1 virtual machine. It has a single virtual processor (2.53 GHz) with 512 MB of ram. This is more than sufficient to handle our incoming connections. | ||
We use Meraki MR16 access points. | |||
Clients we have successfully authenticated on this network include Windows XP, Vista, and 7; Mac OS X; Android, Blackberry, and iOS smartphones; etc. Through MAC address whitelisting, we have also put other devices onto the guest network. | |||
== Samba Configuration == | |||
Samba must be installed and the Linux machine must be joined to the active directory domain before radius can do NTLM authentication. | |||
sudo apt-get install samba winbind smbclient krb5-user | |||
sudo vi /etc/krb5.conf | |||
* Ensure default realm is set to your active directory DNS name (ours is SMUS.LOCAL) | |||
* Under realms, add a section: | |||
<pre> | |||
SMUS.LOCAL = { | |||
kdc = <domain controller DNS name> | |||
kdc = <backup domain controller DNS name> | |||
admin_server = <domain controller DNS name> | |||
} | |||
</pre> | |||
* Now test that your Kerberos settings are correct | |||
sudo kinit Administrator | |||
* Enter your domain administrator password, and if it comes back without any errors you've set up Kerberos correctly | |||
* Now configure Samba | |||
sudo vi /etc/samba/smb.conf | |||
* Change workgroup to your active directory short name (Ours is "SMUSLOCAL") | |||
* Add a new line underneath with your Kerberos realm/Active Directory DNS name: | |||
realm = <AD DNS name> | |||
* Uncomment "security = user" and change to "security = ads" | |||
* Immediately underneath, add the following lines: | |||
password server = <domain controller DNS name> | |||
Now join the Active Directory domain: | |||
sudo net ads join -U Administrator | |||
Then restart Samba and Winbind so that you can authenticate against the AD domain: | |||
sudo /etc/init.d/samba stop; sudo /etc/init.d/winbind stop | |||
sudo /etc/init.d/samba start; sudo /etc/init.d/winbind start | |||
== Freeradius Configuration == | == Freeradius Configuration == | ||
=== Installation === | |||
sudo apt-get install freeradius freeradius-ldap | |||
* Allow the freerad user access to query winbind | |||
sudo adduser freerad winbindd_priv | |||
=== Clients === | |||
We must set up clients that are allowed to authenticate via radius. We have set up one client definition for senior/middle school Meraki access points, another definition for junior school Meraki access points, and a several definitions for the Meraki cloud controller, which does the guest authentication. | |||
<pre> | |||
client <ip range>/24 { | |||
secret = <radius secret> | |||
shortname = meraki_ap | |||
nastype = other | |||
} | |||
client <ip range>/24 { | |||
secret = <radius secret> | |||
shortname = meraki_jr_ap | |||
nastype = other | |||
} | |||
client 64.156.192.220/32 { | |||
secret = <radius secret> | |||
shortname = meraki_cloud1 | |||
nastype = other | |||
} | |||
client 64.156.192.245/32 { | |||
secret = <radius secret> | |||
shortname = meraki_cloud2 | |||
nastype = other | |||
} | |||
client 74.50.51.16/32 { | |||
secret = <radius secret> | |||
shortname = meraki_cloud3 | |||
nastype = other | |||
} | |||
client 74.50.53.101/32 { | |||
secret = <radius secret> | |||
shortname = meraki_cloud4 | |||
nastype = other | |||
} | |||
</pre> | |||
=== Policies === | |||
Add each of these policies under /etc/freeradius/policy.conf | |||
==== Require_staff Policy ==== | |||
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later. | |||
<pre> | |||
require_staff { | |||
update request { | |||
Huntgroup-Name := "<staff group name>" | |||
} | |||
} | |||
</pre> | |||
==== Require_student Policy ==== | |||
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later. We also update any replies to indicate that the student's session timeout is 5 minutes to force them to reauthenticate every 5 minutes. | |||
<pre> | |||
require_student { | |||
update request { | |||
Huntgroup-Name := "<student group name>" | |||
} | |||
} | |||
</pre> | |||
==== Require_guest Policy ==== | |||
Guests are authenticated differently because they are not doing 802.1x EAP/MSCHAP authentication. Instead, they use NTLM authentication (a username and cleartext password). As these passwords are transmitted cleartext over the Internet, it is wise to rotate the passwords often, and also to not use privileged accounts. The accounts we set up for guest wireless access are not allowed to log into school computers, or access any resources other than wireless. | |||
We will set up the actual auth module later. | |||
<pre> | |||
require_guest { | |||
update request { | |||
Huntgroup-Name := "<guest group name>" | |||
} | |||
update control { | |||
Auth-Type := "ntlm_auth_guest" | |||
} | |||
} | |||
</pre> | |||
==== Special_vlan Policy ==== | |||
When we authenticate computers, we also check to see if the machine should go onto a special VLAN. We check computer names for the computer lab VLANs, and we also check which access point they're binding to to check for Junior School machines, which are assigned different VLANs as they are a separate campus. | |||
<pre> | |||
check_unified_vlan { | |||
update reply { | |||
# default settings | |||
Tunnel-Private-Group-ID = 104 | |||
Tunnel-Type = "VLAN" | |||
Tunnel-Medium-Type = "IEEE-802" | |||
} | |||
### computer name policies ### | |||
if ("%{User-Name}" =~ /D7-BROW-MIS-E/i) { | |||
update reply { | |||
Tunnel-Private-Group-ID := 1 | |||
} | |||
} | |||
elsif ("%{User-Name}" =~ /D7-CROT-303-/i) { | |||
update reply { | |||
# Crothall South Lab | |||
Tunnel-Private-Group-ID := 150 | |||
} | |||
} | |||
... | |||
### staff group policies ### | |||
elsif (Ldap-Group == "staffnt") { | |||
update reply { | |||
Tunnel-Private-Group-ID := 104 | |||
} | |||
} | |||
### student grade group policies ### | |||
elsif (Ldap-Group == "Grade 12 Board") { | |||
update reply { | |||
Tunnel-Private-Group-ID := 112 | |||
} | |||
} | |||
elsif (Ldap-Group == "Grade 12 Day") { | |||
update reply { | |||
Tunnel-Private-Group-ID := 114 | |||
} | |||
} | |||
... | |||
### junior school ### | |||
if ("%{Client-Shortname}" == "meraki_jr_ap") { | |||
# authenticating from JR school, change up the VLAN numbers | |||
if (Ldap-Group == "studentsnt") { | |||
# was going to be on student VLAN, put on JR student VLAN | |||
update reply { | |||
Tunnel-Private-Group-ID := 204 | |||
} | |||
} | |||
else { | |||
# otherwise put on JR staff VLAN | |||
update reply { | |||
Tunnel-Private-Group-ID := 200 | |||
} | |||
} | |||
} | |||
} | |||
</pre> | |||
=== Virtual Hosts === | === Virtual Hosts === | ||
We use virtual hosts so that there are different radius servers available to authenticate staff, students, and guests. | |||
sudo vi /etc/freeradius/radiusd.conf | |||
* Comment out all of the listen blocks, as we will be setting these up for each virtualhost | |||
* Now set up your virtualhosts | |||
cd /etc/freeradius/sites-available | |||
cp default staff | |||
cp default student | |||
cp default guest | |||
cd /etc/freeradius/sites-enabled | |||
rm default | |||
ln -s ../sites-available/staff . | |||
ln -s ../sites-available/student . | |||
ln -s ../sites-available/guest . | |||
==== Staff Virtual Host ==== | |||
sudo vi /etc/freeradius/sites-enabled/staff | |||
* Wrap the entire config file into a block. At the top of the file, add "server staff {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server staff {" block. | |||
* Add a listen block immediately under "server staff {" | |||
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting) | |||
** Note that the staff server handles the radius accounting for all IP addresses, but you can configure them separately if desired | |||
<pre> | |||
listen { | |||
port = 0 | |||
type = auth | |||
ipaddr = <ip address> | |||
} | |||
listen { | |||
port = 0 | |||
type = acct | |||
ipaddr = * | |||
} | |||
</pre> | |||
* Update the authorize block so that it has the following items: | |||
<pre> | |||
preprocess | |||
require_staff | |||
suffix | |||
eap { | |||
ok = return | |||
} | |||
files | |||
</pre> | |||
* Update the authentication block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
* Update the preacct block so that it has the following items: | |||
<pre> | |||
preprocess | |||
acct_unique | |||
suffix | |||
</pre> | |||
* Update the accounting block so that it has the following items: | |||
<pre> | |||
attr_filter.accounting_response | |||
</pre> | |||
* Update the post-auth block so that it has the following items: | |||
<pre> | |||
check_unified_vlan | |||
exec | |||
Post-Auth-Type REJECT { | |||
attr_filter.access_reject | |||
} | |||
</pre> | |||
* Update the post-proxy block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
==== Student Virtual Host ==== | |||
sudo vi /etc/freeradius/sites-enabled/student | |||
* Wrap the entire config file into a block. At the top of the file, add "server student {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server student {" block. | |||
* Add a listen block immediately under "server student {" | |||
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting) | |||
<pre> | |||
listen { | |||
port = 0 | |||
type = auth | |||
ipaddr = <ip address> | |||
} | |||
</pre> | |||
* Update the authorize block so that it has the following items: | |||
<pre> | |||
preprocess | |||
ldap | |||
require_student | |||
suffix | |||
eap { | |||
ok = return | |||
} | |||
files | |||
expiration | |||
</pre> | |||
* Update the authentication block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
* Comment out the preacct and accounting blocks, as they are not used | |||
* Update the post-auth block so that it has the following items: | |||
<pre> | |||
check_unified_vlan | |||
exec | |||
Post-Auth-Type REJECT { | |||
attr_filter.access_reject | |||
} | |||
</pre> | |||
* Update the post-proxy block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
==== Guest Virtual Host ==== | |||
sudo vi /etc/freeradius/sites-enabled/guest | |||
* Wrap the entire config file into a block. At the top of the file, add "server guest {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server guest {" block. | |||
* Add a listen block immediately under "server guest {" | |||
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting) | |||
<pre> | |||
listen { | |||
port = 0 | |||
type = auth | |||
ipaddr = <ip address> | |||
} | |||
</pre> | |||
* Update the authorize block so that it has the following items: | |||
<pre> | |||
preprocess | |||
require_guest | |||
suffix | |||
eap { | |||
ok = return | |||
} | |||
files | |||
</pre> | |||
* Update the authentication block so that it has the following items: | |||
<pre> | |||
ntlm_auth_guest | |||
</pre> | |||
* Comment out the preacct and accounting blocks as they are not used | |||
* Update the post-auth block so that it has the following items: | |||
<pre> | |||
check_unified_vlan | |||
exec | |||
Post-Auth-Type REJECT { | |||
attr_filter.access_reject | |||
} | |||
</pre> | |||
* Update the post-proxy block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
==== Inner-Tunnel Virtual Host ==== | |||
The inner-tunnel vhost should already be mostly set up, as it's generally included with Freeradius' default configuration. If it's not, symlink it from the sites-available: | |||
sudo ln -s /etc/freeradius/sites-available/inner-tunnel /etc/freeradius/sites-enabled | |||
Now start editing: | |||
sudo vi /etc/freeradius/sites-enabled/inner-tunnel | |||
* Update the authorize block so that it has the following items: | |||
<pre> | |||
chap | |||
mschap | |||
suffix | |||
update control { | |||
Proxy-To-Realm := LOCAL | |||
} | |||
eap { | |||
ok = return | |||
} | |||
files | |||
expiration | |||
pap | |||
</pre> | |||
* Update the authentication block so that it has the following items. Note that if mschap authentication fails (this means that the user isn't a member of the huntgroup we set earlier), we also check whether mschap_computers authenticates the user correctly. | |||
<pre> | |||
Auth-Type PAP { | |||
pap | |||
} | |||
Auth-Type CHAP { | |||
chap | |||
} | |||
Auth-Type MS-CHAP { | |||
mschap { | |||
reject = 2 | |||
} | |||
if (reject) { | |||
mschap_computers | |||
} | |||
} | |||
unix | |||
eap | |||
</pre> | |||
* Comment out the accounting, preacct, and session blocks, as they are not used | |||
* Update the post-auth block so that it has the following items: | |||
<pre> | |||
Post-Auth-Type REJECT { | |||
attr_filter.access_reject | |||
} | |||
</pre> | |||
* Update the post-proxy block so that it has the following items: | |||
<pre> | |||
eap | |||
</pre> | |||
=== Certificates === | === Certificates === | ||
We need to generate a CSR and get a real certificate for this server. Here are the steps from memory, so they may not be 100% correct. | |||
cd /etc/freeradius/certs | |||
openssl req -out <server_name>.csr -new -newkey rsa:2048 -nodes -keyout <server_name>.key | |||
Now send the CSR to a certificate authority and get it signed. If the CA uses a certificate chain, you need to put all of the certificates into one file, with the server's certificate at the top, then the CA that signed that cert, then the next CA up the chain, etc. Upload the resulting certificate file as <server_name>.crt . | |||
=== EAP === | === EAP === | ||
=== | Now configure EAP to use the certificate along with other parameters. | ||
sudo vi /etc/freeradius/eap.conf | |||
Inside the eap block, set the following: | |||
default_eap_type = peap | |||
Inside the eap/tls block, set the following: | |||
private_key_password = | |||
private_key_file = ${certdir}/<server_name>.key | |||
certificate_file = ${certdir}/<server_name>.crt | |||
=== | Inside the eap/tls/cache block, set the following: | ||
enable = yes | |||
lifetime = 4 # hours | |||
max_entries = 1000 | |||
=== LDAP Connection === | === LDAP Connection === | ||
=== | sudo vi /etc/freeradius/modules/ldap | ||
* Configure TLS if desired under the ldap/tls block | |||
* Set the following values in the ldap block: | |||
server = "<domain controller>:3268" | |||
identity = "<domain query user, for example cn=ldap_user,cn=users,dc=...>" | |||
password = "<domain query user AD password>" | |||
basedn = "<AD base DN>" | |||
filter = "(samAccountName=%{%{mschap:User-Name}:-%{User-Name}})" | |||
groupname_attribute = cn | |||
groupmembership_filter = "(&(objectClass=group)(member=%{control:Ldap-UserDn}))" | |||
groupmembership_attribute = memberOf | |||
chase_referrals = yes | |||
rebind = yes | |||
=== MSCHAP module === | |||
sudo vi /etc/freeradius/modules/mschap | |||
* Set the following values under the mschap block: | |||
with_ntdomain_hack = yes | |||
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\%{outer.request:Huntgroup-Name}" | |||
=== MSCHAP_Computers module === | |||
sudo cp /etc/freeradius/modules/mschap /etc/freeradius/modules/mschap_computers | |||
* Change the block from "mschap {" to "mschap mschap_computers {" | |||
* Change the following values under the mschap mschap_computers block: | |||
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\Domain\\ Computers" | |||
=== NTLM_Auth_Guest module === | |||
sudo cp /etc/freeradius/modules/ntlm_auth /etc/freeradius/modules/ntlm_auth_guest | |||
* Change the block from "exec ntlm_auth {" to "exec ntlm_auth_guest {" | |||
* Change the following values under the exec ntlm_auth_guest block: | |||
program = "/usr/bin/ntlm_auth --request-nt-key --domain=<AD domain> --username=%{mschap:User-Name} --password=%{User-Password} --require-membership-of=<AD domain>\\\\%{request:Huntgroup-Name}" | |||
=== Restart freeradius and pray === | |||
This starts Freeradius in debug mode. You should watch this fly by and verify that all of the configuration you have done above worked properly. If it didn't, Freeradius will complain and then exit. Then, try to get something to actually authenticate (follow the Meraki configuration in the next step to get it using your radius server). | |||
sudo /etc/init.d/freeradius stop | |||
sudo freeradius -X | |||
To start radius for real, CTRL+C your debug session, then run: | |||
sudo /etc/init.d/freeradius start | |||
== Meraki configuration to use radius server == | |||
Note that while this configuration is specific to the Meraki cloud controller, it is also possible to set up 802.1x authentication through radius with other wireless systems. | |||
=== Staff SSID === | |||
* Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-staff. | |||
* Go to Configure -> Access control, and set up the following details: | |||
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication | |||
Network Access, Network sign-on method -> Direct access | |||
Network Access, Authentication server -> Use my radius server, host <ip>, port 1812, secret <radius_secret> | |||
Addressing and traffic, Client IP assignment -> Bridge mode | |||
VLAN setup, VLAN tagging: Use VLAN Tagging | |||
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 112 | |||
VLAN setup, Radius override -> radius response can override VLAN tag | |||
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) | |||
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps) | |||
We noticed on our network that if "Dual band operation with Band Steering" was selected, some older wireless cards did not see the SSID at all. We resolved the issue by just using Dual Band with no Band Steering. | |||
=== Student SSID === | |||
* Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-student. | |||
* Go to Configure -> Access control, and set up the following details: | |||
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication | |||
Network Access, Network sign-on method -> Direct access | |||
Network Access, Authentication server -> Use my radius server, host <ip2>, port 1812, secret <radius_secret> | |||
Addressing and traffic, Client IP assignment -> Bridge mode | |||
VLAN setup, VLAN tagging: Use VLAN Tagging | |||
VLAN setup, VLAN ID: JR tag -> 204, all other APs -> 104 | |||
VLAN setup, Radius override -> radius response can override VLAN tag | |||
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) | |||
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps) | |||
=== Guest SSID === | |||
* Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-guest. | |||
* Go to Configure -> Access control, and set up the following details: | |||
Network Access, Association Requirements -> Open (no encryption) | |||
Network Access, Network sign-on method -> Sign-on splash page | |||
Network access, Network access control -> Enabled: check clients for antivirus software | |||
Network access, Remediation -> Send users to the standard remediation site | |||
Network Access, Captive portal strength -> Block all access until sign-on is complete | |||
Network Access, Walled garden -> Walled garden is disabled | |||
Network Access, Authentication server -> Use my radius server, host <external_ip_address>, port 1812, secret <radius_secret> | |||
Network Access, Failover policy -> Deny access | |||
Network Access, Simultaneous logins -> Allow simultaneous devices per user | |||
Addressing and traffic, Client IP assignment -> Bridge mode | |||
VLAN setup, VLAN tagging: Use VLAN Tagging | |||
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 100 | |||
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) | |||
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps) | |||
Note: make sure you have set up firewall exceptions and IP forwarding through to the external IP address you have configured here. | |||
== Additional Information == | |||
=== P2P blocking through Meraki === | |||
On our guest wifi network, we block P2P traffic. | |||
Under Configure -> Firewall & Traffic Shaping, we added a Layer 7 firewall rule denying P2P traffic. | |||
=== Packetshaper Integration === | |||
We use an application called Penaltybox: http://sourceforge.net/projects/penaltybox/ in combination with our packet shaper in order to restrict students to 10 GB of traffic per week. After this amount of traffic, the student is restricted to 64 Kbit/sec down and 64 Kbit/sec up for 7 days. | |||
In order to get this to work, you must set up port mirroring to a physical server that listens to the traffic in promiscuous mode. It then records how much bandwidth is used by each IP address in the eligible range and applies restrictions when thresholds are met. | |||
In order to compile the penaltybox application on our Debian 6 server and have it support our (newer) packetshaper, we had to apply the following patch: | |||
<pre> | |||
diff -ur penaltybox/src/benconfig/configexception.h penaltybox.new/src/benconfig/configexception.h | |||
--- penaltybox/src/benconfig/configexception.h 2006-08-23 10:29:54.000000000 -0700 | |||
+++ penaltybox.new/src/benconfig/configexception.h 2010-12-23 11:09:18.000000000 -0800 | |||
@@ -10,6 +10,7 @@ | |||
#ifndef __CONFIGEXCEPTION_H | |||
#define __CONFIGEXCEPTION_H | |||
#include <string> | |||
+#include <cstdio> | |||
#include "configtypes.h" | |||
using namespace std; | |||
diff -ur penaltybox/src/benconfig/configloader.cpp penaltybox.new/src/benconfig/configloader.cpp | |||
--- penaltybox/src/benconfig/configloader.cpp 2007-01-17 12:07:13.000000000 -0800 | |||
+++ penaltybox.new/src/benconfig/configloader.cpp 2010-12-23 11:10:06.000000000 -0800 | |||
@@ -25,6 +25,8 @@ | |||
#include "configloader.h" | |||
#include <iostream> | |||
#include <cmath> | |||
+#include <stdio.h> | |||
+#include <stdlib.h> | |||
#include <assert.h> | |||
#include "trimstring.h" | |||
using namespace std; | |||
diff -ur penaltybox/src/capture/Capture.cpp penaltybox.new/src/capture/Capture.cpp | |||
--- penaltybox/src/capture/Capture.cpp 2006-12-13 00:53:56.000000000 -0800 | |||
+++ penaltybox.new/src/capture/Capture.cpp 2010-12-23 11:11:27.000000000 -0800 | |||
@@ -21,6 +21,10 @@ | |||
*************************************************************************/ | |||
#include "Capture.h" | |||
#include <pbconfigloader.h> | |||
+#include <string> | |||
+#include <sstream> | |||
+#include <cstring> | |||
+ | |||
#include <iostream> | |||
using namespace std; | |||
diff -ur penaltybox/src/host/DayTotal.cpp penaltybox.new/src/host/DayTotal.cpp | |||
--- penaltybox/src/host/DayTotal.cpp 2006-12-11 00:20:51.000000000 -0800 | |||
+++ penaltybox.new/src/host/DayTotal.cpp 2010-12-23 11:12:53.000000000 -0800 | |||
@@ -24,6 +24,7 @@ | |||
#include <stdio.h> | |||
#include <time.h> | |||
#include <stdlib.h> | |||
+#include <strings.h> | |||
#include <string> | |||
using namespace std; | |||
diff -ur penaltybox/src/host/HostList.cpp penaltybox.new/src/host/HostList.cpp | |||
--- penaltybox/src/host/HostList.cpp 2006-12-13 01:13:37.000000000 -0800 | |||
+++ penaltybox.new/src/host/HostList.cpp 2010-12-23 11:12:25.000000000 -0800 | |||
@@ -31,6 +31,8 @@ | |||
#include "../pbconfigloader.h" | |||
#include <errno.h> | |||
#include <time.h> | |||
+#include <cstring> | |||
+#include <strings.h> | |||
using namespace std; | |||
using namespace Config; | |||
diff -ur penaltybox/src/host/HostNode.cpp penaltybox.new/src/host/HostNode.cpp | |||
--- penaltybox/src/host/HostNode.cpp 2006-08-22 15:45:19.000000000 -0700 | |||
+++ penaltybox.new/src/host/HostNode.cpp 2010-12-23 11:12:40.000000000 -0800 | |||
@@ -22,6 +22,7 @@ | |||
#include "HostNode.h" | |||
#include <iostream> | |||
+#include <strings.h> | |||
using namespace std; | |||
#include <stdio.h> | |||
#include <assert.h> | |||
diff -ur penaltybox/src/limiter/Packeteer.cpp penaltybox.new/src/limiter/Packeteer.cpp | |||
--- penaltybox/src/limiter/Packeteer.cpp 2006-12-15 18:59:04.000000000 -0800 | |||
+++ penaltybox.new/src/limiter/Packeteer.cpp 2010-12-23 11:14:01.000000000 -0800 | |||
@@ -26,6 +26,9 @@ | |||
#include "../benconfig/trimstring.h" | |||
#include "../pbconfigloader.h" | |||
#include <assert.h> | |||
+#include <string> | |||
+#include <cstring> | |||
+#include <sstream> | |||
#include <openssl/md5.h> | |||
#include <fstream> | |||
@@ -35,6 +38,7 @@ | |||
const int Inbound = 0; | |||
const int Outbound = 1; | |||
+long int ClassID = 1234567; | |||
const char * folder[] = { "Inbound/students", "Outbound/students" }; | |||
@@ -201,11 +205,17 @@ | |||
string entryStartTagEnd = "/pb-" + h->GetIp().toString() + "\">\n"; | |||
string entryFootTag = " </entry>\n</add-delete-schema-objects>\n"; | |||
- string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n"; | |||
+ string s; | |||
+ stringstream st; | |||
+ | |||
+ string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n"; | |||
data += " <attr name=\"iqosInsideHost\"><value>" + h->GetIp().toString() + "</value></attr>\n"; | |||
data += xmlpartition; | |||
data += " <attr name=\"iqosProtocolName\"><value>IP</value></attr>\n"; | |||
- | |||
+ ClassID += 1; | |||
+ st << ClassID; | |||
+ data += " <attr name=\"iqosClassID\"><value>" + st.str() + "</value></attr>\n"; | |||
+ | |||
return entryStartTagBegin + entryStartTagEnd + data + entryFootTag ; | |||
} | |||
@@ -259,12 +269,12 @@ | |||
xml = xmlhead; | |||
xml += this->DeleteXml(*r, folder[x]); | |||
xml += xmlfoot; | |||
- | |||
- sprintf(message, "+Adding Class: %s/pb-%s\n", | |||
+ | |||
+ sprintf(message, "+Adding Class: %s/pb-%s\n", | |||
folder[x], | |||
(*r).c_str()); | |||
- pb_log_debug(message); | |||
+ pb_log_debug(message); | |||
SendRequest(xml); | |||
} | |||
r++; | |||
@@ -378,11 +388,12 @@ | |||
void Packeteer::UploadNotify() { | |||
list<string>::iterator p = hostsToNotify.begin(); | |||
- string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n"; | |||
+ // string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n"; | |||
+ string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + "penaltybox" + "\">\n"; | |||
xml += "<objectclass><oc-value>iqosHostList</oc-value></objectclass>\n"; | |||
while (p != hostsToNotify.end()) { | |||
- pb_log_debug("Adding " + *p + " to redirect\n"); | |||
+ pb_log_debug("Adding R2 " + *p + " to redirect\n"); | |||
xml += "<attr name=\"iqosHostListNames\"><value>" + *p + "</value></attr>\n"; | |||
p++; | |||
} | |||
diff -ur penaltybox/src/pb.cpp penaltybox.new/src/pb.cpp | |||
--- penaltybox/src/pb.cpp 2007-01-11 16:24:48.000000000 -0800 | |||
+++ penaltybox.new/src/pb.cpp 2010-12-23 11:17:48.000000000 -0800 | |||
@@ -23,6 +23,10 @@ | |||
#include <iostream> | |||
#include <fstream> | |||
#include <string> | |||
+#include <cstring> | |||
+#include <strings.h> | |||
+#include <stdlib.h> | |||
+#include <stdio.h> | |||
#include <pbconfigloader.h> | |||
#include <pbversion.h> | |||
diff -ur penaltybox/src/socket/http.cpp penaltybox.new/src/socket/http.cpp | |||
--- penaltybox/src/socket/http.cpp 2006-06-30 19:39:54.000000000 -0700 | |||
+++ penaltybox.new/src/socket/http.cpp 2010-12-23 11:14:26.000000000 -0800 | |||
@@ -20,6 +20,7 @@ | |||
* Written By Benjamin Wilder <mrcawfee@sfsu.edu> | |||
*************************************************************************/ | |||
#include "http.h" | |||
+#include <strings.h> | |||
#include <iostream> | |||
using namespace std; | |||
diff -ur penaltybox/src/socket/url.cpp penaltybox.new/src/socket/url.cpp | |||
--- penaltybox/src/socket/url.cpp 2006-06-30 19:39:54.000000000 -0700 | |||
+++ penaltybox.new/src/socket/url.cpp 2010-12-23 11:14:58.000000000 -0800 | |||
@@ -21,6 +21,7 @@ | |||
*************************************************************************/ | |||
#include "url.h" | |||
#include <stdio.h> | |||
+#include <cstring> | |||
string urlencode(string s) { | |||
string result; | |||
</pre> |
Latest revision as of 10:02, 10 October 2012
Introduction
This page will discuss the backend for the SMUS wireless configuration.
This document is made available under the Creative Commons Attribution ShareAlike 2.5 Canada license.
Prerequisites
Our requirements for wireless on campus are fairly complex. We decided on several prerequisites, for a variety of reasons.
802.1x
We wanted staff and students to be able to sign into the wireless system themselves without any help from the MIS department. Several implementations use a captive portal mechanism to do this, but that results in an SSID with no encryption. By using 802.1x, we can use WPA2-Enterprise encryption on the SSIDs, and staff and students can still configure the connection themselves.
Active Directory Integration
Wherever possible, we have staff and students use their active directory credentials to log into whatever they're trying to access. We wanted this system to also use the active directory credentials. The AD server had preexisting groups we wanted to take advantage of as well, and we added more groups later to further separate out our users.
Different Student and Staff IP addresses
Students on our campus are subject to bandwidth limitations and packet shaping. We do not want to apply these restrictions to staff members. Our packet shaper uses a simple IP range to track which machines to apply restrictions to, so we needed our students to be assigned a different set of IP addresses than our staff.
VLANs for mobile labs
Our mobile laptop labs also need different IP ranges. As we have a senior and middle school, we apply different web filtering to each set of computers. We achieved this using VLAN assignments in freeradius after the machines logged in, based on a regular expression check on the computer name.
Single simultaneous login for students
This is no longer a requirement for our system, so we have removed the sections containing simultaneous use from this document. See the document history from January 3 2012 or earlier to see how we did simultaneous use (although it wasn't fully working).
Login times by grade
We apply different login hours by grade. Grade 12s can use the wireless longer into the evening than grade 11s, which can use it longer than grade 10s, etc. We accomplish this by assigning different VLANs per grade and boarder/day status. This results in different IP ranges that we can apply time-based firewalling on through our PFSense router.
Guest logins
As there are frequently parents and other guests on campus, we wanted it to be fairly simple for them to get their wireless device onto our network. These devices are sometimes not as secure as other devices, so they are separated out onto their own network, and we check their computers for up-to-date antivirus protection through a captive portal before allowing them to login. Antivirus protection is not checked on smartphones and similar devices, only full computers.
Software Used
We use a combination of Freeradius (to do radius authentication), and Samba (for active directory integration) on the backend. The wireless access points are configured using the Meraki cloud controller, although other wifi systems can also tap into the same radius configuration (we tested with Dlink access points as well). Whatever wifi system is selected must support 802.1x authentication through WPA2-Enterprise encryption.
Bug-free support for the functions we're using arrived recently to Samba and Freeradius, and older versions definitely don't work properly. We are running Debian 6 with the stock versions of all packages. We were previously running Ubuntu 10.04 and the versions included there did not work. Freeradius 2.1.10 and Samba 3.5.6 are included with Debian 6, so those are the recommended versions.
Our VLANs are routed through a PFSense 2.0.1 virtual machine. This VM can apply firewalls to any combination of subnet connections, and has good performance for the throughput we need. It also supports time-based firewalling so we can block access to the Internet at specific times per VLAN. Routing and firewalling can also be done through a dedicated router.
Hardware Used
Our radius server runs as a VMWare ESXi 5.1 virtual machine. It has a single virtual processor (2.53 GHz) with 512 MB of ram. This is more than sufficient to handle our incoming connections.
We use Meraki MR16 access points.
Clients we have successfully authenticated on this network include Windows XP, Vista, and 7; Mac OS X; Android, Blackberry, and iOS smartphones; etc. Through MAC address whitelisting, we have also put other devices onto the guest network.
Samba Configuration
Samba must be installed and the Linux machine must be joined to the active directory domain before radius can do NTLM authentication.
sudo apt-get install samba winbind smbclient krb5-user sudo vi /etc/krb5.conf
- Ensure default realm is set to your active directory DNS name (ours is SMUS.LOCAL)
- Under realms, add a section:
SMUS.LOCAL = { kdc = <domain controller DNS name> kdc = <backup domain controller DNS name> admin_server = <domain controller DNS name> }
- Now test that your Kerberos settings are correct
sudo kinit Administrator
- Enter your domain administrator password, and if it comes back without any errors you've set up Kerberos correctly
- Now configure Samba
sudo vi /etc/samba/smb.conf
- Change workgroup to your active directory short name (Ours is "SMUSLOCAL")
- Add a new line underneath with your Kerberos realm/Active Directory DNS name:
realm = <AD DNS name>
- Uncomment "security = user" and change to "security = ads"
- Immediately underneath, add the following lines:
password server = <domain controller DNS name>
Now join the Active Directory domain:
sudo net ads join -U Administrator
Then restart Samba and Winbind so that you can authenticate against the AD domain:
sudo /etc/init.d/samba stop; sudo /etc/init.d/winbind stop sudo /etc/init.d/samba start; sudo /etc/init.d/winbind start
Freeradius Configuration
Installation
sudo apt-get install freeradius freeradius-ldap
- Allow the freerad user access to query winbind
sudo adduser freerad winbindd_priv
Clients
We must set up clients that are allowed to authenticate via radius. We have set up one client definition for senior/middle school Meraki access points, another definition for junior school Meraki access points, and a several definitions for the Meraki cloud controller, which does the guest authentication.
client <ip range>/24 { secret = <radius secret> shortname = meraki_ap nastype = other } client <ip range>/24 { secret = <radius secret> shortname = meraki_jr_ap nastype = other } client 64.156.192.220/32 { secret = <radius secret> shortname = meraki_cloud1 nastype = other } client 64.156.192.245/32 { secret = <radius secret> shortname = meraki_cloud2 nastype = other } client 74.50.51.16/32 { secret = <radius secret> shortname = meraki_cloud3 nastype = other } client 74.50.53.101/32 { secret = <radius secret> shortname = meraki_cloud4 nastype = other }
Policies
Add each of these policies under /etc/freeradius/policy.conf
Require_staff Policy
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later.
require_staff { update request { Huntgroup-Name := "<staff group name>" } }
Require_student Policy
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later. We also update any replies to indicate that the student's session timeout is 5 minutes to force them to reauthenticate every 5 minutes.
require_student { update request { Huntgroup-Name := "<student group name>" } }
Require_guest Policy
Guests are authenticated differently because they are not doing 802.1x EAP/MSCHAP authentication. Instead, they use NTLM authentication (a username and cleartext password). As these passwords are transmitted cleartext over the Internet, it is wise to rotate the passwords often, and also to not use privileged accounts. The accounts we set up for guest wireless access are not allowed to log into school computers, or access any resources other than wireless.
We will set up the actual auth module later.
require_guest { update request { Huntgroup-Name := "<guest group name>" } update control { Auth-Type := "ntlm_auth_guest" } }
Special_vlan Policy
When we authenticate computers, we also check to see if the machine should go onto a special VLAN. We check computer names for the computer lab VLANs, and we also check which access point they're binding to to check for Junior School machines, which are assigned different VLANs as they are a separate campus.
check_unified_vlan { update reply { # default settings Tunnel-Private-Group-ID = 104 Tunnel-Type = "VLAN" Tunnel-Medium-Type = "IEEE-802" } ### computer name policies ### if ("%{User-Name}" =~ /D7-BROW-MIS-E/i) { update reply { Tunnel-Private-Group-ID := 1 } } elsif ("%{User-Name}" =~ /D7-CROT-303-/i) { update reply { # Crothall South Lab Tunnel-Private-Group-ID := 150 } } ... ### staff group policies ### elsif (Ldap-Group == "staffnt") { update reply { Tunnel-Private-Group-ID := 104 } } ### student grade group policies ### elsif (Ldap-Group == "Grade 12 Board") { update reply { Tunnel-Private-Group-ID := 112 } } elsif (Ldap-Group == "Grade 12 Day") { update reply { Tunnel-Private-Group-ID := 114 } } ... ### junior school ### if ("%{Client-Shortname}" == "meraki_jr_ap") { # authenticating from JR school, change up the VLAN numbers if (Ldap-Group == "studentsnt") { # was going to be on student VLAN, put on JR student VLAN update reply { Tunnel-Private-Group-ID := 204 } } else { # otherwise put on JR staff VLAN update reply { Tunnel-Private-Group-ID := 200 } } } }
Virtual Hosts
We use virtual hosts so that there are different radius servers available to authenticate staff, students, and guests.
sudo vi /etc/freeradius/radiusd.conf
- Comment out all of the listen blocks, as we will be setting these up for each virtualhost
- Now set up your virtualhosts
cd /etc/freeradius/sites-available cp default staff cp default student cp default guest cd /etc/freeradius/sites-enabled rm default ln -s ../sites-available/staff . ln -s ../sites-available/student . ln -s ../sites-available/guest .
Staff Virtual Host
sudo vi /etc/freeradius/sites-enabled/staff
- Wrap the entire config file into a block. At the top of the file, add "server staff {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server staff {" block.
- Add a listen block immediately under "server staff {"
- The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
- Note that the staff server handles the radius accounting for all IP addresses, but you can configure them separately if desired
listen { port = 0 type = auth ipaddr = <ip address> } listen { port = 0 type = acct ipaddr = * }
- Update the authorize block so that it has the following items:
preprocess require_staff suffix eap { ok = return } files
- Update the authentication block so that it has the following items:
eap
- Update the preacct block so that it has the following items:
preprocess acct_unique suffix
- Update the accounting block so that it has the following items:
attr_filter.accounting_response
- Update the post-auth block so that it has the following items:
check_unified_vlan exec Post-Auth-Type REJECT { attr_filter.access_reject }
- Update the post-proxy block so that it has the following items:
eap
Student Virtual Host
sudo vi /etc/freeradius/sites-enabled/student
- Wrap the entire config file into a block. At the top of the file, add "server student {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server student {" block.
- Add a listen block immediately under "server student {"
- The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
listen { port = 0 type = auth ipaddr = <ip address> }
- Update the authorize block so that it has the following items:
preprocess ldap require_student suffix eap { ok = return } files expiration
- Update the authentication block so that it has the following items:
eap
- Comment out the preacct and accounting blocks, as they are not used
- Update the post-auth block so that it has the following items:
check_unified_vlan exec Post-Auth-Type REJECT { attr_filter.access_reject }
- Update the post-proxy block so that it has the following items:
eap
Guest Virtual Host
sudo vi /etc/freeradius/sites-enabled/guest
- Wrap the entire config file into a block. At the top of the file, add "server guest {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server guest {" block.
- Add a listen block immediately under "server guest {"
- The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
listen { port = 0 type = auth ipaddr = <ip address> }
- Update the authorize block so that it has the following items:
preprocess require_guest suffix eap { ok = return } files
- Update the authentication block so that it has the following items:
ntlm_auth_guest
- Comment out the preacct and accounting blocks as they are not used
- Update the post-auth block so that it has the following items:
check_unified_vlan exec Post-Auth-Type REJECT { attr_filter.access_reject }
- Update the post-proxy block so that it has the following items:
eap
Inner-Tunnel Virtual Host
The inner-tunnel vhost should already be mostly set up, as it's generally included with Freeradius' default configuration. If it's not, symlink it from the sites-available:
sudo ln -s /etc/freeradius/sites-available/inner-tunnel /etc/freeradius/sites-enabled
Now start editing:
sudo vi /etc/freeradius/sites-enabled/inner-tunnel
- Update the authorize block so that it has the following items:
chap mschap suffix update control { Proxy-To-Realm := LOCAL } eap { ok = return } files expiration pap
- Update the authentication block so that it has the following items. Note that if mschap authentication fails (this means that the user isn't a member of the huntgroup we set earlier), we also check whether mschap_computers authenticates the user correctly.
Auth-Type PAP { pap } Auth-Type CHAP { chap } Auth-Type MS-CHAP { mschap { reject = 2 } if (reject) { mschap_computers } } unix eap
- Comment out the accounting, preacct, and session blocks, as they are not used
- Update the post-auth block so that it has the following items:
Post-Auth-Type REJECT { attr_filter.access_reject }
- Update the post-proxy block so that it has the following items:
eap
Certificates
We need to generate a CSR and get a real certificate for this server. Here are the steps from memory, so they may not be 100% correct.
cd /etc/freeradius/certs openssl req -out <server_name>.csr -new -newkey rsa:2048 -nodes -keyout <server_name>.key
Now send the CSR to a certificate authority and get it signed. If the CA uses a certificate chain, you need to put all of the certificates into one file, with the server's certificate at the top, then the CA that signed that cert, then the next CA up the chain, etc. Upload the resulting certificate file as <server_name>.crt .
EAP
Now configure EAP to use the certificate along with other parameters.
sudo vi /etc/freeradius/eap.conf
Inside the eap block, set the following:
default_eap_type = peap
Inside the eap/tls block, set the following:
private_key_password = private_key_file = ${certdir}/<server_name>.key certificate_file = ${certdir}/<server_name>.crt
Inside the eap/tls/cache block, set the following:
enable = yes lifetime = 4 # hours max_entries = 1000
LDAP Connection
sudo vi /etc/freeradius/modules/ldap
- Configure TLS if desired under the ldap/tls block
- Set the following values in the ldap block:
server = "<domain controller>:3268" identity = "<domain query user, for example cn=ldap_user,cn=users,dc=...>" password = "<domain query user AD password>" basedn = "<AD base DN>" filter = "(samAccountName=%{%{mschap:User-Name}:-%{User-Name}})" groupname_attribute = cn groupmembership_filter = "(&(objectClass=group)(member=%{control:Ldap-UserDn}))" groupmembership_attribute = memberOf chase_referrals = yes rebind = yes
MSCHAP module
sudo vi /etc/freeradius/modules/mschap
- Set the following values under the mschap block:
with_ntdomain_hack = yes ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\%{outer.request:Huntgroup-Name}"
MSCHAP_Computers module
sudo cp /etc/freeradius/modules/mschap /etc/freeradius/modules/mschap_computers
- Change the block from "mschap {" to "mschap mschap_computers {"
- Change the following values under the mschap mschap_computers block:
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\Domain\\ Computers"
NTLM_Auth_Guest module
sudo cp /etc/freeradius/modules/ntlm_auth /etc/freeradius/modules/ntlm_auth_guest
- Change the block from "exec ntlm_auth {" to "exec ntlm_auth_guest {"
- Change the following values under the exec ntlm_auth_guest block:
program = "/usr/bin/ntlm_auth --request-nt-key --domain=<AD domain> --username=%{mschap:User-Name} --password=%{User-Password} --require-membership-of=<AD domain>\\\\%{request:Huntgroup-Name}"
Restart freeradius and pray
This starts Freeradius in debug mode. You should watch this fly by and verify that all of the configuration you have done above worked properly. If it didn't, Freeradius will complain and then exit. Then, try to get something to actually authenticate (follow the Meraki configuration in the next step to get it using your radius server).
sudo /etc/init.d/freeradius stop sudo freeradius -X
To start radius for real, CTRL+C your debug session, then run:
sudo /etc/init.d/freeradius start
Meraki configuration to use radius server
Note that while this configuration is specific to the Meraki cloud controller, it is also possible to set up 802.1x authentication through radius with other wireless systems.
Staff SSID
- Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-staff.
- Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication Network Access, Network sign-on method -> Direct access Network Access, Authentication server -> Use my radius server, host <ip>, port 1812, secret <radius_secret> Addressing and traffic, Client IP assignment -> Bridge mode VLAN setup, VLAN tagging: Use VLAN Tagging VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 112 VLAN setup, Radius override -> radius response can override VLAN tag Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
We noticed on our network that if "Dual band operation with Band Steering" was selected, some older wireless cards did not see the SSID at all. We resolved the issue by just using Dual Band with no Band Steering.
Student SSID
- Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-student.
- Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication Network Access, Network sign-on method -> Direct access Network Access, Authentication server -> Use my radius server, host <ip2>, port 1812, secret <radius_secret> Addressing and traffic, Client IP assignment -> Bridge mode VLAN setup, VLAN tagging: Use VLAN Tagging VLAN setup, VLAN ID: JR tag -> 204, all other APs -> 104 VLAN setup, Radius override -> radius response can override VLAN tag Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
Guest SSID
- Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-guest.
- Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> Open (no encryption) Network Access, Network sign-on method -> Sign-on splash page Network access, Network access control -> Enabled: check clients for antivirus software Network access, Remediation -> Send users to the standard remediation site Network Access, Captive portal strength -> Block all access until sign-on is complete Network Access, Walled garden -> Walled garden is disabled Network Access, Authentication server -> Use my radius server, host <external_ip_address>, port 1812, secret <radius_secret> Network Access, Failover policy -> Deny access Network Access, Simultaneous logins -> Allow simultaneous devices per user Addressing and traffic, Client IP assignment -> Bridge mode VLAN setup, VLAN tagging: Use VLAN Tagging VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 100 Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz) Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
Note: make sure you have set up firewall exceptions and IP forwarding through to the external IP address you have configured here.
Additional Information
P2P blocking through Meraki
On our guest wifi network, we block P2P traffic.
Under Configure -> Firewall & Traffic Shaping, we added a Layer 7 firewall rule denying P2P traffic.
Packetshaper Integration
We use an application called Penaltybox: http://sourceforge.net/projects/penaltybox/ in combination with our packet shaper in order to restrict students to 10 GB of traffic per week. After this amount of traffic, the student is restricted to 64 Kbit/sec down and 64 Kbit/sec up for 7 days.
In order to get this to work, you must set up port mirroring to a physical server that listens to the traffic in promiscuous mode. It then records how much bandwidth is used by each IP address in the eligible range and applies restrictions when thresholds are met.
In order to compile the penaltybox application on our Debian 6 server and have it support our (newer) packetshaper, we had to apply the following patch:
diff -ur penaltybox/src/benconfig/configexception.h penaltybox.new/src/benconfig/configexception.h --- penaltybox/src/benconfig/configexception.h 2006-08-23 10:29:54.000000000 -0700 +++ penaltybox.new/src/benconfig/configexception.h 2010-12-23 11:09:18.000000000 -0800 @@ -10,6 +10,7 @@ #ifndef __CONFIGEXCEPTION_H #define __CONFIGEXCEPTION_H #include <string> +#include <cstdio> #include "configtypes.h" using namespace std; diff -ur penaltybox/src/benconfig/configloader.cpp penaltybox.new/src/benconfig/configloader.cpp --- penaltybox/src/benconfig/configloader.cpp 2007-01-17 12:07:13.000000000 -0800 +++ penaltybox.new/src/benconfig/configloader.cpp 2010-12-23 11:10:06.000000000 -0800 @@ -25,6 +25,8 @@ #include "configloader.h" #include <iostream> #include <cmath> +#include <stdio.h> +#include <stdlib.h> #include <assert.h> #include "trimstring.h" using namespace std; diff -ur penaltybox/src/capture/Capture.cpp penaltybox.new/src/capture/Capture.cpp --- penaltybox/src/capture/Capture.cpp 2006-12-13 00:53:56.000000000 -0800 +++ penaltybox.new/src/capture/Capture.cpp 2010-12-23 11:11:27.000000000 -0800 @@ -21,6 +21,10 @@ *************************************************************************/ #include "Capture.h" #include <pbconfigloader.h> +#include <string> +#include <sstream> +#include <cstring> + #include <iostream> using namespace std; diff -ur penaltybox/src/host/DayTotal.cpp penaltybox.new/src/host/DayTotal.cpp --- penaltybox/src/host/DayTotal.cpp 2006-12-11 00:20:51.000000000 -0800 +++ penaltybox.new/src/host/DayTotal.cpp 2010-12-23 11:12:53.000000000 -0800 @@ -24,6 +24,7 @@ #include <stdio.h> #include <time.h> #include <stdlib.h> +#include <strings.h> #include <string> using namespace std; diff -ur penaltybox/src/host/HostList.cpp penaltybox.new/src/host/HostList.cpp --- penaltybox/src/host/HostList.cpp 2006-12-13 01:13:37.000000000 -0800 +++ penaltybox.new/src/host/HostList.cpp 2010-12-23 11:12:25.000000000 -0800 @@ -31,6 +31,8 @@ #include "../pbconfigloader.h" #include <errno.h> #include <time.h> +#include <cstring> +#include <strings.h> using namespace std; using namespace Config; diff -ur penaltybox/src/host/HostNode.cpp penaltybox.new/src/host/HostNode.cpp --- penaltybox/src/host/HostNode.cpp 2006-08-22 15:45:19.000000000 -0700 +++ penaltybox.new/src/host/HostNode.cpp 2010-12-23 11:12:40.000000000 -0800 @@ -22,6 +22,7 @@ #include "HostNode.h" #include <iostream> +#include <strings.h> using namespace std; #include <stdio.h> #include <assert.h> diff -ur penaltybox/src/limiter/Packeteer.cpp penaltybox.new/src/limiter/Packeteer.cpp --- penaltybox/src/limiter/Packeteer.cpp 2006-12-15 18:59:04.000000000 -0800 +++ penaltybox.new/src/limiter/Packeteer.cpp 2010-12-23 11:14:01.000000000 -0800 @@ -26,6 +26,9 @@ #include "../benconfig/trimstring.h" #include "../pbconfigloader.h" #include <assert.h> +#include <string> +#include <cstring> +#include <sstream> #include <openssl/md5.h> #include <fstream> @@ -35,6 +38,7 @@ const int Inbound = 0; const int Outbound = 1; +long int ClassID = 1234567; const char * folder[] = { "Inbound/students", "Outbound/students" }; @@ -201,11 +205,17 @@ string entryStartTagEnd = "/pb-" + h->GetIp().toString() + "\">\n"; string entryFootTag = " </entry>\n</add-delete-schema-objects>\n"; - string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n"; + string s; + stringstream st; + + string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n"; data += " <attr name=\"iqosInsideHost\"><value>" + h->GetIp().toString() + "</value></attr>\n"; data += xmlpartition; data += " <attr name=\"iqosProtocolName\"><value>IP</value></attr>\n"; - + ClassID += 1; + st << ClassID; + data += " <attr name=\"iqosClassID\"><value>" + st.str() + "</value></attr>\n"; + return entryStartTagBegin + entryStartTagEnd + data + entryFootTag ; } @@ -259,12 +269,12 @@ xml = xmlhead; xml += this->DeleteXml(*r, folder[x]); xml += xmlfoot; - - sprintf(message, "+Adding Class: %s/pb-%s\n", + + sprintf(message, "+Adding Class: %s/pb-%s\n", folder[x], (*r).c_str()); - pb_log_debug(message); + pb_log_debug(message); SendRequest(xml); } r++; @@ -378,11 +388,12 @@ void Packeteer::UploadNotify() { list<string>::iterator p = hostsToNotify.begin(); - string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n"; + // string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n"; + string xml = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + "penaltybox" + "\">\n"; xml += "<objectclass><oc-value>iqosHostList</oc-value></objectclass>\n"; while (p != hostsToNotify.end()) { - pb_log_debug("Adding " + *p + " to redirect\n"); + pb_log_debug("Adding R2 " + *p + " to redirect\n"); xml += "<attr name=\"iqosHostListNames\"><value>" + *p + "</value></attr>\n"; p++; } diff -ur penaltybox/src/pb.cpp penaltybox.new/src/pb.cpp --- penaltybox/src/pb.cpp 2007-01-11 16:24:48.000000000 -0800 +++ penaltybox.new/src/pb.cpp 2010-12-23 11:17:48.000000000 -0800 @@ -23,6 +23,10 @@ #include <iostream> #include <fstream> #include <string> +#include <cstring> +#include <strings.h> +#include <stdlib.h> +#include <stdio.h> #include <pbconfigloader.h> #include <pbversion.h> diff -ur penaltybox/src/socket/http.cpp penaltybox.new/src/socket/http.cpp --- penaltybox/src/socket/http.cpp 2006-06-30 19:39:54.000000000 -0700 +++ penaltybox.new/src/socket/http.cpp 2010-12-23 11:14:26.000000000 -0800 @@ -20,6 +20,7 @@ * Written By Benjamin Wilder <mrcawfee@sfsu.edu> *************************************************************************/ #include "http.h" +#include <strings.h> #include <iostream> using namespace std; diff -ur penaltybox/src/socket/url.cpp penaltybox.new/src/socket/url.cpp --- penaltybox/src/socket/url.cpp 2006-06-30 19:39:54.000000000 -0700 +++ penaltybox.new/src/socket/url.cpp 2010-12-23 11:14:58.000000000 -0800 @@ -21,6 +21,7 @@ *************************************************************************/ #include "url.h" #include <stdio.h> +#include <cstring> string urlencode(string s) { string result;