feat(ansible): add IoT VLAN 5 (192.168.5.0/24, szafa wifi)

MikroTik: add vlan5 interface, bridge VLAN entry (ether3 tagged),
IP 192.168.5.1/24, IPv6 from-pool, DHCP pool/server/network,
firewall rules allowing IoT internet-only (IPv4 and IPv6),
DNS input from vlan5.

OpenWrt: add switch VLAN 5 (WAN+CPU tagged), br-iot bridge on
eth0.5, iot interface, iot firewall zone (forward ACCEPT,
input REJECT).

Also remove ensure_order from all non-firewall api_modify tasks
as RouterOS does not support move on those paths.
This commit is contained in:
2026-05-13 22:27:25 +02:00
parent 120547b1b8
commit 38f0aa699f
9 changed files with 124 additions and 27 deletions
+15 -5
View File
@@ -6,13 +6,16 @@
# input: ACCEPT (SSH, ping reachable from MGMT network) # input: ACCEPT (SSH, ping reachable from MGMT network)
# forward: REJECT (nothing routes through mgmt) # forward: REJECT (nothing routes through mgmt)
# #
# lan — client bridge (eth0.2, wireless clients) # lan — client bridge (eth0.2, LAN ports)
# input: REJECT (clients cannot SSH into the AP itself) # input: REJECT (clients cannot SSH into the AP itself)
# forward: ACCEPT (client traffic passes through to MikroTik, # forward: ACCEPT (traffic passes through to MikroTik for firewalling)
# which does all actual firewalling)
# #
# No forwarding rules between zones — traffic in/out of each zone goes # iot — IoT bridge (eth0.5, wifi only)
# directly to/from MikroTik over the trunk, not through this device. # input: REJECT (IoT devices cannot reach the AP itself)
# forward: ACCEPT (traffic passes through to MikroTik, which allows
# internet only and blocks all internal networks)
#
# No forwarding rules between zones — all inter-zone policy is on MikroTik.
- name: Configure firewall - name: Configure firewall
community.openwrt.uci: community.openwrt.uci:
@@ -42,6 +45,13 @@
option output 'ACCEPT' option output 'ACCEPT'
option forward 'ACCEPT' option forward 'ACCEPT'
config zone
option name 'iot'
list network 'iot'
option input 'REJECT'
option output 'ACCEPT'
option forward 'ACCEPT'
config rule config rule
option name 'Allow-ICMP-mgmt' option name 'Allow-ICMP-mgmt'
option src 'mgmt' option src 'mgmt'
+44
View File
@@ -0,0 +1,44 @@
---
- name: Load IoT WiFi password from OpenBao
ansible.builtin.set_fact:
openwrt_iot_wifi_password: >-
{{
lookup(
'community.hashi_vault.vault_kv2_get',
openbao_fields.iot_wifi.path,
engine_mount_point=openbao_kv_mount
).secret[openbao_fields.iot_wifi.password_key]
}}
no_log: true
- name: Configure IoT WiFi interface (szafa, WPA2, network iot)
community.openwrt.uci:
command: section
config: wireless
type: wifi-iface
name: iot_radio0
find:
device: radio0
ssid: szafa
value:
device: radio0
network: iot
mode: ap
ssid: szafa
encryption: psk2
key: "{{ openwrt_iot_wifi_password }}"
disabled: '0'
replace: true
notify: Reload wireless
- name: Enable radio0
community.openwrt.uci:
command: set
key: wireless.radio0.disabled
value: '0'
notify: Reload wireless
- name: Commit wireless config
community.openwrt.uci:
command: commit
key: wireless
+9
View File
@@ -0,0 +1,9 @@
---
# Secret references only; actual values are loaded from OpenBao/Vault at runtime.
openbao_kv_mount: secret
openbao_fields:
iot_wifi:
path: openwrt_iot_wifi
password_key: password
+6 -2
View File
@@ -24,9 +24,11 @@
- address: 192.168.3.1/24 - address: 192.168.3.1/24
interface: vlan3 interface: vlan3
network: 192.168.3.0 network: 192.168.3.0
- address: 192.168.5.1/24
interface: vlan5
network: 192.168.5.0
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure IPv6 addresses - name: Configure IPv6 addresses
community.routeros.api_modify: community.routeros.api_modify:
@@ -43,6 +45,8 @@
- address: 2001:470:61a3:100::1/64 - address: 2001:470:61a3:100::1/64
advertise: false advertise: false
interface: vlan4 interface: vlan4
- address: ::ffff:ffff:ffff:ffff/64
from-pool: pool1
interface: vlan5
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
+18 -12
View File
@@ -8,7 +8,6 @@
- name: dockers - name: dockers
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure VLAN interfaces - name: Configure VLAN interfaces
community.routeros.api_modify: community.routeros.api_modify:
@@ -26,9 +25,12 @@
comment: SERVER LAN comment: SERVER LAN
interface: bridge1 interface: bridge1
vlan-id: 4 vlan-id: 4
- name: vlan5
comment: IOT
interface: bridge1
vlan-id: 5
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure interface lists - name: Configure interface lists
community.routeros.api_modify: community.routeros.api_modify:
@@ -38,7 +40,6 @@
comment: contains interfaces facing internet comment: contains interfaces facing internet
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure interface list members - name: Configure interface list members
community.routeros.api_modify: community.routeros.api_modify:
@@ -52,7 +53,6 @@
list: wan list: wan
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure bridge ports - name: Configure bridge ports
community.routeros.api_modify: community.routeros.api_modify:
@@ -85,7 +85,6 @@
interface: ether11 interface: ether11
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure bridge VLAN membership - name: Configure bridge VLAN membership
community.routeros.api_modify: community.routeros.api_modify:
@@ -95,6 +94,9 @@
tagged: sfp-sfpplus2,ether3 tagged: sfp-sfpplus2,ether3
untagged: ether1,ether2,ether9 untagged: ether1,ether2,ether9
vlan-ids: 2 vlan-ids: 2
- bridge: bridge1
tagged: bridge1,ether3
vlan-ids: 5
- bridge: bridge1 - bridge: bridge1
tagged: sfp-sfpplus2 tagged: sfp-sfpplus2
untagged: ether10 untagged: ether10
@@ -104,7 +106,6 @@
vlan-ids: 4 vlan-ids: 4
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure IPv4 pools - name: Configure IPv4 pools
community.routeros.api_modify: community.routeros.api_modify:
@@ -116,9 +117,11 @@
- name: dhcp_pool1 - name: dhcp_pool1
ranges: 192.168.255.1-192.168.255.9,192.168.255.11-192.168.255.254 ranges: 192.168.255.1-192.168.255.9,192.168.255.11-192.168.255.254
comment: MGMT DHCP pool comment: MGMT DHCP pool
- name: dhcp_pool2
ranges: 192.168.5.50-192.168.5.250
comment: IOT DHCP pool
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure DHCP servers - name: Configure DHCP servers
community.routeros.api_modify: community.routeros.api_modify:
@@ -134,9 +137,13 @@
interface: bridge1 interface: bridge1
lease-time: 30m lease-time: 30m
comment: MGMT comment: MGMT
- name: dhcp3
address-pool: dhcp_pool2
interface: vlan5
lease-time: 30m
comment: IOT
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure DHCP networks - name: Configure DHCP networks
community.routeros.api_modify: community.routeros.api_modify:
@@ -148,9 +155,11 @@
- address: 192.168.255.0/24 - address: 192.168.255.0/24
dns-none: true dns-none: true
gateway: 192.168.255.10 gateway: 192.168.255.10
- address: 192.168.5.0/24
dns-server: 192.168.5.1
gateway: 192.168.5.1
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
# TODO: IPv6 pools are useful when we have dynamic prefix, but we don't # TODO: IPv6 pools are useful when we have dynamic prefix, but we don't
# We can remove it now # We can remove it now
@@ -163,7 +172,6 @@
prefix-length: 64 prefix-length: 64
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure DNS - name: Configure DNS
community.routeros.api_find_and_modify: community.routeros.api_find_and_modify:
@@ -195,7 +203,6 @@
type: internal type: internal
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure UPnP global settings - name: Configure UPnP global settings
community.routeros.api_find_and_modify: community.routeros.api_find_and_modify:
@@ -217,7 +224,6 @@
type: internal type: internal
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure IPv6 ND defaults - name: Configure IPv6 ND defaults
community.routeros.api_find_and_modify: community.routeros.api_find_and_modify:
@@ -29,7 +29,6 @@
value: y value: y
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure container mounts - name: Configure container mounts
community.routeros.api_modify: community.routeros.api_modify:
@@ -43,7 +42,6 @@
src: /tmp1/tailscale-root src: /tmp1/tailscale-root
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure tailscale container - name: Configure tailscale container
community.routeros.api_modify: community.routeros.api_modify:
@@ -63,4 +61,3 @@
workdir: / workdir: /
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
+32
View File
@@ -53,6 +53,11 @@
comment: Allow from SRV to CAM comment: Allow from SRV to CAM
in-interface: vlan4 in-interface: vlan4
out-interface: vlan3 out-interface: vlan3
- action: accept
chain: forward
comment: Allow from IOT to internet only
in-interface: vlan5
out-interface-list: wan
- action: accept - action: accept
chain: forward chain: forward
comment: Allow from dockers to everywhere comment: Allow from dockers to everywhere
@@ -136,6 +141,17 @@
dst-port: 53 dst-port: 53
in-interface: dockers in-interface: dockers
protocol: tcp protocol: tcp
- action: accept
chain: input
comment: Allow DNS from IOT
dst-port: 53
in-interface: vlan5
protocol: udp
- action: accept
chain: input
dst-port: 53
in-interface: vlan5
protocol: tcp
- action: accept - action: accept
chain: input chain: input
comment: Allow BGP from SRV comment: Allow BGP from SRV
@@ -368,6 +384,11 @@
comment: Allow from SRV to CAM comment: Allow from SRV to CAM
in-interface: vlan4 in-interface: vlan4
out-interface: vlan3 out-interface: vlan3
- action: accept
chain: forward
comment: Allow from IOT to internet only
in-interface: vlan5
out-interface-list: wan
- action: accept - action: accept
chain: forward chain: forward
comment: Allow from dockers to everywhere comment: Allow from dockers to everywhere
@@ -445,6 +466,17 @@
dst-port: 53 dst-port: 53
in-interface: dockers in-interface: dockers
protocol: tcp protocol: tcp
- action: accept
chain: input
comment: Allow DNS from IOT
dst-port: 53
in-interface: vlan5
protocol: udp
- action: accept
chain: input
dst-port: 53
in-interface: vlan5
protocol: tcp
- action: accept - action: accept
chain: input chain: input
comment: Allow BGP from SRV comment: Allow BGP from SRV
-2
View File
@@ -64,7 +64,6 @@
routing-table: main routing-table: main
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure BGP templates - name: Configure BGP templates
community.routeros.api_modify: community.routeros.api_modify:
@@ -96,4 +95,3 @@
templates: klaster templates: klaster
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
-3
View File
@@ -12,7 +12,6 @@
user: "{{ routeros_pppoe_username }}" user: "{{ routeros_pppoe_username }}"
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure 6to4 tunnel interface - name: Configure 6to4 tunnel interface
community.routeros.api_modify: community.routeros.api_modify:
@@ -25,7 +24,6 @@
remote-address: 216.66.80.162 remote-address: 216.66.80.162
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true
- name: Configure veth interface for containers - name: Configure veth interface for containers
community.routeros.api_modify: community.routeros.api_modify:
@@ -41,4 +39,3 @@
comment: Tailscale container comment: Tailscale container
handle_absent_entries: remove handle_absent_entries: remove
handle_entries_content: remove_as_much_as_possible handle_entries_content: remove_as_much_as_possible
ensure_order: true