initial commit
This commit is contained in:
commit
3586c571f3
24 files changed
+887
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
.ansible/
|
||||||
|
*.retry
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# nbops-ansible-router
|
||||||
|
|
||||||
|
Ansible framework for building a Debian 13 BIRD router VM from an initial Debian 12 install.
|
||||||
|
|
||||||
|
The first stage performs the Debian 12 to Debian 13 dist upgrade. Router configuration then installs WireGuard and BIRD, applies forwarding sysctl values, and renders configs from variables.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
- `site.yml` - main entry point.
|
||||||
|
- `inventories/production/hosts.yml` - VM inventory placeholder.
|
||||||
|
- `group_vars/routers.yml` - shared router variables.
|
||||||
|
- `roles/debian_dist_upgrade` - Debian 12 to Debian 13 upgrade workflow.
|
||||||
|
- `roles/bird_router` - WireGuard, sysctl forwarding, CZ.NIC BIRD packages, and BIRD configuration.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Edit `inventories/production/hosts.yml`, then run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ansible-playbook site.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
To run only the OS upgrade stage:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ansible-playbook site.yml --tags debian_upgrade
|
||||||
|
```
|
||||||
|
|
||||||
|
The upgrade role expects the VM to start on Debian 12/bookworm and upgrades it to Debian 13/trixie.
|
||||||
|
|
||||||
|
## Router Secrets
|
||||||
|
|
||||||
|
WireGuard private keys are read from environment variables by default:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export WG1_PRIVATEKEY='...'
|
||||||
|
export WG2_PRIVATEKEY='...'
|
||||||
|
ansible-playbook site.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
For production, prefer Ansible Vault group vars instead of committing secrets. Public keys, allowed IPs, BGP peers, package track, and package version are defined in `group_vars/routers.yml`.
|
||||||
|
|
||||||
|
## BIRD Package Track
|
||||||
|
|
||||||
|
The router role configures the CZ.NIC Labs apt repository for BIRD. Defaults:
|
||||||
|
|
||||||
|
- `bird_track: bird2`
|
||||||
|
- `bird_package_version: 2.19.1-cznic.1~trixie`
|
||||||
|
|
||||||
|
To test BIRD 3 later, set:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bird_track: bird3
|
||||||
|
bird_package_version: ""
|
||||||
|
```
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventories/production/hosts.yml
|
||||||
|
roles_path = roles
|
||||||
|
host_key_checking = True
|
||||||
|
retry_files_enabled = False
|
||||||
|
interpreter_python = auto_silent
|
||||||
|
local_tmp = .ansible/tmp
|
||||||
|
|
||||||
|
[privilege_escalation]
|
||||||
|
become = True
|
||||||
|
become_method = sudo
|
||||||
|
become_ask_pass = False
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
router id 82.215.64.105;
|
||||||
|
|
||||||
|
log syslog all;
|
||||||
|
log "/var/log/bird/bird.log" { debug, trace, remote, warning, error, auth, fatal, bug };
|
||||||
|
#log "/var/log/bird/info-bird.log" { info };
|
||||||
|
|
||||||
|
protocol device { scan time 5; }
|
||||||
|
protocol direct { ipv6; }
|
||||||
|
|
||||||
|
protocol kernel {
|
||||||
|
ipv6 { export none; };
|
||||||
|
# ipv6;
|
||||||
|
scan time 15;
|
||||||
|
# learn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol kernel {
|
||||||
|
ipv4;
|
||||||
|
scan time 15;
|
||||||
|
# export filter rt_export;
|
||||||
|
# learn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static announcev6 {
|
||||||
|
ipv6;
|
||||||
|
description "Static v6 Routes";
|
||||||
|
# route 2a12:bec0:6b0::/44 blackhole;
|
||||||
|
route 2a12:bec0:6b1::/48 via 2a12:bec2:b00b::201;
|
||||||
|
# route 2a12:bec0:6b9::/48 via 2a12:bec2:b00b::1f7;
|
||||||
|
# route 2a12:bec0:210:4::/64 via 2a12:bec0:210:4::1; #Pete-tunnel
|
||||||
|
# route 2a12:bec0:218::/48 via 2a12:bec0:210:4::2; #Pete-range
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static announcev4 {
|
||||||
|
ipv4;
|
||||||
|
description "Static v4 Routes";
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static {
|
||||||
|
ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static {
|
||||||
|
ipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_importv4 {
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_importv6 {
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_nothanks {
|
||||||
|
|
||||||
|
if (net ~ [ fd00:dead:beef:c0::/80 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd4d:6169:6c69:6f77::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd7a:115c:a1e0::/48 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd8c:c43c:133e::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd8c:c43c:133e:1::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd8c:c43c:133e:2::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ fd00:1::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ 2a12:bec2:b00b::/64 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ ::10.10.10.1/128 ]) then
|
||||||
|
reject;
|
||||||
|
if (net ~ [ 2a12:bec0:210:3::/64 ]) then
|
||||||
|
reject;
|
||||||
|
else
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter sbehop {
|
||||||
|
gw = 2a12:bec0:210:3::1;
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter brt_importv6 {
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_export {
|
||||||
|
if (proto = "announcev4") then
|
||||||
|
accept;
|
||||||
|
if (proto = "announcev6") then
|
||||||
|
accept;
|
||||||
|
# reject_bogon_asns();
|
||||||
|
# reject_v6_bogon_prefixes();
|
||||||
|
# reject_smallv6_prefixes();
|
||||||
|
# reject_long_aspaths();
|
||||||
|
reject;
|
||||||
|
# accept; #export Any Accepted Prefixes
|
||||||
|
}
|
||||||
|
|
||||||
|
#EBGP upstream sessions
|
||||||
|
protocol bgp tgj4 {
|
||||||
|
# debug all;
|
||||||
|
local 172.22.10.2 as 213026;
|
||||||
|
neighbor 172.22.10.1 as 199519;
|
||||||
|
# default bgp_local_pref 20;
|
||||||
|
multihop 255;
|
||||||
|
ipv6 {
|
||||||
|
export limit 30;
|
||||||
|
import filter sbehop;
|
||||||
|
export filter rt_nothanks;
|
||||||
|
graceful restart on;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol bgp scaleblade6 {
|
||||||
|
# debug all;
|
||||||
|
local 2a12:bec2:b00b::201 as 213026;
|
||||||
|
neighbor 2a12:bec1::2 as 52041;
|
||||||
|
multihop 255;
|
||||||
|
# default bgp_local_pref 20;
|
||||||
|
ipv6 {
|
||||||
|
export limit 50;
|
||||||
|
import filter rt_importv6;
|
||||||
|
export filter rt_nothanks;
|
||||||
|
graceful restart on;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#IBGP sessions
|
||||||
|
protocol bgp ntbx {
|
||||||
|
local 172.18.72.1 as 213026;
|
||||||
|
neighbor 172.18.72.2 as 213026;
|
||||||
|
multihop 255;
|
||||||
|
ipv6 {
|
||||||
|
import limit 20;
|
||||||
|
# import none;
|
||||||
|
import filter rt_importv6;
|
||||||
|
export filter rt_export;
|
||||||
|
# export none;
|
||||||
|
};
|
||||||
|
# ipv4 {
|
||||||
|
# import limit 20;
|
||||||
|
# import none;
|
||||||
|
# export filter rt_export;
|
||||||
|
## graceful restart on;
|
||||||
|
# };
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
BIRD_RUN_USER=bird
|
||||||
|
BIRD_RUN_GROUP=bird
|
||||||
|
#BIRD_ARGS=
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
net.ipv6.conf.all.forwarding = 1
|
||||||
|
net.ipv6.conf.default.forwarding = 1
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Wireguard to pfSense
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = ${WG1_PRIVATEKEY}
|
||||||
|
Address = 2a12:bec0:6b1::1/64,172.18.72.1/30
|
||||||
|
ListenPort = 51825
|
||||||
|
MTU = 1430
|
||||||
|
|
||||||
|
PreUp = ip neigh add proxy 82.215.64.187 dev eth0
|
||||||
|
|
||||||
|
PostDown = ip neigh del proxy 82.215.64.187 dev eth0
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = SsGjCLJBKQFDuxSnVgwua77fvb/ha4KFRiJcCBk7vF0=
|
||||||
|
AllowedIPs = 2a12:bec0:6b1::2/64,2a12:bec0:6b9::/48,172.18.72.0/30,82.215.64.187/32
|
||||||
|
#2a12:bec0:6b9:2::/64,2a12:bec0:6b9:3::/64,2a12:bec0:6b9:10::/64,2a12:bec0:6b9::/48,172.18.72.0/30,82.215.64.187/32
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Wireguard to TGJ
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = ${WG2_PRIVATEKEY}
|
||||||
|
Address = 2a12:bec0:210:3::2/64,172.22.10.2/30
|
||||||
|
ListenPort = 51820
|
||||||
|
MTU = 1430
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 1XaLeqKZimM1cS57dPzTSf/UGW8bThADjf+oBmRF82I=
|
||||||
|
AllowedIPs = 2a12:bec0:21f::2/64,172.22.10.1/30,2a12:bec0:212::/48,2a12:bec0:210::/48,2a12:bec0:214::/48
|
||||||
|
Endpoint = v4.router.colo.tgj.services:51869
|
||||||
|
PersistentKeepalive = 25
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
82.215.64.187 = Virtual Home IP used by Bird
|
||||||
|
82.215.64.105 = BIRD VPS IP
|
||||||
|
82.215.64.169 = VPS IP
|
||||||
|
v4.router.colo.tgj.services:51869 = TGJ WG Remote Node
|
||||||
|
|
||||||
|
82.215.64.187 is cloud-init added to the default interface, this should be removed in wireguard PreUp, or ansible config
|
||||||
|
|
||||||
|
Should use ansible variables for allowedIPs, private / public keys, etc. anything that should not be committed to github should be in group vars or envy
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
---
|
||||||
|
debian_upgrade_target_release: trixie
|
||||||
|
debian_upgrade_target_major_version: "13"
|
||||||
|
debian_upgrade_source_major_version: "12"
|
||||||
|
|
||||||
|
debian_upgrade_reboot_timeout: 1800
|
||||||
|
|
||||||
|
router_external_interface: eth0
|
||||||
|
|
||||||
|
router_virtual_home_ip: 82.215.64.187
|
||||||
|
router_bird_vps_ip: 82.215.64.105
|
||||||
|
router_vps_ip: 82.215.64.169
|
||||||
|
|
||||||
|
router_sysctl:
|
||||||
|
net.ipv6.conf.all.forwarding: 1
|
||||||
|
net.ipv6.conf.default.forwarding: 1
|
||||||
|
net.ipv4.ip_forward: 1
|
||||||
|
|
||||||
|
bird_enable: true
|
||||||
|
bird_track: bird2
|
||||||
|
bird_package_version: 2.19.1-cznic.1~trixie
|
||||||
|
bird_router_id: 82.215.64.105
|
||||||
|
bird_local_as: 213026
|
||||||
|
bird_run_user: bird
|
||||||
|
bird_run_group: bird
|
||||||
|
bird_log_file: /var/log/bird/bird.log
|
||||||
|
bird_sbehop_gateway: 2a12:bec0:210:3::1
|
||||||
|
|
||||||
|
bird_static_routes_v6:
|
||||||
|
- prefix: 2a12:bec0:6b1::/48
|
||||||
|
via: 2a12:bec2:b00b::201
|
||||||
|
|
||||||
|
bird_reject_prefixes_v6:
|
||||||
|
- fd00:dead:beef:c0::/80
|
||||||
|
- fd4d:6169:6c69:6f77::/64
|
||||||
|
- fd7a:115c:a1e0::/48
|
||||||
|
- fd8c:c43c:133e::/64
|
||||||
|
- fd8c:c43c:133e:1::/64
|
||||||
|
- fd8c:c43c:133e:2::/64
|
||||||
|
- fd00:1::/64
|
||||||
|
- 2a12:bec2:b00b::/64
|
||||||
|
- ::10.10.10.1/128
|
||||||
|
- 2a12:bec0:210:3::/64
|
||||||
|
|
||||||
|
bird_bgp_sessions:
|
||||||
|
- name: tgj4
|
||||||
|
local_address: 172.22.10.2
|
||||||
|
local_as: 213026
|
||||||
|
neighbor_address: 172.22.10.1
|
||||||
|
neighbor_as: 199519
|
||||||
|
address_family: ipv6
|
||||||
|
export_limit: 30
|
||||||
|
import_filter: sbehop
|
||||||
|
export_filter: rt_nothanks
|
||||||
|
graceful_restart: true
|
||||||
|
- name: scaleblade6
|
||||||
|
local_address: 2a12:bec2:b00b::201
|
||||||
|
local_as: 213026
|
||||||
|
neighbor_address: 2a12:bec1::2
|
||||||
|
neighbor_as: 52041
|
||||||
|
address_family: ipv6
|
||||||
|
export_limit: 50
|
||||||
|
import_filter: rt_importv6
|
||||||
|
export_filter: rt_nothanks
|
||||||
|
graceful_restart: true
|
||||||
|
- name: ntbx
|
||||||
|
local_address: 172.18.72.1
|
||||||
|
local_as: 213026
|
||||||
|
neighbor_address: 172.18.72.2
|
||||||
|
neighbor_as: 213026
|
||||||
|
address_family: ipv6
|
||||||
|
import_limit: 20
|
||||||
|
import_filter: rt_importv6
|
||||||
|
export_filter: rt_export
|
||||||
|
|
||||||
|
wireguard_enable: true
|
||||||
|
wireguard_interfaces:
|
||||||
|
- name: wg1
|
||||||
|
description: WireGuard to pfSense
|
||||||
|
private_key_env: WG1_PRIVATEKEY
|
||||||
|
address:
|
||||||
|
- 2a12:bec0:6b1::1/64
|
||||||
|
- 172.18.72.1/30
|
||||||
|
listen_port: 51825
|
||||||
|
mtu: 1430
|
||||||
|
pre_up:
|
||||||
|
- "ip addr del 82.215.64.187/32 dev eth0 2>/dev/null || true"
|
||||||
|
- "ip neigh add proxy 82.215.64.187 dev eth0 2>/dev/null || true"
|
||||||
|
post_down:
|
||||||
|
- "ip neigh del proxy 82.215.64.187 dev eth0 2>/dev/null || true"
|
||||||
|
peers:
|
||||||
|
- public_key: SsGjCLJBKQFDuxSnVgwua77fvb/ha4KFRiJcCBk7vF0=
|
||||||
|
allowed_ips:
|
||||||
|
- 2a12:bec0:6b1::2/64
|
||||||
|
- 2a12:bec0:6b9::/48
|
||||||
|
- 172.18.72.0/30
|
||||||
|
- 82.215.64.187/32
|
||||||
|
- name: wg2
|
||||||
|
description: WireGuard to TGJ
|
||||||
|
private_key_env: WG2_PRIVATEKEY
|
||||||
|
address:
|
||||||
|
- 2a12:bec0:210:3::2/64
|
||||||
|
- 172.22.10.2/30
|
||||||
|
listen_port: 51820
|
||||||
|
mtu: 1430
|
||||||
|
peers:
|
||||||
|
- public_key: 1XaLeqKZimM1cS57dPzTSf/UGW8bThADjf+oBmRF82I=
|
||||||
|
allowed_ips:
|
||||||
|
- 2a12:bec0:21f::2/64
|
||||||
|
- 172.22.10.1/30
|
||||||
|
- 2a12:bec0:212::/48
|
||||||
|
- 2a12:bec0:210::/48
|
||||||
|
- 2a12:bec0:214::/48
|
||||||
|
endpoint: v4.router.colo.tgj.services:51869
|
||||||
|
persistent_keepalive: 25
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
all:
|
||||||
|
children:
|
||||||
|
routers:
|
||||||
|
hosts:
|
||||||
|
router-vm:
|
||||||
|
ansible_host: 10.10.10.10
|
||||||
|
ansible_user: debian
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
router_external_interface: eth0
|
||||||
|
|
||||||
|
router_sysctl:
|
||||||
|
net.ipv6.conf.all.forwarding: 1
|
||||||
|
net.ipv6.conf.default.forwarding: 1
|
||||||
|
net.ipv4.ip_forward: 1
|
||||||
|
|
||||||
|
wireguard_enable: true
|
||||||
|
wireguard_package_name: wireguard-tools
|
||||||
|
wireguard_interfaces: []
|
||||||
|
|
||||||
|
bird_enable: true
|
||||||
|
bird_track: bird2
|
||||||
|
bird_package_name: "{{ bird_track }}"
|
||||||
|
bird_package_version: ""
|
||||||
|
bird_cznic_repo_enabled: true
|
||||||
|
bird_cznic_repo_base_url: https://pkg.labs.nic.cz
|
||||||
|
bird_cznic_repo_distribution: "{{ ansible_facts.distribution_release | default('trixie') }}"
|
||||||
|
bird_cznic_key_url: https://pkg.labs.nic.cz/gpg
|
||||||
|
|
||||||
|
bird_config_path: /etc/bird/bird.conf
|
||||||
|
bird_envvars_path: /etc/bird/envvars
|
||||||
|
bird_service_name: bird
|
||||||
|
bird_router_id: 127.0.0.1
|
||||||
|
bird_local_as: 64512
|
||||||
|
bird_run_user: bird
|
||||||
|
bird_run_group: bird
|
||||||
|
bird_log_file: /var/log/bird/bird.log
|
||||||
|
bird_sbehop_gateway: ""
|
||||||
|
bird_static_routes_v6: []
|
||||||
|
bird_static_routes_v4: []
|
||||||
|
bird_reject_prefixes_v6: []
|
||||||
|
bird_bgp_sessions: []
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
- name: Reload sysctl
|
||||||
|
ansible.builtin.command: sysctl --system
|
||||||
|
listen: reload_sysctl
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Restart WireGuard interfaces
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "wg-quick@{{ item.name }}"
|
||||||
|
state: restarted
|
||||||
|
loop: "{{ wireguard_interfaces }}"
|
||||||
|
listen: restart_wireguard_interfaces
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Restart BIRD
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ bird_service_name }}"
|
||||||
|
state: restarted
|
||||||
|
listen: restart_bird
|
||||||
|
when: bird_enable
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
- name: Validate BIRD package track
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- bird_track in ['bird2', 'bird3']
|
||||||
|
fail_msg: "bird_track must be either bird2 or bird3."
|
||||||
|
when: bird_enable
|
||||||
|
|
||||||
|
- name: Install repository prerequisites
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- apt-transport-https
|
||||||
|
- ca-certificates
|
||||||
|
- python3-debian
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
when: bird_enable and bird_cznic_repo_enabled
|
||||||
|
|
||||||
|
- name: Configure CZ.NIC Labs BIRD apt repository
|
||||||
|
ansible.builtin.deb822_repository:
|
||||||
|
name: "cznic-labs-{{ bird_track }}"
|
||||||
|
types: deb
|
||||||
|
uris: "{{ bird_cznic_repo_base_url }}/{{ bird_track }}"
|
||||||
|
suites: "{{ bird_cznic_repo_distribution }}"
|
||||||
|
components: main
|
||||||
|
signed_by: "{{ bird_cznic_key_url }}"
|
||||||
|
state: present
|
||||||
|
when: bird_enable and bird_cznic_repo_enabled
|
||||||
|
|
||||||
|
- name: Update package cache after configuring CZ.NIC repository
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: true
|
||||||
|
when: bird_enable and bird_cznic_repo_enabled
|
||||||
|
|
||||||
|
- name: Install WireGuard tools
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ wireguard_package_name }}"
|
||||||
|
state: present
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Install selected BIRD package
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ bird_package_name if bird_package_version | length == 0 else bird_package_name + '=' + bird_package_version }}"
|
||||||
|
state: present
|
||||||
|
when: bird_enable
|
||||||
|
|
||||||
|
- name: Configure router sysctl values
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: router-sysctl.conf.j2
|
||||||
|
dest: /etc/sysctl.d/99-router.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: reload_sysctl
|
||||||
|
|
||||||
|
- name: Ensure WireGuard configuration directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/wireguard
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0700"
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Validate WireGuard private keys are provided
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- >-
|
||||||
|
(item.private_key is defined and item.private_key | length > 0)
|
||||||
|
or
|
||||||
|
(item.private_key_env is defined and lookup('ansible.builtin.env', item.private_key_env) | length > 0)
|
||||||
|
fail_msg: "Private key for {{ item.name }} is missing. Set it via Ansible Vault or the matching environment lookup."
|
||||||
|
loop: "{{ wireguard_interfaces }}"
|
||||||
|
no_log: true
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Configure WireGuard interfaces
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: wg.conf.j2
|
||||||
|
dest: "/etc/wireguard/{{ item.name }}.conf"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
loop: "{{ wireguard_interfaces }}"
|
||||||
|
no_log: true
|
||||||
|
notify: restart_wireguard_interfaces
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Enable WireGuard interfaces
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "wg-quick@{{ item.name }}"
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
loop: "{{ wireguard_interfaces }}"
|
||||||
|
when: wireguard_enable
|
||||||
|
|
||||||
|
- name: Ensure BIRD log directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ bird_log_file | dirname }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ bird_run_user }}"
|
||||||
|
group: "{{ bird_run_group }}"
|
||||||
|
mode: "0755"
|
||||||
|
when: bird_enable
|
||||||
|
|
||||||
|
- name: Configure BIRD environment
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: bird-envvars.j2
|
||||||
|
dest: "{{ bird_envvars_path }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: restart_bird
|
||||||
|
when: bird_enable
|
||||||
|
|
||||||
|
- name: Configure BIRD
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: bird.conf.j2
|
||||||
|
dest: "{{ bird_config_path }}"
|
||||||
|
owner: root
|
||||||
|
group: "{{ bird_run_group }}"
|
||||||
|
mode: "0640"
|
||||||
|
validate: "bird -p -c %s"
|
||||||
|
notify: restart_bird
|
||||||
|
when: bird_enable
|
||||||
|
|
||||||
|
- name: Enable BIRD service
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ bird_service_name }}"
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
when: bird_enable
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
BIRD_RUN_USER={{ bird_run_user }}
|
||||||
|
BIRD_RUN_GROUP={{ bird_run_group }}
|
||||||
|
#BIRD_ARGS=
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
router id {{ bird_router_id }};
|
||||||
|
|
||||||
|
log syslog all;
|
||||||
|
log "{{ bird_log_file }}" { debug, trace, remote, warning, error, auth, fatal, bug };
|
||||||
|
|
||||||
|
protocol device { scan time 5; }
|
||||||
|
protocol direct { ipv6; }
|
||||||
|
|
||||||
|
protocol kernel {
|
||||||
|
ipv6 { export none; };
|
||||||
|
scan time 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol kernel {
|
||||||
|
ipv4;
|
||||||
|
scan time 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static announcev6 {
|
||||||
|
ipv6;
|
||||||
|
description "Static v6 Routes";
|
||||||
|
{% for route in bird_static_routes_v6 %}
|
||||||
|
{% if route.blackhole | default(false) %}
|
||||||
|
route {{ route.prefix }} blackhole;
|
||||||
|
{% else %}
|
||||||
|
route {{ route.prefix }} via {{ route.via }};
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static announcev4 {
|
||||||
|
ipv4;
|
||||||
|
description "Static v4 Routes";
|
||||||
|
{% for route in bird_static_routes_v4 %}
|
||||||
|
{% if route.blackhole | default(false) %}
|
||||||
|
route {{ route.prefix }} blackhole;
|
||||||
|
{% else %}
|
||||||
|
route {{ route.prefix }} via {{ route.via }};
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static {
|
||||||
|
ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol static {
|
||||||
|
ipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_importv4 {
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_importv6 {
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_nothanks {
|
||||||
|
{% for prefix in bird_reject_prefixes_v6 %}
|
||||||
|
if (net ~ [ {{ prefix }} ]) then reject;
|
||||||
|
{% endfor %}
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter sbehop {
|
||||||
|
gw = {{ bird_sbehop_gateway }};
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter brt_importv6 {
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter rt_export {
|
||||||
|
if (proto = "announcev4") then accept;
|
||||||
|
if (proto = "announcev6") then accept;
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
{% for session in bird_bgp_sessions %}
|
||||||
|
protocol bgp {{ session.name }} {
|
||||||
|
local {{ session.local_address }} as {{ session.local_as }};
|
||||||
|
neighbor {{ session.neighbor_address }} as {{ session.neighbor_as }};
|
||||||
|
multihop {{ session.multihop | default(255) }};
|
||||||
|
{{ session.address_family | default('ipv6') }} {
|
||||||
|
{% if session.import_limit is defined %}
|
||||||
|
import limit {{ session.import_limit }};
|
||||||
|
{% endif %}
|
||||||
|
{% if session.export_limit is defined %}
|
||||||
|
export limit {{ session.export_limit }};
|
||||||
|
{% endif %}
|
||||||
|
{% if session.import_filter is defined %}
|
||||||
|
import filter {{ session.import_filter }};
|
||||||
|
{% else %}
|
||||||
|
import none;
|
||||||
|
{% endif %}
|
||||||
|
{% if session.export_filter is defined %}
|
||||||
|
export filter {{ session.export_filter }};
|
||||||
|
{% else %}
|
||||||
|
export none;
|
||||||
|
{% endif %}
|
||||||
|
{% if session.graceful_restart | default(false) %}
|
||||||
|
graceful restart on;
|
||||||
|
{% endif %}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{% for key, value in router_sysctl | dictsort %}
|
||||||
|
{{ key }} = {{ value }}
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# {{ item.description | default(item.name) }}
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
{% if item.private_key is defined %}
|
||||||
|
PrivateKey = {{ item.private_key }}
|
||||||
|
{% else %}
|
||||||
|
PrivateKey = {{ lookup('ansible.builtin.env', item.private_key_env) }}
|
||||||
|
{% endif %}
|
||||||
|
Address = {{ item.address | join(',') }}
|
||||||
|
{% if item.listen_port is defined %}
|
||||||
|
ListenPort = {{ item.listen_port }}
|
||||||
|
{% endif %}
|
||||||
|
{% if item.mtu is defined %}
|
||||||
|
MTU = {{ item.mtu }}
|
||||||
|
{% endif %}
|
||||||
|
{% for command in item.pre_up | default([]) %}
|
||||||
|
PreUp = {{ command }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for command in item.post_up | default([]) %}
|
||||||
|
PostUp = {{ command }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for command in item.pre_down | default([]) %}
|
||||||
|
PreDown = {{ command }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for command in item.post_down | default([]) %}
|
||||||
|
PostDown = {{ command }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for peer in item.peers | default([]) %}
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = {{ peer.public_key }}
|
||||||
|
AllowedIPs = {{ peer.allowed_ips | join(',') }}
|
||||||
|
{% if peer.endpoint is defined %}
|
||||||
|
Endpoint = {{ peer.endpoint }}
|
||||||
|
{% endif %}
|
||||||
|
{% if peer.persistent_keepalive is defined %}
|
||||||
|
PersistentKeepalive = {{ peer.persistent_keepalive }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
debian_upgrade_source_major_version: "12"
|
||||||
|
debian_upgrade_target_major_version: "13"
|
||||||
|
debian_upgrade_target_release: trixie
|
||||||
|
debian_upgrade_reboot_timeout: 1800
|
||||||
|
|
||||||
|
debian_upgrade_sources_list_path: /etc/apt/sources.list
|
||||||
|
debian_upgrade_sources_backup_path: /etc/apt/sources.list.bookworm.bak
|
||||||
|
debian_upgrade_deb822_sources_path: /etc/apt/sources.list.d/debian.sources
|
||||||
|
debian_upgrade_deb822_sources_backup_path: /etc/apt/sources.list.d/debian.sources.bookworm.bak
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Reboot after Debian dist upgrade
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: Rebooting after Debian dist upgrade
|
||||||
|
reboot_timeout: "{{ debian_upgrade_reboot_timeout }}"
|
||||||
|
listen: reboot_after_debian_dist_upgrade
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
- name: Validate current host is Debian
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.distribution == "Debian"
|
||||||
|
fail_msg: "This role only supports Debian hosts."
|
||||||
|
|
||||||
|
- name: Validate expected source Debian major version
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.distribution_major_version == debian_upgrade_source_major_version
|
||||||
|
fail_msg: >-
|
||||||
|
Expected Debian {{ debian_upgrade_source_major_version }} before upgrade,
|
||||||
|
found Debian {{ ansible_facts.distribution_major_version }}.
|
||||||
|
success_msg: "Host is Debian {{ debian_upgrade_source_major_version }} and ready for upgrade."
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Update package cache on current release
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: true
|
||||||
|
cache_valid_time: 3600
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Upgrade installed packages before release change
|
||||||
|
ansible.builtin.apt:
|
||||||
|
upgrade: dist
|
||||||
|
autoremove: true
|
||||||
|
autoclean: true
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Check for classic apt sources list
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ debian_upgrade_sources_list_path }}"
|
||||||
|
register: debian_upgrade_sources_list_stat
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Check for deb822 apt sources
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ debian_upgrade_deb822_sources_path }}"
|
||||||
|
register: debian_upgrade_deb822_sources_stat
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Back up current apt sources
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ debian_upgrade_sources_list_path }}"
|
||||||
|
dest: "{{ debian_upgrade_sources_backup_path }}"
|
||||||
|
remote_src: true
|
||||||
|
mode: "0644"
|
||||||
|
force: false
|
||||||
|
when:
|
||||||
|
- ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
- debian_upgrade_sources_list_stat.stat.exists
|
||||||
|
|
||||||
|
- name: Back up current deb822 apt sources
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ debian_upgrade_deb822_sources_path }}"
|
||||||
|
dest: "{{ debian_upgrade_deb822_sources_backup_path }}"
|
||||||
|
remote_src: true
|
||||||
|
mode: "0644"
|
||||||
|
force: false
|
||||||
|
when:
|
||||||
|
- ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
- debian_upgrade_deb822_sources_stat.stat.exists
|
||||||
|
|
||||||
|
- name: Configure Debian target release classic apt sources
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sources.list.j2
|
||||||
|
dest: "{{ debian_upgrade_sources_list_path }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
when:
|
||||||
|
- ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
- debian_upgrade_sources_list_stat.stat.exists or not debian_upgrade_deb822_sources_stat.stat.exists
|
||||||
|
|
||||||
|
- name: Configure Debian target release deb822 apt sources
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: debian.sources.j2
|
||||||
|
dest: "{{ debian_upgrade_deb822_sources_path }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
when:
|
||||||
|
- ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
- debian_upgrade_deb822_sources_stat.stat.exists
|
||||||
|
|
||||||
|
- name: Update package cache for target release
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: true
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Perform Debian dist upgrade
|
||||||
|
ansible.builtin.apt:
|
||||||
|
upgrade: dist
|
||||||
|
autoremove: true
|
||||||
|
autoclean: true
|
||||||
|
dpkg_options: force-confdef,force-confold
|
||||||
|
environment:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
APT_LISTCHANGES_FRONTEND: none
|
||||||
|
notify: reboot_after_debian_dist_upgrade
|
||||||
|
when: ansible_facts.distribution_major_version != debian_upgrade_target_major_version
|
||||||
|
|
||||||
|
- name: Flush reboot handler before verification
|
||||||
|
ansible.builtin.meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Gather facts after possible upgrade
|
||||||
|
ansible.builtin.setup:
|
||||||
|
|
||||||
|
- name: Verify Debian target version
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.distribution == "Debian"
|
||||||
|
- ansible_facts.distribution_major_version == debian_upgrade_target_major_version
|
||||||
|
fail_msg: >-
|
||||||
|
Debian upgrade did not finish as expected. Found
|
||||||
|
{{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}.
|
||||||
|
success_msg: "Host is running Debian {{ debian_upgrade_target_major_version }}."
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Types: deb
|
||||||
|
URIs: http://deb.debian.org/debian
|
||||||
|
Suites: {{ debian_upgrade_target_release }} {{ debian_upgrade_target_release }}-updates
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
Types: deb
|
||||||
|
URIs: http://security.debian.org/debian-security
|
||||||
|
Suites: {{ debian_upgrade_target_release }}-security
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
deb http://deb.debian.org/debian {{ debian_upgrade_target_release }} main contrib non-free non-free-firmware
|
||||||
|
deb http://deb.debian.org/debian {{ debian_upgrade_target_release }}-updates main contrib non-free non-free-firmware
|
||||||
|
deb http://security.debian.org/debian-security {{ debian_upgrade_target_release }}-security main contrib non-free non-free-firmware
|
||||||
Reference in new issue
Block a user