From 3871dc8f901f9dd5945b808f4bd24321ec152bd9 Mon Sep 17 00:00:00 2001 From: "Rasmus \"Pez\" Wejlgaard" Date: Sun, 7 Jun 2026 11:37:45 +0100 Subject: [PATCH] Restrict london-b Samba (445) to LAN + Tailscale, off public internet (#124) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Samba on london-b was allowed on 445/tcp from anywhere via UFW, exposing SMB/CIFS to the public internet. Tailscale already reaches it through the tailscale0 allow-all rule, so scope the explicit rule to the local London LAN (192.168.1.0/24) instead of the world. The common UFW task only ever adds allow rules, so it gained support for an optional per-port from_ip, plus a follow-up task that deletes the superseded world-open variant of any source-restricted port — otherwise the old '445 ALLOW Anywhere' rule would linger on the host and defeat the change. PESO-145 --- ansible/inventory/host_vars/london-b.yml | 5 ++++- ansible/roles/common/tasks/main.yml | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ansible/inventory/host_vars/london-b.yml b/ansible/inventory/host_vars/london-b.yml index 52d7d55..43356fc 100644 --- a/ansible/inventory/host_vars/london-b.yml +++ b/ansible/inventory/host_vars/london-b.yml @@ -33,4 +33,7 @@ common_ufw_allowed_ports: - { port: 32400, proto: tcp, comment: "Plex Media Server" } - { port: 6881, proto: tcp, comment: "BitTorrent" } - { port: 6881, proto: udp, comment: "BitTorrent" } - - { port: 445, proto: tcp, comment: "Samba" } + # SMB is reachable over Tailscale via the tailscale0 allow-all rule; this + # entry additionally allows the local London LAN. Deliberately NOT open to + # the public internet (see PESO-145). + - { port: 445, proto: tcp, from_ip: "192.168.1.0/24", comment: "Samba (LAN only)" } diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml index 2751624..a088acd 100644 --- a/ansible/roles/common/tasks/main.yml +++ b/ansible/roles/common/tasks/main.yml @@ -99,6 +99,7 @@ rule: allow port: "{{ item.port | string }}" proto: "{{ item.proto | default('tcp') }}" + from_ip: "{{ item.from_ip | default(omit) }}" comment: "{{ item.comment | default(omit) }}" loop: "{{ common_ufw_allowed_ports }}" when: @@ -106,6 +107,21 @@ - common_ufw_allowed_ports | length > 0 notify: Reload ufw +# When a port is restricted to a source (from_ip), make sure the older +# unrestricted "allow from anywhere" variant of the same rule isn't left +# lingering on the host — UFW keeps it otherwise, which would defeat the +# source restriction. Deleting an absent rule is a no-op, so this is safe +# on hosts that never had the broad rule. +- name: Remove superseded world-open rules for source-restricted ports + community.general.ufw: + rule: allow + port: "{{ item.port | string }}" + proto: "{{ item.proto | default('tcp') }}" + delete: true + loop: "{{ common_ufw_allowed_ports | selectattr('from_ip', 'defined') | list }}" + when: common_ufw_enabled | bool + notify: Reload ufw + - name: Enable UFW community.general.ufw: state: enabled