Example 2: Configure wpa_supplicant in Ubuntu 24.04

In this example the Ansible role:

  • creates wpa_supplicant configuration

  • starts wpa_supplicant service

  • netplan configured networkd configures IP address, resolver, and routing

Create a playbook

shell> cat lp.yml
---
- hosts: test_01
  become: true
  roles:
    - vbotka.linux_postinstall

Create host_vars/test_01/lp-wpasupplicant.yml

Take a look at the wpa_supplicant services available at the remote host

test_01> systemctl list-unit-files | grep wpa
wpa_supplicant-nl80211@.service  disabled        enabled
wpa_supplicant-wired@.service    disabled        enabled
wpa_supplicant.service           disabled        enabled
wpa_supplicant@.service          disabled        enabled

The utility wpa_supplicant will be installed (4) and the services (13, 22) will be configured to use the binary (10). The nl80211 service wpa_supplicant-nl80211@.service is available. Therefor, in the configuration, we use type: nl80211 (41). This play will start the service wpa_supplicant-nl80211@wlan0.service (40). However, this service will not be started at the system start (39). The attribute disabled (47,52) tells wpa_supplicant which AP to connect automatically to

 1shell> cat host_vars/test_01/lp-wpasupplicant.yml
 2---
 3lp_wpasupplicant: true
 4lp_wpasupplicant_install: true
 5lp_wpasupplicant_debug: false
 6lp_wpasupplicant_debug_classified: false
 7lp_wpasupplicant_conf_only: false
 8lp_wpasupplicant_service_conf_only: false
 9
10lp_wpasupplicant_bin: /usr/sbin/wpa_supplicant
11lp_wpasupplicant_service_conf:
12  - path: /lib/systemd/system
13    service: wpa_supplicant@.service
14    no_extra_spaces: true
15    handlers:
16      - 'reload systemd daemon'
17    ini:
18      - section: Service
19        option: ExecStart
20        value: "{{ lp_wpasupplicant_bin }} -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I"
21  - path: /lib/systemd/system
22    service: wpa_supplicant-nl80211@.service
23    no_extra_spaces: true
24    handlers:
25      - 'reload systemd daemon'
26    ini:
27      - section: Service
28        option: ExecStart
29        value: "{{ lp_wpasupplicant_bin }} -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I"
30
31lp_wpasupplicant_conf_global:
32  - {key: ctrl_interface, value: "{{ lp_wpasupplicant_conf_ctrl_interface }}"}
33  - {key: ctrl_interface_group, value: adm}
34  - {key: fast_reauth, value: 0}
35  - {key: update_config, value: 1}
36
37lp_wpasupplicant_conf:
38  - dev: wlan0
39    enabled: false
40    state: started
41    type: nl80211
42    network:
43      - conf:
44          - {key: ssid, value: '"AP1"'}
45          - {key: psk, value: '"password"'}
46          - {key: pairwise, value: CCMP}
47          - {key: disabled, value: 0}
48      - conf:
49          - {key: ssid, value: '"AP2"'}
50          - {key: psk, value: '"password"'}
51          - {key: pairwise, value: CCMP}
52          - {key: disabled, value: 1}

In this scenario:

  • wpa_supplicant won’t be started at the system start. You have to start the service manually.

  • wpa_supplicant will automatically connect to AP1.

Warning

This role doesn’t test whether a service is already used by other interfaces or not. It’s necessary to disable such services and make sure corresponding wpa_supplicants are not running. Otherwise the restart of such service will crash.

Enable service at system start

Optionally, you might want to enable wpa_supplicant and start it. Disable all access points if you want to avoid accidental connections

lp_wpasupplicant_conf:
  - dev: wlan0
    enabled: true
    state: started
    ...

In this scenario:

  • wpa_supplicant will be started at the system start.

  • wpa_supplicant will not automatically connect to any access point. You can use wpa_cli or wpa_gui to control wpa_supplicant.

Note

  • systemd-networkd uses internal DHCP client. See Example 2: Configure wifi interface by Netplan

  • If you don’t enable DHCP client in the netplan configuration create script wpa_action.sh and run wpa_cli wpa_cli -B -i wlan0 -a /root/bin/wpa_action.sh. By default, the action script won’t be created lp_wpa_action_script: false.

Warning

Setting lp_wpasupplicant_debug_classified: true (6) will display also the passwords.

Configure wpa_supplicant

The below listing is abridged

shell> ansible-playbook lp.yml -t lp_wpasupplicant

TASK [vbotka.linux_postinstall : wpasupplicant: Create wpasupplicant configuration file]
changed: [test_01] => (item=None)
changed: [test_01]

TASK [vbotka.linux_postinstall : wpasupplicant: Configure wpa_supplicant services] *****
changed: [test_01] => (item=/lib/systemd/system/wpa_supplicant@.service)
changed: [test_01] => (item=/lib/systemd/system/wpa_supplicant-nl80211@.service)

TASK [vbotka.linux_postinstall : wpasupplicant: Manage wpa_supplicant services] ********
changed: [test_01] => (item=wpa_supplicant-nl80211@wlan0.service)

TASK [vbotka.linux_postinstall : wpasupplicant: Debug: Services] ***********************
skipping: [test_01]

RUNNING HANDLER [vbotka.linux_postinstall : reconfigure wpa_supplicant] ****************
changed: [test_01] => (item=wpa_supplicant-nl80211@wlan0.service)

PLAY RECAP *****************************************************************************
test_01: ok=7 changed=4 unreachable=0 failed=0 skipped=15 rescued=0 ignored=0

Note

  • There is no item (item=None) reported by the task Create wpasupplicant configuration file because the log is disabled no_log: "{{ not lp_wpasupplicant_debug_classified }}"

The command is idempotent

shell> ansible-playbook lp.yml -t lp_wpasupplicant
  ...
PLAY RECAP ******************************************************************
test_01: ok=11 changed=0 unreachable=0 failed=0 skipped=15 rescued=0 ignored=0

Show the process at the remote host

test_01> pgrep -a wpa_supplicant
124727 /usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-wlan0.conf -Dnl80211 -iwlan0

Show the status of the service at the remote host

test_01 > systemctl status wpa_supplicant-nl80211@wlan0.service
 wpa_supplicant-nl80211@wlan0.service - WPA supplicant daemon (interface- and nl80211 driver-specific version)
     Loaded: loaded (/usr/lib/systemd/system/wpa_supplicant-nl80211@.service; disabled; preset: enabled)
     Active: active (running) since Tue 2024-05-28 13:52:49 CEST; 3 weeks 3 days ago
   Main PID: 124727 (wpa_supplicant)
      Tasks: 1 (limit: 9282)
     Memory: 1.3M (peak: 2.2M swap: 1.3M swap peak: 1.3M)
        CPU: 2min 21.899s
     CGroup: /system.slice/system-wpa_supplicant\x2dnl80211.slice/wpa_supplicant-nl80211@wlan0.service
             └─124727 /usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-wlan0.conf -Dnl80211 -iw>

Jun 21 12:55:25 test_01 wpa_supplicant[124727]: wlan0: WPA: Group rekeying completed with <sanitized> [GTK=CCMP]

The service is active and the connection to the access-point completed.

Display the link and IP address

test_01> iw wlan0 link
Connected to <sanitized> (on wlan0)
	SSID: AP1
	freq: 2412.0
	RX: 250263021 bytes (2007924 packets)
	TX: 2194111 bytes (16115 packets)
	signal: -24 dBm
	rx bitrate: 104.0 MBit/s MCS 13
	tx bitrate: 144.4 MBit/s MCS 15 short GI
	bss flags: short-preamble short-slot-time
	dtim period: 2
	beacon int: 100

test_01> ip address show wlan0
10: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether <sanitized> brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.150/24 metric 100 brd 10.1.0.255 scope global dynamic wlan0
       valid_lft 42339sec preferred_lft 42339sec
    inet6 fe80::429b:cdff:fe03:4ca/64 scope link 
       valid_lft forever preferred_lft forever

Show the configuration of networkd

test_01> networkctl
IDX LINK  TYPE     OPERATIONAL SETUP
  1 lo    loopback carrier     unmanaged
  2 eth0  ether    routable    configured
  3 wlan0 wlan     routable    configured

3 links listed.