This article describes how to set up a lab environment to authenticate devices dynamically using RADIUS and assign VLANs based on authentication results.
The lab includes a Juniper EX4100 switch, a QFX core switch, a FreeRADIUS server, a DHCP server, and a client device.
Topology
Example IP Addressing
1. Configure the FreeRADIUS and DHCP Server (VM2)
Assign a physical NIC on VM2 to the management VLAN (192.168.3.0/24) to enable communication with the switches.
Linux Network Configuration
Update `/etc/netplan` (for Ubuntu) or `/etc/network/interfaces` (for Debian-based systems):
cat <<EOL | sudo tee /etc/netplan/01-network-config.yaml network: version: 2 ens192: dhcp4: no addresses: - 192.168.3.1/24 EOL
Or using below command (this will be deleted after any reboot.
ip add add 192.168.3.1/24 dev ens192 ip route add 192.168.0.0/16 dev ens192 via 192.168.3.254 Apply changes: sudo netplan apply
Install necessary packages
sudo apt update sudo apt upgrade or sudo apt-get update sudo apt-get install -y freeradius freeradius-utils
RADIUS Server Configuration for Dynamic VLANs
sudo bash -c "cat > /etc/freeradius/3.0/clients.conf" <<EOF client AccessSwitch { ipaddr = 192.168.99.1 secret = Juniper123 require_message_authenticator = no } EOF
cat /etc/freeradius/3.0/clients.conf sudo bash -c "cat > /etc/freeradius/3.0/mods-config/files/authorize" <<EOF 0050569e1ccf Cleartext-Password := "0050569e1ccf" Tunnel-Type = VLAN, Tunnel-Medium-Type = IEEE-802, Tunnel-Private-Group-Id = "20" EOF
Restart freeradius
sudo systemctl restart freeradius sudo systemctl stop freeradius Other useful commands. sudo systemctl restart freeradius sudo systemctl stop freeradius To monitor freeradius messages: sudo freeradius -X
2. Configure VM1 as a Simulated Guest
On VM1, configure it to act as a RADIUS client and request DHCP once authenticated.
Install necessary tools: sudo apt update sudo apt upgrade sudo apt update && sudo apt install wpa_supplicant isc-dhcp-client -y
Configure `wpa_supplicant` for 802.1X
sudo bash -c "cat > /etc/wpa_supplicant/wpa_supplicant.conf" <<EOF ctrl_interface=/var/run/wpa_supplicant network={ key_mgmt=IEEE8021X eap=PEAP identity="Guest" password="Juniper123" phase2="auth=PAP" } EOF
Bring up the interface:
sudo wpa_supplicant -i ens34 -c /etc/wpa_supplicant/wpa_supplicant.conf -B
cat <<EOL | sudo tee /etc/netplan/01-netcfg.yaml network: version: 2 ethernets: ens34: dhcp4: true EOL
Apply the interface configuration and initialize the dhcp process.
sudo netplan apply sudo dhclient ens34
3: Configure DHCP on the Core
set system host-name CoreSwitch set system services dhcp-local-server group printers interface irb.20 set interfaces ge-0/0/0 unit 0 family ethernet-switching interface-mode access set interfaces ge-0/0/0 unit 0 family ethernet-switching vlan members Server set interfaces ge-0/0/47 unit 0 family ethernet-switching interface-mode trunk set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members all set interfaces irb unit 3 family inet address 192.168.3.254/24 set interfaces irb unit 20 family inet address 192.168.20.254/24 set interfaces irb unit 20 proxy-arp restricted set interfaces irb unit 30 family inet address 192.168.30.254/24 set interfaces irb unit 99 family inet address 192.168.99.254/24 set interfaces irb unit 99 proxy-arp restricted set access address-assignment pool Guest-pool family inet network 192.168.20.0/24 set access address-assignment pool Guest-pool family inet range Guest-range low 192.168.20.34 set access address-assignment pool Guest-pool family inet range Guest-range high 192.168.20.40 set protocols lldp interface all set vlans Guest vlan-id 20 set vlans Guest l3-interface irb.20 set vlans MgmtVLAN vlan-id 99 set vlans MgmtVLAN l3-interface irb.99 set vlans SecureVLAN vlan-id 30 set vlans SecureVLAN l3-interface irb.30 set vlans Server vlan-id 3 set vlans Server l3-interface irb.3
Step 4: Configure EX4100 (Access)
set system host-name AccessSwitch set system management-instance set interfaces interface-range access-ports member-range ge-0/0/0 to ge-0/0/35 set interfaces interface-range access-ports unit 0 family ethernet-switching interface-mode access set interfaces interface-range access-ports unit 0 family ethernet-switching vlan members Guest set interfaces ge-0/0/47 unit 0 family ethernet-switching interface-mode trunk set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 20 set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 30 set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 99 set interfaces irb unit 99 family inet address 192.168.99.1/24 set access radius-server 192.168.3.1 port 1812 <<<<< -- make sure you are matchig the port on the Access switch and the Radius Server set access radius-server 192.168.3.1 secret "$9$cwZrKWNdsJGiLxGik.zFcylKLx-VwgaZ" set access radius-server 192.168.3.1 source-address 192.168.99.1 set access profile auth-profile authentication-order radius set access profile auth-profile radius authentication-server 192.168.3.1 set access profile auth-profile radius accounting-server 192.168.3.1 set routing-options static route 0.0.0.0/0 next-hop 192.168.99.254 set protocols dot1x authenticator authentication-profile-name auth-profile set protocols dot1x authenticator no-mac-table-binding set protocols dot1x authenticator interface access-ports supplicant multiple set protocols dot1x authenticator interface access-ports mac-radius restrict set protocols dot1x authenticator interface access-ports mac-radius authentication-protocol pap set protocols dot1x authenticator interface access-ports reauthentication 28800 set protocols lldp interface all set vlans Guest description "Guest VLAN" set vlans Guest vlan-id 20 set vlans Guest forwarding-options dhcp-security ip-source-guard set vlans Management description "Management VLAN" set vlans Management vlan-id 99 set vlans Management l3-interface irb.99 set vlans Secure description "Secure VLAN" set vlans Secure vlan-id 30 set vlans Secure forwarding-options dhcp-security ip-source-guard
root@VM2-IP232-JNPR32:~# sudo freeradius -X FreeRADIUS Version 3.0.26 Copyright (C) 1999-2021 The FreeRADIUS server project and contributors There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE <snipped> Ready to process requests !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BlastRADIUS check: Received packet without Proxy-State. Setting "limit_proxy_state = true" for client AccessSwitch !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! The packet does not contain Message-Authenticator, which is a security issue. UPGRADE THE CLIENT AS YOUR NETWORK MAY BE VULNERABLE TO THE BLASTRADIUS ATTACK. Once the client is upgraded, set "require_message_authenticator = true" for client AccessSwitch !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (0) Received Access-Request Id 200 from 192.168.99.1:56300 to 192.168.3.1:1812 length 167 (0) User-Name = "0050569e1ccf" (0) User-Password = "0050569e1ccf" (0) NAS-Port = 632 (0) Service-Type = Call-Check (0) Acct-Session-Id = "8O2.1x815752d50002da85" (0) NAS-Port-Id = "ge-0/0/0.0" (0) Calling-Station-Id = "00-50-56-9e-1c-cf" (0) Called-Station-Id = "bc-0f-fe-08-8f-92" (0) EAP-Key-Name = 0x00 (0) NAS-Identifier = "AccessSwitch" (0) NAS-Port-Type = Ethernet (0) NAS-IP-Address = 192.168.99.1 (0) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/default (0) authorize { (0) policy filter_username { (0) if (&User-Name) { (0) if (&User-Name) -> TRUE (0) if (&User-Name) { (0) if (&User-Name =~ / /) { (0) if (&User-Name =~ / /) -> FALSE (0) if (&User-Name =~ /@[^@]*@/ ) { (0) if (&User-Name =~ /@[^@]*@/ ) -> FALSE (0) if (&User-Name =~ /\.\./ ) { (0) if (&User-Name =~ /\.\./ ) -> FALSE (0) if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) { (0) if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) -> FALSE (0) if (&User-Name =~ /\.$/) { (0) if (&User-Name =~ /\.$/) -> FALSE (0) if (&User-Name =~ /@\./) { (0) if (&User-Name =~ /@\./) -> FALSE (0) } # if (&User-Name) = notfound (0) } # policy filter_username = notfound (0) [preprocess] = ok (0) [chap] = noop (0) [mschap] = noop (0) [digest] = noop (0) suffix: Checking for suffix after "@" (0) suffix: No '@' in User-Name = "0050569e1ccf", looking up realm NULL (0) suffix: No such realm "NULL" (0) [suffix] = noop (0) eap: No EAP-Message, not doing EAP (0) [eap] = noop (0) files: users: Matched entry 0050569e1ccf at line 1 (0) [files] = ok (0) [expiration] = noop (0) [logintime] = noop (0) [pap] = updated (0) } # authorize = updated (0) Found Auth-Type = PAP (0) # Executing group from file /etc/freeradius/3.0/sites-enabled/default (0) Auth-Type PAP { (0) pap: Login attempt with password (0) pap: Comparing with "known good" Cleartext-Password (0) pap: User authenticated successfully (0) [pap] = ok (0) } # Auth-Type PAP = ok (0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default (0) post-auth { (0) if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) { (0) if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) -> FALSE (0) update { (0) No attributes updated for RHS &session-state: (0) } # update = noop (0) [exec] = noop (0) policy remove_reply_message_if_eap { (0) if (&reply:EAP-Message && &reply:Reply-Message) { (0) if (&reply:EAP-Message && &reply:Reply-Message) -> FALSE (0) else { (0) [noop] = noop (0) } # else = noop (0) } # policy remove_reply_message_if_eap = noop (0) if (EAP-Key-Name && &reply:EAP-Session-Id) { (0) if (EAP-Key-Name && &reply:EAP-Session-Id) -> FALSE (0) } # post-auth = noop (0) Sent Access-Accept Id 200 from 192.168.3.1:1812 to 192.168.99.1:56300 length 54 (0) Tunnel-Type = VLAN (0) Tunnel-Medium-Type = IEEE-802 (0) Tunnel-Private-Group-Id = "20" (0) Finished request Waking up in 4.9 seconds. (0) Cleaning up request packet ID 200 with timestamp +28 due to cleanup_delay was reached Ready to process requests
{master:0}[edit] root@CoreSwitch# run show dhcp server binding IP address Session Id Hardware address Expires State Interface 192.168.20.35 6 00:50:56:9e:1c:cf 86338 BOUND irb.20 192.168.20.36 7 00:50:56:9e:1c:cf 86093 BOUND irb.20
{master:0}[edit] root@AccessSwitch# run show dot1x interface ge-0/0/0 Jan 20 12:21:34 802.1X Information: Interface Role State MAC address User ge-0/0/0.0 Authenticator Authenticated 00:50:56:9E:1C:CF 0050569e1ccf {master:0}[edit] root@AccessSwitch# run show dhcp-security binding Jan 20 12:21:44 IP address MAC address Vlan Expires State Interface 192.168.20.35 00:50:56:9e:1c:cf Guest 86387 BOUND ge-0/0/0.0 {master:0}[edit] root@AccessSwitch# run show dhcp-security binding ip-source-guard Jan 20 12:21:48 IP address MAC address Vlan Expires State Interface 192.168.20.35 00:50:56:9e:1c:cf Guest 86383 BOUND ge-0/0/0.0 root@AccessSwitch# run show ethernet-switching table Jan 20 12:31:39 MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC GBP - group based policy) Ethernet switching table : 3 entries, 3 learned Routing instance : default-switch Vlan MAC MAC Age GBP Logical NH RTR name address flags Tag interface Index ID Guest 00:50:56:9e:1c:cf D - ge-0/0/0.0 0 0 Guest 7c:25:86:73:69:a0 D - ge-0/0/47.0 0 0 Management 7c:25:86:73:69:a0 D - ge-0/0/47.0 0 0 {master:0}[edit] root@AccessSwitch# run show vlans Jan 20 12:31:50 Routing instance VLAN name Tag Interfaces default-switch Guest 20 ge-0/0/0.0* ge-0/0/47.0* default-switch Management 99 ge-0/0/47.0* default-switch Secure 30 ge-0/0/47.0* default-switch default 1
2025-01-09 : Article Created
2026-01-20 : Font formatting has been corrected throughout the document.