Introduction
Components involved
Installation
Replication of production setup
Here, we replicate the relevant parts of the present installation as a starting point.
Base virtual machine preparation
Imported Last School's Debian9 VM template "Debian9-base.ova" into Virtual Box as Debian9-base_8021x, re-initializing all MAC addresses. The description for this virtual machine template is:
Debian 9 amd64 installation - Hostname: debian9-base - User accounts (username password): ls last root last - Partitioning: --- Physical: ------ 1GB RAID boot flag ------ 29GB RAID --- RAID: ------ md0: ext3 /boot ------ md1: LVM - part of volume group debian9-base --- LVM (VG/LV): ------ debian9-base/root: 18.6GB ext4 / ------ debian9-base/swap: 3.72GB swap area - Up to date as of 2017-09-27 - sources.list includes: Sections: main contrib non-free Additional repository: backports - Apt-cacher configured as per Last School site (Proxy credentials will need to be entered in /etc/apt/apt.conf.d/02proxy by user) - SSH access installed and enabled - Gnome and Firefox configured to auto-detect proxy settings - Extra software installed: vlc gimp emacs fonts-indic tcpdump iperf exfat-utils wireshark - One network interface as bridged adapter, cable connected.
Added a second ethernet adapter in settings, connected to "Not attached", re-initialized its MAC address
Increased the allocated CPUs to 2
The network configuration is now as follows (interface name seen in guest OS - Adapter name in VirtualBox settings - Adapter "Attached to" setting in VirtualBox settings):
enp0s3 - Adapter 1 - Bridged adapter
enp0s8 - Adapter 2 - Not attached
Booted, logged in to GUI, connected DHCP
In terminal:
rm /etc/apt/apt.conf.d/02proxy apt-get update apt-get upgrade
Rebooted the virtual machine
Set strong passwords for ls and root users
Installed my ssh public key in root's .ssh/authorized_keys file.
Installation of relevant services:
Shorewall (based on LASTSCHL-207):
apt-get install shorewall apt-get install ipset mv /etc/shorewall{,-orig} mkdir /etc/shorewall
Configuration:
root@debian9-base:/etc/shorewall# for i in `ls`; do echo "========= $i ========="; cat $i | grep -v "^#" | grep -v "^$"; echo "========= $i ========="; echo ""; done ========= hosts ========= ========= hosts ========= ========= interfaces ========= net enp0s3 detect tcpflags,dhcp,nosmurfs,routefilter,logmartians wifi enp0s8 detect tcpflags,nosmurfs,routefilter,logmartians ========= interfaces ========= ========= masq ========= enp0s3 192.168.9.0/24 ========= masq ========= ========= policy ========= $FW net REJECT INFO(uid) $FW wifi ACCEPT INFO(uid) wifi all REJECT net all DROP INFO all all REJECT info ========= policy ========= ========= routestopped ========= ========= routestopped ========= ========= rules ========= Invalid(DROP) net all ACCEPT:INFO(uid) net $FW tcp 22 ACCEPT:INFO(uid) net $FW udp 123 ACCEPT:INFO(uid) net $FW icmp ACCEPT:INFO(uid) $FW net tcp 465,587,995,993 ACCEPT:INFO(uid) $FW net udp 53,123 ACCEPT:INFO(uid) $FW net icmp ACCEPT:INFO(uid) $FW net tcp - - - - root ACCEPT:INFO(uid) $FW net udp - - - - root ACCEPT:INFO(uid) $FW net icmp - - - - root ACCEPT:INFO(uid) $FW net tcp - - - - _apt ACCEPT:INFO(uid) $FW net udp - - - - _apt ACCEPT:INFO(uid) $FW net icmp - - - - _apt ========= rules ========= ========= shorewall.conf ========= .... STARTUP_ENABLED=Yes .... IP_FORWARDING=On .... ========= shorewall.conf ========= ========= zones ========= fw firewall net ipv4 wifi ipv4 ========= zones =========
In /etc/default/shorewall, set
startup=1
root@debian9-base:~# cat /etc/rsyslog.d/40-shorewall.conf :msg, contains, "Shorewall:" /var/log/shorewall & stop root@debian9-base:~# cat /etc/logrotate.d/shorewall /var/log/shorewall-init.log { weekly rotate 108 compress nomissingok create 0640 root adm } /var/log/shorewall { rotate 731 daily nomissingok notifempty delaycompress compress dateext postrotate reload rsyslog >/dev/null 2>&1 || true endscript } root@debian9-base:~# cat /etc/logrotate.d/rsyslog /var/log/syslog /var/log/auth.log { rotate 731 daily dateext nomissingok notifempty delaycompress compress postrotate invoke-rc.d rsyslog rotate > /dev/null endscript } /var/log/mail.info /var/log/mail.warn /var/log/mail.err /var/log/mail.log /var/log/daemon.log /var/log/kern.log /var/log/user.log /var/log/lpr.log /var/log/cron.log /var/log/debug /var/log/messages { rotate 4 weekly missingok notifempty compress delaycompress sharedscripts postrotate invoke-rc.d rsyslog rotate > /dev/null endscript } root@debian9-base:~# cat /etc/logrotate.conf # see "man logrotate" for details # rotate log files weekly weekly # keep 4 weeks worth of backlogs rotate 4 # create new (empty) log files after rotating old ones create # uncomment this if you want your log files compressed #compress # packages drop log rotation information into this directory include /etc/logrotate.d # no packages own wtmp, or btmp -- we'll rotate them here /var/log/wtmp { nomissingok monthly create 0664 root utmp rotate 24 } /var/log/btmp { nomissingok monthly create 0660 root utmp rotate 24 } # system-specific logs may be configured here
systemctl enable shorewall.service
Configure network and DHCP (based on LASTSCHL-212):
systemctl disable network-manager.service systemctl disable NetworkManager.service unlink /etc/resolv.conf echo nameserver 192.168.10.1 > /etc/resolv.conf mkdir /etc/ltsp
root@debian9-base:~# cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). # The loopback network interface auto lo iface lo inet loopback # The external interface auto enp0s3 iface enp0s3 inet static address 192.168.10.52 network 192.168.10.0 netmask 255.255.255.0 broadcast 192.168.10.255 gateway 192.168.10.1 # The wifi interface auto enp0s8 iface enp0s8 inet static address 192.168.9.1 netmask 255.255.255.0 broadcast 192.168.9.255 root@debian9-base:~# cat /etc/dhcp/dhcpd.conf | grep -v "^#" | grep -v "^$" # Some of the following lines are there by default and are probably not required ddns-update-style none; option domain-name "example.org"; option domain-name-servers ns1.example.org, ns2.example.org; default-lease-time 600; max-lease-time 7200; log-facility local7; include "/etc/ltsp/dhcpd.conf"; root@debian9-base:~# cat /etc/ltsp/dhcpd.conf # # Default LTSP dhcpd.conf config file. # authoritative; subnet 192.168.9.0 netmask 255.255.255.0 { range 192.168.9.40 192.168.9.250; option domain-name "test.av"; option domain-name-servers 192.168.9.1; option broadcast-address 192.168.9.255; option routers 192.168.9.1; option subnet-mask 255.255.255.0; option root-path "/opt/ltsp/amd64"; if substring( option vendor-class-identifier, 0, 9 ) = "PXEClient" { filename "/ltsp/amd64/pxelinux.0"; } else { filename "/ltsp/amd64/nbi.img"; } }
apt-get install isc-dhcp-server
In /etc/default/isc-dhcp-server, set:
INTERFACESv4="enp0s8"
Configure DNS (based on LASTSCHL-211):
apt-get install dnsmasq touch /var/log/dnsmasq chmod 640 /var/log/dnsmasq
root@debian9-base:~# cat /etc/dnsmasq.conf | grep -v "^#" | grep -v "^$" strict-order interface=enp0s8 expand-hosts domain=test.av log-queries log-facility=/var/log/dnsmasq root@debian9-base:~# cat /etc/logrotate.d/dnsmasq /var/log/dnsmasq { rotate 731 daily nomissingok notifempty delaycompress compress dateext postrotate reload rsyslog >/dev/null 2>&1 || true endscript } root@debian9-base:~# cat /etc/hostname server.test.av root@debian9-base:~# cat /etc/hosts 127.0.0.1 localhost 192.168.9.1 test.av 192.168.9.1 server.test.av server # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
New stuff
Download the latest version of the attached shwl_add_shwl_del_sl_pmu archive and extract it somewhere convenient.
Shorewall
Add to /etc/shorewall/hosts:
wifi1 enp0s8:dynamic
Modify /etc/shorewall/policy:
# Just after: wifi all REJECT # Added: wifi1 net ACCEPT INFO wifi1 $FW ACCEPT INFO(uid) $FW wifi1 ACCEPT INFO(uid) # Before: net all DROP INFO
Add to /etc/shorewall/zones:
.... wifi1:wifi ipv4 dynamic_shared
In /etc/shorewall/shorewall.conf set:
SAVE_IPSETS=Yes
Add to /etc/shorewall/rules (replace IP addresses with actual IP address of wifi routers):
ACCEPT:INFO(uid) wifi:192.168.9.2,192.168.9.3,192.168.9.4 $FW udp 1812
FreeRADIUS
apt-get install freeradius systemctl enable freeradius.service
Modify /etc/freeradius/3.0/mods-available/eap:
comment the following:
.... # md5 { # } .... # leap { # } .... # gtc { # # The default challenge, which many clients # # ignore.. # #challenge = "Password: " # # # The plain-text response which comes back # # is put into a User-Password attribute, # # and passed to another module for # # authentication. This allows the EAP-GTC # # response to be checked against plain-text, # # or crypt'd passwords. # # # # If you say "Local" instead of "PAP", then # # the module will look for a User-Password # # configured for the request, and do the # # authentication itself. # # # auth_type = PAP # } .... # tls { # # Point to the common TLS configuration # tls = tls-common # # # # # As part of checking a client certificate, the EAP-TLS # # sets some attributes such as TLS-Client-Cert-CN. This # # virtual server has access to these attributes, and can # # be used to accept or reject the request. # # # # virtual_server = check-eap-tls # } ....
modify the 'default_eap_type' directive under section 'eap' to be:
default_eap_type = peap
and the 'default_eap_type' directive under section 'ttls' to be:
default_eap_type = mschapv2
Modify /etc/freeradius/3.0/sites-available/default, comment the following lines:
# All the listen sections except the IPv4 version with "type = auth" listen { ipaddr = * port = 0 type = acct limit { } } listen { type = auth ipv6addr = :: # any. ::1 == localhost port = 0 limit { max_connections = 16 lifetime = 0 idle_timeout = 30 } } listen { ipv6addr = :: port = 0 type = acct limit { } } # In the authorize section: chap mschap digest files -ldap pap # In the authenticate section: Auth-Type PAP { pap } Auth-Type CHAP { chap } Auth-Type MS-CHAP { mschap } mschap digest
Uncomment the following line in the 'authorize' section:
auth_log
Add the following line at the end of the 'post-auth' section and at the beginning of the Post-Auth-Type REJECT section:
reply_log
Add the following in the post-auth section, just before the Post-Auth-Type REJECT section:
update reply { Session-Timeout := 3600 Termination-Action := 1 }
Modify /etc/freeradius/3.0/sites-available/inner-tunnel, comment the following lines:
# The whole listen section listen { ipaddr = 127.0.0.1 port = 18120 type = auth } # In the authorize section: chap mschap files -ldap # In the authenticate section: Auth-Type PAP { pap } Auth-Type CHAP { chap } Auth-Type MS-CHAP { mschap }
Add the following line after 'filter_username' and before 'suffix' in the 'authorize' section:
auth_log
Add the following line at the end of the 'post-auth' section and at the beginning of the Post-Auth-Type REJECT section:
reply_log
Modify /etc/freeradius/3.0/radiusd.conf, set (in the 'log' section):
auth = yes
Modify /etc/freeradius/3.0/clients.conf, comment the 'client localhost' and 'client localhost_ipv6' section and add (replace with actual IP addresses of wifi routers):
client wifi-ap1 { ipaddr = 192.168.9.2 secret = password # Replace with an actual password } client wifi-ap2 { ipaddr = 192.168.9.3 secret = password # Replace with an actual password } client wifi-ap3 { ipaddr = 192.168.9.4 secret = password # Replace with an actual password }
Modify /etc/logrotate.d/freeradius, modify the following options as follows:
rotate 732 nomissingok dateext # Needs to be added
Certificates
as freerad?
Modify /etc/freeradius/3.0/certs/server.cnf, set the following settings:
... [ req ] ... input_password = password # Replace with an actual password output_password = password # Replace with an actual password ... [certificate_authority] countryName = IN stateOrProvinceName = Tamil Nadu localityName = Auroville organizationName = Test emailAddress = admin@test.av commonName = "Test Certificate Authority" ...
Modify /etc/freeradius/3.0/certs/ca.cnf, set the following settings:
... [ CA_default ] ... crlDistributionPoints = URI:http://server.test.av/test_ca.crl [ req ] ... input_password = password # Replace with an actual password output_password = password # Replace with an actual password [server] countryName = IN stateOrProvinceName = Tamil Nadu localityName = Auroville organizationName = Test emailAddress = admin@test.av commonName = "Test Server Certificate" [v3_ca] ... crlDistributionPoints = URI:http://server.test.av/test_ca.crl ...
as freerad ("@@@" right way to do it?):
cd /etc/freeradius/3.0/certs rm -f *.pem *.der *.csr *.crt *.key *.p12 serial* index.txt* make ca.pem make ca.der make server.pem make server.csr
Modify /etc/freeradius/3.0/mods-available/eap, modify the following directives under section 'tls-config tls-common' to be:
private_key_password = password # Replace password with the password chosen previously private_key_file = /etc/freeradius/3.0/certs/server.pem .... certificate_file = /etc/freeradius/3.0/certs/server.pem .... ca_file = /etc/freeradius/3.0/certs/ca.pem
MySQL
apt-get install mysql-server freeradius-mysql mysql -uroot CREATE DATABASE radius; exit mysql -uroot radius < /etc/freeradius/3.0/mods-config/sql/main/mysql/schema.sql
Edit /etc/freeradius/3.0/mods-config/sql/main/mysql/setup.sql. Modify the following lines:
CREATE USER 'radius'@'localhost'; SET PASSWORD FOR 'radius'@'localhost' = PASSWORD('radpass');
to
CREATE USER 'freerad'@'localhost' IDENTIFIED VIA unix_socket;
and update the username 'radius' to be 'freerad' wherever else it is mentioned in the file.
mysql -uroot radius < /etc/freeradius/3.0/mods-config/sql/main/mysql/setup.sql
cd /etc/freeradius/3.0/mods-enabled ln -s ../mods-available/sql sql
In /etc/freeradius/3.0/mods-enabled/sql, set the following options:
driver = "rlm_sql_mysql" dialect = "mysql" server = "localhost" port = 3306 login = "freerad" password = "" radius_db = "radius" logfile = ${logdir}/sqllog.sql # @@@ Do we need this?
Modify /etc/freeradius/3.0/sites-enabled/inner-tunnel, find the following line under authorize, post-auth and Post-Auth-Type REJECT sections
-sql
modify it to
sql
Modify /etc/freeradius/3.0/sites-enabled/default, find the following line under authorize, post-auth and Post-Auth-Type REJECT sections
-sql
In the post-auth and Post-Auth-Type REJECT sections, modify it to
sql
In the authorize section, comment it out.
Python module / script_launcher.py script
apt-get install libpython2.7-dev # It is not fully sure whether this package is needed cd /etc/freeradius/3.0/mods-enabled ln -s ../mods-available/python python
Put the following in it:
# # Make sure the PYTHONPATH environmental variable contains the # directory(s) for the modules listed below. # # Uncomment any func_* which are included in your module. If # rlm_python is called for a section which does not have # a function defined, it will return NOOP. # python { module = script_launcher python_path = ${modconfdir}/${.:name}:/usr/lib/python2.7 mod_post_auth = ${.module} func_post_auth = post_auth }
Modify /etc/freeradius/3.0/sites-enabled/inner-tunnel:
... # Add this line just after 'sql' in the 'post-auth' section python ...
Modify /etc/freeradius/3.0/mods-available/eap, modify the 'copy_request_to_tunnel' directive under both sections 'peap' and 'ttls' to be:
copy_request_to_tunnel = yes
Place the script_launcher.py script from the shwl_add_shwl_del_sl_pmu archive at /etc/freeradius/3.0/mods-config/python/script_launcher.py
chown freerad:freerad /etc/freeradius/3.0/mods-config/python/script_launcher.py chmod 640 /etc/freeradius/3.0/mods-config/python/script_launcher.py
sudo
apt-get install sudo
Create /etc/sudoers.d/shwl_add_shwl_del_pmu, permissions 640 root:root, with:
freerad ALL=(root:root) NOPASSWD:/sbin/shorewall,/usr/bin/arp-scan
shwl_add / shwl_del scripts
Prerequisites from above: sudo, FreeRADIUS python module / script_launcher.py script, shorewall, FreeRADIUS MySQL
apt-get install arp-scan # Install the shwl_*.sh scripts from the shwl_add_shwl_del_sl_pmu archive in /usr/local/sbin/ chown root:freerad /usr/local/sbin/shwl_* chmod 750 /usr/local/sbin/shwl_* mkdir /var/local/shwl_add chown freerad:freerad /var/local/shwl_add chmod 700 /var/local/shwl_add chmod a-s /var/local/shwl_add
Add the following line to freerad's crontab
*/1 * * * * /usr/local/sbin/shwl_del.sh # @@@ figure out optimal interval
Settings in /usr/local/sbin/shwl_add.sh (at top of file):
.... # Settings cfg_shwl_zone="wifi1" # Shorewall dynamic zone to which client devices' IP addresses need to be added # @@@ figure out a few optimal intervals cfg_shwl_retry_delay=2 # Number of seconds to wait, in case of failure in adding IP to shorewall dynamic zone, before attempting second time cfg_file_location="/var/local/shwl_add" # Folder where runtime information will be stored cfg_file_location_owner_user="freerad" # User by which above folder should be owned cfg_file_location_owner_group="freerad" # Group by which above folder should be owned cfg_ip_srch_iface="enp0s8" # Network interface on which to scan for devices cfg_ip_srch_initial_delay=0.75 # How many seconds to wait before first attempt at scanning cfg_ip_srch_retry_delay=4 # How many seconds to wait in between further attempts at scanning cfg_ip_srch_max_attempts=50 # Maximum number of attempts at scanning before giving up cfg_mysql_user="freerad" # MySQL username cfg_mysql_db="shwl_add_shwl_del_pmu" # MySQL database name where to log events cfg_mysql_log_table="event_log" # Table in MySQL database where to log events ....
Settings in /usr/local/sbin/shwl_del.sh (at top of file):
.... # Settings cfg_ip_match_pattern="192.168." # Pattern to match all IP addresses that might be in the shorewall dynamic zone # @@@ figure out a few optimal intervals cfg_session_expiry_timeout=3660 # Session duration (should be slightly longer than Session-Timeout attribute specified in FreeRADIUS) cfg_shwl_zone="wifi1" # Shorewall dynamic zone containing clients' IP addresses cfg_file_location="/var/local/shwl_add" # Folder where runtime information is stored cfg_file_location_owner_user="freerad" # User by which above folder should be owned cfg_file_location_owner_group="freerad" # Group by which above folder should be owned cfg_mysql_user="freerad" # MySQL username cfg_mysql_db="shwl_add_shwl_del_pmu" # MySQL database name where to log events cfg_mysql_log_table="event_log" # Table in MySQL database where to log events ....
MySQL
mysql -uroot CREATE DATABASE shwl_add_shwl_del_pmu; GRANT ALL on shwl_add_shwl_del_pmu.event_log TO 'freerad'@'localhost'; exit mysql -uroot shwl_add_shwl_del_pmu < shwl_add_shwl_del_pmu.sql # Updating shwl_add_shwl_del_pmu.sql to the full path of the shwl_add_shwl_del_pmu.sql file extracted from the shwl_add_shwl_del_sl_pmu archive
pam_to_mysql_update.sh script
Prerequisities from above: sudo, FreeRADIUS MySQL, shwl_add / shwl_del scripts MySQL
apt-get install libpam-script sshpass mkdir /usr/share/libpam-script/pam-script.d/pam_to_mysql_update cd /usr/share/libpam-script/pam-script.d/pam_to_mysql_update # Install the pam_to_mysql_update.sh script from the shwl_add_shwl_del_sl_pmu archive in here ln -s pam_to_mysql_update.sh pam_script_auth ln -s pam_to_mysql_update.sh pam_script_passwd mysql -uroot GRANT ALL on radius.radcheck TO 'freerad'@'localhost'; exit pam-auth-update # And, uncheck the box for "Support for authentication by external scripts"
Add the following line at the end of /etc/pam.d/common-auth:
.... auth required pam_script.so onerr=fail dir=/usr/share/libpam-script/pam-script.d/pam_to_mysql_update/
Add the following line at the end of /etc/pam.d/common-password:
.... password required pam_script.so onerr=fail dir=/usr/share/libpam-script/pam-script.d/pam_to_mysql_update/
Settings in /usr/share/libpam-script/pam-script.d/pam_to_mysql_update/pam_to_mysql_update.sh (at top of file):
.... # Settings cfg_mysql_user="freerad" # MySQL username cfg_mysql_user_db="radius" # MySQL database name where to update passwords cfg_mysql_log_db="shwl_add_shwl_del_pmu" # MySQL database name where to log events cfg_mysql_user_table="radcheck" # Table in MySQL database where to update passwords cfg_mysql_log_table="event_log" # Table in MySQL database where to log events cfg_verbose=0 # Print verbose messages on stdout ....
Managing users
The below procedures also create/change password for/delete system users as well as users for FreeRADIUS.
Adding users
Replace 'user' with the desired username.
mysql -uroot use radius; INSERT INTO radcheck VALUES ('','user','NT-Password',':=',''); exit adduser user # When prompted for "Current password:", ignore and press enter
Changing password
It is sufficient to use standard utilities such as 'passwd', the password will be updated in the MySQL database as well. Tested with 'passwd' and User Accounts applet in GNOME. In case prompted with "Current password:" (exactly as written here) it is sufficient to ignore and press enter.
Deleting users
Replace 'user' with the username to be deleted.
mysql -uroot use radius; DELETE FROM radcheck WHERE username='user'; exit deluser user
WiFi router (NAS) configuration
TP-Link Archer C20 v4 00000004
TP-Link TD-W8968 V4 0x00000001
TP-Link TL-WR740N v4 00000000
Supplicant configuration
Linux
Android
Windows 10
Mac OS
iPhone
Sources
https://wiki.freeradius.org/guide/Basic-configuration-HOWTO
https://wiki.freeradius.org/guide/SQL-HOWTO-for-freeradius-3.x-on-Debian-Ubuntu
https://wiki.freeradius.org/modules/Rlm_python
https://wiki.freeradius.org/config/Certificates
http://deployingradius.com/documents/configuration/certificates.html
http://deployingradius.com/documents/protocols/compatibility.html