diff --git a/Readme.md b/Readme.md index c3ed9b9..c4ecc2b 100644 --- a/Readme.md +++ b/Readme.md @@ -1,40 +1,138 @@ -# ansible-ffmwu.git +# Ansible Freifunk MWU -An dieser Stelle soll der ganze ansible-script-junk entstehen, um ein FFMWU-Gateway automagisiert aufzusetzen. Das Geraffel kann später auch auf andere server-Typen erweitert werden, wenn sinnvoll. -Ein server muss minimal vorbereitet sein, bevor er mit den hiesigen Skripten zum Gate (oder zu Sonstigem) gemacht werden kann. Insbesondere müssen die folgenden Voraussetzungen erfüllt sein (diese werden vom playbook `test-prerequisites.yml` getestet): +Wir, die Freifunk MWU Community, nutzen Ansible um unsere Freifunk Server aufzusetzen und zu konfigurieren. In +diesem Repository verwalten wir unsere Ansible Roles und Playbooks. + +Ein Server muss minimal vorbereitet sein, bevor dieser per Ansible z.B. zu einem Freifunk-Gateway gemacht werden kann. Insbesondere müssen die folgenden Voraussetzungen erfüllt sein (diese werden vom playbook `playbook-test-prereqs.yml` getestet): - Ein dedizierter (v)server muss existieren und unter einer IPv4- und einer IPv6-Adresse öffentlich erreichbar sein. -- Die Adressen sollen im MWU-DNS eingetragen sein. -- Es muss eine nakte unterstützte linux-Version aufgesetzt sein (aktuell Ubuntu 14.04, bald Debian). -- Es muss einen user admin geben, auf den die Admins Zugriff haben; dieser muss root-Zugang über sudo haben. +- Die Adressen müssen im MWU-DNS eingetragen sein. +- Als Betriebssystem muss das aktuelle Debian Stable installiert sein. +- Es muss einen User admin geben, auf den die Admins Zugriff haben; dieser muss Root-Zugang über sudo haben. -Zusätzlich ist sehr empfehlenswert, dass die Admins die Maschinen mit ihren fqdns in ihrer ssh-config definiert haben. +Die Server werden mit ihren FQDNs im Ansible Inventory hinterlegt, bedenkt das für eure ssh-config. -Bisher gibt es hier zwei Sammlungen von files: zum Einen der Beginn des eigentlichen Zwecks: bisher kann eine Rolle (auf Basis der obigen Voraussetzungen) alle FFMWU-Server in dem ihnen allen identischen Aspekt vorbereiten, der Pflege der ssh keys der admins. Zum Anderen gibt es ein playbook, das eine lokale Test-VM aufsetzt, auf der man alle eigentlichen playbooks und Rollen testen kann, ohne ernsthaften Schaden anzurichten. +## Variablen für jedes Mesh -## Aufsetzen und Pflegen von Gateways +Viele Rollen brauchen spezifische Informationen, wie IP-Adresse, Masken, Interface-Namen, etc. +Wir verwalten diese Mesh-Informationen in einem Dictionary unter `inventory/group_vars/all`: -Alle FFMWU-Gatways sind auch FFMWU-Server, alle anderen server bei uns überraschenderweise auch; so sind auch Alle im inventory in der Gruppe 'ff-servers' zusammengefasst. Der Aspekt, der allen FFMWU-Servern gemein ist, sind die ssh-keys der admins. Auf einigen servern gibt es allerdings weitere Zugriffsberechtigte (spezialisierte admins). +``` +meshes: + mz: + site_number: 37 + site_code: ffmz + site_name: Mainz + ipv4_network: 10.37.0.0/18 + ipv6: + ula: + - fd37:b4dc:4b1e::/48 + public: + - 2a03:2260:11a::/48 + dnssl: + - ffmz.org + - user.ffmz.org + batman: + it: 10000 + gw: server 96mbit/96mbit + mm: 0 + dat: 0 + iface_mtu: 1350 + peers_mesh_repo: https://github.com/freifunk-mwu/peers-ffmz.git + peers_intragate_repo: https://github.com/freifunk-mwu/ffmz-infrastructure-peers.git -So gibt es eine Rolle ('ffmwu-server'), die allen hosts dieser Gruppe zugewiesen ist (über das playbook 'ffmwu-servers.yml', später auch über Abhängigkeiten der speziellern playbooks). Dieses playbook (einfach starten) weist die Rolle zu, welche ihrerseits die shh keys auf den hosts pflegt. + wi: + site_number: 56 + site_code: ffwi + site_name: Wiesbaden + ipv4_network: 10.56.0.0/18 + ipv6: + ula: + - fd56:b4dc:4b1e::/48 + public: + - 2a03:2260:11b::/48 + dnssl: + - ffwi.org + - user.ffwi.org + batman: + it: 10000 + gw: server 96mbit/96mbit + mm: 0 + dat: 0 + iface_mtu: 1350 + peers_mesh_repo: https://github.com/freifunk-mwu/peers-ffwi.git + peers_intragate_repo: https://github.com/freifunk-mwu/ffwi-infrastructure-peers.git +``` -Die Rolle besteht aus nur einem task und einer definierten Variable, die die keys der admins enthält. Sind auf einem host weitere ssh keys von Nöten, so werden disse als hostvar definiert. -## Erzeugen einer test-VM +## Aufsetzen eines neuen Gateways -Um die playbooks und Rollen gefahrlos testen zu können, bietet sich ein test host an. Hierfür kann eine lokale VM zu Einsatz kommen, wenn die Voraussetzungen stimmen. +- FQDN im Inventory zur Gruppe ffmwu-gateways hinzufügen +- Host-Variablen setzen + - inventory/host_vars/$FQDN -Damit auf der lokalen Maschine (der ansible controle machine) VMs ablaufen (und mit dem playbook angelegt werden) können, müssen verschiedene Voraussetzungen erfüllt sein. U. a.: +``` +--- +# Gateway-Nummer, von der vieles abgeleitet wird. Integer zwischen 1-254. Muss eindeutig unter allen FFMWU Servern sein. +magic: -- installierte Pakete zu libvirt, kvm und qemu und Pakete virt-manager, isomaster -- >15G freier Plattenplatz -- ansible >= 2.1 +# Pfade zu den fastd secrets im passwordstore +fastd_secrets: + mzVPN: "{{ lookup('passwordstore', 'fastd/mzVPN/$Hostname') }}" + wiVPN: "{{ lookup('passwordstore', 'fastd/wiVPN/$Hostname') }}" + mzigVPN: "{{ lookup('passwordstore', 'fastd/mzVPN/$Hostname') }}" + wiigVPN: "{{ lookup('passwordstore', 'fastd/wiVPN/$Hostname') }}" -Leider sind die letzten 2 Meter der Aufgabe offenbar in dieser Art nicht automatisierbar. Deshalb muss der user an einer Stelle mit 'isomaster' kurz etwas manuell durchführen -Das playbook 'loctevm-reset.yml' einfach ausführen. +# FFRL (muss vorher bereits zugewiesen worden sein) +# Öffentliche IPv4 NAT Adresse +ffrl_public_ipv4_nat: -### bekannte Probleme +ffrl_exit_server: + ffrl-a-ak-ber: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: + ffrl-b-ak-ber: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: + ffrl-a-ix-dus: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: + ffrl-b-ix-dus: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: + ffrl-a-fra2-fra: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: + ffrl-b-fra2-fra: + public_ipv4_address: + tunnel_ipv4_network: # Format: IP/Maske + tunnel_ipv4_address: + tunnel_ipv4_netmask: + tunnel_ipv6_address: + tunnel_ipv6_netmask: -- Wenn die VM wegen Zugriffsfehler auf die virtuellen volumes nicht startet, können die Berechtigungen der übergeordneten Verzeichnisse Schuld sein -> hier mal schauen. -- Ein Schritt scheint nicht automagisierbar, hier werden isomaster & der user benötigt. -- Bisher wird direkt die 64bit-Version ausgewählt. +``` +- Testen, ob alle Voraussetzungen erfüllt sind: `ansible-playbook playbook-test-prerequisites.yml` +- Neues Gateway aufsetzen per `ansible-playbook playbook-gateways.yml` + - Hierbei werden die definierten Rollen auch auf schon aufgesetzte Gateways angewandt, was unkritisch ist, weil wir unsere Rollen idempotent schreiben. + - Um die Rollen nur auf das neu aufzusetzende Gateway anzuwenden: `ansible-playbook playbook-gateways.yml --limit=$FQDN` diff --git a/ansible.cfg b/ansible.cfg index 3d96197..81d49c2 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,10 +1,9 @@ [defaults] -# local inventory = ./inventory/hosts retry_files_save_path = ~/.ansible/retry-files #vault_password_file = ~/.ansible/vault-password-file -# remote remote_tmp = $HOME/ansible_tmp +ansible_managed = Ansible managed - don't edit this file! #[ssh_connection] #pipelining = True diff --git a/inventory/group_vars/all b/inventory/group_vars/all new file mode 100644 index 0000000..a7b254f --- /dev/null +++ b/inventory/group_vars/all @@ -0,0 +1,86 @@ +--- +as_private_mwu: 65037 +as_public_ffrl: 201701 + +routing_tables: + icvpn: 23 + mwu: 41 + internet: 61 + +icvpn_ipv4_network: 10.207.0.0/16 +mwu_icvpn_ipv4_network: 10.207.37.0/24 +bgp_loopback_net: 10.37.0.0/18 + +meshes: + mz: + site_number: 37 + site_code: ffmz + site_name: Mainz + ipv4_network: 10.37.0.0/18 + ipv6: + ula: + - fd37:b4dc:4b1e::/48 + public: + - 2a03:2260:11a::/48 + dnssl: + - ffmz.org + - user.ffmz.org + batman: + it: 10000 + gw: server 96mbit/96mbit + mm: 0 + dat: 0 + iface_mtu: 1350 + peers_mesh_repo: https://github.com/freifunk-mwu/peers-ffmz.git + peers_intragate_repo: https://github.com/freifunk-mwu/ffmz-infrastructure-peers.git + + wi: + site_number: 56 + site_code: ffwi + site_name: Wiesbaden + ipv4_network: 10.56.0.0/18 + ipv6: + ula: + - fd56:b4dc:4b1e::/48 + public: + - 2a03:2260:11b::/48 + dnssl: + - ffwi.org + - user.ffwi.org + batman: + it: 10000 + gw: server 96mbit/96mbit + mm: 0 + dat: 0 + iface_mtu: 1350 + peers_mesh_repo: https://github.com/freifunk-mwu/peers-ffwi.git + peers_intragate_repo: https://github.com/freifunk-mwu/ffwi-infrastructure-peers.git + +bgp_mwu_servers: + spinat: + ipv4: 10.37.0.7 + ipv6: fd37:b4dc:4b1e::a25:7 + lotuswurzel: + ipv4: 10.37.0.23 + ipv6: fd37:b4dc:4b1e::a25:17 + ingwer: + ipv4: 10.37.0.161 + ipv6: fd37:b4dc:4b1e::a25:a1 + wasserfloh: + ipv4: 10.37.0.231 + ipv6: fd37:b4dc:4b1e::a25:e7 + zuckerwatte: + ipv4: 10.37.1.2 + ipv6: fd37:b4dc:4b1e::a25:102 + aubergine: + ipv4: 10.37.1.3 + ipv6: fd37:b4dc:4b1e::a25:103 + zwiebel: + ipv4: 10.37.1.0 + ipv6: fd37:b4dc:4b1e::a25:100 + glueckskeks: + ipv4: 10.37.1.1 + ipv6: fd37:b4dc:4b1e::a25:101 + suesskartoffel: + ipv4: 10.37.1.4 + ipv6: fd37:b4dc:4b1e::a25:104 diff --git a/playbook-gateways.yml b/playbook-gateways.yml new file mode 100755 index 0000000..87fe129 --- /dev/null +++ b/playbook-gateways.yml @@ -0,0 +1,22 @@ +#!/usr/bin/ansible-playbook +--- + +- hosts: ffmwu-gateways + remote_user: admin + + roles: + - server-repos + - server-basic + - service-haveged + - service-ntpd + - kmod-batman + - network-routetables + - network-batman + - network-meshbridge + - service-dhcpd + - service-radvd + - service-fastd-mesh + - service-fastd-intragate + - git-fastd-peers + - network-fastd + - network-ffrl diff --git a/roles/git-fastd-peers/tasks/main.yml b/roles/git-fastd-peers/tasks/main.yml new file mode 100644 index 0000000..d3086dd --- /dev/null +++ b/roles/git-fastd-peers/tasks/main.yml @@ -0,0 +1,42 @@ +--- +- name: install git packages + apt: + name: "{{ item }}" + state: present + with_items: + - git + become: true + +- name: create fastd peer mesh directories + file: + path: "/etc/fastd/{{ item.key }}VPN/peers" + state: directory + mode: 0755 + owner: admin + group: admin + with_dict: "{{ meshes }}" + become: true + +- name: create fastd peer intragate directories + file: + path: "/etc/fastd/{{ item.key }}igVPN/peers" + state: directory + mode: 0755 + owner: admin + group: admin + with_dict: "{{ meshes }}" + become: true + +- name: clone fastd peer mesh repos + git: + repo: "{{ item.value.peers_mesh_repo }}" + dest: "/etc/fastd/{{ item.key }}VPN/peers" + update: no + with_dict: "{{ meshes }}" + +- name: clone fastd peer intragate repos + git: + repo: "{{ item.value.peers_intragate_repo }}" + dest: "/etc/fastd/{{ item.key }}igVPN/peers" + update: no + with_dict: "{{ meshes }}" diff --git a/roles/kmod-batman/tasks/main.yml b/roles/kmod-batman/tasks/main.yml new file mode 100644 index 0000000..1ee26f7 --- /dev/null +++ b/roles/kmod-batman/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: install batman-module and linux headers + apt: + state: present + name: "{{ item }}" + update_cache: yes + cache_valid_time: 21600 + with_items: + - linux-headers-amd64 + - batman-adv-dkms + - batctl + become: true + +- name: configure batman module to load on system boot + template: + src: batman-adv.module.conf.j2 + dest: /etc/modules-load.d/batman-adv.conf + become: true diff --git a/roles/kmod-batman/templates/batman-adv.module.conf.j2 b/roles/kmod-batman/templates/batman-adv.module.conf.j2 new file mode 100644 index 0000000..35d76b4 --- /dev/null +++ b/roles/kmod-batman/templates/batman-adv.module.conf.j2 @@ -0,0 +1,6 @@ +# +# Load batman-adv module on system boot +# {{ ansible_managed }} +# +batman-adv +dummy diff --git a/roles/network-batman/handlers/main.yml b/roles/network-batman/handlers/main.yml new file mode 100644 index 0000000..545dadd --- /dev/null +++ b/roles/network-batman/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: activate sysfs variables + systemd: + name: sysfsutils + state: restarted + become: true diff --git a/roles/network-batman/tasks/main.yml b/roles/network-batman/tasks/main.yml new file mode 100644 index 0000000..bc0ff67 --- /dev/null +++ b/roles/network-batman/tasks/main.yml @@ -0,0 +1,22 @@ +--- +- name: create dummy interfaces + template: + src: dummy.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}0" + with_dict: "{{ meshes }}" + become: true + +- name: create batman interfaces + template: + src: batman.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}BAT" + with_dict: "{{ meshes }}" + become: true + +- name: set sysfs variables + template: + src: sysfs.j2 + dest: "/etc/sysfs.d/99-{{ item.key }}BAT.conf" + with_dict: "{{ meshes }}" + notify: activate sysfs variables + become: true diff --git a/roles/network-batman/templates/batman.j2 b/roles/network-batman/templates/batman.j2 new file mode 100644 index 0000000..4a21e56 --- /dev/null +++ b/roles/network-batman/templates/batman.j2 @@ -0,0 +1,18 @@ +{% set ip4hex = item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') | ip4_hex() -%} +{% set mac = '0201' + ip4hex -%} +# +# {{ ansible_managed }} +# +auto {{ item.key }}BAT +iface {{ item.key }}BAT inet manual + pre-up /sbin/ip link add name $IFACE type batadv + pre-up /sbin/ip link set address {{ mac | hwaddr('linux') }} dev $IFACE + pre-up /sbin/ip link set dev {{ item.key }}0 master $IFACE + pre-up /sbin/ip link set up dev $IFACE + post-up /sbin/ip addr flush dev $IFACE + post-up /usr/sbin/batctl -m $IFACE it {{ item.value.batman.it }} + post-up /usr/sbin/batctl -m $IFACE gw {{ item.value.batman.gw }} + post-up /usr/sbin/batctl -m $IFACE mm {{ item.value.batman.mm }} + post-up /usr/sbin/batctl -m $IFACE dat {{ item.value.batman.dat }} + post-down /sbin/ip link set dev {{ item.key }}0 nomaster + post-down /sbin/ip link delete $IFACE 2>&1 || true diff --git a/roles/network-batman/templates/dummy.j2 b/roles/network-batman/templates/dummy.j2 new file mode 100644 index 0000000..6427cf2 --- /dev/null +++ b/roles/network-batman/templates/dummy.j2 @@ -0,0 +1,12 @@ +{% set ip4hex = item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') | ip4_hex() -%} +{% set mac = '0200' + ip4hex -%} +# +# {{ ansible_managed }} +# +auto {{ item.key }}0 +iface {{ item.key }}0 inet manual + pre-up /sbin/ip link add $IFACE type dummy + pre-up /sbin/ip link set address {{ mac | hwaddr('linux') }} dev $IFACE + pre-up /sbin/ip link set up dev $IFACE + post-up /sbin/ip addr flush dev $IFACE + post-down /sbin/ip link delete $IFACE 2>&1 || true diff --git a/roles/network-batman/templates/sysfs.j2 b/roles/network-batman/templates/sysfs.j2 new file mode 100644 index 0000000..63aeea6 --- /dev/null +++ b/roles/network-batman/templates/sysfs.j2 @@ -0,0 +1,4 @@ +# +# {{ ansible_managed }} +# +class/net/{{ item.key }}BAT/mesh/hop_penalty = 60 diff --git a/roles/network-fastd/tasks/main.yml b/roles/network-fastd/tasks/main.yml new file mode 100644 index 0000000..1474772 --- /dev/null +++ b/roles/network-fastd/tasks/main.yml @@ -0,0 +1,14 @@ +--- +- name: create fastd mesh interfaces + template: + src: fastd-mesh.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}VPN" + with_dict: "{{ meshes }}" + become: true + +- name: create fastd intragate interfaces + template: + src: fastd-intragate.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}igVPN" + with_dict: "{{ meshes }}" + become: true diff --git a/roles/network-fastd/templates/fastd-intragate.j2 b/roles/network-fastd/templates/fastd-intragate.j2 new file mode 100644 index 0000000..f9d105b --- /dev/null +++ b/roles/network-fastd/templates/fastd-intragate.j2 @@ -0,0 +1,10 @@ +{% set ip4hex = item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') | ip4_hex() -%} +{% set mac = '0212' + ip4hex -%} +# +# {{ ansible_managed }} +# +allow-hotplug {{ item.key }}igVPN +iface {{ item.key }}igVPN inet manual + pre-up /sbin/ip link set address {{ mac | hwaddr('linux') }} dev $IFACE + post-up /sbin/ip link set dev $IFACE up + post-up /sbin/ip link set dev $IFACE master {{ item.key }}BAT diff --git a/roles/network-fastd/templates/fastd-mesh.j2 b/roles/network-fastd/templates/fastd-mesh.j2 new file mode 100644 index 0000000..cc64fcb --- /dev/null +++ b/roles/network-fastd/templates/fastd-mesh.j2 @@ -0,0 +1,10 @@ +{% set ip4hex = item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') | ip4_hex() -%} +{% set mac = '0211' + ip4hex -%} +# +# {{ ansible_managed }} +# +allow-hotplug {{ item.key }}VPN +iface {{ item.key }}VPN inet manual + pre-up /sbin/ip link set address {{ mac | hwaddr('linux') }} dev $IFACE + post-up /sbin/ip link set dev $IFACE up + post-up /sbin/ip link set dev $IFACE master {{ item.key }}BAT diff --git a/roles/network-ffrl/tasks/main.yml b/roles/network-ffrl/tasks/main.yml new file mode 100644 index 0000000..439c2de --- /dev/null +++ b/roles/network-ffrl/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: create ffrl interfaces + template: + src: ffrl.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}" + with_dict: "{{ ffrl_exit_server }}" + become: true diff --git a/roles/network-ffrl/templates/ffrl.j2 b/roles/network-ffrl/templates/ffrl.j2 new file mode 100644 index 0000000..2dddfc0 --- /dev/null +++ b/roles/network-ffrl/templates/ffrl.j2 @@ -0,0 +1,16 @@ +# +# {{ ansible_managed }} +# +auto {{ item.key }} +iface {{ item.key }} inet static + address {{ item.value.tunnel_ipv4_address }} + netmask {{ item.value.tunnel_ipv4_netmask }} + pre-up /sbin/ip tunnel add $IFACE mode gre local {{ ansible_default_ipv4.address | ipaddr('public') }} remote {{ item.value.public_ipv4_address | ipaddr('public') }} ttl 255 + post-up /sbin/ip link set $IFACE mtu 1400 + post-up /sbin/ip addr add {{ ffrl_public_ipv4_nat }}/32 dev $IFACE + post-down /sbin/ip tunnel del $IFACE + +iface {{ item.key }} inet6 static + address {{ item.value.tunnel_ipv6_network | ipaddr('net') | ipaddr('2') | ipaddr('address') }} + netmask {{ item.value.tunnel_ipv6_netmask }} + diff --git a/roles/network-meshbridge/handlers/main.yml b/roles/network-meshbridge/handlers/main.yml new file mode 100644 index 0000000..545dadd --- /dev/null +++ b/roles/network-meshbridge/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: activate sysfs variables + systemd: + name: sysfsutils + state: restarted + become: true diff --git a/roles/network-meshbridge/tasks/main.yml b/roles/network-meshbridge/tasks/main.yml new file mode 100644 index 0000000..06ea01b --- /dev/null +++ b/roles/network-meshbridge/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- name: create mesh bridges + template: + src: bridge.j2 + dest: "/etc/network/interfaces.d/{{ item.key }}BR" + with_dict: "{{ meshes }}" + become: true + +- name: set sysfs variables + template: + src: sysfs.j2 + dest: "/etc/sysfs.d/99-{{ item.key }}BR.conf" + with_dict: "{{ meshes }}" + notify: activate sysfs variables + become: true diff --git a/roles/network-meshbridge/templates/bridge.j2 b/roles/network-meshbridge/templates/bridge.j2 new file mode 100644 index 0000000..7a81040 --- /dev/null +++ b/roles/network-meshbridge/templates/bridge.j2 @@ -0,0 +1,22 @@ +{% set ip4hex = item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') | ip4_hex() -%} +{% set mac = '0210' + ip4hex -%} +# +# {{ ansible_managed }} +# +auto {{ item.key }}BR +iface {{ item.key }}BR inet manual + address {{ item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') }} + network {{ item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('network') }} + netmask {{ item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('netmask') }} + broadcast {{ item.value.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('broadcast') }} + pre-up /sbin/ip link add name $IFACE type bridge + pre-up /sbin/ip link set address {{ mac | hwaddr('linux') }} dev $IFACE + pre-up /sbin/ip link set dev {{ item.key }}BAT master $IFACE + pre-up /sbin/ip link set up dev $IFACE +{% for ip_type, ip_list in item.value.ipv6.iteritems() %} +{% for ip in ip_list %} + up /sbin/ip address add {{ ip | ipaddr('net') | ipsubnet(64, 0) | ipaddr(magic) }} dev $IFACE +{% endfor %} +{% endfor %} + post-down /sbin/ip link set dev {{ item.key }}BAT nomaster + post-down /sbin/ip link delete $IFACE 2>&1 || true diff --git a/roles/network-meshbridge/templates/sysfs.j2 b/roles/network-meshbridge/templates/sysfs.j2 new file mode 100644 index 0000000..04bed17 --- /dev/null +++ b/roles/network-meshbridge/templates/sysfs.j2 @@ -0,0 +1,4 @@ +# +# {{ ansible_managed }} +# +class/net/{{ item.key }}BR/bridge/hash_max = 16384 diff --git a/roles/network-routetables/tasks/main.yml b/roles/network-routetables/tasks/main.yml new file mode 100644 index 0000000..ba14fc9 --- /dev/null +++ b/roles/network-routetables/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: create routing tables + lineinfile: + path: /etc/iproute2/rt_tables + regexp: '^{{ item.value }}' + line: "{{ item.value }}{{ '\t' }}{{ item.key }}" + state: present + with_dict: "{{ routing_tables }}" + become: true diff --git a/roles/server-basic/tasks/main.yml b/roles/server-basic/tasks/main.yml new file mode 100644 index 0000000..f5e28b4 --- /dev/null +++ b/roles/server-basic/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: ensure common packages are installed + apt: + state: present + name: "{{ item }}" + update_cache: yes + cache_valid_time: 21600 + with_items: "{{ packages }}" + become: true + +- name: ensure vim is default editor + alternatives: + name: editor + path: /usr/bin/vim.basic + become: true + +- name: set timezone to Europe/Berlin + timezone: + name: Europe/Berlin + become: true diff --git a/roles/server-basic/vars/main.yml b/roles/server-basic/vars/main.yml new file mode 100644 index 0000000..45cb744 --- /dev/null +++ b/roles/server-basic/vars/main.yml @@ -0,0 +1,10 @@ +--- +packages: + - apt-transport-https + - ifupdown2 + - man-db + - mlocate + - mosh + - sudo + - sysfsutils + - vim diff --git a/roles/server-repos/tasks/main.yml b/roles/server-repos/tasks/main.yml new file mode 100644 index 0000000..c7a6724 --- /dev/null +++ b/roles/server-repos/tasks/main.yml @@ -0,0 +1,34 @@ +--- +- name: ensure dirmngr and apt-transport-https are installed + apt: + state: present + name: "{{ item }}" + update_cache: yes + cache_valid_time: 21600 + with_items: + - dirmngr + - apt-transport-https + become: true + +- name: ensure apt key for universe-factory is present + apt_key: + state: present + id: 16ef3f64cb201d9c + keyserver: pgp.mit.edu + become: true + +- name: ensure apt key for freifunk-mwu is present + apt_key: + state: present + id: 83A70084 + url: "http://repo.freifunk-mwu.de/83A70084.gpg.key" + become: true + +- name: ensure needed apt repos are present + apt_repository: + state: present + repo: "{{ item.repo }}" + update_cache: "{{ item.update_cache }}" + filename: "{{ item.name }}" + with_items: "{{ repos }}" + become: true diff --git a/roles/server-repos/vars/main.yml b/roles/server-repos/vars/main.yml new file mode 100644 index 0000000..40a6cb1 --- /dev/null +++ b/roles/server-repos/vars/main.yml @@ -0,0 +1,12 @@ +--- +repos: + - name: fastd + repo: 'deb https://repo.universe-factory.net/debian/ sid main' + update_cache: yes + - name: freifunk + repo: 'deb http://repo.freifunk-mwu.de/debian jessie main' + update_cache: yes + - name: freifunk + repo: 'deb-src http://repo.freifunk-mwu.de/debian jessie main' + update_cache: yes + diff --git a/roles/service-dhcpd/handlers/main.yml b/roles/service-dhcpd/handlers/main.yml new file mode 100644 index 0000000..88a46e2 --- /dev/null +++ b/roles/service-dhcpd/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: restart isc dhcp server + systemd: + name: isc-dhcp-server + enabled: yes + state: restarted + become: true diff --git a/roles/service-dhcpd/tasks/main.yml b/roles/service-dhcpd/tasks/main.yml new file mode 100644 index 0000000..b958b4f --- /dev/null +++ b/roles/service-dhcpd/tasks/main.yml @@ -0,0 +1,39 @@ +--- +- name: install dhcp packages + apt: + name: isc-dhcp-server + state: present + become: true + +- name: enable systemd unit isc-dhcp-server + systemd: + name: isc-dhcp-server + enabled: yes + daemon_reload: yes + become: true + +- name: concatenate meshbridge interfaces + set_fact: + dhcp_interfaces: "{% for key, value in meshes.iteritems() %}{{ key }}BR{% if not loop.last %} {% endif %}{% endfor %}" + +- name: set ipv4 interfaces isc dhcp should listen on + lineinfile: + path: /etc/default/isc-dhcp-server + regexp: '^INTERFACESv4="' + line: 'INTERFACESv4="{{ dhcp_interfaces }}"' + notify: restart isc dhcp server + become: true + +- name: set ipv6 interfaces isc dhcp should listen on + lineinfile: + path: /etc/default/isc-dhcp-server + regexp: '^INTERFACESv6="' + line: 'INTERFACESv6=""' + become: true + +- name: configure isc dhcp server + template: + src: dhcpd.conf.j2 + dest: /etc/dhcp/dhcpd.conf +# notify: restart isc dhcp server + become: true diff --git a/roles/service-dhcpd/templates/dhcpd.conf.j2 b/roles/service-dhcpd/templates/dhcpd.conf.j2 new file mode 100644 index 0000000..7b21f82 --- /dev/null +++ b/roles/service-dhcpd/templates/dhcpd.conf.j2 @@ -0,0 +1,28 @@ +# +# {{ ansible_managed }} +# +ddns-update-style none; + +authoritative; +server-name "{{ inventory_hostname_short }}"; + +log-facility local7; + +default-lease-time 300; +min-lease-time 300; +max-lease-time 300; + +{% for mesh in meshes.values() %} +# DHCP subnet for site {{ mesh.site_name }} ({{ mesh.site_code }}) +subnet {{ mesh.ipv4_network | ipaddr('network') }} netmask {{ mesh.ipv4_network | ipaddr('netmask') }} { + range {{ mesh.ipv4_network | ipsubnet(22, ipv4_dhcp_range) | ipaddr('net') | ipaddr('network') }} {{ mesh.ipv4_network | ipsubnet(22, ipv4_dhcp_range) | ipaddr('net') | ipaddr('broadcast') }}; + option routers {{ mesh.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') }}; + option domain-name-servers {{ mesh.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') }}; + option domain-search {% for domain in mesh.dnssl %}"{{ domain }}"{% if not loop.last %}, {% endif %}{% endfor %}; + option ntp-servers {{ mesh.ipv4_network | ipaddr('net') | ipaddr(magic) | ipaddr('address') }}; + option interface-mtu {{ mesh.iface_mtu }}; +} +{% if not loop.last %} + +{% endif %} +{% endfor %} diff --git a/roles/service-fastd-intragate/tasks/main.yml b/roles/service-fastd-intragate/tasks/main.yml new file mode 100644 index 0000000..9284cf1 --- /dev/null +++ b/roles/service-fastd-intragate/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: install fastd packages + apt: + name: fastd + state: present + become: true + +- name: create fastd intragate directories + file: + path: "/etc/fastd/{{ item.key }}igVPN" + state: directory + mode: 0755 + with_dict: "{{ meshes }}" + become: true + +- name: template fastd mesh config + template: + src: fastd-intragate.conf.j2 + dest: "/etc/fastd/{{ item.key }}igVPN/fastd.conf" + with_dict: "{{ meshes }}" + become: true + +- name: write fastd intragate secret + template: + src: fastd-secret.conf.j2 + dest: "/etc/fastd/{{ item.key }}igVPN/secret.conf" + with_dict: "{{ meshes }}" + become: true diff --git a/roles/service-fastd-intragate/templates/fastd-intragate.conf.j2 b/roles/service-fastd-intragate/templates/fastd-intragate.conf.j2 new file mode 100644 index 0000000..7f84c1c --- /dev/null +++ b/roles/service-fastd-intragate/templates/fastd-intragate.conf.j2 @@ -0,0 +1,23 @@ +# +# {{ ansible_managed }} +# +log level warn; +hide ip addresses yes; +hide mac addresses yes; + +method "aes128-ctr+umac"; + +interface "{{ item.key }}igVPN"; + +bind {{ ansible_default_ipv4.address | ipaddr('public') }}:101{{ item.value.site_number }}; +bind {{ ansible_default_ipv6.address | ipaddr('public') | ipwrap }}:101{{ item.value.site_number }}; + +include "secret.conf"; +mtu 1406; + +peer group "servers" { + include peers from "peers/gates"; + include peers from "peers/services"; +} + +status socket "/var/run/fastd-{{ item.key }}ig.status"; diff --git a/roles/service-fastd-intragate/templates/fastd-secret.conf.j2 b/roles/service-fastd-intragate/templates/fastd-secret.conf.j2 new file mode 100644 index 0000000..a55490b --- /dev/null +++ b/roles/service-fastd-intragate/templates/fastd-secret.conf.j2 @@ -0,0 +1,9 @@ +{% set local_interface = item.key + 'igVPN' -%} +# +# {{ ansible_managed }} +# +{% for interface in fastd_secrets %} +{% if local_interface == interface %} +secret "{{ fastd_secrets[interface] }}"; +{% endif %} +{% endfor %} diff --git a/roles/service-fastd-mesh/tasks/main.yml b/roles/service-fastd-mesh/tasks/main.yml new file mode 100644 index 0000000..dc377de --- /dev/null +++ b/roles/service-fastd-mesh/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: install fastd packages + apt: + name: fastd + state: present + become: true + +- name: create fastd directories + file: + path: "/etc/fastd/{{ item.key }}VPN" + state: directory + mode: 0755 + with_dict: "{{ meshes }}" + become: true + +- name: template fastd mesh config + template: + src: fastd-mesh.conf.j2 + dest: "/etc/fastd/{{ item.key }}VPN/fastd.conf" + with_dict: "{{ meshes }}" + become: true + +- name: write fastd mesh secret + template: + src: fastd-secret.conf.j2 + dest: "/etc/fastd/{{ item.key }}VPN/secret.conf" + with_dict: "{{ meshes }}" + become: true diff --git a/roles/service-fastd-mesh/templates/fastd-mesh.conf.j2 b/roles/service-fastd-mesh/templates/fastd-mesh.conf.j2 new file mode 100644 index 0000000..eb81c7b --- /dev/null +++ b/roles/service-fastd-mesh/templates/fastd-mesh.conf.j2 @@ -0,0 +1,30 @@ +# +# {{ ansible_managed }} +# +log level warn; +hide ip addresses yes; +hide mac addresses yes; + +method "salsa2012+umac"; + +interface "{{ item.key }}VPN"; + +bind {{ ansible_default_ipv4.address | ipaddr('public') }}:100{{ item.value.site_number }}; +bind {{ ansible_default_ipv6.address | ipaddr('public') | ipwrap }}:100{{ item.value.site_number }}; + +include "secret.conf"; +mtu 1406; + +peer group "vpn_nodes" { + peer limit 150; + include peers from "peers"; +{% if item.key == "mz" %} + include peers from "peers_bingen"; +{% endif %} +} + +peer group "servers" { + include peers from "peers/servers"; +} + +status socket "/var/run/fastd-{{ item.key }}.status"; diff --git a/roles/service-fastd-mesh/templates/fastd-secret.conf.j2 b/roles/service-fastd-mesh/templates/fastd-secret.conf.j2 new file mode 100644 index 0000000..87a4945 --- /dev/null +++ b/roles/service-fastd-mesh/templates/fastd-secret.conf.j2 @@ -0,0 +1,9 @@ +{% set local_interface = item.key + 'VPN' -%} +# +# {{ ansible_managed }} +# +{% for interface in fastd_secrets %} +{% if local_interface == interface %} +secret "{{ fastd_secrets[interface] }}"; +{% endif %} +{% endfor %} diff --git a/roles/service-haveged/handlers/main.yml b/roles/service-haveged/handlers/main.yml new file mode 100644 index 0000000..8c64ad5 --- /dev/null +++ b/roles/service-haveged/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: reload systemd + systemd: + daemon_reload: yes + become: true diff --git a/roles/service-haveged/tasks/main.yml b/roles/service-haveged/tasks/main.yml new file mode 100644 index 0000000..3e3f5a7 --- /dev/null +++ b/roles/service-haveged/tasks/main.yml @@ -0,0 +1,14 @@ +--- +- name: install haveged + apt: + name: haveged + state: present + notify: reload systemd + become: true + +- name: start and enable systemd unit haveged + systemd: + name: haveged + enabled: yes + state: started + become: true diff --git a/roles/service-ntpd/tasks/main.yml b/roles/service-ntpd/tasks/main.yml new file mode 100644 index 0000000..072f0f8 --- /dev/null +++ b/roles/service-ntpd/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: ensure systemd-timesyncd is disabled + systemd: + name: systemd-timesyncd + enabled: no + state: stopped + become: true + +- name: install ntp packages + apt: + state: present + name: "{{ item }}" + update_cache: yes + cache_valid_time: 21600 + with_items: + - ntp + - ntp-doc + - ntpdate + - ntpstat + become: true + +- name: enable and start ntp daemon + systemd: + name: ntp + enabled: yes + state: started + daemon_reload: yes + become: true + diff --git a/roles/service-radvd/tasks/main.yml b/roles/service-radvd/tasks/main.yml new file mode 100644 index 0000000..71d1521 --- /dev/null +++ b/roles/service-radvd/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: install radvd packages + apt: + name: radvd + state: present + become: true + +- name: enable systemd unit radvd + systemd: + name: radvd + enabled: yes + daemon_reload: yes + become: true + +- name: configure radvd + template: + src: radvd.conf.j2 + dest: /etc/radvd.conf + #notify: restart radvd + become: true diff --git a/roles/service-radvd/templates/radvd.conf.j2 b/roles/service-radvd/templates/radvd.conf.j2 new file mode 100644 index 0000000..4e6bd86 --- /dev/null +++ b/roles/service-radvd/templates/radvd.conf.j2 @@ -0,0 +1,43 @@ +# +# {{ ansible_managed }} +# +{% for key, value in meshes.iteritems() %} +interface {{ key }}BR +{ + AdvSendAdvert on; + IgnoreIfMissing on; + MaxRtrAdvInterval 900; + AdvLinkMTU {{ value.iface_mtu }}; + +{% for ip_type, ip_list in value.ipv6.iteritems() %} +{% for prefix in ip_list %} +{% if ip_type == "ula" %} + RDNSS {{ prefix | ipaddr('net') | ipsubnet(64, 0) | ipaddr(magic) }} + { + FlushRDNSS off; + }; +{% endif %} +{% endfor %} +{% endfor %} + +{% for ip_type, ip_list in value.ipv6.iteritems() %} +{% for prefix in ip_list %} +{% if ip_type == "public" %} + prefix {{ prefix | ipaddr('net') | ipsubnet(64, magic) }} +{% else %} + prefix {{ prefix | ipaddr('net') | ipsubnet(64, 0) }} +{% endif %} + { + AdvValidLifetime 864000; + AdvPreferredLifetime 172800; + }; +{% endfor %} +{% if not loop.last %} + +{% endif %} +{% endfor %} +}; +{% if not loop.last %} + +{% endif %} +{% endfor %}