Refactor lmn_vpn role

- Separate `lmn_vpn` from `lmn_teacherlaptop`.
- Implement a check for the availability of the wireguard-server during the wg-config rollout.
- Enhance variable support with a standardized naming schema:
  - VPN selection via `vpn` variable (`none`, `wg`).
  - Wireguard configuration (endpoint, allowed IPs, ip_cdr, dns, searchpath).
- Run wg-config role in separate play with serial 1 to avoid conflicts, when the role attempts
  to determine the next free Wireguard IP on the server when role try to Add a check to verify if the radius certificate is revoked.
- Ensure required packages and services are only installed and configured if the `vpn` variable is set.
- Provide documentation for `lmn_vpn` module.
This commit is contained in:
Raphael Dannecker 2025-03-20 21:13:20 +01:00
parent a68aaeb81c
commit f1cb7486a5
11 changed files with 676 additions and 580 deletions

View file

@ -1,43 +0,0 @@
#!/usr/bin/bash
#
set -eu
if [[ "$CONNECTION_ID" = "VPN-Schule" ]]; then
USERNAME=$(ps -o pid,user,args -C sddm-helper | sed -nE 's/.*user (.*)$/\1/p')
USERID=$(id -u "${USERNAME}")
GROUPID=$(id -g "${USERNAME}")
KRB5CCNAME=$(ls /tmp/krb5cc_"${USERID}"_*)
export KRB5CCNAME
printenv >&2
if [[ "$NM_DISPATCHER_ACTION" = "up" ]]; then
# Exit if server is already mounted
findmnt /srv/samba/schools/default-school > /dev/null && exit 0
if ! klist -s -c "${KRB5CCNAME}"; then
#echo "try to renew KRB5-Ticket" >&2
#sudo -u "${USERNAME}" kinit -R -c "${KRB5CCNAME}"
echo "KRB5-Ticket is expired. Sleep 3 seconds and hope it will be renewed after." >&2
sleep 3
fi
echo "prepare mountpoints" >&2
umask 0002
mkdir -p /srv/samba/schools/default-school
chmod 777 /srv/samba/schools/default-school
mkdir -p "/lmn/media/${USERNAME}/share"
mount -t cifs //server/default-school/ /srv/samba/schools/default-school \
-o "sec=krb5i,cruid=${USERID},user=${USERNAME},uid=${USERID},gid=${GROUPID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10"
echo "after mount" >&2
mount --bind /srv/samba/schools/default-school/share "/lmn/media/${USERNAME}/share"
SUDO_USER=$USERNAME /usr/local/bin/install-printers.sh
elif [[ "$NM_DISPATCHER_ACTION" = "pre-down" ]]; then
# FIXME: Only umount server when Wireguard-Connection was the only connection to server.
# Dirty fix (works only in fvs-IP-Range)
if ! (ip r s | grep "10.190." | grep -v wg0); then
echo "Try to umount server shares"
umount "/lmn/media/${USERNAME}/share"
umount /srv/samba/schools/default-school
fi
fi
fi

View file

@ -1,26 +0,0 @@
#!/usr/bin/bash
set -eu
exit_script() {
echo "unmounting media - terminated by trap!" >> "/tmp/${SUDO_UID}-exit-mount.log"
findmnt "/lmn/media/${SUDO_USER}/share" && umount "/lmn/media/${SUDO_USER}/share"
findmnt "/srv/samba/schools/default-school" && umount "/srv/samba/schools/default-school"
trap - SIGHUP SIGINT SIGTERM # clear the trap
kill -- -$$ # Sends SIGTERM to child/sub processes
}
findmnt /srv/samba/schools/default-school > /dev/null && exit 0
umask 0002
mkdir -p /srv/samba/schools/default-school
chmod 777 /srv/samba/schools/default-school
mkdir -p "/lmn/media/${SUDO_USER}/share"
mount -t cifs //server/default-school/ /srv/samba/schools/default-school \
-o "sec=krb5i,cruid=${SUDO_UID},user=${SUDO_USER},uid=${SUDO_UID},gid=${SUDO_GID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10"
mount --bind /srv/samba/schools/default-school/share "/lmn/media/${SUDO_USER}/share"
echo "Einbindung erfolgreich!"
echo "Dieses Fenster bitte nicht schließen!"
trap exit_script SIGHUP SIGINT SIGTERM
sleep infinity

View file

@ -3,7 +3,6 @@
ansible.builtin.apt:
name:
- plasma-discover
- wireguard
- nextcloud-desktop
- dolphin-nextcloud
# - krb5-auth-dialog
@ -18,24 +17,6 @@
- lmn-packagekit.rules
- lmn-networkmanager.rules
- name: Copy mountserver script to /usr/local/bin
ansible.builtin.copy:
src: mountserver
dest: /usr/local/bin/
mode: "0755"
- name: Copy NetworkManager dispatcher-script (10-lmn-mount.sh)
ansible.builtin.copy:
src: 10-lmn-mount.sh
dest: /etc/NetworkManager/dispatcher.d/
mode: "0755"
- name: Create link to dispatcher-script (10-lmn-mount.sh)
ansible.builtin.file:
src: ../10-lmn-mount.sh
dest: /etc/NetworkManager/dispatcher.d/pre-down.d/10-lmn-mount.sh
state: link
- name: Deploy sudo configurations (apt for role-teacher)
ansible.builtin.copy:
dest: /etc/sudoers.d/90-lmn-teacherlaptop
@ -45,10 +26,3 @@
content: |
%role-teacher ALL=(root) NOPASSWD: /usr/bin/apt
%role-teacher ALL=(root) NOPASSWD: /usr/sbin/cryptsetup
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/mountserver
- name: Configure Wireguard
ansible.builtin.include_tasks: wg_config.yml
tags:
- never
- wgconfig

View file

@ -1,109 +0,0 @@
---
- name: Set facts wg_clientname
ansible.builtin.set_fact:
wg_clientname: "{{ ansible_hostname }}"
- name: Get Wiregard-Privatekey from server
ansible.builtin.shell:
cmd: grep PrivateKey /etc/wireguard/wg0.conf | sed -En 's/.*=\s*(.+)/\1/p'
register: wg_serverprivkey
delegate_to: wireguard_server
- name: Create public key (Server)
ansible.builtin.command:
cmd: "wg pubkey"
args:
stdin: "{{ wg_serverprivkey.stdout }}"
register: wg_serverpubkey
- name: Set facts wg_publickey (Server)
ansible.builtin.set_fact:
wg_serverpublickey: "{{ wg_serverpubkey.stdout }}"
- name: Check if Wiregard-Config exists on server
ansible.builtin.command:
cmd: "grep -A 3 '# BEGIN ANSIBLE MANAGED BLOCK {{ wg_clientname }}' /etc/wireguard/wg0.conf"
failed_when: False
register: wg_serverconfig
delegate_to: wireguard_server
- name: Set facts wg_ip
ansible.builtin.set_fact:
wg_ip: "{{ wg_serverconfig.stdout | regex_search('AllowedIPs = ([0-9.]+)/32', '\\1', multiline=True) | first }}"
when: wg_serverconfig.rc == 0 and wg_ip is not defined
- name: Check if Wireguard exists on client
ansible.builtin.stat:
path: /etc/NetworkManager/system-connections/wg0.nmconnection
register: wg_clientconfig
- name: Search IP address in NetworkManager config
ansible.builtin.command:
cmd: cat /etc/NetworkManager/system-connections/wg0.nmconnection
register: wg_address
when: wg_clientconfig.stat.exists
- name: Set facts wg_ip
ansible.builtin.set_fact:
wg_ip: "{{ wg_address.stdout | regex_search('address1=([0-9.]+)/.*', '\\1', multiline=True) | first }}"
when: wg_address.rc is defined and wg_address.rc == 0 and wg_ip is not defined
- name: Set facts wg_privatekey
ansible.builtin.set_fact:
wg_privatekey: "{{ wg_address.stdout | regex_search('private-key=(.*)$', '\\1', multiline=True) | first }}"
when: wg_address.rc is defined and wg_address.rc == 0 and wg_privatekey is not defined
- name: Search maximum AllowedIP
ansible.builtin.shell:
cmd: grep AllowedIPs /etc/wireguard/wg0.conf | sed -En 's/.*=\s*([0-9.]+)\/32.*/\1/p' | sort -t . -k 3,3n -k 4,4n | tail -n 1
register: wg_ipmax
delegate_to: wireguard_server
when: wg_ip is not defined
- name: Set facts wg_ip
ansible.builtin.set_fact:
wg_ip: "{{ wg_ipmax.stdout | ipmath(1) }}"
when: wg_ipmax.rc is defined and wg_ipmax.rc == 0 and wg_ipmax.stdout and wg_ip is not defined
- name: Create private key
ansible.builtin.command:
cmd: "wg genkey"
register: wg_genkey
when: wg_privatekey is not defined
- name: Set facts wg_privatekey
ansible.builtin.set_fact:
wg_privatekey: "{{ wg_genkey.stdout }}"
when: wg_genkey.stdout is defined
- name: Create Wireguard-Config
ansible.builtin.template:
src: wg0.nmconnection.j2
dest: /etc/NetworkManager/system-connections/wg0.nmconnection
mode: 0600
- name: Create public key
ansible.builtin.command:
cmd: "wg pubkey"
args:
stdin: "{{ wg_privatekey }}"
register: wg_pubkey
- name: Set facts wg_publickey
ansible.builtin.set_fact:
wg_publickey: "{{ wg_pubkey.stdout }}"
- name: Print WG IP
debug:
msg: "{{ wg_publickey }} -- {{ wg_pubkey.stdout }}"
- name: Set Wireguard Serverconfig
ansible.builtin.blockinfile:
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ wg_clientname }}"
path: /etc/wireguard/wg0.conf
block: |
[Peer]
PublicKey = {{ wg_publickey }}
AllowedIPs = {{ wg_ip }}/32
delegate_to: wireguard_server

View file

@ -1,26 +0,0 @@
[connection]
id=VPN-Schule
type=wireguard
autoconnect=false
interface-name=wg0
[wireguard]
listen-port=51820
private-key={{ wg_privatekey }}
mtu=1280
[wireguard-peer.{{ wg_serverpublickey }}]
endpoint={{ wg_endpoint }}
allowed-ips={{ wg_allowed_ips }}
[ipv4]
address1={{ wg_ip }}/{{ wg_ip_cdr }}
dns={{ wg_dns }}
dns-search={{ wg_dns_search }}
method=manual
[ipv6]
addr-gen-mode=stable-privacy
method=ignore
[proxy]