diff --git a/roles/backbone/tasks/main.yml b/roles/backbone/tasks/main.yml index 2ffb0ba50127f8afa27106b434901251f94078bf..49aa3e5502950dd6e661d2a18261b4b8d37fe992 100644 --- a/roles/backbone/tasks/main.yml +++ b/roles/backbone/tasks/main.yml @@ -6,9 +6,53 @@ - wireguard-tools state: present +- ansible.builtin.set_fact: + bb_bgp_local_host: "{{ bb_bgp_peers[ansible_facts['hostname']] }}" + +- name: Ensure wireguard private key permissions (please create private key manually if this fails) + ansible.builtin.file: + path: /etc/systemd/network/wg-private.key + mode: 0640 + owner: root + group: systemd-network + +- name: Deploy loopback netdev interface + ansible.builtin.template: + src: bbbgplo.netdev.j2 + dest: "/etc/systemd/network/bbbgplo.netdev" + mode: 0640 + owner: root + group: systemd-network + +- name: Deploy loopback network interface + ansible.builtin.template: + src: bbbgplo.network.j2 + dest: "/etc/systemd/network/bbbgplo.network" + mode: 0640 + owner: root + group: systemd-network + +- name: Deploy bird base config + ansible.builtin.template: + src: bird.conf.j2 + dest: "/etc/bird/bird.conf" + mode: 0640 + owner: bird + group: bird + +- ansible.builtin.set_fact: + bb_bgp_local_host: "" + +- name: Create /etc/bird/peers + ansible.builtin.file: + path: /etc/bird/peers + state: directory + mode: 0750 + owner: bird + group: bird + - name: Deploy lines include_tasks: wireguard_line.yml loop: "{{ bb_bgp_peers[ansible_facts['hostname']].lines }}" loop_control: loop_var: local_line - diff --git a/roles/backbone/tasks/wireguard_tunnel.yml b/roles/backbone/tasks/wireguard_tunnel.yml index 51cda9db9d82db69468d05fbf9215cc3a9ffa5bc..95339e9ee2bc990cbfb39ed1521c9fd02541388a 100644 --- a/roles/backbone/tasks/wireguard_tunnel.yml +++ b/roles/backbone/tasks/wireguard_tunnel.yml @@ -13,30 +13,56 @@ bb_bgp_remote_host: "{{ bb_bgp_peers[bb_bgp_remote_line.hostname] }}" bb_bgp_local_host: "{{ bb_bgp_peers[bb_bgp_local_line.hostname] }}" +- ansible.builtin.set_fact: + # WARNING: the shellscript-based backbone generates IPv6 addresses inside + # the tunnel from the IPv4 offset! ip6offset is only used to generate + # loopback IPs. + # BGP session endpoints (addresses in fd21:711:ffff:ffff::) use the IPv4 offset! + bb_bgp_local_ip6: "fd21:711:ffff:ffff::{{ tunnel.idx }}:{{ bb_bgp_local_host.ip4offset }}" + bb_bgp_remote_ip6: "fd21:711:ffff:ffff::{{ tunnel.idx }}:{{ bb_bgp_remote_host.ip4offset }}" + bb_bgp_local_ip4: "100.100.{{ tunnel.idx }}.{{ bb_bgp_local_host.ip4offset }}" + bb_bgp_remote_ip4: "100.100.{{ tunnel.idx }}.{{ bb_bgp_remote_host.ip4offset }}" + bb_bgp_interface_name: "{{ bb_bgp_local_line_name }}{{ bb_bgp_remote_line_name }}" + - ansible.builtin.debug: - msg: "{{ bb_bgp_local_line }}" + msg: "{{ bb_bgp_local_host }}" - ansible.builtin.debug: msg: "{{ bb_bgp_remote_line }}" - name: Deploy netdev file for wireguard tunnel ansible.builtin.template: src: wg-tunnel.netdev.j2 - dest: "/etc/systemd/network/{{ bb_bgp_remote_line_name }}.netdev" + dest: "/etc/systemd/network/{{ bb_bgp_interface_name }}.netdev" mode: 0750 owner: root group: systemd-network vars: - local_port: "{{ 12000 + (tunnel.idx|int - 1) * 1000 + bb_bgp_remote_host.ip4offset|int }}" - remote_port: "{{ 12000 + (tunnel.idx|int - 1) * 1000 + bb_bgp_local_host.ip4offset|int }}" + local_port: "{{ 12000 + tunnel.idx|int * 1000 + bb_bgp_remote_host.ip4offset|int }}" + remote_port: "{{ 12000 + tunnel.idx|int * 1000 + bb_bgp_local_host.ip4offset|int }}" + +- name: Ensure netdev file permissions + ansible.builtin.file: + path: "/etc/systemd/network/{{ bb_bgp_interface_name }}.netdev" + mode: 0640 + owner: root + group: systemd-network - name: Deploy network file for wireguard tunnel ansible.builtin.template: src: wg-tunnel.network.j2 - dest: "/etc/systemd/network/{{ bb_bgp_remote_line_name }}.network" - mode: 0750 + dest: "/etc/systemd/network/{{ bb_bgp_interface_name }}.network" + mode: 0640 owner: root group: systemd-network +- name: Deploy bird peer config file for tunnel + ansible.builtin.template: + src: bird-peer.conf.j2 + dest: "/etc/bird/peers/{{ bb_bgp_interface_name }}.network" + mode: 0640 + owner: bird + group: bird + - ansible.builtin.set_fact: bb_bgp_remote_line_name: "" bb_bgp_local_line_name: "" @@ -44,3 +70,8 @@ bb_bgp_local_line: "" bb_bgp_remote_host: "" bb_bgp_local_host: "" + bb_bgp_local_ip6: "" + bb_bgp_remote_ip6: "" + bb_bgp_local_ip4: "" + bb_bgp_remote_ip4: "" + bb_bgp_interface_name: "" diff --git a/roles/backbone/templates/bbbgplo.netdev.j2 b/roles/backbone/templates/bbbgplo.netdev.j2 new file mode 100644 index 0000000000000000000000000000000000000000..492364ea2ec20fbae349c494cd3d167125172560 --- /dev/null +++ b/roles/backbone/templates/bbbgplo.netdev.j2 @@ -0,0 +1,4 @@ +[NetDev] +Name=bbbgplo +Kind=dummy + diff --git a/roles/backbone/templates/bbbgplo.network.j2 b/roles/backbone/templates/bbbgplo.network.j2 new file mode 100644 index 0000000000000000000000000000000000000000..b90720c083dd7b0c21fd8b37169001ff10669e5e --- /dev/null +++ b/roles/backbone/templates/bbbgplo.network.j2 @@ -0,0 +1,19 @@ +[Match] +Name=bbbgplo + +[Network] +DHCP=no + +[Address] +Address=fd21:b4dc::a38:{{ bb_bgp_local_host.ip6offset }}/128 + +[Address] +Address=10.191.255.{{ bb_bgp_local_host.ip4offset }}/32 + +[Route] +Destination=fd21:b4dc::a38:{{ bb_bgp_local_host.ip6offset }}/128 +Type=local + +[Route] +Destination=10.191.255.{{ bb_bgp_local_host.ip4offset }}/32 +Type=local diff --git a/roles/backbone/templates/bird-peer.conf.j2 b/roles/backbone/templates/bird-peer.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..9253bea44be8e3da8999a3c5b6886b47ddb2c3c5 --- /dev/null +++ b/roles/backbone/templates/bird-peer.conf.j2 @@ -0,0 +1,23 @@ +protocol bgp {{ bb_bgp_interface_name }}_v6 { + local as BB_BGP_ASN; + neighbor {{ bb_bgp_remote_ip6 }} as {{ bb_bgp_remote_host.asn }}; + interface "{{ bb_bgp_interface_name }}"; + bfd on; + ipv6 { + import filter ffs_backbone_bgp_import; + export filter ffs_backbone_bgp_export; + }; +} + +protocol bgp {{ bb_bgp_interface_name }}_v4 { + local as BB_BGP_ASN; + neighbor {{ bb_bgp_remote_ip4 }} as {{ bb_bgp_remote_host.asn }}; + interface "{{ bb_bgp_interface_name }}"; + bfd on; + ipv4 { + import filter ffs_backbone_bgp_import; + export filter ffs_backbone_bgp_export; + }; +} + + diff --git a/roles/backbone/templates/bird.conf.j2 b/roles/backbone/templates/bird.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..efdc6efbe3d607ff9510f666d0c94cd1ebd2aa95 --- /dev/null +++ b/roles/backbone/templates/bird.conf.j2 @@ -0,0 +1,57 @@ +log syslog all; +#debug protocols all; +#debug channels all; + +define BB_BGP_ASN = {{ bb_bgp_local_host.asn }}; + +router id {{ bb_bgp_local_host.routerid }}; + +protocol device { +}; + +protocol static static_myself_v6 { + ipv6; + route fd21:b4dc::a38:{{ bb_bgp_local_host.ip6offset }}/128 via "lo"; +}; + +protocol static static_myself_v4 { + ipv4; + route 10.191.255.{{ bb_bgp_local_host.ip4offset }}/32 via "lo"; +}; + +function is_default_route() { + if net.type = NET_IP4 && net ~ [ 0.0.0.0/0 ] then return true; + if net.type = NET_IP6 && net ~ [ ::/0 ] then return true; + return false; +}; + +filter nodefaultroute { + if is_default_route() then reject; + accept; +}; + +protocol kernel t_kernel { + ipv6 { + import none; + export filter nodefaultroute; + }; +}; + +function is_ffs_net() { + if net.type = NET_IP4 && net ~ [ 10.190.0.0/15+ ] then return true; + if net.type = NET_IP6 && net ~ [ fd21:b4dc:4b00::/40 ] then return true; + return false; +}; + +filter ffs_backbone_bgp_import { + if is_ffs_net() then accept; + else reject; +}; + +filter ffs_backbone_bgp_export { + if is_ffs_net() then accept; + else reject; +}; + +include "/etc/bird/peers/*"; + diff --git a/roles/backbone/templates/wg-tunnel.netdev.j2 b/roles/backbone/templates/wg-tunnel.netdev.j2 index edcccb9e27069aa17ea56c1aea8c930aae586b12..81d10361e681a4c08b97acb7472c77a59a71f9e2 100644 --- a/roles/backbone/templates/wg-tunnel.netdev.j2 +++ b/roles/backbone/templates/wg-tunnel.netdev.j2 @@ -1,11 +1,12 @@ [NetDev] -Name={{ bb_bgp_remote_line_name }} +Name={{ bb_bgp_interface_name }} Kind=wireguard MTUBytes=1280 [WireGuard] ListenPort={{ local_port }} -PrivateKeyFile=/etc/wireguard/wg-private.key +PrivateKeyFile=/etc/systemd/network/wg-private.key +RouteTable=off [WireGuardPeer] PublicKey={{ bb_bgp_remote_host.wg_pubkey }} diff --git a/roles/backbone/templates/wg-tunnel.network.j2 b/roles/backbone/templates/wg-tunnel.network.j2 new file mode 100644 index 0000000000000000000000000000000000000000..0a3abb1e1a11cafbbcd1f5852df4b0e2292808e8 --- /dev/null +++ b/roles/backbone/templates/wg-tunnel.network.j2 @@ -0,0 +1,15 @@ +[Match] +Name={{ bb_bgp_interface_name }} + +[Network] +DHCP=no +IPv6AcceptRA=false +IPForward=yes + +[Address] +Address={{ bb_bgp_local_ip4 }}/32 +Peer={{ bb_bgp_remote_ip4 }}/32 + +[Address] +Address={{ bb_bgp_local_ip6 }}/128 +Peer={{ bb_bgp_remote_ip6 }}/128 diff --git a/roles/backbone/vars_plugins/backbone_csv_vars.py b/roles/backbone/vars_plugins/backbone_csv_vars.py index 201b38b8e2bb36ee1a61dc547874338fb89429ba..c90a5db97759ebb0a74fe50ab0a433cb4b906fa6 100644 --- a/roles/backbone/vars_plugins/backbone_csv_vars.py +++ b/roles/backbone/vars_plugins/backbone_csv_vars.py @@ -143,7 +143,7 @@ class VarsModule(BaseVarsPlugin): try: tunnels_next_idx[tunnel_key] += 1 except KeyError: - tunnels_next_idx[tunnel_key] = 1 + tunnels_next_idx[tunnel_key] = 0 tunnel = Tunnel(line_a=line_a, line_b=line_b,