From 93a0f07846709812bb2f8ed655ecf24112a3e030 Mon Sep 17 00:00:00 2001 From: Raphael Dannecker Date: Wed, 17 Dec 2025 13:19:43 +0100 Subject: [PATCH 1/2] Apply libvirt firewall policy only on devices with vm_support --- roles/lmn_exam/tasks/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/roles/lmn_exam/tasks/main.yml b/roles/lmn_exam/tasks/main.yml index aba8b29..4670933 100644 --- a/roles/lmn_exam/tasks/main.yml +++ b/roles/lmn_exam/tasks/main.yml @@ -62,9 +62,11 @@ src: no-way-out.xml.j2 dest: "/etc/firewalld/policies/no-way-out-{{ item }}.xml" mode: '0644' - loop: - - HOST - - libvirt + vars: + zones: + - HOST + - "{{ 'libvirt' if vm_support | default(false) else '' }}" + loop: "{{ zones | reject('match','^$') }}" when: - exam_destination_allowed_ipv4 is defined - exam_destination_allowed_ipv4 | length > 0 From 9ee19d145924e5cd7acd21ea010bde4dc2a93ab0 Mon Sep 17 00:00:00 2001 From: Raphael Dannecker Date: Wed, 17 Dec 2025 13:24:24 +0100 Subject: [PATCH 2/2] Apply outbound restriction in exam_mode on macvtap interfaces too --- roles/lmn_exam/files/pam-exec.sh | 6 +++ roles/lmn_exam/tasks/main.yml | 10 +++++ .../lmn_exam/templates/no-way-out-nftable.j2 | 41 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 roles/lmn_exam/templates/no-way-out-nftable.j2 diff --git a/roles/lmn_exam/files/pam-exec.sh b/roles/lmn_exam/files/pam-exec.sh index 4f54861..f905cfc 100644 --- a/roles/lmn_exam/files/pam-exec.sh +++ b/roles/lmn_exam/files/pam-exec.sh @@ -5,10 +5,16 @@ if [[ "${PAM_USER}" =~ -exam$ ]]; then systemctl start firewalld.service + if [[ -f /usr/local/sbin/no-way-out-nftable ]]; then + /usr/local/sbin/no-way-out-nftable || true + fi if systemctl is-enabled --quiet libvirtd.service; then systemctl restart libvirtd.service fi elif ! (users | grep -q -- "-exam"); then + if /usr/sbin/nft list tables | /usr/bin/grep -q filtermacvtap; then + /usr/sbin/nft delete table netdev filtermacvtap || true + fi systemctl stop firewalld.service if systemctl is-enabled --quiet libvirtd.service; then systemctl restart libvirtd.service diff --git a/roles/lmn_exam/tasks/main.yml b/roles/lmn_exam/tasks/main.yml index 4670933..838fd68 100644 --- a/roles/lmn_exam/tasks/main.yml +++ b/roles/lmn_exam/tasks/main.yml @@ -71,6 +71,16 @@ - exam_destination_allowed_ipv4 is defined - exam_destination_allowed_ipv4 | length > 0 +- name: Install no-way-out nf-table for macvtap device + ansible.builtin.template: + src: no-way-out-nftable.j2 + dest: "/usr/local/sbin/no-way-out-nftable" + mode: '0755' + when: + - exam_destination_allowed_ipv4 is defined + - exam_destination_allowed_ipv4 | length > 0 + - vm_support is defined and vm_support + - name: Enable login script via pam_exec.so ansible.builtin.lineinfile: dest: /etc/pam.d/common-session diff --git a/roles/lmn_exam/templates/no-way-out-nftable.j2 b/roles/lmn_exam/templates/no-way-out-nftable.j2 new file mode 100644 index 0000000..2c6efb8 --- /dev/null +++ b/roles/lmn_exam/templates/no-way-out-nftable.j2 @@ -0,0 +1,41 @@ +#!/usr/bin/bash + +set -eu + +interfaces=$(/usr/bin/ip link | /usr/bin/sed -En 's/.*(macvtap-.*)@.*/\1/p') +gateway=$(/usr/bin/ip route list default | /usr/bin/head -1 | /usr/bin/cut -f 3 -d " ") + +filterchain="" +for interface in ${interfaces}; do + filterchain=$(cat <<- EOF +${filterchain} + + chain filterin_${interface} { + type filter hook ingress device ${interface} priority filter; policy drop; + ip saddr \$allowed_ipv4 accept + ip saddr ${gateway} accept; + ip saddr 255.255.255.255 accept; + } + + chain filterout_${interface} { + type filter hook egress device ${interface} priority filter; policy drop; + ip daddr \$allowed_ipv4 accept + ip daddr ${gateway} accept; + ip daddr 255.255.255.255 accept; + } +EOF +) +done + + + +nft_table=$(cat <<- EOF +define allowed_ipv4 = { {{ exam_destination_allowed_ipv4 | join(",") }} } + +table netdev filtermacvtap { +${filterchain} +} +EOF +) + +echo "$nft_table" | /usr/sbin/nft -f -