Remake Ansible playbook to target MikroTik router
Basically, I've exported configuration from Mikrotik router using /export and vibe-coded playbook using the file.
This commit is contained in:
20
ansible/README.md
Normal file
20
ansible/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
## RouterOS Ansible
|
||||
|
||||
This directory contains the new Ansible automation for the MikroTik router.
|
||||
|
||||
- Transport: RouterOS API (`community.routeros` collection), not SSH CLI scraping.
|
||||
- Layout: one playbook (`playbooks/routeros.yml`) importing domain task files from `tasks/`.
|
||||
- Goal: idempotent convergence using `community.routeros.api_modify` for managed paths.
|
||||
|
||||
### Quick start
|
||||
|
||||
1. Install dependencies:
|
||||
- `ansible-galaxy collection install -r ansible/requirements.yml`
|
||||
- `python -m pip install librouteros hvac`
|
||||
2. Configure secret references in `ansible/vars/routeros-secrets.yml`.
|
||||
3. Store required fields in OpenBao under configured KV path.
|
||||
4. Export token (`OPENBAO_TOKEN` or `VAULT_TOKEN`).
|
||||
5. Run:
|
||||
- `ANSIBLE_CONFIG=ansible/ansible.cfg ansible-playbook ansible/playbooks/routeros.yml`
|
||||
|
||||
More details and design rationale: `docs/ansible/routeros-design.md`.
|
||||
5
ansible/ansible.cfg
Normal file
5
ansible/ansible.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
[defaults]
|
||||
inventory = inventory/hosts.yml
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
result_format = yaml
|
||||
@@ -1,2 +0,0 @@
|
||||
[openwrt]
|
||||
2001:470:61a3:100:ffff:ffff:ffff:ffff ansible_scp_extra_args="-O"
|
||||
6
ansible/inventory/hosts.yml
Normal file
6
ansible/inventory/hosts.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
all:
|
||||
children:
|
||||
mikrotik:
|
||||
hosts:
|
||||
crs418:
|
||||
ansible_host: 192.168.255.10
|
||||
@@ -1,6 +0,0 @@
|
||||
- name: Configure router
|
||||
hosts: openwrt
|
||||
remote_user: root
|
||||
roles:
|
||||
- ansible-openwrt
|
||||
- router
|
||||
92
ansible/playbooks/routeros.yml
Normal file
92
ansible/playbooks/routeros.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
- name: Converge MikroTik RouterOS config
|
||||
hosts: mikrotik
|
||||
gather_facts: false
|
||||
connection: local
|
||||
|
||||
vars_files:
|
||||
- ../vars/routeros-secrets.yml
|
||||
|
||||
pre_tasks:
|
||||
- name: Load router secrets from OpenBao
|
||||
ansible.builtin.set_fact:
|
||||
routeros_api_username: >-
|
||||
{{
|
||||
lookup(
|
||||
'community.hashi_vault.vault_kv2_get',
|
||||
openbao_fields.routeros_api.path,
|
||||
engine_mount_point=openbao_kv_mount
|
||||
).secret[openbao_fields.routeros_api.username_key]
|
||||
}}
|
||||
routeros_api_password: >-
|
||||
{{
|
||||
lookup(
|
||||
'community.hashi_vault.vault_kv2_get',
|
||||
openbao_fields.routeros_api.path,
|
||||
engine_mount_point=openbao_kv_mount
|
||||
).secret[openbao_fields.routeros_api.password_key]
|
||||
}}
|
||||
routeros_pppoe_username: >-
|
||||
{{
|
||||
lookup(
|
||||
'community.hashi_vault.vault_kv2_get',
|
||||
openbao_fields.wan_pppoe.path,
|
||||
engine_mount_point=openbao_kv_mount
|
||||
).secret[openbao_fields.wan_pppoe.username_key]
|
||||
}}
|
||||
routeros_pppoe_password: >-
|
||||
{{
|
||||
lookup(
|
||||
'community.hashi_vault.vault_kv2_get',
|
||||
openbao_fields.wan_pppoe.path,
|
||||
engine_mount_point=openbao_kv_mount
|
||||
).secret[openbao_fields.wan_pppoe.password_key]
|
||||
}}
|
||||
routeros_tailscale_container_password: >-
|
||||
{{
|
||||
lookup(
|
||||
'community.hashi_vault.vault_kv2_get',
|
||||
openbao_fields.routeros_tailscale_container.path,
|
||||
engine_mount_point=openbao_kv_mount
|
||||
).secret[openbao_fields.routeros_tailscale_container.container_password_key]
|
||||
}}
|
||||
no_log: true
|
||||
|
||||
module_defaults:
|
||||
group/community.routeros.api:
|
||||
hostname: "{{ ansible_host }}"
|
||||
username: "{{ routeros_api_username }}"
|
||||
password: "{{ routeros_api_password }}"
|
||||
tls: true
|
||||
validate_certs: false
|
||||
validate_cert_hostname: false
|
||||
force_no_cert: true
|
||||
encoding: UTF-8
|
||||
|
||||
tasks:
|
||||
- name: Preflight checks
|
||||
ansible.builtin.import_tasks: ../tasks/preflight.yml
|
||||
|
||||
- name: Base network configuration
|
||||
ansible.builtin.import_tasks: ../tasks/base.yml
|
||||
|
||||
- name: WAN and tunnel interfaces
|
||||
ansible.builtin.import_tasks: ../tasks/wan.yml
|
||||
|
||||
- name: Hardware and platform tuning
|
||||
ansible.builtin.import_tasks: ../tasks/hardware.yml
|
||||
|
||||
- name: RouterOS container configuration
|
||||
ansible.builtin.import_tasks: ../tasks/containers.yml
|
||||
|
||||
- name: Addressing configuration
|
||||
ansible.builtin.import_tasks: ../tasks/addressing.yml
|
||||
|
||||
- name: Firewall configuration
|
||||
ansible.builtin.import_tasks: ../tasks/firewall.yml
|
||||
|
||||
- name: Routing configuration
|
||||
ansible.builtin.import_tasks: ../tasks/routing.yml
|
||||
|
||||
- name: System configuration
|
||||
ansible.builtin.import_tasks: ../tasks/system.yml
|
||||
5
ansible/requirements.yml
Normal file
5
ansible/requirements.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
collections:
|
||||
- name: community.routeros
|
||||
version: ">=3.16.0"
|
||||
- name: community.hashi_vault
|
||||
version: ">=7.1.0"
|
||||
@@ -1,53 +0,0 @@
|
||||
# Would never work without this awesome blogpost
|
||||
# https://farcaller.net/2024/making-cilium-bgp-work-with-ipv6/
|
||||
|
||||
log "/tmp/bird.log" all;
|
||||
log syslog all;
|
||||
|
||||
#Router ID
|
||||
router id 192.168.1.1;
|
||||
|
||||
protocol kernel kernel4 {
|
||||
learn;
|
||||
scan time 10;
|
||||
merge paths yes;
|
||||
ipv4 {
|
||||
import none;
|
||||
export all;
|
||||
};
|
||||
}
|
||||
|
||||
protocol kernel kernel6 {
|
||||
learn;
|
||||
scan time 10;
|
||||
merge paths yes;
|
||||
ipv6 {
|
||||
import none;
|
||||
export all;
|
||||
};
|
||||
}
|
||||
|
||||
protocol device {
|
||||
scan time 10;
|
||||
}
|
||||
|
||||
protocol direct {
|
||||
interface "*";
|
||||
}
|
||||
|
||||
protocol bgp homelab {
|
||||
debug { events };
|
||||
passive;
|
||||
direct;
|
||||
local 2001:470:61a3:100:ffff:ffff:ffff:ffff as 65000;
|
||||
neighbor range 2001:470:61a3:100::/64 as 65000;
|
||||
ipv4 {
|
||||
extended next hop yes;
|
||||
import all;
|
||||
export all;
|
||||
};
|
||||
ipv6 {
|
||||
import all;
|
||||
export all;
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
- name: Reload bird
|
||||
service:
|
||||
name: bird
|
||||
state: restarted
|
||||
enabled: true
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
- name: Install bird2
|
||||
opkg:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
# Workaround for opkg module not handling multiple names at once well
|
||||
loop:
|
||||
- bird2
|
||||
- bird2c
|
||||
|
||||
- name: Set up bird.conf
|
||||
ansible.builtin.copy:
|
||||
src: bird.conf
|
||||
dest: /etc/bird.conf
|
||||
mode: "644"
|
||||
notify: Reload bird
|
||||
48
ansible/tasks/addressing.yml
Normal file
48
ansible/tasks/addressing.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
- name: Configure IPv4 addresses
|
||||
community.routeros.api_modify:
|
||||
path: ip address
|
||||
data:
|
||||
- address: 172.17.0.1/16
|
||||
interface: dockers
|
||||
network: 172.17.0.0
|
||||
- address: 192.168.4.1/24
|
||||
interface: lo
|
||||
network: 192.168.4.0
|
||||
- address: 192.168.100.20/24
|
||||
interface: sfp-sfpplus1
|
||||
network: 192.168.100.0
|
||||
- address: 192.168.255.10/24
|
||||
interface: bridge1
|
||||
network: 192.168.255.0
|
||||
- address: 192.168.0.1/24
|
||||
interface: vlan2
|
||||
network: 192.168.0.0
|
||||
- address: 192.168.1.1/24
|
||||
interface: vlan4
|
||||
network: 192.168.1.0
|
||||
- address: 192.168.3.1/24
|
||||
interface: vlan3
|
||||
network: 192.168.3.0
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv6 addresses
|
||||
community.routeros.api_modify:
|
||||
path: ipv6 address
|
||||
data:
|
||||
- address: 2001:470:70:dd::2/64
|
||||
advertise: false
|
||||
interface: sit1
|
||||
- address: ::ffff:ffff:ffff:ffff/64
|
||||
from-pool: pool1
|
||||
interface: vlan2
|
||||
- address: 2001:470:61a3:500:ffff:ffff:ffff:ffff/64
|
||||
interface: dockers
|
||||
- address: 2001:470:61a3:100::1/64
|
||||
advertise: false
|
||||
interface: vlan4
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
226
ansible/tasks/base.yml
Normal file
226
ansible/tasks/base.yml
Normal file
@@ -0,0 +1,226 @@
|
||||
---
|
||||
- name: Configure bridges
|
||||
community.routeros.api_modify:
|
||||
path: interface bridge
|
||||
data:
|
||||
- name: bridge1
|
||||
vlan-filtering: true
|
||||
- name: dockers
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure VLAN interfaces
|
||||
community.routeros.api_modify:
|
||||
path: interface vlan
|
||||
data:
|
||||
- name: vlan2
|
||||
comment: LAN (PC, WIFI)
|
||||
interface: bridge1
|
||||
vlan-id: 2
|
||||
- name: vlan3
|
||||
comment: KAMERY
|
||||
interface: bridge1
|
||||
vlan-id: 3
|
||||
- name: vlan4
|
||||
comment: SERVER LAN
|
||||
interface: bridge1
|
||||
vlan-id: 4
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure interface lists
|
||||
community.routeros.api_modify:
|
||||
path: interface list
|
||||
data:
|
||||
- name: wan
|
||||
comment: contains interfaces facing internet
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure interface list members
|
||||
community.routeros.api_modify:
|
||||
path: interface list member
|
||||
data:
|
||||
- interface: pppoe-gpon
|
||||
list: wan
|
||||
- interface: lte1
|
||||
list: wan
|
||||
- interface: sit1
|
||||
list: wan
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure bridge ports
|
||||
community.routeros.api_modify:
|
||||
path: interface bridge port
|
||||
data:
|
||||
- bridge: dockers
|
||||
interface: veth1
|
||||
comment: Tailscale container interface
|
||||
- bridge: bridge1
|
||||
interface: ether1
|
||||
pvid: 2
|
||||
- bridge: bridge1
|
||||
interface: ether2
|
||||
pvid: 2
|
||||
- bridge: bridge1
|
||||
interface: ether8
|
||||
pvid: 4
|
||||
- bridge: bridge1
|
||||
interface: ether9
|
||||
pvid: 2
|
||||
- bridge: bridge1
|
||||
interface: ether10
|
||||
pvid: 3
|
||||
- bridge: bridge1
|
||||
interface: sfp-sfpplus2
|
||||
- bridge: bridge1
|
||||
interface: ether11
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure bridge VLAN membership
|
||||
community.routeros.api_modify:
|
||||
path: interface bridge vlan
|
||||
data:
|
||||
- bridge: bridge1
|
||||
tagged: sfp-sfpplus2
|
||||
untagged: ether1,ether2,ether9
|
||||
vlan-ids: 2
|
||||
- bridge: bridge1
|
||||
tagged: sfp-sfpplus2
|
||||
untagged: ether10
|
||||
vlan-ids: 3
|
||||
- bridge: bridge1
|
||||
untagged: ether8
|
||||
vlan-ids: 4
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv4 pools
|
||||
community.routeros.api_modify:
|
||||
path: ip pool
|
||||
data:
|
||||
- name: dhcp_pool0
|
||||
ranges: 192.168.0.50-192.168.0.250
|
||||
comment: LAN DHCP pool
|
||||
- name: dhcp_pool1
|
||||
ranges: 192.168.255.1-192.168.255.9,192.168.255.11-192.168.255.254
|
||||
comment: MGMT DHCP pool
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure DHCP servers
|
||||
community.routeros.api_modify:
|
||||
path: ip dhcp-server
|
||||
data:
|
||||
- name: dhcp1
|
||||
address-pool: dhcp_pool0
|
||||
interface: vlan2
|
||||
lease-time: 30m
|
||||
comment: LAN
|
||||
- name: dhcp2
|
||||
address-pool: dhcp_pool1
|
||||
interface: bridge1
|
||||
lease-time: 30m
|
||||
comment: MGMT
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure DHCP networks
|
||||
community.routeros.api_modify:
|
||||
path: ip dhcp-server network
|
||||
data:
|
||||
- address: 192.168.0.0/24
|
||||
dns-server: 192.168.0.1
|
||||
gateway: 192.168.0.1
|
||||
- address: 192.168.255.0/24
|
||||
dns-none: true
|
||||
gateway: 192.168.255.10
|
||||
handle_absent_entries: remove
|
||||
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
|
||||
# We can remove it now
|
||||
- name: Configure IPv6 pools
|
||||
community.routeros.api_modify:
|
||||
path: ipv6 pool
|
||||
data:
|
||||
- name: pool1
|
||||
prefix: 2001:470:61a3::/48
|
||||
prefix-length: 64
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure DNS
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ip dns
|
||||
find: {}
|
||||
values:
|
||||
allow-remote-requests: true
|
||||
cache-size: 20480
|
||||
servers: 1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1001
|
||||
|
||||
- name: Configure NAT-PMP global settings
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ip nat-pmp
|
||||
find: {}
|
||||
values:
|
||||
enabled: true
|
||||
|
||||
- name: Configure NAT-PMP interfaces
|
||||
community.routeros.api_modify:
|
||||
path: ip nat-pmp interfaces
|
||||
data:
|
||||
- interface: dockers
|
||||
type: internal
|
||||
- interface: pppoe-gpon
|
||||
type: external
|
||||
- interface: vlan2
|
||||
type: internal
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure UPnP global settings
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ip upnp
|
||||
find: {}
|
||||
values:
|
||||
enabled: true
|
||||
|
||||
- name: Configure UPnP interfaces
|
||||
community.routeros.api_modify:
|
||||
path: ip upnp interfaces
|
||||
data:
|
||||
- interface: dockers
|
||||
type: internal
|
||||
- interface: pppoe-gpon
|
||||
type: external
|
||||
- interface: vlan2
|
||||
type: internal
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv6 ND defaults
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ipv6 nd
|
||||
find:
|
||||
default: true
|
||||
values:
|
||||
advertise-dns: true
|
||||
66
ansible/tasks/containers.yml
Normal file
66
ansible/tasks/containers.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
- name: Configure container runtime defaults
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: container config
|
||||
find: {}
|
||||
values:
|
||||
registry-url: https://ghcr.io
|
||||
tmpdir: /tmp1/pull
|
||||
|
||||
- name: Configure container env lists
|
||||
community.routeros.api_modify:
|
||||
path: container envs
|
||||
data:
|
||||
- key: ADVERTISE_ROUTES
|
||||
list: tailscale
|
||||
value: 192.168.0.0/24,192.168.1.0/24,192.168.4.1/32,192.168.100.1/32,192.168.255.0/24,10.42.0.0/16,10.43.0.0/16,10.44.0.0/16,2001:470:61a3::/48
|
||||
- key: CONTAINER_GATEWAY
|
||||
list: tailscale
|
||||
value: 172.17.0.1
|
||||
- key: PASSWORD
|
||||
list: tailscale
|
||||
value: "{{ routeros_tailscale_container_password }}"
|
||||
- key: TAILSCALE_ARGS
|
||||
list: tailscale
|
||||
value: --accept-routes --advertise-exit-node --snat-subnet-routes=false
|
||||
- key: UPDATE_TAILSCALE
|
||||
list: tailscale
|
||||
value: y
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure container mounts
|
||||
community.routeros.api_modify:
|
||||
path: container mounts
|
||||
data:
|
||||
- dst: /var/lib/tailscale
|
||||
list: tailscale
|
||||
src: /usb1/tailscale
|
||||
- dst: /root
|
||||
list: tailscale-root
|
||||
src: /tmp1/tailscale-root
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure tailscale container
|
||||
community.routeros.api_modify:
|
||||
path: container
|
||||
data:
|
||||
- dns: 172.17.0.1
|
||||
envlists: tailscale
|
||||
hostname: mikrotik
|
||||
interface: veth1
|
||||
layer-dir: ""
|
||||
mountlists: tailscale
|
||||
name: tailscale-mikrotik:latest
|
||||
remote-image: fluent-networks/tailscale-mikrotik:latest
|
||||
root-dir: /usb1/containers/tailscale
|
||||
start-on-boot: true
|
||||
tmpfs: /tmp:67108864:01777
|
||||
workdir: /
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
480
ansible/tasks/firewall.yml
Normal file
480
ansible/tasks/firewall.yml
Normal file
@@ -0,0 +1,480 @@
|
||||
---
|
||||
- name: Configure IPv4 firewall filter rules
|
||||
community.routeros.api_modify:
|
||||
path: ip firewall filter
|
||||
data:
|
||||
- action: fasttrack-connection
|
||||
chain: forward
|
||||
connection-state: established,related
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow all already established connections
|
||||
connection-state: established,related
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow LTE modem management (next rule forbids it otherwise)
|
||||
dst-address: 192.168.8.1
|
||||
out-interface: lte1
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding 192.168.0.0/16 to WAN
|
||||
dst-address: 192.168.0.0/16
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-network-unreachable
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding 10.0.0.0/8 to WAN
|
||||
dst-address: 10.0.0.0/8
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-network-unreachable
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding 172.16.0.0/12 to WAN
|
||||
dst-address: 172.16.0.0/12
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-network-unreachable
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding 100.64.0.0/10 to WAN
|
||||
dst-address: 100.64.0.0/10
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-network-unreachable
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from LAN to everywhere
|
||||
in-interface: vlan2
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from SRV to internet
|
||||
in-interface: vlan4
|
||||
out-interface-list: wan
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from SRV to CAM
|
||||
in-interface: vlan4
|
||||
out-interface: vlan3
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from dockers to everywhere
|
||||
in-interface: dockers
|
||||
- action: jump
|
||||
chain: forward
|
||||
comment: Allow port forwards
|
||||
in-interface: pppoe-gpon
|
||||
jump-target: allow-ports
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Reject all remaining (port unreachable from WAN)
|
||||
in-interface-list: wan
|
||||
log-prefix: FORWARD REJECT
|
||||
reject-with: icmp-port-unreachable
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Reject all remaining (net prohibited from LAN)
|
||||
log-prefix: FORWARD REJECT
|
||||
reject-with: icmp-net-prohibited
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow all already established connections
|
||||
connection-state: established,related
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow HE tunnel
|
||||
in-interface: pppoe-gpon
|
||||
protocol: ipv6-encap
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow ICMP
|
||||
protocol: icmp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow Winbox
|
||||
dst-port: 8291
|
||||
log: true
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow SSH Mikrotik
|
||||
dst-port: 2137
|
||||
log: true
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow RouterOS API-SSL from MGMT
|
||||
dst-port: 8729
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from LAN
|
||||
dst-port: 53
|
||||
in-interface: vlan2
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: vlan2
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from SRV
|
||||
dst-port: 53
|
||||
in-interface: vlan4
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from dockers
|
||||
dst-port: 53
|
||||
in-interface: dockers
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: dockers
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow BGP from SRV
|
||||
dst-port: 179
|
||||
in-interface: vlan4
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: NAT-PMP from LAN
|
||||
dst-port: 5351
|
||||
in-interface: vlan2
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: NAT-PMP from dockers (for tailscale)
|
||||
dst-port: 5351
|
||||
in-interface: dockers
|
||||
protocol: udp
|
||||
- action: reject
|
||||
chain: input
|
||||
comment: Reject all remaining
|
||||
log-prefix: INPUT REJECT
|
||||
reject-with: icmp-port-unreachable
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow TS3
|
||||
dst-port: 9987
|
||||
out-interface: vlan4
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
dst-port: 30033
|
||||
out-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow HTTP
|
||||
dst-port: 80
|
||||
out-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow HTTPS
|
||||
dst-port: 443
|
||||
out-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow SSH Gitea
|
||||
dst-port: 22
|
||||
out-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow anything udp to Tailscale
|
||||
dst-address: 172.17.0.2
|
||||
out-interface: dockers
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: allow-ports
|
||||
comment: Allow anything from GPON to LAN (NAT-PMP)
|
||||
dst-address: 192.168.0.0/24
|
||||
in-interface: pppoe-gpon
|
||||
out-interface: vlan2
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv4 NAT rules
|
||||
community.routeros.api_modify:
|
||||
path: ip firewall nat
|
||||
data:
|
||||
- action: masquerade
|
||||
chain: srcnat
|
||||
comment: Masquerade to internet
|
||||
out-interface-list: wan
|
||||
- action: masquerade
|
||||
chain: srcnat
|
||||
comment: GPON ONT management
|
||||
dst-address: 192.168.100.1
|
||||
- action: masquerade
|
||||
chain: srcnat
|
||||
comment: LTE Modem management
|
||||
dst-address: 192.168.8.1
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: TS3
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 9987
|
||||
protocol: udp
|
||||
to-addresses: 10.44.0.0
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 30033
|
||||
protocol: tcp
|
||||
to-addresses: 10.44.0.0
|
||||
- action: src-nat
|
||||
chain: srcnat
|
||||
comment: src-nat from LAN to TS3 to some Greenland address
|
||||
dst-address: 10.44.0.0
|
||||
dst-port: 9987
|
||||
in-interface: '!pppoe-gpon'
|
||||
protocol: udp
|
||||
to-addresses: 128.0.70.5
|
||||
- action: src-nat
|
||||
chain: srcnat
|
||||
dst-address: 10.44.0.0
|
||||
dst-port: 30033
|
||||
in-interface: '!pppoe-gpon'
|
||||
protocol: tcp
|
||||
to-addresses: 128.0.70.5
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: HTTPS
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 443
|
||||
protocol: tcp
|
||||
to-addresses: 10.44.0.6
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: HTTP
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 80
|
||||
protocol: tcp
|
||||
to-addresses: 10.44.0.6
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: SSH Gitea
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 22
|
||||
protocol: tcp
|
||||
to-addresses: 10.44.0.6
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: sunshine
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 47984
|
||||
in-interface: pppoe-gpon
|
||||
protocol: tcp
|
||||
to-addresses: 192.168.0.67
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: sunshine
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 47989
|
||||
in-interface: pppoe-gpon
|
||||
protocol: tcp
|
||||
to-addresses: 192.168.0.67
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: sunshine
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 48010
|
||||
in-interface: pppoe-gpon
|
||||
protocol: tcp
|
||||
to-addresses: 192.168.0.67
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: sunshine
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 48010
|
||||
in-interface: pppoe-gpon
|
||||
protocol: udp
|
||||
to-addresses: 192.168.0.67
|
||||
- action: dst-nat
|
||||
chain: dstnat
|
||||
comment: sunshine
|
||||
dst-address: 139.28.40.212
|
||||
dst-port: 47998-48000
|
||||
in-interface: pppoe-gpon
|
||||
protocol: udp
|
||||
to-addresses: 192.168.0.67
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv6 firewall filter rules
|
||||
community.routeros.api_modify:
|
||||
path: ipv6 firewall filter
|
||||
data:
|
||||
- action: fasttrack-connection
|
||||
chain: forward
|
||||
connection-state: established,related
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow all already established connections
|
||||
connection-state: established,related
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding routed /48 from tunnelbroker to WAN
|
||||
dst-address: 2001:470:61a3::/48
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-no-route
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Forbid forwarding routed /64 from tunnelbroker to WAN
|
||||
dst-address: 2001:470:71:dd::/64
|
||||
out-interface-list: wan
|
||||
reject-with: icmp-no-route
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from LAN to everywhere
|
||||
in-interface: vlan2
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow ICMPv6 from internet to LAN
|
||||
in-interface-list: wan
|
||||
out-interface: vlan2
|
||||
protocol: icmpv6
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from SRV to internet
|
||||
in-interface: vlan4
|
||||
out-interface-list: wan
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from internet to SRV nodes
|
||||
dst-address: 2001:470:61a3:100::/64
|
||||
in-interface-list: wan
|
||||
out-interface: vlan4
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from internet to homelab LB
|
||||
dst-address: 2001:470:61a3:400::/112
|
||||
in-interface-list: wan
|
||||
out-interface: vlan4
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from SRV to CAM
|
||||
in-interface: vlan4
|
||||
out-interface: vlan3
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from dockers to everywhere
|
||||
in-interface: dockers
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow from internet to dockers
|
||||
dst-address: 2001:470:61a3:500::/64
|
||||
in-interface-list: wan
|
||||
out-interface: dockers
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow tcp transmission port to LAN
|
||||
dst-port: 51413
|
||||
out-interface: vlan2
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: forward
|
||||
comment: Allow udp transmission port to LAN
|
||||
dst-port: 51413
|
||||
out-interface: vlan2
|
||||
protocol: udp
|
||||
- action: reject
|
||||
chain: forward
|
||||
comment: Reject all remaining
|
||||
reject-with: icmp-no-route
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow all already established connections
|
||||
connection-state: established,related
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow ICMPv6
|
||||
protocol: icmpv6
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow Winbox
|
||||
dst-port: 8291
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow SSH Mikrotik
|
||||
dst-port: 2137
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from LAN
|
||||
dst-port: 53
|
||||
in-interface: vlan2
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: vlan2
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from SRV
|
||||
dst-port: 53
|
||||
in-interface: vlan4
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: vlan4
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow DNS from dockers
|
||||
dst-port: 53
|
||||
in-interface: dockers
|
||||
protocol: udp
|
||||
- action: accept
|
||||
chain: input
|
||||
dst-port: 53
|
||||
in-interface: dockers
|
||||
protocol: tcp
|
||||
- action: accept
|
||||
chain: input
|
||||
comment: Allow BGP from SRV
|
||||
dst-port: 179
|
||||
in-interface: vlan4
|
||||
protocol: tcp
|
||||
src-address: 2001:470:61a3:100::/64
|
||||
- action: reject
|
||||
chain: input
|
||||
comment: Reject all remaining
|
||||
reject-with: icmp-admin-prohibited
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure IPv6 NAT rules
|
||||
community.routeros.api_modify:
|
||||
path: ipv6 firewall nat
|
||||
data:
|
||||
- action: src-nat
|
||||
chain: srcnat
|
||||
comment: src-nat tailnet to internet
|
||||
out-interface-list: wan
|
||||
src-address: fd7a:115c:a1e0::/48
|
||||
to-address: 2001:470:61a3:600::/64
|
||||
- action: masquerade
|
||||
chain: srcnat
|
||||
disabled: true
|
||||
in-interface: vlan2
|
||||
out-interface: vlan4
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
103
ansible/tasks/hardware.yml
Normal file
103
ansible/tasks/hardware.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
- name: Configure ethernet interface metadata and SFP options
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: interface ethernet
|
||||
find:
|
||||
default-name: "{{ item.default_name }}"
|
||||
values: "{{ item.config }}"
|
||||
loop:
|
||||
- default_name: ether1
|
||||
config:
|
||||
comment: Mój pc
|
||||
- default_name: ether2
|
||||
config:
|
||||
comment: Wifi środek
|
||||
- default_name: ether8
|
||||
config:
|
||||
comment: Serwer
|
||||
- default_name: ether9
|
||||
config:
|
||||
comment: Wifi góra
|
||||
- default_name: ether10
|
||||
config:
|
||||
comment: Kamera na domu
|
||||
- default_name: ether11
|
||||
config:
|
||||
comment: KVM serwer
|
||||
- default_name: sfp-sfpplus1
|
||||
config:
|
||||
auto-negotiation: false
|
||||
comment: GPON WAN
|
||||
speed: 2.5G-baseX
|
||||
- default_name: sfp-sfpplus2
|
||||
config:
|
||||
comment: GARAŻ
|
||||
loop_control:
|
||||
label: "{{ item.default_name }}"
|
||||
|
||||
- name: Configure LTE interface defaults
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: interface lte
|
||||
find:
|
||||
default-name: lte1
|
||||
values:
|
||||
apn-profiles: default-nodns
|
||||
comment: Backup LTE WAN
|
||||
|
||||
- name: Configure LTE APN profiles
|
||||
community.routeros.api_modify:
|
||||
path: interface lte apn
|
||||
data:
|
||||
- add-default-route: false
|
||||
apn: internet
|
||||
comment: default but without dns and default route
|
||||
ipv6-interface: lte1
|
||||
name: default-nodns
|
||||
use-network-apn: true
|
||||
use-peer-dns: false
|
||||
# Default APN we can't really remove yet I don't want to reconfigure it
|
||||
- add-default-route: true
|
||||
apn: internet
|
||||
authentication: none
|
||||
default-route-distance: 2
|
||||
ip-type: auto
|
||||
name: default
|
||||
use-network-apn: true
|
||||
use-peer-dns: true
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure temporary disk for containers
|
||||
community.routeros.api_modify:
|
||||
path: disk
|
||||
data:
|
||||
- slot: tmp1
|
||||
type: tmpfs
|
||||
# This is not ideal, there's no unique identifier for usb disk,
|
||||
# after reinstall it might be assigned to another slot
|
||||
# Just adding disk with slot usb1 and not specifying anything else
|
||||
# so ansible doesn't touch it
|
||||
- slot: usb1
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure switch settings
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: interface ethernet switch
|
||||
find:
|
||||
.id: "0"
|
||||
values:
|
||||
qos-hw-offloading: true
|
||||
# Enabling L3 offloading would cause all packets to skip firewall and NAT
|
||||
l3-hw-offloading: false
|
||||
|
||||
- name: Configure neighbor discovery settings
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ip neighbor discovery-settings
|
||||
find: {}
|
||||
values:
|
||||
discover-interface-list: '!dynamic'
|
||||
46
ansible/tasks/preflight.yml
Normal file
46
ansible/tasks/preflight.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
- name: Verify API connectivity and fetch basic facts
|
||||
community.routeros.api_facts:
|
||||
gather_subset:
|
||||
- default
|
||||
- hardware
|
||||
|
||||
- name: Show target identity
|
||||
ansible.builtin.debug:
|
||||
msg: "Managing {{ ansible_host }} ({{ ansible_facts['net_model'] | default('unknown model') }})"
|
||||
|
||||
- name: Assert expected router model
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts['net_model'] is defined
|
||||
- ansible_facts['net_model'] == "CRS418-8P-8G-2S+"
|
||||
fail_msg: "Unexpected router model: {{ ansible_facts['net_model'] | default('unknown') }}"
|
||||
success_msg: "Router model matches expected CRS418-8P-8G-2S+"
|
||||
|
||||
- name: Read RouterOS device-mode flags
|
||||
community.routeros.api:
|
||||
path: system/device-mode
|
||||
register: routeros_device_mode
|
||||
check_mode: false
|
||||
changed_when: false
|
||||
|
||||
- name: Assert container feature is enabled in device mode
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- not (routeros_device_mode.skipped | default(false))
|
||||
- (routeros_device_mode | to_nice_json | lower) is search('container[^a-z0-9]+(yes|true)')
|
||||
fail_msg: "RouterOS device-mode does not report container as enabled. Payload: {{ routeros_device_mode | to_nice_json }}"
|
||||
success_msg: "RouterOS device-mode confirms container=yes"
|
||||
|
||||
- name: Read configured disks
|
||||
community.routeros.api_info:
|
||||
path: disk
|
||||
register: routeros_disks
|
||||
check_mode: false
|
||||
|
||||
- name: Assert usb1 disk is present
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- (routeros_disks.result | selectattr('slot', 'equalto', 'usb1') | list | length) > 0
|
||||
fail_msg: "Required disk slot usb1 is not present on router."
|
||||
success_msg: "Required disk usb1 is present"
|
||||
99
ansible/tasks/routing.yml
Normal file
99
ansible/tasks/routing.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
- name: Configure IPv4 routes
|
||||
community.routeros.api_modify:
|
||||
path: ip route
|
||||
data:
|
||||
- comment: Tailnet
|
||||
disabled: false
|
||||
distance: 1
|
||||
dst-address: 100.64.0.0/10
|
||||
gateway: 172.17.0.2
|
||||
routing-table: main
|
||||
scope: 30
|
||||
suppress-hw-offload: false
|
||||
target-scope: 10
|
||||
- disabled: false
|
||||
distance: 1
|
||||
dst-address: 0.0.0.0/0
|
||||
gateway: pppoe-gpon
|
||||
routing-table: main
|
||||
scope: 30
|
||||
suppress-hw-offload: false
|
||||
target-scope: 10
|
||||
vrf-interface: pppoe-gpon
|
||||
- disabled: false
|
||||
distance: 2
|
||||
dst-address: 0.0.0.0/0
|
||||
gateway: 192.168.8.1
|
||||
routing-table: main
|
||||
scope: 30
|
||||
suppress-hw-offload: false
|
||||
target-scope: 10
|
||||
vrf-interface: lte1
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure IPv6 routes
|
||||
community.routeros.api_modify:
|
||||
path: ipv6 route
|
||||
data:
|
||||
- disabled: false
|
||||
distance: 1
|
||||
dst-address: 2000::/3
|
||||
gateway: 2001:470:70:dd::1
|
||||
scope: 30
|
||||
target-scope: 10
|
||||
- comment: Tailnet
|
||||
disabled: false
|
||||
dst-address: fd7a:115c:a1e0::/48
|
||||
gateway: 2001:470:61a3:500::1
|
||||
pref-src: ""
|
||||
routing-table: main
|
||||
suppress-hw-offload: false
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure BGP instance
|
||||
community.routeros.api_modify:
|
||||
path: routing bgp instance
|
||||
data:
|
||||
- name: bgp-homelab
|
||||
as: 65000
|
||||
disabled: false
|
||||
router-id: 192.168.1.1
|
||||
routing-table: main
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure BGP templates
|
||||
community.routeros.api_modify:
|
||||
path: routing bgp template
|
||||
data:
|
||||
- name: klaster
|
||||
afi: ip,ipv6
|
||||
as: 6500
|
||||
disabled: false
|
||||
# Default template
|
||||
- name: default
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure BGP connections
|
||||
community.routeros.api_modify:
|
||||
path: routing bgp connection
|
||||
data:
|
||||
- name: bgp1
|
||||
afi: ip,ipv6
|
||||
as: 65000
|
||||
connect: true
|
||||
disabled: false
|
||||
instance: bgp-homelab
|
||||
listen: true
|
||||
local.role: ibgp
|
||||
remote.address: 2001:470:61a3:100::3/128
|
||||
routing-table: main
|
||||
templates: klaster
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
43
ansible/tasks/system.yml
Normal file
43
ansible/tasks/system.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
- name: Configure system clock
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: system clock
|
||||
find: {}
|
||||
values:
|
||||
time-zone-name: Europe/Warsaw
|
||||
|
||||
- name: Configure dedicated Ansible management user
|
||||
community.routeros.api_modify:
|
||||
path: user
|
||||
data:
|
||||
- name: "{{ routeros_api_username }}"
|
||||
group: full
|
||||
password: "{{ routeros_api_password }}"
|
||||
disabled: false
|
||||
comment: "Ansible management user"
|
||||
handle_absent_entries: ignore
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
|
||||
- name: Configure service ports and service enablement
|
||||
community.routeros.api_find_and_modify:
|
||||
ignore_dynamic: false
|
||||
path: ip service
|
||||
find:
|
||||
name: "{{ item.name }}"
|
||||
values: "{{ item }}"
|
||||
loop:
|
||||
- name: ftp
|
||||
disabled: true
|
||||
- name: telnet
|
||||
disabled: true
|
||||
- name: www
|
||||
disabled: true
|
||||
- name: ssh
|
||||
port: 2137
|
||||
- name: api
|
||||
disabled: true
|
||||
- name: api-ssl
|
||||
disabled: false
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
44
ansible/tasks/wan.yml
Normal file
44
ansible/tasks/wan.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
- name: Configure PPPoE client
|
||||
community.routeros.api_modify:
|
||||
path: interface pppoe-client
|
||||
data:
|
||||
- disabled: false
|
||||
interface: sfp-sfpplus1
|
||||
keepalive-timeout: 2
|
||||
name: pppoe-gpon
|
||||
password: "{{ routeros_pppoe_password }}"
|
||||
use-peer-dns: true
|
||||
user: "{{ routeros_pppoe_username }}"
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure 6to4 tunnel interface
|
||||
community.routeros.api_modify:
|
||||
path: interface 6to4
|
||||
data:
|
||||
- comment: Hurricane Electric IPv6 Tunnel Broker
|
||||
local-address: 139.28.40.212
|
||||
mtu: 1472
|
||||
name: sit1
|
||||
remote-address: 216.66.80.162
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
|
||||
- name: Configure veth interface for containers
|
||||
community.routeros.api_modify:
|
||||
path: interface veth
|
||||
data:
|
||||
- address: 172.17.0.2/16,2001:470:61a3:500::1/64
|
||||
container-mac-address: 7E:7E:A1:B1:2A:7C
|
||||
dhcp: false
|
||||
gateway: 172.17.0.1
|
||||
gateway6: 2001:470:61a3:500:ffff:ffff:ffff:ffff
|
||||
mac-address: 7E:7E:A1:B1:2A:7B
|
||||
name: veth1
|
||||
comment: Tailscale container
|
||||
handle_absent_entries: remove
|
||||
handle_entries_content: remove_as_much_as_possible
|
||||
ensure_order: true
|
||||
19
ansible/vars/routeros-secrets.yml
Normal file
19
ansible/vars/routeros-secrets.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# Secret references only; actual values are loaded from OpenBao/Vault at runtime.
|
||||
|
||||
# KVv2 mount and secret path (full secret path is <mount>/data/<path>).
|
||||
openbao_kv_mount: secret
|
||||
|
||||
# Field names expected in the OpenBao secret.
|
||||
openbao_fields:
|
||||
routeros_api:
|
||||
path: routeros_api
|
||||
username_key: username
|
||||
password_key: password
|
||||
wan_pppoe:
|
||||
path: wan_pppoe
|
||||
username_key: username
|
||||
password_key: password
|
||||
routeros_tailscale_container:
|
||||
path: router_tailscale
|
||||
container_password_key: container_password
|
||||
Reference in New Issue
Block a user