Refactor lmn_wlan role

- Consolidate `lmn_wlan`, `lmn_wlan_nm`, and `lmn_wlan_8021x` into single `lmn_wlan` role.
- Implement a check for the availability of the radius-server during the EAP-TLS rollout.
- Enhance variable support with a standardized naming schema:
    - Mode selection via `wlan` variable (`none`, `psk`, `eap-tls`).
    - EAP-TLS CA configuration (CA information, email address, CA password).
    - Introduce a switch to force the (re-)issue of existing certificates.
    - PSK configuration through `wlan_ssid` and `wlan_password`.
- Add a check to verify if the radius certificate is revoked.
- Ensure required packages and services are only installed and configured if the `wifi` variable is set.
This commit is contained in:
Finn Hercke 2025-03-20 16:37:04 +01:00
parent 9f1c60eefd
commit a68aaeb81c
9 changed files with 561 additions and 538 deletions

View file

@ -0,0 +1,13 @@
---
wlan: none
wlan_force_issue: false
wlan_ssid: "Linux-Wlan"
wlan_password: "VerySecurePassw0rd"
wlan_eap_ca:
C: "DE"
ST: "Baden-Wuerttemberg"
L: "Reutlingen"
O: "Linuxschule"
emailAddress: "admin@example.com"
CN: "Radius Certificate Authority"
password: "OtherVerySecurePassw0rd"

View file

@ -0,0 +1,53 @@
---
# WPA-Enterprise (EAP-TLS) - Check if certificate needs to be re-enrolled
- name: Check if certificate is already active on client
ansible.builtin.stat:
path: "/etc/ssl/certs/{{ wlan_ssid }}.crt"
register: cert_client_active
- name: Extract serial from certificate
ansible.builtin.command: 'openssl x509 -noout -serial -in /etc/ssl/certs/{{ wlan_ssid }}.crt'
changed_when: false
register: cert_serial
when: cert_client_active.stat.exists
- name: Download crl from radius-server
ansible.builtin.get_url:
force: true
mode: "0644"
url: "http://radius.steinbeis.schule/radius-ca.crl"
dest: /tmp/radius-ca.crl
when: cert_client_active.stat.exists
- name: Get radius-server ca crl
community.crypto.x509_crl_info:
path: /tmp/radius-ca.crl
list_revoked_certificates: true
register: radius_crl
when: cert_client_active.stat.exists
- name: Check if radius-server is reachable
ansible.builtin.command: echo "Test if radius-server is reachable"
delegate_to: radius_server
register: radius_reachable
changed_when: false
ignore_unreachable: true
- name: Inform that radius_server is unreachable
ansible.builtin.debug:
msg:
- "Couldn't access radius_server. Possible reasons"
- "* server not reachable"
- "* no matching ssh-key"
changed_when: true
when: radius_reachable.unreachable is defined and radius_reachable.unreachable
- name: Issue radius certificate
ansible.builtin.include_tasks: eap-tls_issue-certificate.yaml
when:
- radius_reachable.unreachable is not defined or not radius_reachable.unreachable
- |
( not cert_client_active.stat.exists ) or
(cert_serial.stdout | replace('serial=','') | int(base=16) ) in ( radius_crl.revoked_certificates | map(attribute='serial_number') | list ) or
wlan_force_issue

View file

@ -1,10 +1,11 @@
---
# WPA-Enterprise (EAP-TLS) - (re-)enroll certificate on client
- name: Create private key for client certificate
community.crypto.openssl_privatekey:
path: /etc/ssl/private/{{ ssid }}.key
path: /etc/ssl/private/{{ wlan_ssid }}.key
- name: Check if a certificate is already issued to client
stat:
ansible.builtin.stat:
path: "/etc/freeradius/3.0/certs/issued/{{ ansible_hostname }}.crt"
register: cert_already_issued
delegate_to: radius_server
@ -13,20 +14,20 @@
community.crypto.x509_crl:
path: "/etc/freeradius/3.0/certs/ca.crl"
privatekey_path: "/etc/freeradius/3.0/certs/ca.key"
privatekey_passphrase: "{{ radiusca_password }}"
privatekey_passphrase: "{{ wlan_eap_ca.password }}"
crl_mode: "update"
issuer:
C: "DE"
ST: "Baden-Wuerttemberg"
L: "Reutlingen"
O: "Ferdinand-von-Steinbeis-Schule Reutlingen"
emailAddress: "admin@steinbeis.schule"
CN: "Radius Certificate Authority"
C: "{{ wlan_eap_ca.C }}"
ST: "{{ wlan_eap_ca.ST }}"
L: "{{ wlan_eap_ca.L }}"
O: "{{ wlan_eap_ca.O }}"
emailAddress: "{{ wlan_eap_ca.emailAddress }}"
CN: "{{ wlan_eap_ca.CN }}"
last_update: "+0s"
next_update: "+365d"
revoked_certificates:
- path: "/etc/freeradius/3.0/certs/issued/{{ ansible_hostname }}.crt"
revocation_date: 20250311120100Z
revocation_date: "{{ ansible_date_time.iso8601_basic_short | replace('T', '') }}Z"
reason: "unspecified"
delegate_to: radius_server
when: cert_already_issued.stat.exists
@ -34,12 +35,12 @@
- name: Create CSR for client certificate
community.crypto.openssl_csr_pipe:
common_name: "{{ ansible_hostname }}"
country_name: "{{ country_name }}"
state_or_province_name: "{{ state_or_province_name }}"
locality_name: "{{ locality_name }}"
organization_name: "{{ organization_name }}"
privatekey_path: /etc/ssl/private/{{ ssid }}.key
email_address: "{{ admin_email }}"
country_name: "{{ wlan_eap_ca.C }}"
state_or_province_name: "{{ wlan_eap_ca.ST }}"
locality_name: "{{ wlan_eap_ca.L }}"
organization_name: "{{ wlan_eap_ca.O }}"
privatekey_path: /etc/ssl/private/{{ wlan_ssid }}.key
email_address: "{{ wlan_eap_ca.emailAddress }}"
register: csr
- name: Sign CSR on Radius
@ -48,7 +49,7 @@
provider: ownca
ownca_path: /etc/freeradius/3.0/certs/ca.pem
ownca_privatekey_path: /etc/freeradius/3.0/certs/ca.key
ownca_privatekey_passphrase: "{{ radiusca_password }}"
ownca_privatekey_passphrase: "{{ wlan_eap_ca.password }}"
ownca_not_after: +1825d # 5 Years
delegate_to: radius_server
register: certificate
@ -69,26 +70,27 @@
- name: Write certificate to client
ansible.builtin.copy:
dest: /etc/ssl/certs/{{ ssid }}.crt
dest: /etc/ssl/certs/{{ wlan_ssid }}.crt
mode: '0644'
content: "{{ certificate.certificate }}"
- name: Check if NetworkManager config exists {{ ssid }}
- name: Check if NetworkManager config exists {{ wlan_ssid }}
ansible.builtin.stat:
path: /etc/NetworkManager/system-connections/{{ ssid }}.nmconnection
path: /etc/NetworkManager/system-connections/{{ wlan_ssid }}.nmconnection
register: nm_connection
- name: Create or modify connection via nmcli {{ ssid }}
- name: Create or modify connection via nmcli {{ wlan_ssid }}
ansible.builtin.command: >
nmcli c {% if nm_connection.stat.exists %} modify {{ ssid }} {% else %} add {% endif %}
nmcli c {% if nm_connection.stat.exists %} modify {{ wlan_ssid }} {% else %} add {% endif %}
type wifi
ifname {{ ansible_interfaces | select('search', 'wl.+') | first }}
con-name "{{ ssid }}"
con-name "{{ wlan_ssid }}"
connection.permissions ""
802-11-wireless.ssid "{{ ssid }}"
802-11-wireless.ssid "{{ wlan_ssid }}"
802-11-wireless-security.key-mgmt wpa-eap
802-1x.eap tls
802-1x.identity {{ ansible_hostname }}
802-1x.client-cert /etc/ssl/certs/{{ ssid }}.crt
802-1x.private-key /etc/ssl/private/{{ ssid }}.key
802-1x.client-cert /etc/ssl/certs/{{ wlan_ssid }}.crt
802-1x.private-key /etc/ssl/private/{{ wlan_ssid }}.key
802-1x.private-key-password dummy
changed_when: false

View file

@ -1,4 +1,5 @@
---
# Setup requirements
- name: Install packages related to wifi
ansible.builtin.apt:
name:
@ -28,3 +29,14 @@
enabled: true
daemon_reload: true
when: "'teacherlaptop' not in group_names"
# lmn_wlan - Initial configuration based on the WLAN variable
# When WLAN type is set to PSK
- name: Configure WPA-PSK
ansible.builtin.include_tasks: wpa-psk.yaml
when: wlan == 'psk'
# When WLAN type is set to EAP-TLS (802.1x)
- name: Configure WPA-Enterprise (EAP-TLS)
ansible.builtin.include_tasks: eap-tls_check-certificate.yaml
when: wlan == 'eap-tls'

View file

@ -1,13 +1,14 @@
---
# WPA-PSK - Configure SSID on client
- name: Configure WLAN for devices
community.general.nmcli:
conn_name: "{{ ssid }}"
conn_name: "{{ wlan_ssid }}"
type: wifi
ssid: "{{ ssid }}"
ssid: "{{ wlan_ssid }}"
ifname: "{{ ansible_interfaces | select('search', 'wl.+') | first }}"
wifi_sec:
key-mgmt: wpa-psk
psk: "{{ wifipasswd }}"
psk: "{{ wlan_password }}"
autoconnect: true
state: present
when: |
@ -15,9 +16,9 @@
ansible_interfaces | select('search', 'wl.+') | first is defined
- name: Provide WLAN config during installation
template:
ansible.builtin.template:
src: ssid.nmconnection.j2
dest: "/etc/NetworkManager/system-connections/{{ ssid }}.nmconnection"
dest: "/etc/NetworkManager/system-connections/{{ wlan_ssid }}.nmconnection"
mode: '0600'
when: |
run_in_installer|default(false)|bool and

View file

@ -1,67 +0,0 @@
## Make sure to use an initrd providing firmware:
## wget https://cdimage.debian.org/cdimage/firmware/testing/current/firmware.cpio.gz
## cat initrd.gz firmware.cpio.gz > initrd-fw.gz
---
- name: Install packages related to iwd and wifi
ansible.builtin.apt:
name:
- iwd
- systemd-resolved
- firmware-realtek # for our wifi sticks
- rfkill
state: latest
- name: Disable wpa-supplicant
ansible.builtin.systemd:
name: wpa_supplicant.service
enabled: False
- name: Enable iwd
ansible.builtin.systemd:
name: iwd.service
enabled: True
- name: Prepare directory for iwd
file:
path: /var/lib/iwd/
state: directory
- name: Configure iwd for wifi device
ansible.builtin.copy:
dest: /var/lib/iwd/{{ ssid }}.psk
content: |
[Security]
Passphrase={{ wifipasswd }}
- name: Use iwd (NetworkManager)
blockinfile:
dest: /etc/NetworkManager/NetworkManager.conf
block: |
[device]
match-device=interface-name:wl*
wifi.backend=iwd
[connection]
match-device=interface-name:wl*
ipv4.route-metric=2048
- name: Provide service to enable WiFi on boot
ansible.builtin.copy:
dest: /etc/systemd/system/enable-wifi.service
content: |
[Unit]
Description=Switch WiFi on
[Service]
Type=oneshot
ExecStart=/usr/sbin/rfkill unblock wlan
[Install]
WantedBy=multi-user.target
when: "'teacherlaptop' not in group_names"
- name: Enable the enable-wifi service
ansible.builtin.systemd:
name: enable-wifi.service
enabled: True
daemon_reload: True
when: "'teacherlaptop' not in group_names"