diff --git a/ansible.cfg b/ansible.cfg index 8d528bd..e2d6a32 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -33,3 +33,6 @@ become_ask_pass = True # TO know what changed always = yes + +[ssh_connection] +pipelining = True diff --git a/group_vars/all/vars.yml b/group_vars/all/vars.yml index c3f0502..2b53213 100644 --- a/group_vars/all/vars.yml +++ b/group_vars/all/vars.yml @@ -50,8 +50,8 @@ dns_host_suffix_backup: 153 backup_dns_servers: - "80.67.169.12" # French Data Network (FDN) (ns0.fdn.fr) -# Misc -mtu: 1400 +# Finally raised! +mtu: 1500 subnet_ids: ap: "14{{ apartment_block_id }}" @@ -78,3 +78,9 @@ radius_pg_re2o_ro_password: "{{ vault_re2o_db_user_passwords.re2o_ro }}" apartment_block_dhcp: "{{ apartment_block }}" + + + +# Careful, this is not byte-aligned, just nibble-aligned (RIPE gave us a /28). +# However, we ALWAYS keep the trailing 0 to have byte alignment. +ipv6_base_prefix: "2a09:6840" diff --git a/network.yml b/network.yml index bca43c0..43f2297 100755 --- a/network.yml +++ b/network.yml @@ -22,9 +22,12 @@ # Déploiement du service re2o aurore-firewall et keepalived +# radvd: IPv6 SLAAC (/64 subnets, private IPs). +# Must NOT be on routeur-aurore-*, or will with DHCPv6! - hosts: ~routeur-(pacaterie|edc|fleming|gs).*\.adm\.auro\.re roles: - router + - radvd # Radius (backup only for now) diff --git a/nuke-radius-dbs.yml b/nuke-radius-dbs.yml new file mode 100755 index 0000000..b23f08f --- /dev/null +++ b/nuke-radius-dbs.yml @@ -0,0 +1,7 @@ +#!/usr/bin/env ansible-playbook +--- +- hosts: ~radius-(edc|fleming|pacaterie|gs).* + roles: + - radius + vars: + nuke_radius: true diff --git a/roles/baseconfig/templates/resolv.conf b/roles/baseconfig/templates/resolv.conf index c94128f..935eeeb 100644 --- a/roles/baseconfig/templates/resolv.conf +++ b/roles/baseconfig/templates/resolv.conf @@ -1,3 +1,4 @@ domain adm.auro.re nameserver 10.128.0.253 +nameserver 2a09:6840:128::253 nameserver 80.67.169.12 diff --git a/roles/radius/tasks/main.yml b/roles/radius/tasks/main.yml index 9172c79..ba3024e 100644 --- a/roles/radius/tasks/main.yml +++ b/roles/radius/tasks/main.yml @@ -15,7 +15,7 @@ git: repo: "https://gitlab.federez.net/re2o/re2o.git" dest: "/var/www/re2o" - version: "master_freeradius_python3" + version: "dev" force: true - name: Template local re2o settings @@ -118,6 +118,29 @@ password: "{{ radius_pg_replication_password }}" become_user: postgres + +- name: Nuking - Stop freeradius + systemd: + name: freeradius + state: stopped + when: nuke_radius|bool + +- name: Nuking - Remove old subscription if it exists + community.general.postgresql_subscription: + name: "re2o_subscription_{{ inventory_hostname_short | replace('-','_') }}" + db: re2o + state: absent + become_user: postgres + when: nuke_radius|bool + ignore_errors: yes + +- name: Nuking - Destroy old local DB if it exists + community.general.postgresql_db: + name: re2o + state: absent + become_user: postgres + when: nuke_radius|bool + - name: Create local DB community.general.postgresql_db: name: re2o @@ -128,7 +151,6 @@ lc_ctype: 'fr_FR.UTF-8' become_user: postgres - - name: Dump radius re2o PostgreSQL database schema from master community.general.postgresql_db: name: re2o diff --git a/roles/radvd/handlers/main.yml b/roles/radvd/handlers/main.yml new file mode 100644 index 0000000..0bc0b9d --- /dev/null +++ b/roles/radvd/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart radvd + systemd: + state: restarted + name: radvd diff --git a/roles/radvd/tasks/main.yml b/roles/radvd/tasks/main.yml new file mode 100644 index 0000000..75c72c1 --- /dev/null +++ b/roles/radvd/tasks/main.yml @@ -0,0 +1,22 @@ +--- + + +# Warning: radvd installation seems to fail if the configuration +# file doesn't already exist when the package is installed, +# so the order is important. +- name: Configure radvd + template: + src: radvd.conf.j2 + dest: /etc/radvd.conf + mode: 0644 + notify: restart radvd + tags: + - radconf + +- name: Install radvd + apt: + update_cache: true + name: radvd + state: present + notify: restart radvd + diff --git a/roles/radvd/templates/radvd.conf.j2 b/roles/radvd/templates/radvd.conf.j2 new file mode 100644 index 0000000..dc5f1a2 --- /dev/null +++ b/roles/radvd/templates/radvd.conf.j2 @@ -0,0 +1,81 @@ +# -*- mode: conf-unix; coding: utf-8 -*- + +## +# Bornes Wi-Fi +## + +# Not deployed yet! +# Need to add an interface for this VLAN on "routeur-*" hosts. + +# interface ens19 { # XXX - FIX THE INTERFACE NAME +# AdvSendAdvert on; +# AdvLinkMTU {{ mtu }}; +# AdvDefaultPreference high; +# MaxRtrAdvInterval 30; +# +# AdvRASrcAddress { +# {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::0:250; # Unifi controller +# }; +# +# prefix {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::/64 { +# AdvRouterAddr on; +# }; +# +# # La zone DNS +# DNSSL borne.auro.re {}; +# +# # Les DNS récursifs +# RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::{{ dns_host_suffix_main }} {}; +# RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::{{ dns_host_suffix_backup }} {}; +# }; + +## +# Utilisateurs filaire +## +interface ens20 { + AdvSendAdvert on; + AdvLinkMTU {{ mtu }}; + AdvDefaultPreference high; + MaxRtrAdvInterval 30; + + AdvRASrcAddress { + fe80::1; # link-local virtual IP used with keepalived + }; + + prefix {{ ipv6_base_prefix }}:{{ subnet_ids.users_wired }}::/64 { + AdvRouterAddr on; + }; + + DNSSL fil.{{ apartment_block_dhcp }}.auro.re {}; # TODO: fix this shitty workaround. + + RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.users_wired }}::{{ dns_host_suffix_main }} {}; + RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.users_wired }}::{{ dns_host_suffix_backup }} {}; +}; + + +## +# Utilisateurs wifi +## +interface ens21 { + AdvSendAdvert on; + AdvLinkMTU {{ mtu }}; + AdvDefaultPreference high; + MaxRtrAdvInterval 30; + + AdvRASrcAddress { + fe80::1; + }; + + prefix {{ ipv6_base_prefix }}:{{ subnet_ids.users_wifi }}::/64 { + AdvRouterAddr on; + }; + + DNSSL wifi.{{ apartment_block_dhcp }}.auro.re {}; # TODO: fix this shitty workaround. + + RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.users_wifi }}::{{ dns_host_suffix_main }} {}; + RDNSS {{ ipv6_base_prefix }}:{{ subnet_ids.users_wifi }}::{{ dns_host_suffix_backup }} {}; +}; + + + +# For public IPs: will use DHCPv6, deployed on routeur-aurore alone. diff --git a/roles/router/tasks/main.yml b/roles/router/tasks/main.yml index dd7f865..d09a2c8 100644 --- a/roles/router/tasks/main.yml +++ b/roles/router/tasks/main.yml @@ -6,6 +6,12 @@ value: '1' sysctl_set: yes +- name: Enable IPv6 packet forwarding + ansible.posix.sysctl: + name: net.ipv6.conf.all.forwarding + value: '1' + sysctl_set: yes + - name: Install aurore-firewall (re2o-service) import_role: name: re2o-service diff --git a/roles/router/templates/firewall_config.py b/roles/router/templates/firewall_config.py index bd013d3..4f6b755 100644 --- a/roles/router/templates/firewall_config.py +++ b/roles/router/templates/firewall_config.py @@ -24,8 +24,8 @@ ### Give me a role -# routeur4 = routeur IPv4 -role = ['routeur4'] +# previously: routeur4 = routeur IPv4 +role = ['routeur'] ### Specify each interface role diff --git a/roles/router/templates/keepalived.conf b/roles/router/templates/keepalived.conf index 6e51fd9..cd217f3 100644 --- a/roles/router/templates/keepalived.conf +++ b/roles/router/templates/keepalived.conf @@ -2,12 +2,12 @@ global_defs { notification_email { monitoring.aurore@lists.crans.org } - notification_email_from routeur-edc-backup@auro.re + notification_email_from routeur-{{ apartment_block }}{% if 'backup' in inventory_hostname %}-backup{% endif %}@auro.re smtp_server smtp.crans.org } -vrrp_instance VI_ROUT_{{ apartment_block }} { +vrrp_instance VI_ROUT_{{ apartment_block }}_IPv4 { {% if 'backup' in inventory_hostname %} state BACKUP priority 100 @@ -21,12 +21,11 @@ vrrp_instance VI_ROUT_{{ apartment_block }} { interface ens18 # Shared by MASTER and BACKUP - virtual_router_id {{ apartment_block_id }} + virtual_router_id 4{{ apartment_block_id }} # Timeout in seconds before failover kicks in. advert_int 2 - # Used to authenticate VRRP communication between master and backup. authentication { auth_type PASS @@ -39,19 +38,72 @@ vrrp_instance VI_ROUT_{{ apartment_block }} { # Routing subnet 10.129.{{ apartment_block_id }}.254/16 brd 10.129.255.255 dev ens19 scope global - # Public subnet: wired + + # NATed subnet: wired 45.66.108.25{{ apartment_block_id }}/24 brd 45.66.108.255 dev ens19 scope global - # Public subnet: wifi + + # NATed subnet: wifi 45.66.109.25{{ apartment_block_id }}/24 brd 45.66.109.255 dev ens19 scope global # Wired 10.{{ subnet_ids.users_wired }}.0.254/16 brd 10.{{ subnet_ids.users_wired }}.255.255 dev ens20 scope global + # Wifi 10.{{ subnet_ids.users_wifi }}.0.254/16 brd 10.{{ subnet_ids.users_wifi }}.255.255 dev ens21 scope global } + virtual_routes { # 10.129.0.1 is Yggdrasil src 10.129.{{ apartment_block_id }}.254 to 0.0.0.0/0 via 10.129.0.1 dev ens19 } } + +vrrp_instance VI_ROUT_{{ apartment_block }}_IPv6 { + {% if 'backup' in inventory_hostname %} + state BACKUP + priority 100 + {% else %} + state MASTER + priority 150 + {% endif %} + + + # Interface used for VRRP communication. + interface ens18 + + # Shared by MASTER and BACKUP + virtual_router_id 6{{ apartment_block_id }} + + # Timeout in seconds before failover kicks in. + advert_int 2 + + # Used to authenticate VRRP communication between master and backup. + authentication { + auth_type PASS + auth_pass {{ keepalived_password }} + } + + smtp_alert + + virtual_ipaddress { + # Routing subnet + fe80::1/64 dev ens19 scope global + {{ ipv6_base_prefix }}:129::{{ apartment_block_id }}:254/64 dev ens19 scope global + + # Wired + fe80::1/64 dev ens20 scope global + + # Wifi + fe80::1/64 dev ens21 scope global + } + + + virtual_routes { + # For IPv6, the master router is routeur-aurore, NOT yggdrasil, + # because yggdrasil doesn't support BGPv6 announcements. + src {{ ipv6_base_prefix }}:129::{{ apartment_block_id }}:254 to ::/0 via {{ ipv6_base_prefix }}:129::0:254 dev ens19 + } +} + + diff --git a/roles/unbound/templates/recursive.conf.j2 b/roles/unbound/templates/recursive.conf.j2 index 62c93be..efdebe1 100644 --- a/roles/unbound/templates/recursive.conf.j2 +++ b/roles/unbound/templates/recursive.conf.j2 @@ -11,20 +11,32 @@ server: logfile: "/var/log/unbound/unbound.log" do-ip4: yes - # FIXME: IPv6 deployment... someday... - do-ip6: no + do-ip6: yes # IP addresses on which to listen. + # + # Note: dns_host_suffix is dynamically set in this role's tasks, + # and changes depending on whether we're handling the main or backup + # recursive DNS node. + + # IPv4 interface: 10.{{ subnet_ids.ap }}.0.{{ dns_host_suffix }} interface: 10.{{ subnet_ids.users_wired }}.0.{{ dns_host_suffix }} interface: 10.{{ subnet_ids.users_wifi }}.0.{{ dns_host_suffix }} + + # IPv6 + interface: {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::0:{{ dns_host_suffix }} + interface: {{ ipv6_base_prefix }}:{{ subnet_ids.users_wired }}::0:{{ dns_host_suffix }} + interface: {{ ipv6_base_prefix }}:{{ subnet_ids.users_wifi }}::0:{{ dns_host_suffix }} + # By default, anything other than localhost is refused. # Whitelist some subnets: access-control: 10.{{ subnet_ids.ap }}.0.0/16 allow access-control: 10.{{ subnet_ids.users_wired }}.0.0/16 allow access-control: 10.{{ subnet_ids.users_wifi }}.0.0/16 allow + access-control: {{ ipv6_base_prefix }}::/32 allow # Fuck it... :) num-threads: {{ ansible_processor_vcpus }}