private_net_cidr: 192.168.56.0/24
wild_net_cidr: 192.168.57.0/24
public_vpn_net_cidr: 10.177.86.0/24
+public_wg_net_cidr: 10.177.87.0/24
campus_vpn_net_cidr: 10.84.138.0/24
+campus_wg_net_cidr: 10.84.139.0/24
#+END_SRC
The network addresses are needed in several additional formats, e.g.
private_net_mask:
"{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
private_net_and_mask: "{{ private_net }} {{ private_net_mask }}"
+wild_net: "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+ "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+ "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
public_vpn_net:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('network') }}"
public_vpn_net_mask:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}"
public_vpn_net_and_mask:
"{{ public_vpn_net }} {{ public_vpn_net_mask }}"
+public_wg_net:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+ "{{ public_wg_net }} {{ public_wg_net_mask }}"
campus_vpn_net:
"{{ campus_vpn_net_cidr | ansible.utils.ipaddr('network') }}"
campus_vpn_net_mask:
"{{ campus_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}"
campus_vpn_net_and_mask:
"{{ campus_vpn_net }} {{ campus_vpn_net_mask }}"
-wild_net: "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
-wild_net_mask:
- "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
-wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}"
-wild_net_broadcast:
- "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+campus_wg_net:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+ "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
#+END_SRC
The institute prefers to configure its services with IP addresses
wifi_wan_addr_cidr: "{{ wild_net_cidr | ansible.utils.ipaddr('2') }}"
front_vpn_addr_cidr:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_port: 39608
+front_wg_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+wg_client_front_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('3') }}"
+campus_wg_port: 51820
+campus_wg_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+wg_appl_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+wg_client_gate_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('3') }}"
core_addr: "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
gate_addr: "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
"{{ wifi_wan_addr_cidr | ansible.utils.ipaddr('address') }}"
front_vpn_addr:
"{{ front_vpn_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+ "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+ "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_client_front_addr:
+ "{{ wg_client_front_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wg_addr:
+ "{{ campus_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_appl_addr:
+ "{{ wg_appl_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_client_gate_addr:
+ "{{ wg_client_gate_addr_cidr | ansible.utils.ipaddr('address') }}"
#+END_SRC
: $ sudo apt install netplan.io systemd-resolved unattended-upgrades \
: _ ntp isc-dhcp-server bind9 apache2 openvpn \
: _ postfix dovecot-imapd fetchmail expect rsync \
-: _ gnupg openssh-server
+: _ gnupg openssh-server wireguard
The Nextcloud configuration requires Apache2, MariaDB and a number of
PHP modules. Installing them while Core was on a cable modem sped up
: $ sudo apt install netplan.io systemd-resolved unattended-upgrades \
: _ ufw isc-dhcp-server postfix openvpn \
-: _ openssh-server
+: _ openssh-server wireguard
Next, the administrator concatenated a personal public ssh key and the
key found in [[file:Secret/ssh_admin/][=Secret/ssh_admin/=]] (created by [[*The CA Command][The CA Command]]) into an
- p: mynetworks
v: >-
{{ public_vpn_net_cidr }}
+ {{ public_wg_net_cidr }}
127.0.0.0/8
[::ffff:127.0.0.0]/104
[::1]/128
state: restarted
#+END_SRC
+** Configure Public WireGuard™
+
+Front uses WireGuard™ to provide a public VPN service. Core has an
+interface on this VPN (address: ~core_wg_addr~) and is expected to
+forward packets between it and the institute's other private networks.
+
+The following example [[file:Secret/front-wg0.conf][=Secret/front-wg0.conf=]] configuration recognizes
+Core by its public key, ~lGhC51~, and routes the institute's private
+networks to it. It also recognizes a member client, Dick's Notebook,
+by its public key ~4qd4xd...~ assigning it host number 4 on the VPN.
+
+#+CAPTION: [[file:Secret/front-wg0.conf][=Secret/front-wg0.conf=]]
+#+BEGIN_SRC conf :tangle Secret/front-wg0.conf
+[Interface]
+Address = 10.177.87.1/24
+PrivateKey = AJkzVxfTm/KvRjzTN/9X2jYy+CAugiwZfN5F3JTegms=
+ListenPort = 39608
+PostUp = resolvectl dns wg0 192.168.56.1
+PostUp = resolvectl domain wg0 small.private
+
+# Core
+[Peer]
+PublicKey = lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c=
+AllowedIPs = 10.177.87.2
+# AllowedIPs = 192.168.56.0/24 OpenVPN has this route.
+AllowedIPs = 10.84.138.0/24, 10.84.139.0/24
+
+# dicks-note
+[Peer]
+PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8=
+AllowedIPs = 10.177.87.4
+#+END_SRC
+
+The configuration used on Dick's notebook when it is abroad looks like
+this:
+
+#+CAPTION: WireGuard™ tunnel on Dick's notebook, used abroad
+#+BEGIN_SRC conf
+[Interface]
+Address = 10.177.87.3
+PrivateKey = WAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs=
+PostUp = resolvectl dns wg0 192.168.56.1
+PostUp = resolvectl domain wg0 small.private
+
+# Front
+[Peer]
+PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4=
+AllowedIPs = 10.177.87.1
+AllowedIPs = 10.177.87.0/24
+AllowedIPs = 192.168.56.0/24
+AllowedIPs = 10.84.138.0/24, 10.84.139.0/24
+AllowedIPs = 10.177.86.0/24
+#+END_SRC
+
+The following tasks install WireGuard™, configure it with
+=Secret/front-wg0.conf=, and enable the service.
+
+#+CAPTION: [[file:roles_t/front/tasks/main.yml][=roles_t/front/tasks/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/front/tasks/main.yml
+
+- name: Install WireGuard™.
+ become: yes
+ apt: pkg=wireguard
+
+- name: Configure WireGuard™.
+ become: yes
+ copy:
+ src: ../Secret/front-wg0.conf
+ dest: /etc/wireguard/wg0.conf
+ mode: u=r,g=,o=
+ owner: root
+ group: root
+ notify: Reload WireGuard™.
+
+- name: Enable/Start WireGuard™ on boot.
+ become: yes
+ systemd:
+ service: wg-quick@wg0
+ enabled: yes
+ state: started
+#+END_SRC
+
+#+CAPTION: [[file:roles_t/front/handlers/main.yml][=roles_t/front/handlers/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/front/handlers/main.yml
+
+- name: Reload WireGuard™.
+ become: yes
+ command: wg setconf wg0
+#+END_SRC
+
** Configure Kamailio
Front uses Kamailio to provide a SIP service on the public VPN so that
#+CAPTION: ~kamailio~
#+BEGIN_SRC conf
listen=udp:{{ front_vpn_addr }}:5060
+listen=udp:{{ front_wg_addr }}:5060
#+END_SRC
The Ansible tasks that install and configure Kamailio follow, but
option broadcast-address 192.168.56.255;
option routers 192.168.56.2;
option ntp-servers 192.168.56.1;
- option rfc3442-routes 24, 10,177,86, 192,168,56,1, 0, 192,168,56,2;
+ option rfc3442-routes 24, 10,177,86, 192,168,56,1,
+ 24, 10,177,87, 192,168,56,1,
+ 0, 192,168,56,2;
}
host core {
{{ private_net_cidr }};
{{ wild_net_cidr }};
{{ public_vpn_net_cidr }};
+ {{ public_wg_net_cidr }};
{{ campus_vpn_net_cidr }};
+ {{ campus_wg_net_cidr }};
localhost;
};
v: >-
{{ private_net_cidr }}
{{ public_vpn_net_cidr }}
+ {{ public_wg_net_cidr }}
{{ campus_vpn_net_cidr }}
+ {{ campus_wg_net_cidr }}
127.0.0.0/8
[::ffff:127.0.0.0]/104
[::1]/128
state: restarted
#+END_SRC
+** Configure Core WireGuard™ Interface
+
+Core connects to Front's WireGuard™ service to provide members abroad
+with a route to the campus networks. As described in [[*Configure Public WireGuard™][Configure
+Public WireGuard™]] for Front, Core is expected to forward packets from/to the
+private networks.
+
+The following example [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]] configuration recognizes
+Front by its public key, ~S+6HaT~, looking for it at the institute's
+public IP address and a special port.
+
+#+CAPTION: [[file:Secret/core-wg0.conf][=Secret/core-wg0.conf=]]
+#+BEGIN_SRC conf :tangle Secret/core-wg0.conf
+[Interface]
+Address = 10.177.87.2
+PrivateKey = AI+KhwnsHzSPqyIyAObx7EBBTBXFZPiXb2/Qcts8zEI=
+
+# Front
+[Peer]
+EndPoint = 192.168.15.5:39608
+PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4=
+AllowedIPs = 10.177.87.1
+AllowedIPs = 10.177.87.0/24
+#+END_SRC
+
+The following tasks install WireGuard™, configure it with
+=Secret/core-wg0.conf=, and enable the service.
+
+#+CAPTION: [[file:roles_t/core/tasks/main.yml][=roles_t/core/tasks/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/core/tasks/main.yml
+
+- name: Install WireGuard™.
+ become: yes
+ apt: pkg=wireguard
+
+- name: Configure WireGuard™.
+ become: yes
+ copy:
+ src: ../Secret/core-wg0.conf
+ dest: /etc/wireguard/wg0.conf
+ mode: u=r,g=,o=
+ owner: root
+ group: root
+ notify: Reload WireGuard™.
+
+- name: Enable/Start WireGuard™ on boot.
+ become: yes
+ systemd:
+ service: wg-quick@wg0
+ enabled: yes
+ state: started
+#+END_SRC
+
+#+CAPTION: [[file:roles_t/core/handlers/main.yml][=roles_t/core/handlers/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/core/handlers/main.yml
+
+- name: Reload WireGuard™.
+ become: yes
+ command: wg setconf wg0
+#+END_SRC
+
** Configure NAGIOS
Core runs a ~nagios4~ server to monitor "services" on institute hosts.
know!
Forwarding rules are also needed to route packets from the campus VPN
-(the ~ovpn~ tunnel device) to the institute's LAN and back. The
-public VPN on Front will also be included since its packets arrive at
-Gate's ~lan~ interface, coming from Core. Thus forwarding between
-public and campus VPNs is also allowed.
+(the ~ovpn~ tunnel device) or WireGuard™ subnet (the ~wg0~ tunnel
+device) to the institute's LAN and back. The public VPN on Front will
+also be included since its packets arrive at Gate's ~lan~ interface,
+coming from Core. Thus forwarding between public and campus VPNs is
+also allowed.
#+NAME: ufw-forward-private
#+CAPTION: ~ufw-forward-private~
#+BEGIN_SRC conf
-A FORWARD -i lan -o ovpn -j ACCEPT
-A FORWARD -i ovpn -o lan -j ACCEPT
+-A FORWARD -i lan -o wg0 -j ACCEPT
+-A FORWARD -i wg0 -o lan -j ACCEPT
#+END_SRC
Note that there are no forwarding rules to allow packets to pass from
state: restarted
#+END_SRC
+** Configure Campus WireGuard™
+
+Gate uses WireGuard™ to provide a campus VPN service. Gate's routes
+and firewall rules allow packets to be forwarded to/from the
+institute's private networks: the private Ethernet and the public VPN.
+(It should /not/ forward packets to/from the wild Ethernet.) The only
+additional route Gate needs is to the public VPN via Core. The rest
+(private Ethernet and campus VPN) are directly connected.
+
+The following example [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]] configuration recognizes
+a wired IoT appliance (public key ~LdsCsg~) and a member client,
+Dick's Notebook (public key ~4qd4xd~), assigning them the host numbers
+3 and 4 respectively. (Dick's Notebook's host number is /not
+coincidentally/ 4 here as well as on Front's WireGuard™ subnet.)
+
+#+CAPTION: [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]]
+#+BEGIN_SRC conf :tangle Secret/gate-wg0.conf
+[Interface]
+Address = 10.84.139.1/24
+PrivateKey = yOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U=
+ListenPort = 51820
+
+# IoT appliance
+[Peer]
+PublicKey = LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ=
+AllowedIPs = 10.84.139.3
+
+# dicks-note
+[Peer]
+PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8=
+AllowedIPs = 10.84.139.4
+#+END_SRC
+
+The configuration used on the IoT appliance looks like this:
+
+#+CAPTION: WireGuard™ tunnel on an IoT appliance
+#+BEGIN_SRC conf
+[Interface]
+Address = 10.84.139.2
+PrivateKey = KIwQT5eGOl9w1qOa5I+2xx5kJH3z4xdpmirS/eGdsXY=
+
+# Gate
+[Peer]
+PublicKey = y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI=
+AllowedIPs = 10.84.139.1
+AllowedIPs = 10.84.139.0/24
+AllowedIPs = 192.168.56.0/24
+AllowedIPs = 10.177.86.0/24
+AllowedIPs = 10.177.87.0/24
+AllowedIPs = 10.84.138.0/24
+#+END_SRC
+
+And the configuration used on Dick's notebook when it is on campus
+looks like this:
+
+#+CAPTION: WireGuard™ tunnel on Dick's notebook, used on campus
+#+BEGIN_SRC conf
+[Interface]
+Address = 10.84.139.3
+PrivateKey = WAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs=
+PostUp = resolvectl dns wg0 192.168.56.1
+PostUp = resolvectl domain wg0 small.private
+
+# Gate
+[Peer]
+PublicKey = y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI=
+AllowedIPs = 10.84.139.1
+AllowedIPs = 10.84.139.0/24
+AllowedIPs = 192.168.56.0/24
+AllowedIPs = 10.177.86.0/24
+AllowedIPs = 10.177.87.0/24
+AllowedIPs = 10.84.138.0/24
+#+END_SRC
+
+The following tasks install WireGuard™, configure it with
+=Secret/gate-wg0.conf=, and enable the service.
+
+#+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml
+
+- name: Install WireGuard™.
+ become: yes
+ apt: pkg=wireguard
+
+- name: Configure WireGuard™.
+ become: yes
+ copy:
+ src: ../Secret/gate-wg0.conf
+ dest: /etc/wireguard/wg0.conf
+ mode: u=r,g=,o=
+ owner: root
+ group: root
+ notify: Reload WireGuard™.
+
+- name: Enable/Start WireGuard™ on boot.
+ become: yes
+ systemd:
+ service: wg-quick@wg0
+ enabled: yes
+ state: started
+#+END_SRC
+
+#+CAPTION: [[file:roles_t/gate/handlers/main.yml][=roles_t/gate/handlers/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/handlers/main.yml
+
+- name: Reload WireGuard™.
+ become: yes
+ command: wg setconf wg0
+#+END_SRC
+
* The Campus Role
private_net_cidr: 192.168.56.0/24
wild_net_cidr: 192.168.57.0/24
public_vpn_net_cidr: 10.177.86.0/24
+public_wg_net_cidr: 10.177.87.0/24
campus_vpn_net_cidr: 10.84.138.0/24
+campus_wg_net_cidr: 10.84.139.0/24
private_net:
"{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
private_net_mask:
"{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
private_net_and_mask: "{{ private_net }} {{ private_net_mask }}"
+wild_net: "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+ "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+ "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
public_vpn_net:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('network') }}"
public_vpn_net_mask:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}"
public_vpn_net_and_mask:
"{{ public_vpn_net }} {{ public_vpn_net_mask }}"
+public_wg_net:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+ "{{ public_wg_net }} {{ public_wg_net_mask }}"
campus_vpn_net:
"{{ campus_vpn_net_cidr | ansible.utils.ipaddr('network') }}"
campus_vpn_net_mask:
"{{ campus_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}"
campus_vpn_net_and_mask:
"{{ campus_vpn_net }} {{ campus_vpn_net_mask }}"
-wild_net: "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
-wild_net_mask:
- "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
-wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}"
-wild_net_broadcast:
- "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+campus_wg_net:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+ "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
core_addr_cidr: "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
gate_addr_cidr: "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
wifi_wan_addr_cidr: "{{ wild_net_cidr | ansible.utils.ipaddr('2') }}"
front_vpn_addr_cidr:
"{{ public_vpn_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_port: 39608
+front_wg_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+wg_client_front_addr_cidr:
+ "{{ public_wg_net_cidr | ansible.utils.ipaddr('3') }}"
+campus_wg_port: 51820
+campus_wg_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+wg_appl_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+wg_client_gate_addr_cidr:
+ "{{ campus_wg_net_cidr | ansible.utils.ipaddr('3') }}"
core_addr: "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
gate_addr: "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
"{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
wifi_wan_addr:
"{{ wifi_wan_addr_cidr | ansible.utils.ipaddr('address') }}"
-front_private_addr:
- "{{ front_private_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_vpn_addr:
+ "{{ front_vpn_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+ "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+ "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_client_front_addr:
+ "{{ wg_client_front_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wg_addr:
+ "{{ campus_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_appl_addr:
+ "{{ wg_appl_addr_cidr | ansible.utils.ipaddr('address') }}"
+wg_client_gate_addr:
+ "{{ wg_client_gate_addr_cidr | ansible.utils.ipaddr('address') }}"
core_ethernet: enp0s3