From 8c91e1edb0e96dc883b68066aee73bf2d1a14b20 Mon Sep 17 00:00:00 2001 From: Matt Birkholz Date: Sun, 15 Jun 2025 12:24:13 -0600 Subject: [PATCH] Update README.html. --- README.html | 2243 ++++++++++++++++++++++++--------------------------- 1 file changed, 1061 insertions(+), 1182 deletions(-) diff --git a/README.html b/README.html index 6d8b648..188d504 100644 --- a/README.html +++ b/README.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + A Small Institute @@ -24,8 +24,8 @@ an expendable public face (easily wiped clean) while maintaining a secure and private campus that can function with or without the Internet.

-
-

1. Overview

+
+

1. Overview

This small institute has a public server on the Internet, Front, that @@ -48,7 +48,7 @@ connects to Front making the institute email, cloud, etc. available to members off campus.

-
+
                 =                                                   
               _|||_                                                 
         =-The-Institute-=                                           
@@ -83,7 +83,7 @@ desktops.  When off campus, members access institute resources via the
 VPN on Front (via hotel Wi-Fi).  When on campus, members can use the
 much faster and always available (despite Internet connectivity
 issues) VPN on Gate (via campus Wi-Fi).  A member's Android phones and
-devices can use the same Wi-Fis, VPNs (via the OpenVPN app) and
+devices can use the same Wi-Fis, VPNs (via the WireGuard™ app) and
 services.  On a desktop or by phone, at home or abroad, members can
 access their email and the institute's private web and cloud.
 

@@ -95,8 +95,8 @@ uses OpenPGP encryption to secure message content.

-
-

2. Caveats

+
+

2. Caveats

This small institute prizes its privacy, so there is little or no @@ -144,8 +144,8 @@ month) because of this assumption.

-
-

3. The Services

+
+

3. The Services

The small institute's network is designed to provide a number of @@ -157,8 +157,8 @@ policies. On first reading, those subsections should be skipped; they reference particulars first introduced in the following chapter.

-
-

3.1. The Name Service

+
+

3.1. The Name Service

The institute has a public domain, e.g. small.example.org, and a @@ -172,8 +172,8 @@ names like core.

-
-

3.2. The Email Service

+
+

3.2. The Email Service

Front provides the public SMTP (Simple Mail Transfer Protocol) service @@ -247,8 +247,8 @@ setting for the maximum message size is given in a code block labeled configurations wherever <<postfix-message-size>> appears.

-
-

3.2.1. The Postfix Configurations

+
+

3.2.1. The Postfix Configurations

The institute aims to accommodate encrypted email containing short @@ -263,7 +263,7 @@ handle maxi-messages.

-postfix-message-size
- { p: message_size_limit, v: 104857600 }
+postfix-message-size
- { p: message_size_limit, v: 104857600 }
 
@@ -278,7 +278,7 @@ re-sending the bounce (or just grabbing the go-bag!).

-postfix-queue-times
- { p: delay_warning_time, v: 1h }
+postfix-queue-times
- { p: delay_warning_time, v: 1h }
 - { p: maximal_queue_lifetime, v: 4h }
 - { p: bounce_queue_lifetime, v: 4h }
 
@@ -292,7 +292,7 @@ disables relaying (other than for the local networks).

-postfix-relaying
- p: smtpd_relay_restrictions
+postfix-relaying
- p: smtpd_relay_restrictions
   v: permit_mynetworks reject_unauth_destination
 
@@ -304,7 +304,7 @@ effect.

-postfix-maildir
- { p: home_mailbox, v: Maildir/ }
+postfix-maildir
- { p: home_mailbox, v: Maildir/ }
 
@@ -315,8 +315,8 @@ in the respective roles below.

-
-

3.2.2. The Dovecot Configurations

+
+

3.2.2. The Dovecot Configurations

The Dovecot settings on both Front and Core disable POP and require @@ -330,7 +330,7 @@ The official documentation for Dovecot once was a Wiki but now is

-dovecot-tls
protocols = imap
+dovecot-tls
protocols = imap
 ssl = required
 
@@ -342,7 +342,7 @@ configuration keeps them from even listening at the IMAP port

-dovecot-ports
service imap-login {
+dovecot-ports
service imap-login {
   inet_listener imap {
     port = 0
   }
@@ -356,7 +356,7 @@ directories.
 

-dovecot-maildir
mail_location = maildir:~/Maildir
+dovecot-maildir
mail_location = maildir:~/Maildir
 
@@ -368,15 +368,15 @@ common settings with host specific settings for ssl_cert and
-
-

3.3. The Web Services

+
+

3.3. The Web Services

Front provides the public HTTP service that serves institute web pages at e.g. https://small.example.org/. The small institute initially runs with a self-signed, "snake oil" server certificate, causing browsers to warn of possible fraud, but this certificate is easily -replaced by one signed by a recognized authority, as discussed in The +replaced by one signed by a recognized authority, as discussed in The Front Role.

@@ -431,15 +431,15 @@ will automatically wipe it within 15 minutes.

-
-

3.4. The Cloud Service

+
+

3.4. The Cloud Service

Core runs Nextcloud to provide a private institute cloud at https://core.small.private/nextcloud/. It is managed manually per The Nextcloud Server Administration Guide. The code and data, including especially database dumps, are stored in /Nextcloud/ which -is included in Core's backup procedure as described in Backups. The +is included in Core's backup procedure as described in Backups. The default Apache2 configuration expects to find the web scripts in /var/www/nextcloud/, so the institute symbolically links this to /Nextcloud/nextcloud/. @@ -453,130 +453,15 @@ private network.

-
-

3.5. The VPN Services

+
+

3.5. Accounts

-The institute's public and campus VPNs have many common configuration -options that are discussed here. These are included, with example -certificates and network addresses, in the complete server -configurations of The Front Role and The Gate Role, as well as the -matching client configurations in The Core Role and the .ovpn files -generated by The Client Command. The configurations are based on the -documentation for OpenVPN v2.4: the openvpn(8) manual page and this -web page. -

-
-
-

3.5.1. The VPN Configuration Options

-
-

-The institute VPNs use UDP on a subnet topology (rather than -point-to-point) with "split tunneling". The UDP support accommodates -real-time, connection-less protocols. The split tunneling is for -efficiency with frontier bandwidth. The subnet topology, with the -client-to-client option, allows members to "talk" to each other on -the VPN subnets using any (experimental) protocol. -

- -
-openvpn-dev-mode
dev-type tun
-dev ovpn
-topology subnet
-client-to-client
-
-
- -

-A keepalive option is included on the servers so that clients detect -an unreachable server and reset the TLS session. The option's default -is doubled to 2 minutes out of respect for frontier service -interruptions. -

- -
-openvpn-keepalive
keepalive 10 120
-
-
- -

-As mentioned in The Name Service, the institute uses a campus name -server. OpenVPN is instructed to push its address and the campus -search domain. -

- -
-openvpn-dns
push "dhcp-option DOMAIN {{ domain_priv }}"
-push "dhcp-option DNS {{ core_addr }}"
-
-
- -

-The institute does not put the OpenVPN server in a chroot jail, but -it does drop privileges to run as user nobody:nobody. The -persist- options are needed because nobody cannot open the tunnel -device nor the key files. -

- -
-openvpn-drop-priv
user nobody
-group nogroup
-persist-key
-persist-tun
-
-
- -

-The institute does a little additional hardening, sacrificing some -compatibility with out-of-date clients. Such clients are generally -frowned upon at the institute. Here cipher is set to AES-256-GCM, -the default for OpenVPN v2.4, and auth is upped to SHA256 from -SHA1. -

- -
-openvpn-crypt
cipher AES-256-GCM
-auth SHA256
-
-
- -

-Finally, a max-client limit was chosen to frustrate flooding while -accommodating a few members with a handful of devices each. -

- -
-openvpn-max
max-clients 20
-
-
- -

-The institute's servers are lightly loaded so a few debugging options -are appropriate. To help recognize host addresses in the logs, and -support direct client-to-client communication, host IP addresses are -made "persistent" in the ipp.txt file. The server's status is -periodically written to the openvpn-status.log and verbosity is -raised from the default level 1 to level 3 (just short of a deluge). -

- -
-openvpn-debug
ifconfig-pool-persist ipp.txt
-status openvpn-status.log
-verb 3
-
-
-
-
-
-
-

3.6. Accounts

-
-

A small institute has just a handful of members. For simplicity (and thus security) static configuration files are preferred over complex account management systems, LDAP, Active Directory, and the like. The Ansible scripts configure the same set of user accounts on Core and -Front. The Institute Commands (e.g. ./inst new dick) capture the +Front. The Institute Commands (e.g. ./inst new dick) capture the processes of enrolling, modifying and retiring members of the institute. They update the administrator's membership roll, and run Ansible to create (and disable) accounts on Core, Front, Nextcloud, @@ -591,9 +476,9 @@ accomplished via the campus cloud and the resulting desktop files can all be private (readable and writable only by the owner) by default.

-
-

3.6.1. The Administration Accounts

-
+
+

3.5.1. The Administration Accounts

+

The institute avoids the use of the root account (uid 0) because it is exempt from the normal Unix permissions checking. The sudo @@ -601,22 +486,22 @@ command is used to consciously (conscientiously!) run specific scripts and programs as root. When installation of a Debian OS leaves the host with no user accounts, just the root account, the next step is to create a system administrator's account named sysadm and to give -it permission to use the sudo command (e.g. as described in The +it permission to use the sudo command (e.g. as described in The Front Machine). When installation prompts for the name of an initial, privileged user account the same name is given (e.g. as -described in The Core Machine). Installation may not prompt and +described in The Core Machine). Installation may not prompt and still create an initial user account with a distribution specific name (e.g. pi). Any name can be used as long as it is provided as the value of ansible_user in hosts. Its password is specified by a vault-encrypted variable in the Secret/become.yml file. (The -hosts and Secret/become.yml files are described in The Ansible +hosts and Secret/become.yml files are described in The Ansible Configuration.)

-
-

3.6.2. The Monkey Accounts

-
+
+

3.5.2. The Monkey Accounts

+

The institute's Core uses a special account named monkey to run background jobs with limited privileges. One of those jobs is to keep @@ -626,9 +511,9 @@ account is created on Front as well.

-
-

3.7. Keys

-
+
+

3.6. Keys

+

The institute keeps its "master secrets" in an encrypted volume on an off-line hard drive, e.g. a LUKS (Linux Unified Key @@ -658,36 +543,26 @@ Front's.)

-The institute uses a number of X.509 certificates to authenticate VPN -clients and servers. They are created by the EasyRSA Certificate -Authority stored in Secret/CA/. +The institute uses a couple X.509 certificates to authenticate +servers. They are created by the EasyRSA Certificate Authority stored +in Secret/CA/.

Secret/CA/pki/ca.crt
The institute CA certificate, used to sign the other certificates.
-
Secret/CA/pki/issued/small.example.org.crt
The public Apache, -Postfix, and OpenVPN servers on Front.
- -
Secret/CA/pki/issued/gate.small.private.crt
The campus -OpenVPN server on Gate.
+
Secret/CA/pki/issued/small.example.org.crt
The public +Postfix, Dovecot and Apache servers on Front.
Secret/CA/pki/issued/core.small.private.crt
The campus -Apache (thus Nextcloud), and Dovecot-IMAPd servers.
- -
Secret/CA/pki/issued/core.crt
Core's client certificate, by -which it authenticates to Front.
+Postfix, Dovecot and Apache (thus Nextcloud) servers on Core.

-The ./inst client command creates client certificates and keys, and -can generate OpenVPN configuration (.ovpn) files for Android and -Debian. The command updates the institute membership roll, requiring -the member's username, keeping a list of the member's clients (in case -all authorizations need to be revoked quickly). The list of client -certificates that have been revoked is stored along with the -membership roll (in private/members.yml as the value of revoked). +The ./inst client command updates the institute membership roll, +which lists members and their clients' public keys, and is stored in +private/members.yml.

@@ -705,8 +580,8 @@ e.g. root@core.small.private.

The institute administrator updates a couple encrypted copies of this -drive after enrolling new members, changing a password, issuing VPN -credentials, etc. +drive after enrolling new members, changing a password, +(de)authorizing a VPN client, etc.

@@ -722,9 +597,9 @@ the administrator's password keep, to install a new SSH key.
 

-
-

3.8. Backups

-
+
+

3.7. Backups

+

The small institute backs up its data, but not so much so that nothing can be deleted. It actually mirrors user directories (/home/), the @@ -759,7 +634,7 @@ files mentioned in the Nextcloud database dump).

-private/backup
#!/bin/bash -e
+private/backup
#!/bin/bash -e
 #
 # DO NOT EDIT.  Maintained (will be replaced) by Ansible.
 #
@@ -861,8 +736,8 @@ finish
 
-
-

4. The Particulars

+
+

4. The Particulars

This chapter introduces Ansible variables intended to simplify @@ -874,13 +749,13 @@ stored in separate files: public/vars.yml a

The example settings in this document configure VirtualBox VMs as -described in the Testing chapter. For more information about how a +described in the Testing chapter. For more information about how a small institute turns the example Ansible code into a working Ansible -configuration, see chapter The Ansible Configuration. +configuration, see chapter The Ansible Configuration.

-
-

4.1. Generic Particulars

+
+

4.1. Generic Particulars

The small institute's domain name is used quite frequently in the @@ -919,22 +794,22 @@ domain_priv: small.private

-
-

4.2. Subnets

+
+

4.2. Subnets

-The small institute uses a private Ethernet, two VPNs, and an -untrusted Ethernet (for the campus Wi-Fi access point). Each must -have a unique private network address. Hosts using the VPNs are also -using foreign private networks, e.g. a notebook on a hotel Wi-Fi. To -better the chances that all of these networks get unique addresses, -the small institute uses addresses in the IANA's (Internet Assigned -Numbers Authority's) private network address ranges except the -192.168 address range already in widespread use. This still leaves -69,632 8 bit networks (each addressing up to 254 hosts) from which to -choose. The following table lists their CIDRs (subnet numbers in -Classless Inter-Domain Routing notation) in abbreviated form (eliding -69,624 rows). +The small institute uses a private Ethernet, two VPNs, and a "wild", +untrusted Ethernet for the campus Wi-Fi access point(s) and wired IoT +appliances. Each must have a unique private network address. Hosts +using the VPNs are also using foreign private networks, e.g. a +notebook on a hotel Wi-Fi. To better the chances that all of these +networks get unique addresses, the small institute uses addresses in +the IANA's (Internet Assigned Numbers Authority's) private network +address ranges except the 192.168 address range already in +widespread use. This still leaves 69,632 8 bit networks (each +addressing up to 254 hosts) from which to choose. The following table +lists their CIDRs (subnet numbers in Classless Inter-Domain Routing +notation) in abbreviated form (eliding 69,624 rows).

@@ -1020,7 +895,7 @@ example result follows the code. -
+

=> 10.62.17.0/24

@@ -1033,21 +908,21 @@ code block below. The small institute treats these addresses as sensitive information so again the code block below "tangles" into private/vars.yml rather than public/vars.yml. Two of the addresses are in 192.168 subnets because they are part of a test -configuration using mostly-default VirtualBoxes (described here). +configuration using mostly-default VirtualBoxes (described here).

private/vars.yml

 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
-campus_vpn_net_cidr:        10.84.138.0/24
+public_wg_net_cidr:         10.177.87.0/24
+campus_wg_net_cidr:         10.84.139.0/24
 

The network addresses are needed in several additional formats, e.g. -network address and subnet mask (10.84.138.0 255.255.255.0). The +network address and subnet mask (10.84.139.0 255.255.255.0). The following boilerplate uses Ansible's ipaddr filter to set several corresponding variables, each with an appropriate suffix, e.g. _net_and_mask rather than _net_cidr. @@ -1059,24 +934,24 @@ e.g. _net_and_mask rather than _net_cidr. private_net_mask: "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}" private_net_and_mask: "{{ private_net }} {{ private_net_mask }}" -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 }}" -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') }}" +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_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 }}"

@@ -1101,14 +976,13 @@ virtual machines and networks, and the VirtualBox user manual uses

-Finally, five host addresses are needed frequently in the Ansible +Finally, four host addresses are needed frequently in the Ansible code. The first two are Core's and Gate's addresses on the private -Ethernet. The next two are Gate's and the campus Wi-Fi's addresses on -the "wild" subnet, the untrusted Ethernet (wild_net) between Gate -and the campus Wi-Fi access point(s) and IoT appliances. The last is -Front's address on the public VPN, perversely called -front_private_addr. The following code block picks the obvious IP -addresses for Core (host 1) and Gate (host 2). +Ethernet. The other two are Gate's and the campus Wi-Fi's addresses +on the wild Ethernet. The following code block chooses host 1 for +Core and host 2 for Gate on the private Ethernet. On the wild +Ethernet, host 1 is Gate and host 2 is the access point (or wired +IoT appliance).

@@ -1116,36 +990,33 @@ addresses for Core (host 1) and Gate (host 2). gate_addr_cidr: "{{ private_net_cidr | ansible.utils.ipaddr('2') }}" gate_wild_addr_cidr: "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}" -wifi_wan_addr_cidr: "{{ wild_net_cidr | ansible.utils.ipaddr('2') }}" -front_private_addr_cidr: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('1') }}" +front_wg_addr_cidr: + "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}" core_addr: "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}" gate_addr: "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}" gate_wild_addr: "{{ 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_wg_addr: + "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
-
-

5. The Hardware

+
+

5. The Hardware

The small institute's network was built by its system administrator using Ansible on a trusted notebook. The Ansible configuration and scripts were generated by "tangling" the Ansible code included here. -(The Ansible Configuration describes how to do this.) The following +(The Ansible Configuration describes how to do this.) The following sections describe how Front, Gate and Core were prepared for Ansible.

-
-

5.1. The Front Machine

+
+

5.1. The Front Machine

Front is the small institute's public facing server, a virtual machine @@ -1158,8 +1029,8 @@ possible to quickly re-provision a new Front machine from a frontier Internet café using just the administrator's notebook.

-
-

5.1.1. A Digital Ocean Droplet

+
+

5.1.1. A Digital Ocean Droplet

The following example prepared a new front on a Digital Ocean droplet. @@ -1183,7 +1054,7 @@ root@ubuntu#

The freshly created Digital Ocean droplet came with just one account, root, but the small institute avoids remote access to the "super -user" account (per the policy in The Administration Accounts), so the +user" account (per the policy in The Administration Accounts), so the administrator created a sysadm account with the ability to request escalated privileges via the sudo command.

@@ -1206,7 +1077,7 @@ notebook$ The password was generated by gpw, saved in the administrator's password keep, and later added to Secret/become.yml as shown below. (Producing a working Ansible configuration with Secret/become.yml -file is described in The Ansible Configuration.) +file is described in The Ansible Configuration.)

@@ -1220,7 +1091,7 @@ notebook_     >>Secret/become.yml
 

After creating the sysadm account on the droplet, the administrator concatenated a personal public ssh key and the key found in -Secret/ssh_admin/ (created by The CA Command) into an admin_keys +Secret/ssh_admin/ (created by The CA Command) into an admin_keys file, copied it to the droplet, and installed it as the authorized_keys for sysadm.

@@ -1252,7 +1123,8 @@ in Secret/ssh_front/ to the droplet and restarted the SSH server.

-notebook$ scp Secret/ssh_front/etc/ssh/ssh_host_* sysadm@159.65.75.60:
+notebook$ ( cd Secret/ssh_front/etc/ssh/;
+notebook_   scp ssh_host_* sysadm@159.65.75.60: )
 notebook$ ssh sysadm@159.65.75.60
 sysadm@ubuntu$ chmod 600 ssh_host_*
 sysadm@ubuntu$ chmod 644 ssh_host_*.pub
@@ -1303,8 +1175,8 @@ address.
 
-
-

5.2. The Core Machine

+
+

5.2. The Core Machine

Core is the small institute's private file, email, cloud and whatnot @@ -1328,7 +1200,7 @@ The following example prepared a new core on a PC with Debian 11 freshly installed. During installation, the machine was named core, no desktop or server software was installed, no root password was set, and a privileged account named sysadm was created (per the policy in -The Administration Accounts). +The Administration Accounts).

@@ -1344,7 +1216,7 @@ Is the information correct? [Y/n]
 The password was generated by gpw, saved in the administrator's
 password keep, and later added to Secret/become.yml as shown below.
 (Producing a working Ansible configuration with Secret/become.yml
-file is described in The Ansible Configuration.)
+file is described in The Ansible Configuration.)
 

@@ -1363,7 +1235,7 @@ modem and installed them as shown below.
 
 
 $ sudo apt install netplan.io systemd-resolved unattended-upgrades \
-_                  ntp isc-dhcp-server bind9 apache2 openvpn \
+_                  ntp isc-dhcp-server bind9 apache2 wireguard \
 _                  postfix dovecot-imapd fetchmail expect rsync \
 _                  gnupg openssh-server
 
@@ -1392,7 +1264,7 @@ _ nagios-nrpe-plugin

Next, the administrator concatenated a personal public ssh key and the -key found in Secret/ssh_admin/ (created by The CA Command) into an +key found in Secret/ssh_admin/ (created by The CA Command) into an admin_keys file, copied it to Core, and installed it as the authorized_keys for sysadm.

@@ -1432,7 +1304,7 @@ a new, private IP address and a default route.

In the example command lines below, the address 10.227.248.1 was generated by the random subnet address picking procedure described in -Subnets, and is named core_addr in the Ansible code. The second +Subnets, and is named core_addr in the Ansible code. The second address, 10.227.248.2, is the corresponding address for Gate's Ethernet interface, and is named gate_addr in the Ansible code. @@ -1448,8 +1320,8 @@ At this point Core was ready for provisioning with Ansible.

-
-

5.3. The Gate Machine

+
+

5.3. The Gate Machine

Gate is the small institute's route to the Internet, and the campus @@ -1470,7 +1342,7 @@ USB-Ethernet adapter, or a wireless adapter connected to a campground Wi-Fi access point, etc. -

+
 =============== | ==================================================
                 |                                           Premises
           (Campus ISP)                                              
@@ -1483,8 +1355,8 @@ campground Wi-Fi access point, etc.
                 +----Ethernet switch                                
 
-
-

5.3.1. Alternate Gate Topology

+
+

5.3.1. Alternate Gate Topology

While Gate and Core really need to be separate machines for security @@ -1493,7 +1365,7 @@ This avoids the need for a second Wi-Fi access point and leads to the following topology.

-
+
 =============== | ==================================================
                 |                                           Premises
            (House ISP)                                              
@@ -1517,12 +1389,12 @@ its Ethernet and Wi-Fi clients are allowed to communicate).
 

-
-

5.3.2. Original Gate Topology

+
+

5.3.2. Original Gate Topology

The Ansible code in this document is somewhat dependent on the -physical network shown in the Overview wherein Gate has three network +physical network shown in the Overview wherein Gate has three network interfaces.

@@ -1531,7 +1403,7 @@ The following example prepared a new gate on a PC with Debian 11 freshly installed. During installation, the machine was named gate, no desktop or server software was installed, no root password was set, and a privileged account named sysadm was created (per the policy in -The Administration Accounts). +The Administration Accounts).

@@ -1547,7 +1419,7 @@ Is the information correct? [Y/n]
 The password was generated by gpw, saved in the administrator's
 password keep, and later added to Secret/become.yml as shown below.
 (Producing a working Ansible configuration with Secret/become.yml
-file is described in The Ansible Configuration.)
+file is described in The Ansible Configuration.)
 

@@ -1566,13 +1438,13 @@ cable modem and installed them as shown below.
 
 
 $ sudo apt install netplan.io systemd-resolved unattended-upgrades \
-_                  ufw isc-dhcp-server postfix openvpn \
+_                  ufw isc-dhcp-server postfix wireguard \
 _                  openssh-server
 

Next, the administrator concatenated a personal public ssh key and the -key found in Secret/ssh_admin/ (created by The CA Command) into an +key found in Secret/ssh_admin/ (created by The CA Command) into an admin_keys file, copied it to Gate, and installed it as the authorized_keys for sysadm.

@@ -1612,7 +1484,7 @@ a new, private IP address.

In the example command lines below, the address 10.227.248.2 was generated by the random subnet address picking procedure described in -Subnets, and is named gate_addr in the Ansible code. +Subnets, and is named gate_addr in the Ansible code.

@@ -1624,7 +1496,7 @@ Gate was also connected to the USB Ethernet dongles cabled to the
 campus Wi-Fi access point and the campus ISP.  The three network
 adapters are known by their MAC addresses, the values of the variables
 gate_lan_mac, gate_wild_mac, and gate_isp_mac.  (For more
-information, see the Gate role's Configure Netplan task.)
+information, see the Gate role's Configure Netplan task.)
 

@@ -1634,28 +1506,28 @@ At this point Gate was ready for provisioning with Ansible.

-
-

6. The All Role

+
+

6. The All Role

The all role contains tasks that are executed on all of the institute's servers. At the moment there is just the one.

-
-

6.1. Include Particulars

+
+

6.1. Include Particulars

The all role's task contains a reference to a common institute particular, the institute's domain_name, a variable found in the public/vars.yml file. Thus the first task of the all role is to -include the variables defined in this file (described in The +include the variables defined in this file (described in The Particulars). The code block below is the first to tangle into -roles/all/tasks/main.yml. +roles/all/tasks/main.yml.

-roles/all/tasks/main.yml
---
+roles/all/tasks/main.yml
---
 - name: Include public variables.
   include_vars: ../public/vars.yml
   tags: accounts
@@ -1663,8 +1535,8 @@ Particulars).  The code block below is the first to tangle into
 
-
-

6.2. Enable Systemd Resolved

+
+

6.2. Enable Systemd Resolved

The systemd-networkd and systemd-resolved service units are not @@ -1685,7 +1557,7 @@ follows these recommendations (and not the suggestion to enable

-roles_t/all/tasks/main.yml

+roles_t/all/tasks/main.yml

 - name: Install systemd-resolved.
   become: yes
   apt: pkg=systemd-resolved
@@ -1721,18 +1593,18 @@ follows these recommendations (and not the suggestion to enable
 
-
-

6.3. Trust Institute Certificate Authority

+
+

6.3. Trust Institute Certificate Authority

All servers should recognize the institute's Certificate Authority as trustworthy, so its certificate is added to the set of trusted CAs on each host. More information about how the small institute manages its -X.509 certificates is available in Keys. +X.509 certificates is available in Keys.

-roles_t/all/tasks/main.yml

+roles_t/all/tasks/main.yml

 - name: Trust the institute CA.
   become: yes
   copy:
@@ -1746,7 +1618,7 @@ X.509 certificates is available in Keys.
 
-roles_t/all/handlers/main.yml

+roles_t/all/handlers/main.yml

 - name: Update CAs.
   become: yes
   command: update-ca-certificates
@@ -1755,15 +1627,15 @@ X.509 certificates is available in Keys.
 
-
-

7. The Front Role

+
+

7. The Front Role

The front role installs and configures the services expected on the institute's publicly accessible "front door": email, web, VPN. The virtual machine is prepared with an Ubuntu Server install and remote access to a privileged, administrator's account. (For details, see -The Front Machine.) +The Front Machine.)

@@ -1777,18 +1649,12 @@ replacing the "snake oil" is as easy as replacing these two files, perhaps with symbolic links to, for example, /etc/letsencrypt/live/small.example.org/fullchain.pem.

- -

-Note that the OpenVPN server does not use /etc/server.crt. It -uses the institute's CA and server certificates, and expects client -certificates signed by the institute CA. -

-
-

7.1. Include Particulars

+
+

7.1. Include Particulars

-The first task, as in The All Role, is to include the institute +The first task, as in The All Role, is to include the institute particulars. The front role refers to private variables and the membership roll, so these are included was well.

@@ -1810,8 +1676,8 @@ membership roll, so these are included was well.
-
-

7.2. Configure Hostname

+
+

7.2. Configure Hostname

This task ensures that Front's /etc/hostname and /etc/mailname are @@ -1841,8 +1707,8 @@ delivery.

-
-

7.3. Add Administrator to System Groups

+
+

7.3. Add Administrator to System Groups

The administrator often needs to read (directories of) log files owned @@ -1862,8 +1728,8 @@ these groups speeds up debugging.

-
-

7.4. Configure SSH

+
+

7.4. Configure SSH

The SSH service on Front needs to be known to Monkey. The following @@ -1901,8 +1767,8 @@ those stored in Secret/ssh_front/etc/ssh/

- -
-

7.6. Install Rsync

+
+

7.6. Install Rsync

Monkey uses Rsync to keep the institute's public web site up-to-date. @@ -1958,8 +1824,8 @@ Monkey uses Rsync to keep the institute's public web site up-to-date.

-
-

7.7. Install Unattended Upgrades

+
+

7.7. Install Unattended Upgrades

The institute prefers to install security updates as soon as possible. @@ -1974,13 +1840,13 @@ The institute prefers to install security updates as soon as possible.

-
-

7.8. Configure User Accounts

+
+

7.8. Configure User Accounts

User accounts are created immediately so that Postfix and Dovecot can start delivering email immediately, without returning "no such -recipient" replies. The Account Management chapter describes the +recipient" replies. The Account Management chapter describes the members and usernames variables used below.

@@ -2018,8 +1884,8 @@ recipient" replies. The Account Management chapter de
-
-

7.9. Install Server Certificate

+
+

7.9. Install Server Certificate

The servers on Front use the same certificate (and key) to @@ -2049,8 +1915,8 @@ readable by root.

-
-

7.10. Configure Postfix on Front

+
+

7.10. Configure Postfix on Front

Front uses Postfix to provide the institute's public SMTP service, and @@ -2067,7 +1933,7 @@ The appropriate answers are listed here but will be checked

-As discussed in The Email Service above, Front's Postfix configuration +As discussed in The Email Service above, Front's Postfix configuration includes site-wide support for larger message sizes, shorter queue times, the relaying configuration, and the common path to incoming emails. These and a few Front-specific Postfix configurations @@ -2075,14 +1941,14 @@ settings make up the complete configuration (below).

-Front relays messages from the institute's public VPN via which Core -relays messages from the campus. +Front relays messages from the institute's public WireGuard™ subnet +via which Core relays messages from the campus.

-postfix-front-networks
- p: mynetworks
+postfix-front-networks
- p: mynetworks
   v: >-
-     {{ public_vpn_net_cidr }}
+     {{ public_wg_net_cidr }}
      127.0.0.0/8
      [::ffff:127.0.0.0]/104
      [::1]/128
@@ -2096,7 +1962,7 @@ difficult for internal hosts, who do not have (public) domain names.
 

-postfix-front-restrictions
- p: smtpd_recipient_restrictions
+postfix-front-restrictions
- p: smtpd_recipient_restrictions
   v: >-
      permit_mynetworks
      reject_unauth_pipelining
@@ -2117,13 +1983,13 @@ messages; incoming messages are delivered locally, without
 

-postfix-header-checks
- p: smtp_header_checks
+postfix-header-checks
- p: smtp_header_checks
   v: regexp:/etc/postfix/header_checks.cf
 
-postfix-header-checks-content
/^Received:/    IGNORE
+postfix-header-checks-content
/^Received:/    IGNORE
 /^User-Agent:/  IGNORE
 
@@ -2135,7 +2001,7 @@ Debian default for inet_interfaces.

-postfix-front
- { p: smtpd_tls_cert_file, v: /etc/server.crt }
+postfix-front
- { p: smtpd_tls_cert_file, v: /etc/server.crt }
 - { p: smtpd_tls_key_file, v: /etc/server.key }
 <<postfix-front-networks>>
 <<postfix-front-restrictions>>
@@ -2204,8 +2070,8 @@ start and enable the service.
 
-
-

7.11. Configure Public Email Aliases

+
+

7.11. Configure Public Email Aliases

The institute's Front needs to deliver email addressed to a number of @@ -2229,7 +2095,7 @@ created by a more specialized role. abuse: root webmaster: root admin: root - monkey: monkey@{{ front_private_addr }} + monkey: monkey@{{ front_wg_addr }} root: {{ ansible_user }} path: /etc/aliases marker: "# {mark} INSTITUTE MANAGED BLOCK" @@ -2246,8 +2112,8 @@ created by a more specialized role.

-
-

7.12. Configure Dovecot IMAPd

+
+

7.12. Configure Dovecot IMAPd

Front uses Dovecot's IMAPd to allow user Fetchmail jobs on Core to @@ -2256,7 +2122,7 @@ default with POP and IMAP (without TLS) support disabled. This is a bit "over the top" given that Core accesses Front via VPN, but helps to ensure privacy even when members must, in extremis, access recent email directly from their accounts on Front. For more information -about Front's role in the institute's email services, see The Email +about Front's role in the institute's email services, see The Email Service.

@@ -2312,8 +2178,8 @@ and enables it to start at every reboot.
-
-

7.13. Configure Apache2

+
+

7.13. Configure Apache2

This is the small institute's public web site. It is simple, static, @@ -2349,7 +2215,7 @@ taken from https://www

-apache-ciphers
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
+apache-ciphers
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
 SSLHonorCipherOrder on
 SSLCipherSuite {{ [ 'ECDHE-ECDSA-AES128-GCM-SHA256',
                     'ECDHE-ECDSA-AES256-GCM-SHA384',
@@ -2404,7 +2270,7 @@ used on all of the institute's web sites.
 

-apache-userdir-front
UserDir /home/www-users
+apache-userdir-front
UserDir /home/www-users
 <Directory /home/www-users/>
         Require all granted
         AllowOverride None
@@ -2419,7 +2285,7 @@ HTTPS URLs.
 

-apache-redirect-front
<VirtualHost *:80>
+apache-redirect-front
<VirtualHost *:80>
         Redirect permanent / https://{{ domain_name }}/
 </VirtualHost>
 
@@ -2444,7 +2310,7 @@ the inside of a VirtualHost block. They should apply globally.

-apache-front
ServerName {{ domain_name }}
+apache-front
ServerName {{ domain_name }}
 ServerAdmin webmaster@{{ domain_name }}
 
 DocumentRoot /home/www
@@ -2603,147 +2469,96 @@ the users' ~/Public/HTML/ directories.
 
-
-

7.14. Configure OpenVPN

+
+

7.14. Configure Public WireGuard™ Subnet

-Front uses OpenVPN to provide the institute's public VPN service. The -configuration is straightforward with one complication. OpenVPN needs -to know how to route to the campus VPN, which is only accessible when -Core is connected. OpenVPN supports these dynamic routes internally -with client-specific configuration files. The small institute uses -one of these, /etc/openvpn/ccd/core, so that OpenVPN will know to -route packets for the campus networks to Core. +Front uses WireGuard™ to provide a public (Internet accessible) VPN +service. Core has an interface on this VPN and is expected to forward +packets between it and the institute's other private networks.

-
-openvpn-ccd-core
iroute {{ private_net_and_mask }}
-iroute {{ campus_vpn_net_and_mask }}
-
-
-

-The VPN clients are not configured to route all of their traffic -through the VPN, so Front pushes routes to the other institute -networks. The clients thus know to route traffic for the private -Ethernet or campus VPN to Front on the public VPN. (If the clients -were configured to route all traffic through the VPN, the one -default route is all that would be needed.) Front itself is in the -same situation, outside the institute networks with a default route -through some ISP, and thus needs the same routes as the clients. +The following example private/front-wg0.conf configuration recognizes +Core by its public key and routes the institute's private networks to +it. It also recognizes Dick's notebook and his (replacement) phone, +assigning them host numbers 4 and 6 on the VPN.

-openvpn-front-routes
route {{ private_net_and_mask }}
-route {{ campus_vpn_net_and_mask }}
-push "route {{ private_net_and_mask }}"
-push "route {{ campus_vpn_net_and_mask }}"
+private/front-wg0.conf
[Interface]
+Address = 10.177.87.1/24
+ListenPort = 39608
+PostUp = wg set %i private-key /etc/wireguard/private-key
+PostUp = resolvectl dns %i 192.168.56.1
+PostUp = resolvectl domain %i small.private
+
+# Core
+[Peer]
+PublicKey = lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c=
+AllowedIPs = 10.177.87.2
+AllowedIPs = 192.168.56.0/24
+AllowedIPs = 10.84.139.0/24
+
+# dick
+[Peer]
+PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8=
+AllowedIPs = 10.177.87.4
+
+# dicks-razr
+[Peer]
+PublicKey = zho0qMxoLclJSQu4GeJEcMkk0hx4Q047OcNc8vOejVw=
+AllowedIPs = 10.177.87.6
 

-The complete OpenVPN configuration for Front includes a server -option, the client-config-dir option, the routes mentioned above, -and the common options discussed in The VPN Service. +The configuration used on Dick's notebook when it is abroad looks like +this:

-openvpn-front
server {{ public_vpn_net_and_mask }}
-client-config-dir /etc/openvpn/ccd
-<<openvpn-front-routes>>
-<<openvpn-dev-mode>>
-<<openvpn-keepalive>>
-<<openvpn-dns>>
-<<openvpn-drop-priv>>
-<<openvpn-crypt>>
-<<openvpn-max>>
-<<openvpn-debug>>
-ca /usr/local/share/ca-certificates/{{ domain_name }}.crt
-cert server.crt
-key server.key
-dh dh2048.pem
-tls-crypt shared.key
+WireGuard™ tunnel on Dick's notebook, used abroad
[Interface]
+Address = 10.177.87.3
+PostUp = wg set %i private-key /etc/wireguard/private-key
+PostUp = resolvectl dns %i 192.168.56.1
+PostUp = resolvectl domain %i 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.139.0/24
 

-Finally, here are the tasks (and handler) required to install and -configure the OpenVPN server on Front. +The following tasks install WireGuard™, configure it with +private/front-wg0.conf, and enable the service.

roles_t/front/tasks/main.yml

-- name: Install OpenVPN.
-  become: yes
-  apt: pkg=openvpn
-
-- name: Enable IP forwarding.
-  become: yes
-  sysctl:
-    name: net.ipv4.ip_forward
-    value: "1"
-    state: present
-
-- name: Create OpenVPN client configuration directory.
-  become: yes
-  file:
-    path: /etc/openvpn/ccd
-    state: directory
-  notify: Restart OpenVPN.
-
-- name: Install OpenVPN client configuration for Core.
-  become: yes
-  copy:
-    content: |
-      <<openvpn-ccd-core>>
-    dest: /etc/openvpn/ccd/core
-  notify: Restart OpenVPN.
-
-- name: Disable former VPN clients.
+- name: Install WireGuard™.
   become: yes
-  copy:
-    content: "disable\n"
-    dest: /etc/openvpn/ccd/{{ item }}
-  loop: "{{ revoked }}"
-  tags: accounts
+  apt: pkg=wireguard
 
-- name: Install OpenVPN server certificate/key.
+- name: Configure WireGuard™.
   become: yes
   copy:
-    src: ../Secret/CA/pki/{{ item.path }}.{{ item.typ }}
-    dest: /etc/openvpn/server.{{ item.typ }}
-    mode: "{{ item.mode }}"
-  loop:
-  - { path: "issued/{{ domain_name }}", typ: crt,
-      mode: "u=r,g=r,o=r" }
-  - { path: "private/{{ domain_name }}", typ: key,
-      mode: "u=r,g=,o=" }
-  notify: Restart OpenVPN.
-
-- name: Install OpenVPN secrets.
-  become: yes
-  copy:
-    src: ../Secret/{{ item.src }}
-    dest: /etc/openvpn/{{ item.dest }}
+    src: ../private/front-wg0.conf
+    dest: /etc/wireguard/wg0.conf
     mode: u=r,g=,o=
-  loop:
-  - { src: front-dh2048.pem, dest: dh2048.pem }
-  - { src: front-shared.key, dest: shared.key }
-  notify: Restart OpenVPN.
-
-- name: Configure OpenVPN.
-  become: yes
-  copy:
-    content: |
-      <<openvpn-front>>
-    dest: /etc/openvpn/server.conf
-    mode: u=r,g=r,o=
-  notify: Restart OpenVPN.
+    owner: root
+    group: root
+  notify: Restart WireGuard™.
 
-- name: Enable/Start OpenVPN.
+- name: Enable/Start WireGuard™ on boot.
   become: yes
   systemd:
-    service: openvpn@server
+    service: wg-quick@wg0
     enabled: yes
     state: started
 
@@ -2751,17 +2566,17 @@ configure the OpenVPN server on Front.
roles_t/front/handlers/main.yml

-- name: Restart OpenVPN.
+- name: Restart WireGuard™.
   become: yes
   systemd:
-    service: openvpn@server
+    service: wg-quick@wg0
     state: restarted
 
-
-

7.15. Configure Kamailio

+
+

7.15. Configure Kamailio

Front uses Kamailio to provide a SIP service on the public VPN so that @@ -2779,11 +2594,11 @@ the public VPN. To enforce this expectation, Kamailio is instructed to listen only on Front's public VPN. The private name sip.small.private resolves to this address for the convenience of members configuring SIP clients. The server configuration -specifies the actual IP, known here as front_private_addr. +specifies the actual IP, known here as front_wg_addr.

-kamailio
listen=udp:{{ front_private_addr }}:5060
+kamailio
listen=udp:{{ front_wg_addr }}:5060
 
@@ -2808,9 +2623,9 @@ The first step is to install Kamailio.

Now the configuration drop concerns the network device on which -Kamailio will be listening, the tun device created by OpenVPN. The -added configuration settings inform Systemd that Kamailio should not -be started before the tun device has appeared. +Kamailio will be listening, the wg0 device created by WireGuard™. +The added configuration settings inform Systemd that Kamailio should +not be started before the wg0 device has appeared.

@@ -2821,13 +2636,13 @@ be started before the tun device has appeared. path: /etc/systemd/system/kamailio.service.d state: directory -- name: Create Kamailio dependence on OpenVPN server. +- name: Create Kamailio dependence on WireGuard™ interface. become: yes copy: content: | [Unit] - Requires=sys-devices-virtual-net-ovpn.device - After=sys-devices-virtual-net-ovpn.device + Requires=sys-devices-virtual-net-wg0.device + After=sys-devices-virtual-net-wg0.device dest: /etc/systemd/system/kamailio.service.d/depend.conf notify: Reload Systemd.
@@ -2877,22 +2692,22 @@ Finally, Kamailio can be configured and started.
-
-

8. The Core Role

+
+

8. The Core Role

The core role configures many essential campus network services as well as the institute's private cloud, so the core machine has horsepower (CPUs and RAM) and large disks and is prepared with a Debian install and remote access to a privileged, administrator's -account. (For details, see The Core Machine.) +account. (For details, see The Core Machine.)

-
-

8.1. Include Particulars

+
+

8.1. Include Particulars

-The first task, as in The Front Role, is to include the institute +The first task, as in The Front Role, is to include the institute particulars and membership roll.

@@ -2911,8 +2726,8 @@ particulars and membership roll.
-
-

8.2. Configure Hostname

+
+

8.2. Configure Hostname

This task ensures that Core's /etc/hostname and /etc/mailname are @@ -2945,8 +2760,8 @@ proper email delivery.

-
-

8.3. Configure Systemd Resolved

+
+

8.3. Configure Systemd Resolved

Core runs the campus name server, so Resolved is configured to use it @@ -2990,17 +2805,15 @@ list, and to disable its cache and stub listener.

-
-

8.4. Configure Netplan

+
+

8.4. Configure Netplan

Core's network interface is statically configured using Netplan and an /etc/netplan/60-core.yaml file. That file provides Core's address on the private Ethernet, the campus name server and search domain, and the default route through Gate to the campus ISP. A second route, -through Core itself to Front, is advertised to other hosts, but is not -created here. It is created by OpenVPN when Core connects to Front's -VPN. +through Core itself to Front, is advertised to other hosts.

@@ -3050,8 +2863,8 @@ fact was an empty hash at first boot on a simulated campus Ethernet.)

-
-

8.5. Configure DHCP For the Private Ethernet

+
+

8.5. Configure DHCP For the Private Ethernet

Core speaks DHCP (Dynamic Host Configuration Protocol) using the @@ -3091,7 +2904,8 @@ log-facility daemon; 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,87, 192,168,56,1, + 0, 192,168,56,2; } host core { @@ -3149,12 +2963,12 @@ the real private/core-dhcpd.conf (<

-
-

8.6. Configure BIND9

+
+

8.6. Configure BIND9

Core uses BIND9 to provide name service for the institute as described -in The Name Service. The configuration supports reverse name lookups, +in The Name Service. The configuration supports reverse name lookups, resolving many private network addresses to private domain names.

@@ -3219,11 +3033,11 @@ probably be used as forwarders rather than Google.

-bind-options
acl "trusted" {
+bind-options
acl "trusted" {
         {{ private_net_cidr }};
         {{ wild_net_cidr }};
-        {{ public_vpn_net_cidr }};
-        {{ campus_vpn_net_cidr }};
+        {{ public_wg_net_cidr }};
+        {{ campus_wg_net_cidr }};
         localhost;
 };
 
@@ -3248,7 +3062,7 @@ probably be used as forwarders rather than Google.
 
-bind-local
include "/etc/bind/zones.rfc1918";
+bind-local
include "/etc/bind/zones.rfc1918";
 
 zone "{{ domain_priv }}." {
         type master;
@@ -3261,13 +3075,13 @@ probably be used as forwarders rather than Google.
         file "/etc/bind/db.private";
 };
 
-zone "{{ public_vpn_net_cidr | ansible.utils.ipaddr('revdns')
+zone "{{ public_wg_net_cidr | ansible.utils.ipaddr('revdns')
          | regex_replace('^0\.','') }}" {
         type master;
         file "/etc/bind/db.public_vpn";
 };
 
-zone "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('revdns')
+zone "{{ campus_wg_net_cidr | ansible.utils.ipaddr('revdns')
          | regex_replace('^0\.','') }}" {
         type master;
         file "/etc/bind/db.campus_vpn";
@@ -3296,7 +3110,7 @@ probably be used as forwarders rather than Google.
 test    IN      CNAME   core.small.private.
 live    IN      CNAME   core.small.private.
 ntp     IN      CNAME   core.small.private.
-sip     IN      A       10.177.86.1
+sip     IN      A       10.177.87.1
 ;
 core    IN      A       192.168.56.1
 gate    IN      A       192.168.56.2
@@ -3360,8 +3174,8 @@ probably be used as forwarders rather than Google.
 
-
-

8.7. Add Administrator to System Groups

+
+

8.7. Add Administrator to System Groups

The administrator often needs to read (directories of) log files owned @@ -3381,15 +3195,15 @@ these groups speeds up debugging.

-
-

8.8. Configure Monkey

+
+

8.8. Configure Monkey

The small institute runs cron jobs and web scripts that generate reports and perform checks. The un-privileged jobs are run by a system account named monkey. One of Monkey's more important jobs on Core is to run rsync to update the public web site on Front (as -described in *Configure Apache2). +described in *Configure Apache2).

@@ -3449,8 +3263,8 @@ described in *Configure Apache2).
-
-

8.9. Install Unattended Upgrades

+
+

8.9. Install Unattended Upgrades

The institute prefers to install security updates as soon as possible. @@ -3465,11 +3279,11 @@ The institute prefers to install security updates as soon as possible.

-
-

8.10. Install Expect

+
+

8.10. Install Expect

-The expect program is used by The Institute Commands to interact +The expect program is used by The Institute Commands to interact with Nextcloud on the command line.

@@ -3482,12 +3296,12 @@ with Nextcloud on the command line.
-
-

8.11. Configure User Accounts

+
+

8.11. Configure User Accounts

User accounts are created immediately so that backups can begin -restoring as soon as possible. The Account Management chapter +restoring as soon as possible. The Account Management chapter describes the members and usernames variables.

@@ -3525,8 +3339,8 @@ describes the members and usernames variables.
-
-

8.12. Install Server Certificate

+
+

8.12. Install Server Certificate

The servers on Core use the same certificate (and key) to authenticate @@ -3550,13 +3364,12 @@ themselves to institute clients. They share the /etc/server.crt and notify: - Restart Postfix. - Restart Dovecot. - - Restart OpenVPN.

-
-

8.13. Install NTP

+
+

8.13. Install NTP

Core uses NTP to provide a time synchronization service to the campus. @@ -3572,8 +3385,8 @@ The default daemon's default configuration is fine.

-
-

8.14. Configure Postfix on Core

+
+

8.14. Configure Postfix on Core

Core uses Postfix to provide SMTP service to the campus. The default @@ -3589,7 +3402,7 @@ The appropriate answers are listed here but will be checked

-As discussed in The Email Service above, Core delivers email addressed +As discussed in The Email Service above, Core delivers email addressed to any internal domain name locally, and uses its smarthost Front to relay the rest. Core is reachable only on institute networks, so there is little benefit in enabling TLS, but it does need to handle @@ -3602,11 +3415,11 @@ Core relays messages from any institute network.

-postfix-core-networks
- p: mynetworks
+postfix-core-networks
- p: mynetworks
   v: >-
      {{ private_net_cidr }}
-     {{ public_vpn_net_cidr }}
-     {{ campus_vpn_net_cidr }}
+     {{ public_wg_net_cidr }}
+     {{ campus_wg_net_cidr }}
      127.0.0.0/8
      [::ffff:127.0.0.0]/104
      [::1]/128
@@ -3618,7 +3431,7 @@ Core uses Front to relay messages to the Internet.
 

-postfix-core-relayhost
- { p: relayhost, v: "[{{ front_private_addr }}]" }
+postfix-core-relayhost
- { p: relayhost, v: "[{{ front_wg_addr }}]" }
 
@@ -3630,7 +3443,7 @@ file.

-postfix-transport
.{{ domain_name }}      local:$myhostname
+postfix-transport
.{{ domain_name }}      local:$myhostname
 .{{ domain_priv }}      local:$myhostname
 
@@ -3641,7 +3454,7 @@ The complete list of Core's Postfix settings for

-postfix-core
<<postfix-relaying>>
+postfix-core
<<postfix-relaying>>
 - { p: smtpd_tls_security_level, v: none }
 - { p: smtp_tls_security_level, v: none }
 <<postfix-message-size>>
@@ -3712,12 +3525,12 @@ enable the service.  Whenever /etc/postfix/transport is changed, the
 
-
-

8.15. Configure Private Email Aliases

+
+

8.15. Configure Private Email Aliases

The institute's Core needs to deliver email addressed to institute -aliases including those advertised on the campus web site, in VPN +aliases including those advertised on the campus web site, in X.509 certificates, etc. System daemons like cron(8) may also send email to e.g. monkey. The following aliases are installed in /etc/aliases with a special marker so that additional blocks can be @@ -3750,8 +3563,8 @@ installed by more specialized roles.

-
-

8.16. Configure Dovecot IMAPd

+
+

8.16. Configure Dovecot IMAPd

Core uses Dovecot's IMAPd to store and serve member emails. As on @@ -3761,7 +3574,7 @@ top" given that Core is only accessed from private (encrypted) networks, but helps to ensure privacy even when members accidentally attempt connections from outside the private networks. For more information about Core's role in the institute's email services, see -The Email Service. +The Email Service.

@@ -3769,7 +3582,7 @@ The institute follows the recommendation in the package README.Debian (in /usr/share/dovecot-core/) but replaces the default "snake oil" certificate with another, signed by the institute. (For more information about the institute's X.509 certificates, see -Keys.) +Keys.)

@@ -3815,8 +3628,8 @@ and enables it to start at every reboot.

-
-

8.17. Configure Fetchmail

+
+

8.17. Configure Fetchmail

Core runs a fetchmail for each member of the institute. Individual @@ -3833,14 +3646,14 @@ the username. The template is only used when the record has a

-fetchmail-config
# Permissions on this file may be no greater than 0600.
+fetchmail-config
# Permissions on this file may be no greater than 0600.
 
 set no bouncemail
 set no spambounce
 set no syslog
 #set logfile /home/{{ item }}/.fetchmail.log
 
-poll {{ front_private_addr }} protocol imap timeout 15
+poll {{ front_wg_addr }} protocol imap timeout 15
     username {{ item }}
     password "{{ members[item].password_fetchmail }}" fetchall
     ssl sslproto tls1.2+ sslcertck sslcommonname {{ domain_name }}
@@ -3852,11 +3665,11 @@ The Systemd service description.
 

-fetchmail-service
[Unit]
+fetchmail-service
[Unit]
 Description=Fetchmail --idle task for {{ item }}.
 AssertPathExists=/home/{{ item }}/.fetchmailrc
-After=openvpn@front.service
-Wants=sys-devices-virtual-net-ovpn.device
+After=wg-quick@wg0.service
+Wants=sys-devices-virtual-net-wg0.device
 
 [Service]
 User={{ item }}
@@ -3969,12 +3782,12 @@ Otherwise the following task might be appropriate.
 
-
-

8.18. Configure Apache2

+
+

8.18. Configure Apache2

This is the small institute's campus web server. It hosts several web -sites as described in The Web Services. +sites as described in The Web Services.

@@ -4045,7 +3858,7 @@ naming a sub-directory in the member's home directory on Core. The

-apache-userdir-core
UserDir Public/HTML
+apache-userdir-core
UserDir Public/HTML
 <Directory /home/*/Public/HTML/>
         Require all granted
         AllowOverride None
@@ -4060,7 +3873,7 @@ redirect, the encryption ciphers and certificates.
 

-apache-live
<VirtualHost *:80>
+apache-live
<VirtualHost *:80>
         ServerName live
         ServerAlias live.{{ domain_priv }}
         ServerAdmin webmaster@core.{{ domain_priv }}
@@ -4087,7 +3900,7 @@ familiar.
 

-apache-test
<VirtualHost *:80>
+apache-test
<VirtualHost *:80>
         ServerName test
         ServerAlias test.{{ domain_priv }}
         ServerAdmin webmaster@core.{{ domain_priv }}
@@ -4116,7 +3929,7 @@ trained staffers, monitored by a revision control system, etc.
 

-apache-campus
<VirtualHost *:80>
+apache-campus
<VirtualHost *:80>
         ServerName www
         ServerAlias www.{{ domain_priv }}
         ServerAdmin webmaster@core.{{ domain_priv }}
@@ -4233,8 +4046,8 @@ The a2ensite command enables them.
 
-
-

8.19. Configure Website Updates

+
+

8.19. Configure Website Updates

Monkey on Core runs /usr/local/sbin/webupdate every 15 minutes via a @@ -4243,7 +4056,7 @@ Monkey on Core runs /usr/local/sbin/webupdate every 15 minutes via a

-private/webupdate
#!/bin/bash -e
+private/webupdate
#!/bin/bash -e
 #
 # DO NOT EDIT.  This file was tangled from institute.org.
 
@@ -4259,7 +4072,7 @@ rsync -avz --delete --chmod=g-w         \
 The following tasks install the webupdate script from private/,
 and create Monkey's cron job.  An example webupdate script is
-provided here.
+provided here.
 

@@ -4284,109 +4097,79 @@ provided here.
-
-

8.20. Configure OpenVPN Connection to Front

+
+

8.20. Configure Core WireGuard™ Interface

-Core connects to Front's public VPN to provide members abroad with a -route to the campus networks. As described in the configuration of -Front's OpenVPN service, Front expects Core to connect using a client -certificate with Common Name Core. +Core connects to Front's WireGuard™ service to provide members abroad +with a route to the campus networks. As described in Configure Public +WireGuard™ Subnet for Front, Core is expected to forward packets from/to the +private networks.

-Core's OpenVPN client configuration uses the Debian default Systemd -service unit to keep Core connected to Front. The configuration -is installed in /etc/openvpn/front.conf so the Systemd service is -called openvpn@front. +The following example private/core-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.

-openvpn-core
client
-dev-type tun
-dev ovpn
-remote {{ front_addr }}
-nobind
-<<openvpn-drop-priv>>
-<<openvpn-crypt>>
-remote-cert-tls server
-verify-x509-name {{ domain_name }} name
-verb 3
-ca /usr/local/share/ca-certificates/{{ domain_name }}.crt
-cert client.crt
-key client.key
-tls-crypt shared.key
+private/core-wg0.conf
[Interface]
+Address = 10.177.87.2
+PostUp = wg set %i private-key /etc/wireguard/private-key
+
+# Front
+[Peer]
+EndPoint = 192.168.15.5:39608
+PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4=
+AllowedIPs = 10.177.87.1
+AllowedIPs = 10.177.87.0/24
 

-The tasks that install and configure the OpenVPN client configuration -for Core. +The following tasks install WireGuard™, configure it with +private/core-wg0.conf, and enable the service.

roles_t/core/tasks/main.yml

-- name: Install OpenVPN.
-  become: yes
-  apt: pkg=openvpn
-
-- name: Enable IP forwarding.
+- name: Install WireGuard™.
   become: yes
-  sysctl:
-    name: net.ipv4.ip_forward
-    value: "1"
-    state: present
+  apt: pkg=wireguard
 
-- name: Install OpenVPN secret.
+- name: Configure WireGuard™.
   become: yes
   copy:
-    src: ../Secret/front-shared.key
-    dest: /etc/openvpn/shared.key
+    src: ../private/core-wg0.conf
+    dest: /etc/wireguard/wg0.conf
     mode: u=r,g=,o=
-  notify: Restart OpenVPN.
-
-- name: Install OpenVPN client certificate/key.
-  become: yes
-  copy:
-    src: ../Secret/CA/pki/{{ item.path }}.{{ item.typ }}
-    dest: /etc/openvpn/client.{{ item.typ }}
-    mode: "{{ item.mode }}"
-  loop:
-  - { path: "issued/core", typ: crt, mode: "u=r,g=r,o=r" }
-  - { path: "private/core", typ: key, mode: "u=r,g=,o=" }
-  notify: Restart OpenVPN.
-
-- name: Configure OpenVPN.
-  become: yes
-  copy:
-    content: |
-      <<openvpn-core>>
-    dest: /etc/openvpn/front.conf
-    mode: u=r,g=r,o=
-  notify: Restart OpenVPN.
+    owner: root
+    group: root
+  notify: Restart WireGuard™.
 
-- name: Enable/Start OpenVPN.
+- name: Enable/Start WireGuard™ on boot.
   become: yes
   systemd:
-    service: openvpn@front
-    state: started
+    service: wg-quick@wg0
     enabled: yes
+    state: started
 
roles_t/core/handlers/main.yml

-- name: Restart OpenVPN.
+- name: Restart WireGuard™.
   become: yes
   systemd:
-    service: openvpn@front
+    service: wg-quick@wg0
     state: restarted
 
-
-

8.21. Configure NAGIOS

+
+

8.21. Configure NAGIOS

Core runs a nagios4 server to monitor "services" on institute hosts. @@ -4429,7 +4212,8 @@ Core and Campus (and thus Gate) machines. backrefs: yes loop: - { regexp: "^( *cfg_file *= *localhost.cfg)", line: "# \\1" } - - { regexp: "^( *admin_email *= *)", line: "\\1{{ ansible_user }}@localhost" } + - { regexp: "^( *admin_email *= *)", + line: "\\1{{ ansible_user }}@localhost" } notify: Reload NAGIOS4. - name: Configure NAGIOS4 contacts. @@ -4467,8 +4251,8 @@ Core and Campus (and thus Gate) machines.

-
-

8.21.1. Configure NAGIOS Monitors for Core

+
+

8.21.1. Configure NAGIOS Monitors for Core

The first block in nagios.cfg specifies monitors for services on @@ -4543,8 +4327,8 @@ used here may specify plugin arguments.

-
-

8.21.2. Custom NAGIOS Monitor inst_sensors

+
+

8.21.2. Custom NAGIOS Monitor inst_sensors

The check_sensors plugin is included in the package @@ -4572,7 +4356,8 @@ small institute substitutes a slightly modified version, echo "" print_usage echo "" - echo "This plugin checks hardware status using the lm_sensors package." + echo -n "This plugin checks hardware status" + echo " using the lm_sensors package." echo "" support exit $STATE_OK @@ -4655,8 +4440,8 @@ Core.

-
-

8.21.3. Configure NAGIOS Monitors for Remote Hosts

+
+

8.21.3. Configure NAGIOS Monitors for Remote Hosts

The following sections contain code blocks specifying monitors for @@ -4673,12 +4458,12 @@ plugin with pre-defined arguments appropriate for the institute. The commands are defined in code blocks interleaved with the blocks that monitor them. The command blocks are appended to nrpe.cfg and the monitoring blocks to nagios.cfg. The nrpe.cfg file is installed -on each campus host by the campus role's Configure NRPE tasks. +on each campus host by the campus role's Configure NRPE tasks.

-
-

8.21.4. Configure NAGIOS Monitors for Gate

+
+

8.21.4. Configure NAGIOS Monitors for Gate

Define the monitored host, gate. Monitor its response to network @@ -4809,12 +4594,12 @@ Monitor inst_sensors on Gate.

-
-

8.22. Configure Backups

+
+

8.22. Configure Backups

The following task installs the backup script from private/. An -example script is provided in here. +example script is provided in here.

@@ -4829,20 +4614,20 @@ example script is provided in here.
-
-

8.23. Configure Nextcloud

+
+

8.23. Configure Nextcloud

Core runs Nextcloud to provide a private institute cloud, as described -in The Cloud Service. Installing, restoring (from backup), and +in The Cloud Service. Installing, restoring (from backup), and upgrading Nextcloud are manual processes documented in The Nextcloud Admin Manual, Maintenance. However Ansible can help prepare Core before an install or restore, and perform basic security checks afterwards.

-
-

8.23.1. Prepare Core For Nextcloud

+
+

8.23.1. Prepare Core For Nextcloud

The Ansible code contained herein prepares Core to run Nextcloud by @@ -5036,7 +4821,7 @@ created manually. The following task would work (mysql_user supports check_implicit_admin) but the nextcloud database was not created above. Thus both database and user are created manually, with SQL -given in the 8.23.5 subsection below, before occ +given in the 8.23.5 subsection below, before occ maintenance:install can run.

@@ -5074,8 +4859,8 @@ its document root.
-
-

8.23.2. Configure PHP

+
+

8.23.2. Configure PHP

The following tasks set a number of PHP parameters for better @@ -5118,8 +4903,8 @@ performance, as recommended by Nextcloud.

-
-

8.23.3. Create /Nextcloud/

+
+

8.23.3. Create /Nextcloud/

The Ansible tasks up to this point have completed Core's LAMP stack @@ -5177,8 +4962,8 @@ sudo mount /Nextcloud

-
-

8.23.4. Restore Nextcloud

+
+

8.23.4. Restore Nextcloud

Restoring Nextcloud in the newly created /Nextcloud/ presumably @@ -5211,7 +4996,7 @@ The database is restored with the following commands, which assume the last dump was made February 20th 2022 and thus was saved in /Nextcloud/20220220.bak. The database will need to be created first as when installing Nextcloud. The appropriate SQL are -given in Install Nextcloud below. +given in Install Nextcloud below.

@@ -5229,8 +5014,8 @@ Overview web page.

-
-

8.23.5. Install Nextcloud

+
+

8.23.5. Install Nextcloud

Installing Nextcloud in the newly created /Nextcloud/ starts with @@ -5300,8 +5085,8 @@ Administration > Overview page.

-
-

8.23.6. Afterwards

+
+

8.23.6. Afterwards

Whether Nextcloud was restored or installed, there are a few things @@ -5483,14 +5268,14 @@ run before the next backup.

-
-

9. The Gate Role

+
+

9. The Gate Role

The gate role configures the services expected at the campus gate: access to the private Ethernet from the untrusted Ethernet (e.g. a campus Wi-Fi AP) via VPN, and access to the Internet via NAT. The -gate machine uses three network interfaces (see The Gate Machine) +gate machine uses three network interfaces (see The Gate Machine) configured with persistent names used in its firewall rules.

@@ -5512,8 +5297,8 @@ applied first, by which Gate gets a campus machine's DNS and Postfix configurations, etc.

-
-

9.1. Include Particulars

+
+

9.1. Include Particulars

The following should be familiar boilerplate by now. @@ -5534,8 +5319,8 @@ The following should be familiar boilerplate by now.

-
-

9.2. Configure Netplan

+
+

9.2. Configure Netplan

Gate's network interfaces are configured using Netplan and two files. @@ -5584,7 +5369,7 @@ new network plan. addresses: [ {{ core_addr }} ] search: [ {{ domain_priv }} ] routes: - - to: {{ public_vpn_net_cidr }} + - to: {{ public_wg_net_cidr }} via: {{ core_addr }} wild: match: @@ -5631,8 +5416,8 @@ campus ISP without interference from Ansible.

-
-

9.3. UFW Rules

+
+

9.3. UFW Rules

Gate uses the Uncomplicated FireWall (UFW) to install its packet @@ -5642,8 +5427,8 @@ expect to be able to exercise experimental services on random ports. The default policy settings in /etc/default/ufw are ACCEPT and ACCEPT for input and output, and DROP for forwarded packets. Forwarding was enabled in the kernel previously (when configuring -OpenVPN) using Ansible's sysctl module. It does not need to be set -in /etc/ufw/sysctl.conf. +WireGuard™) using Ansible's sysctl module. It does not need to be +set in /etc/ufw/sysctl.conf.

@@ -5656,7 +5441,7 @@ should not be routing their Internet traffic through their VPN.

-ufw-nat
-A POSTROUTING -s {{ private_net_cidr }} -o isp -j MASQUERADE
+ufw-nat
-A POSTROUTING -s {{ private_net_cidr }} -o isp -j MASQUERADE
 -A POSTROUTING -s {{    wild_net_cidr }} -o isp -j MASQUERADE
 
@@ -5671,7 +5456,7 @@ packet).

-ufw-forward-nat
-A FORWARD -i lan  -o isp  -j ACCEPT
+ufw-forward-nat
-A FORWARD -i lan  -o isp  -j ACCEPT
 -A FORWARD -i wild -o isp  -j ACCEPT
 -A FORWARD -i isp  -o lan  {{ ACCEPT_RELATED }}
 -A FORWARD -i isp  -o wild {{ ACCEPT_RELATED }}
@@ -5696,26 +5481,26 @@ 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 +(the wg0 WireGuard™ 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.

-ufw-forward-private
-A FORWARD -i lan  -o ovpn -j ACCEPT
--A FORWARD -i ovpn -o lan  -j ACCEPT
+ufw-forward-private
-A FORWARD -i lan  -o wg0  -j ACCEPT
+-A FORWARD -i wg0  -o lan  -j ACCEPT
 

Note that there are no forwarding rules to allow packets to pass from -the wild device to the lan device, just the ovpn device. +the wild device to the lan device, just the wg0 device.

-
-

9.4. Install UFW

+
+

9.4. Install UFW

The following tasks install the Uncomplicated Firewall (UFW), set its @@ -5775,8 +5560,8 @@ sudo ufw enable

-
-

9.5. Configure DHCP For The Wild Ethernet

+
+

9.5. Configure DHCP For The Wild Ethernet

To accommodate commodity Wi-Fi access points, as well as wired IoT @@ -5902,146 +5687,132 @@ command would not be necessary.

-
-

9.6. Install Server Certificate

+
+

9.6. Configure Campus WireGuard™ Subnet

-The (OpenVPN) server on Gate uses an institute certificate (and key) -to authenticate itself to its clients. It uses the /etc/server.crt -and /etc/server.key files just because the other servers (on Core -and Front) do. +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 private/gate-wg0.conf configuration recognizes +a wired IoT appliance, Dick's notebook and his replacement phone, +assigning them the host numbers 3, 4 and 6 respectively.

-roles_t/gate/tasks/main.yml

-- name: Install server certificate/key.
-  become: yes
-  copy:
-    src: ../Secret/CA/pki/{{ item.path }}.{{ item.typ }}
-    dest: /etc/server.{{ item.typ }}
-    mode: "{{ item.mode }}"
-  loop:
-  - { path: "issued/gate.{{ domain_priv }}", typ: crt,
-      mode: "u=r,g=r,o=r" }
-  - { path: "private/gate.{{ domain_priv }}", typ: key,
-      mode: "u=r,g=,o=" }
-  notify: Restart OpenVPN.
+private/gate-wg0.conf
[Interface]
+Address = 10.84.139.1/24
+ListenPort = 51820
+PostUp = wg set %i private-key /etc/wireguard/private-key
+
+# thing
+[Peer]
+PublicKey = LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ=
+AllowedIPs = 10.84.139.3
+
+# dick
+[Peer]
+PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8=
+AllowedIPs = 10.84.139.4
+
+# dicks-razr
+[Peer]
+PublicKey = zho0qMxoLclJSQu4GeJEcMkk0hx4Q047OcNc8vOejVw=
+AllowedIPs = 10.84.139.6
 
-
-
-
-

9.7. Configure OpenVPN

-
+

-Gate uses OpenVPN to provide the institute's campus VPN service. Its -clients are not configured to route all of their traffic through -the VPN, so Gate pushes routes to the other institute networks. Gate -itself is on the private Ethernet and thereby learns about the route -to Front. +The configuration used on thing, the IoT appliance, looks like this:

-openvpn-gate-routes
push "route {{ private_net_and_mask }}"
-push "route {{ public_vpn_net_and_mask }}"
+WireGuard™ tunnel on an IoT appliance
[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.87.0/24
 

-The complete OpenVPN configuration for Gate includes a server -option, the pushed routes mentioned above, and the common options -discussed in The VPN Services. +And the configuration used on Dick's notebook when it is on campus +looks like this:

-openvpn-gate
server {{ campus_vpn_net_and_mask }}
-client-config-dir /etc/openvpn/ccd
-<<openvpn-gate-routes>>
-<<openvpn-dev-mode>>
-<<openvpn-keepalive>>
-<<openvpn-dns>>
-<<openvpn-drop-priv>>
-<<openvpn-crypt>>
-<<openvpn-max>>
-<<openvpn-debug>>
-ca /usr/local/share/ca-certificates/{{ domain_name }}.crt
-cert /etc/server.crt
-key /etc/server.key
-dh dh2048.pem
-tls-crypt shared.key
+WireGuard™ tunnel on Dick's notebook, used on campus
[Interface]
+Address = 10.84.139.3
+PostUp = wg set %i private-key /etc/wireguard/private-key
+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.87.0/24
 

-Finally, here are the tasks (and handler) required to install and -configure the OpenVPN server on Gate. +The following tasks install WireGuard™, configure it with +private/gate-wg0.conf, and enable the service.

roles_t/gate/tasks/main.yml

-- name: Install OpenVPN.
-  become: yes
-  apt: pkg=openvpn
-
-- name: Enable IP forwarding.
+- name: Install WireGuard™.
   become: yes
-  sysctl:
-    name: net.ipv4.ip_forward
-    value: "1"
-    state: present
+  apt: pkg=wireguard
 
-- name: Create OpenVPN client configuration directory.
-  become: yes
-  file:
-    path: /etc/openvpn/ccd
-    state: directory
-  notify: Restart OpenVPN.
-
-- name: Disable former VPN clients.
-  become: yes
-  copy:
-    content: "disable\n"
-    dest: /etc/openvpn/ccd/{{ item }}
-  loop: "{{ revoked }}"
-  notify: Restart OpenVPN.
-  tags: accounts
-
-- name: Install OpenVPN secrets.
+- name: Configure WireGuard™.
   become: yes
   copy:
-    src: ../Secret/{{ item.src }}
-    dest: /etc/openvpn/{{ item.dest }}
+    src: ../private/gate-wg0.conf
+    dest: /etc/wireguard/wg0.conf
     mode: u=r,g=,o=
-  loop:
-  - { src: gate-dh2048.pem, dest: dh2048.pem }
-  - { src: gate-shared.key, dest: shared.key }
-  notify: Restart OpenVPN.
+    owner: root
+    group: root
+  notify: Restart WireGuard™.
 
-- name: Configure OpenVPN.
+- name: Enable/Start WireGuard™ on boot.
   become: yes
-  copy:
-    content: |
-      <<openvpn-gate>>
-    dest: /etc/openvpn/server.conf
-    mode: u=r,g=r,o=
-  notify: Restart OpenVPN.
+  systemd:
+    service: wg-quick@wg0
+    enabled: yes
+    state: started
 
roles_t/gate/handlers/main.yml

-- name: Restart OpenVPN.
+- name: Restart WireGuard™.
   become: yes
   systemd:
-    service: openvpn@server
+    service: wg-quick@wg0
     state: restarted
 
-
-

10. The Campus Role

+
+

10. The Campus Role

The campus role configures generic campus server machines: network @@ -6053,13 +5824,12 @@ system administrator's account on Core.

-Wireless campus devices can get a key to the campus VPN from the -./inst client campus command, but their OpenVPN client must be -configured manually. +Wireless campus devices register their public keys using the ./inst +client command which updates the WireGuard™ configuration on Gate.

-
-

10.1. Include Particulars

+
+

10.1. Include Particulars

The following should be familiar boilerplate by now. @@ -6075,8 +5845,8 @@ The following should be familiar boilerplate by now.

-
-

10.2. Configure Hostname

+
+

10.2. Configure Hostname

Clients should be using the expected host name. @@ -6103,52 +5873,10 @@ Clients should be using the expected host name.

-
-

10.3. Configure Systemd Resolved

+
+

10.3. Configure Systemd Timesyncd

-Campus machines use the campus name server on Core (or dns.google), -and include the institute's private domain in their search lists. -

- -
-roles_t/campus/tasks/main.yml

-- name: Configure resolved.
-  become: yes
-  lineinfile:
-    path: /etc/systemd/resolved.conf
-    regexp: "{{ item.regexp }}"
-    line: "{{ item.line }}"
-  loop:
-  - { regexp: '^ *DNS *=', line: "DNS={{ core_addr }}" }
-  - { regexp: '^ *FallbackDNS *=', line: "FallbackDNS=8.8.8.8" }
-  - { regexp: '^ *Domains *=', line: "Domains={{ domain_priv }}" }
-  notify:
-  - Reload Systemd.
-  - Restart Systemd resolved.
-
-
- -
-roles_t/campus/handlers/main.yml
---
-- name: Reload Systemd.
-  become: yes
-  systemd:
-    daemon-reload: yes
-
-- name: Restart Systemd resolved.
-  become: yes
-  systemd:
-    service: systemd-resolved
-    state: restarted
-
-
-
-
-
-

10.4. Configure Systemd Timesyncd

-
-

The institute uses a common time reference throughout the campus. This is essential to campus security, improving the accuracy of log and file timestamps. @@ -6166,7 +5894,7 @@ and file timestamps.

-roles_t/campus/handlers/main.yml

+roles_t/campus/handlers/main.yml
---
 - name: Restart systemd-timesyncd.
   become: yes
   systemd:
@@ -6176,9 +5904,9 @@ and file timestamps.
 
-
-

10.5. Add Administrator to System Groups

-
+
+

10.4. Add Administrator to System Groups

+

The administrator often needs to read (directories of) log files owned by groups root and adm. Adding the administrator's account to @@ -6197,9 +5925,9 @@ these groups speeds up debugging.

-
-

10.6. Install Unattended Upgrades

-
+
+

10.5. Install Unattended Upgrades

+

The institute prefers to install security updates as soon as possible.

@@ -6213,9 +5941,9 @@ The institute prefers to install security updates as soon as possible.
-
-

10.7. Configure Postfix on Campus

-
+
+

10.6. Configure Postfix on Campus

+

The Postfix settings used by the campus include message size, queue times, and the relayhost Core. The default Debian configuration @@ -6275,9 +6003,9 @@ tasks below.

-
-

10.8. Set Domain Name

-
+
+

10.7. Set Domain Name

+

The host's fully qualified (private) domain name (FQDN) is set by an alias in its /etc/hosts file, as is customary on Debian. (See "The @@ -6299,13 +6027,13 @@ manpage.)

-
-

10.9. Configure NRPE

-
+
+

10.8. Configure NRPE

+

Each campus host runs an NRPE (a NAGIOS Remote Plugin Executor) server so that the NAGIOS4 server on Core can collect statistics. The -NAGIOS service is discussed in the Configure NRPE section of The Core +NAGIOS service is discussed in the Configure NRPE section of The Core Role.

@@ -6359,8 +6087,8 @@ Role.
-
-

11. The Ansible Configuration

+
+

11. The Ansible Configuration

The small institute uses Ansible to maintain the configuration of its @@ -6369,7 +6097,7 @@ runs playbook site.yml to apply the appro role(s) to each host. Examples of these files are included here, and are used to test the roles. The example configuration applies the institutional roles to VirtualBox machines prepared according to -chapter Testing. +chapter Testing.

@@ -6382,13 +6110,13 @@ while changes to the institute's particulars are committed to a separate revision history.

-
-

11.1. ansible.cfg

+
+

11.1. ansible.cfg

The Ansible configuration file ansible.cfg contains just a handful of settings, some included just to create a test jig as described in -Testing. +Testing.

    @@ -6397,7 +6125,7 @@ of settings, some included just to create a test jig as described in that Python 3 can be expected on all institute hosts.
  • vault_password_file is set to suppress prompts for the vault password. The institute keeps its vault password in Secret/ (as -described in Keys) and thus sets this parameter to +described in Keys) and thus sets this parameter to Secret/vault-password.
  • inventory is set to avoid specifying it on the command line.
  • roles_path is set to the recently tangled roles files in @@ -6414,8 +6142,8 @@ described in Keys) and thus sets this parameter to
-
-

11.2. hosts

+
+

11.2. hosts

The Ansible inventory file hosts describes all of the institute's @@ -6427,7 +6155,7 @@ describes three test servers named front, core and

-hosts
all:
+hosts
all:
   vars:
     ansible_user: sysadm
     ansible_ssh_extra_args: -i Secret/ssh_admin/id_rsa
@@ -6492,8 +6220,8 @@ the Secret/vault-password file.
 

-
-

11.3. playbooks/site.yml

+
+

11.3. playbooks/site.yml

The example playbooks/site.yml playbook (below) applies the @@ -6526,8 +6254,8 @@ the example inventory: hosts.

-
-

11.4. Secret/vault-password

+
+

11.4. Secret/vault-password

As already mentioned, the small institute keeps its Ansible vault @@ -6539,17 +6267,17 @@ example password matches the example encryptions above.

-Secret/vault-password
alitysortstagess
+Secret/vault-password
alitysortstagess
 
-
-

11.5. Creating A Working Ansible Configuration

+
+

11.5. Creating A Working Ansible Configuration

A working Ansible configuration can be "tangled" from this document to -produce the test configuration described in the Testing chapter. The +produce the test configuration described in the Testing chapter. The tangling is done by Emacs's org-babel-tangle function and has already been performed with the resulting tangle included in the distribution with this document. @@ -6592,7 +6320,7 @@ would be copied, with appropriate changes, into new subdirectories public/ and private/.

  • ~/net/Secret would be a symbolic link to the (auto-mounted?) location of the administrator's encrypted USB drive, as described in -section Keys.
  • +section Keys.

    @@ -6628,8 +6356,8 @@ super-project's directory.

    -
    -

    11.6. Maintaining A Working Ansible Configuration

    +
    +

    11.6. Maintaining A Working Ansible Configuration

    The Ansible roles currently tangle into the roles_t/ directory to @@ -6648,8 +6376,8 @@ their way back to the code block in this document.

    -
    -

    12. The Institute Commands

    +
    +

    12. The Institute Commands

    The institute's administrator uses a convenience script to reliably @@ -6659,8 +6387,8 @@ Ansible configuration. The Ansible commands it executes are expected to get their defaults from ./ansible.cfg.

    -
    -

    12.1. Sub-command Blocks

    +
    +

    12.1. Sub-command Blocks

    The code blocks in this chapter tangle into the inst script. Each @@ -6684,8 +6412,8 @@ The first code block is the header of the ./inst script.

    -
    -

    12.2. Sanity Check

    +
    +

    12.2. Sanity Check

    The next code block does not implement a sub-command; it implements @@ -6745,8 +6473,8 @@ permissions. It probes past the Secret/ mount poin

    -
    -

    12.3. Importing Ansible Variables

    +
    +

    12.3. Importing Ansible Variables

    To ensure that Ansible and ./inst are sympatico vis-a-vi certain @@ -6768,7 +6496,12 @@ them. mysystem "ansible-playbook playbooks/check-inst-vars.yml >/dev/null"; -our ($domain_name, $domain_priv, $front_addr, $gate_wild_addr); +our ($domain_name, $domain_priv, $private_net_cidr, + $front_addr, $front_wg_pubkey, + $public_wg_net_cidr, $public_wg_port, + $gate_wild_addr, $gate_wg_pubkey, + $campus_wg_net_cidr, $campus_wg_port, + $core_addr, $core_wg_pubkey); do "./private/vars.pl";

    @@ -6787,16 +6520,107 @@ The playbook that updates private/vars.pl: content: | $domain_name = "{{ domain_name }}"; $domain_priv = "{{ domain_priv }}"; + $private_net_cidr = "{{ private_net_cidr }}"; + $front_addr = "{{ front_addr }}"; + $front_wg_pubkey = "{{ front_wg_pubkey }}"; + + $public_wg_net_cidr = "{{ public_wg_net_cidr }}"; + + $public_wg_port = "{{ public_wg_port }}"; + $gate_wild_addr = "{{ gate_wild_addr }}"; + $gate_wg_pubkey = "{{ gate_wg_pubkey }}"; + + $campus_wg_net_cidr = "{{ campus_wg_net_cidr }}"; + $campus_wg_port = "{{ campus_wg_port }}"; + + $core_addr = "{{ core_addr }}"; + $core_wg_pubkey = "{{ core_wg_pubkey }}"; dest: ../private/vars.pl mode: u=rw,g=,o=
    + +

    +Most of these settings are already in private/vars.yml. The +following few provide the servers' public keys and ports. +

    + +
    +=private/vars.yml
    front_wg_pubkey: S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4=
    +public_wg_port:  39608
    +
    +gate_wg_pubkey:  y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI=
    +campus_wg_port:  51820
    +
    +core_wg_pubkey:  lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c=
    +
    +
    + +

    +All of the private keys used in the example/test configuration are +listed in the following table. The first three are copied to +/etc/wireguard/private-key on each of the corresponding test +machines: front, gate and core. The rest are installed on +the test client to give it different personae. +

    + +
    + + +++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Test HostWireGuard™ Private Key
    frontAJkzVxfTm/KvRjzTN/9X2jYy+CAugiwZfN5F3JTegms=
    gateyOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U=
    coreAI+KhwnsHzSPqyIyAObx7EBBTBXFZPiXb2/Qcts8zEI=
    thingKIwQT5eGOl9w1qOa5I+2xx5kJH3z4xdpmirS/eGdsXY=
    dickWAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs=
    dicks-phoneoG/Kou9HOBCBwHAZGypPA1cZWUL6nR6WoxBiXc/OQWQ=
    dicks-razrIGNcF0VpkIBcJQAcLZ9jgRmk0SYyUr/WwSNXZoXXUWQ=
    -
    -

    12.4. The CA Command

    +
    +

    12.4. The CA Command

    The next code block implements the CA sub-command, which creates a @@ -6859,14 +6683,8 @@ config. my $dom = $domain_name; my $pvt = $domain_priv; mysystem "cd Secret/CA; ./easyrsa build-server-full $dom nopass"; - mysystem "cd Secret/CA; ./easyrsa build-server-full gate.$pvt nopass"; mysystem "cd Secret/CA; ./easyrsa build-server-full core.$pvt nopass"; - mysystem "cd Secret/CA; ./easyrsa build-client-full core nopass"; umask 077; - mysystem "openvpn --genkey secret Secret/front-shared.key"; - mysystem "openvpn --genkey secret Secret/gate-shared.key"; - mysystem "openssl dhparam -out Secret/front-dh2048.pem 2048"; - mysystem "openssl dhparam -out Secret/gate-dh2048.pem 2048"; mysystem "mkdir --mode=700 Secret/root.gnupg"; mysystem ("gpg --homedir Secret/root.gnupg", @@ -6902,13 +6720,13 @@ config.

    -
    -

    12.5. The Config Command

    +
    +

    12.5. The Config Command

    The next code block implements the config sub-command, which provisions network services by running the site.yml playbook -described in playbooks/site.yml. It recognizes an optional -n +described in playbooks/site.yml. It recognizes an optional -n flag indicating that the service configurations should just be checked. Given an optional host name, it provisions (or checks) just the named host. @@ -6953,12 +6771,12 @@ Example command lines:

    -
    -

    12.6. Account Management

    +
    +

    12.6. Account Management

    For general information about members and their Unix accounts, see -Accounts. The account management sub-commands maintain a mapping +Accounts. The account management sub-commands maintain a mapping associating member "usernames" (Unix account names) with their records. The mapping is stored among other things in private/members.yml as the value associated with the key members. @@ -6969,17 +6787,19 @@ A new member's record in the members mapping will have the st key value current. That key gets value former when the member leaves.3 Access by former members is revoked by invalidating the Unix account passwords, removing any authorized SSH keys from Front -and Core, and disabling their VPN certificates. +and Core, and removing their public keys from the WireGuard™ +configurations.

    The example file (below) contains a membership roll with one -membership record, for an account named dick, which was issued -client certificates for devices named dick-note, dick-phone and -dick-razr. dick-phone appears to be lost because its certificate -was revoked. Dick's membership record includes a vault-encrypted -password (for Fetchmail) and the two password hashes installed on -Front and Core. (The example hashes are truncated versions.) +membership record, for an account named dick, which registered the +public keys of devices named dick, dicks-phone and dicks-razr. +dicks-razr is presumably a replacement for dicks-phone, which was +lost and its key invalidated. Lastly, Dick's membership record +includes a vault-encrypted password (for Fetchmail) and the two +password hashes installed on Front and Core. (The example hashes are +truncated versions.)

    @@ -6988,9 +6808,9 @@ members: dick: status: current clients: - - dick-note - - dick-phone - - dick-razr + - dick 4 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= + - dicks-phone 5 --WFbTSff17QiYObXoU+7mjaEUCqKjgvLqA49pAxqVeWg= + - dicks-razr 6 zho0qMxoLclJSQu4GeJEcMkk0hx4Q047OcNc8vOejVw= password_front: $6$17h49U76$c7TsH6eMVmoKElNANJU1F1LrRrqzYVDreNu.QarpCoSt9u0gTHgiQ password_core: @@ -7004,8 +6824,8 @@ members: 6535633263656434393030333032343533626235653332626330666166613833 usernames: - dick -revoked: -- dick-phone +clients: +- thing 3 LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ=
    @@ -7021,7 +6841,7 @@ is used instead. private/members-empty.yml
    ---
     members:
     usernames: []
    -revoked: []
    +clients: []
     
    @@ -7083,7 +6903,7 @@ read from the file. The dump subroutine is another story (below). if (keys %{$yaml->{"members"}}) { print $O "members:\n"; for my $user (sort keys %{$yaml->{"members"}}) { - print_member ($O, $yaml->{"members"}->{$user}); + print_member ($O, $user, $yaml->{"members"}->{$user}); } print $O "usernames:\n"; for my $user (sort keys %{$yaml->{"members"}}) { @@ -7093,13 +6913,13 @@ read from the file. The dump subroutine is another story (below). print $O "members:\n"; print $O "usernames: []\n"; } - if (@{$yaml->{"revoked"}}) { - print $O "revoked:\n"; - for my $name (@{$yaml->{"revoked"}}) { + if (@{$yaml->{"clients"}}) { + print $O "clients:\n"; + for my $name (@{$yaml->{"clients"}}) { print $O "- $name\n"; } } else { - print $O "revoked: []\n"; + print $O "clients: []\n"; } close $O or die "Could not close $pathname: $!\n"; } @@ -7121,10 +6941,9 @@ each record.
    inst
    
    -sub print_member ($$) {
    -  my ($out, $member) = @_;
    -  print $out "  ", $member->{"username"}, ":\n";
    -  print $out "    username: ", $member->{"username"}, "\n";
    +sub print_member ($$$) {
    +  my ($out, $username, $member) = @_;
    +  print $out "  ", $username, ":\n";
       print $out "    status: ", $member->{"status"}, "\n";
       if (@{$member->{"clients"} || []}) {
         print $out "    clients:\n";
    @@ -7142,7 +6961,7 @@ each record.
           print $out "      $line\n";
         }
       }
    -  my @standard_keys = ( "username", "status", "clients",
    +  my @standard_keys = ( "status", "clients",
                             "password_front", "password_core",
                             "password_fetchmail" );
       my @other_keys = (sort
    @@ -7157,8 +6976,8 @@ each record.
     
    -
    -

    12.7. The New Command

    +
    +

    12.7. The New Command

    The next code block implements the new sub-command. It adds a new @@ -7192,14 +7011,11 @@ initial, generated password. mysystem ("ansible-playbook -e \@Secret/become.yml", " playbooks/nextcloud-new.yml", " -e user=$user", " -e pass=\"$epass\""); - $members->{$user} = { "username" => $user, - "status" => "current", + $members->{$user} = { "status" => "current", "password_front" => $front, "password_core" => $core, "password_fetchmail" => $vault }; - write_members_yaml - { "members" => $members, - "revoked" => $yaml->{"revoked"} }; + write_members_yaml $yaml; mysystem ("ansible-playbook -e \@Secret/become.yml", " -t accounts -l core,front playbooks/site.yml"); exit; @@ -7262,8 +7078,8 @@ initial, generated password.

    -
    -

    12.8. The Pass Command

    +
    +

    12.8. The Pass Command

    The institute's passwd command on Core securely emails root with a @@ -7277,8 +7093,8 @@ Ansible site.yml playbook to update the message is sent to member@core.

    -
    -

    12.8.1. Less Aggressive passwd.

    +
    +

    12.8.1. Less Aggressive passwd.

    The next code block implements the less aggressive passwd command. @@ -7374,8 +7190,8 @@ print "

    -
    -

    12.8.2. Less Aggressive Pass Command

    +
    +

    12.8.2. Less Aggressive Pass Command

    The following code block implements the ./inst pass command, used by @@ -7472,8 +7288,8 @@ users:resetpassword command using expect(1).

    -
    -

    12.8.3. Installing the Less Aggressive passwd

    +
    +

    12.8.3. Installing the Less Aggressive passwd

    The following Ansible tasks install the less aggressive passwd @@ -7541,11 +7357,11 @@ configuration so that the email to root can be encrypted.

    -
    -

    12.9. The Old Command

    +
    +

    12.9. The Old Command

    -The old command disables a member's accounts and clients. +The old command disables a member's account (and thus their clients).

    @@ -7560,9 +7376,7 @@ The old command disables a member's accounts and clients. mysystem ("ansible-playbook -e \@Secret/become.yml", "playbooks/nextcloud-old.yml -e user=$user"); $member->{"status"} = "former"; - write_members_yaml { "members" => $members, - "revoked" => [ sort @{$member->{"clients"}}, - @{$yaml->{"revoked"}} ] }; + write_members_yaml $yaml; mysystem ("ansible-playbook -e \@Secret/become.yml", "-t accounts playbooks/site.yml"); exit; @@ -7587,174 +7401,246 @@ The old command disables a member's accounts and clients.
    -
    -

    12.10. The Client Command

    +
    +

    12.10. The Client Command

    -The client command creates an OpenVPN configuration (.ovpn) file -authorizing wireless devices to connect to the institute's VPNs. The -command uses the EasyRSA CA in Secret/. The generated configuration -is slightly different depending on the type of host, given as the -first argument to the command. +The client command registers the public key of a client wishing to +connect to the institute's WireGuard™ subnets. The command allocates +a host number, associates it with the provided public key, and updates +the configuration files front-wg0.conf and gate-wg0.conf. These +are distributed to the servers, which are then reset. Thereafter the +servers recognize the new peer (and drop packets from any "peer" that +is no longer authorized).

    -
      -
    • ./inst client android NEW USER
      -An android host runs OpenVPN for Android or work-alike. Two files -are generated. campus.ovpn configures a campus VPN connection, -and public.ovpn configures a connection to the institute's public -VPN.
    • - -
    • ./inst client debian NEW USER
      -A debian host runs a Debian desktop with Network Manager. Again -two files are generated, for the campus and public VPNs.
    • - -
    • ./inst client campus NEW
      -A campus host is a Debian host (with or without desktop) that is -used by the institute generally, is not the property of a member, -never roams off campus, and so is remotely administered with -Ansible. One file is generated, campus.ovpn.
    • -
    -

    -The administrator uses encrypted email to send .ovpn files to new -members. New members install the network-manager-openvpn-gnome and -openvpn-systemd-resolved packages, and import the .ovpn files into -Network Manager on their desktops. The .ovpn files for an -Android device are transferred by USB stick and should automatically -install when "opened". On campus hosts, the system administrator -copies the campus.ovpn file to /etc/openvpn/campus.conf. +The client command also generates template WireGuard™ configuration +files for the client. They contain the necessary parameters except +the client's PrivateKey, which in most cases should be found in the +local /etc/wireguard/private-key, not in the configuration files. +Private keys (and corresponding public keys) should be generated on +the client (i.e. by the WireGuard for Android™ app) and never revealed +(i.e. sent in email, copied to a network drive, etc.).

    -The OpenVPN configurations generated for Debian hosts specify an up -script, update-systemd-resolved, installed in /etc/openvpn/ by the -openvpn-systemd-resolved package. The following configuration lines -instruct the OpenVPN clients to run this script whenever the -connection is restarted. +The generated configuration vary depending on the type of client, +which must be given as the first argument to the command. For most +types, two configuration files are generated. campus.conf contains +the client's campus VPN configuration, and public.conf the client's +public VPN configuration.

    -
    -openvpn-up
    script-security 2
    -up /etc/openvpn/update-systemd-resolved
    -up-restart
    -
    -
    +
      +
    • ./inst client android NAME USER PUBKEY
      +An android client runs WireGuard for Android™ or work-alike.
    • + +
    • ./inst client debian NAME USER PUBKEY
      +A debian client runs a Debian/Linux desktop with Network Manager +(though wg-quick is currently used).
    • + +
    • ./inst client campus NAME PUBKEY
      +A campus client is an institute machine (with or without desktop) +that is used by the institute generally, is not the property of a +member, never roams off campus, and so is remotely administered with +Ansible. Just one configuration file is generated: campus.conf.
    • +
    + +

    +The administrator emails the template .conf files to new members. +(They contain no secrets.) The members will have already installed +the wireguard package in order to run the wg genkey and wg +pubkey commands. After receiving the .conf templates, they paste +in their private keys and install the resulting files in +e.g. /etc/wireguard/wg0.conf and wg1.conf. To connect, members +run a command like systemctl start wg-quick@wg0. (There may be +better support in Network Manager soon.) +

    -inst
    sub write_template ($$$$$$$$$);
    -sub read_file ($);
    -sub add_client ($$$);
    +inst
    sub write_wg_server ($$$$$);
    +sub write_wg_client ($$$$$$);
    +sub hostnum_to_ipaddr ($$);
    +sub hostnum_to_ipaddr_cidr ($$);
     
     if (defined $ARGV[0] && $ARGV[0] eq "client") {
    -  die "Secret/CA/easyrsa: not found\n" if ! -x "Secret/CA/easyrsa";
       my $type = $ARGV[1]||"";
       my $name = $ARGV[2]||"";
       my $user = $ARGV[3]||"";
    -  if ($type eq "campus") {
    -    die "usage: $0 client campus NAME\n" if @ARGV != 3;
    +  my $pubkey = $ARGV[4]||"";
    +  if ($type eq "android" || $type eq "debian") {
    +    die "usage: $0 client $type NAME USER PUBKEY\n" if @ARGV != 5;
         die "$name: invalid host name\n" if $name !~ /^[a-z][-a-z0-9]+$/;
    -  } elsif ($type eq "android" || $type eq "debian") {
    -    die "usage: $0 client $type NAME USER\n" if @ARGV != 4;
    +  } elsif ($type eq "campus") {
    +    die "usage: $0 client campus NAME PUBKEY\n" if @ARGV != 4;
         die "$name: invalid host name\n" if $name !~ /^[a-z][-a-z0-9]+$/;
    +    $pubkey = $user;
    +    $user = "";
       } else {
    -    die "usage: $0 client [debian|android|campus]\n" if @ARGV != 4;
    +    die "usage: $0 client [debian|android|campus]\n";
       }
       my $yaml;
    -  my $member;
    -  if ($type ne "campus") {
    -    $yaml = read_members_yaml;
    -    my $members = $yaml->{"members"};
    -    if (@ARGV == 4) {
    -      $member = $members->{$user};
    -      die "$user: does not exist\n" if ! defined $member;
    -    }
    -    if (defined $member) {
    -      my ($owner) = grep { grep { $_ eq $name } @{$_->{"clients"}} }
    -                    values %{$members};
    -      die "$name: owned by $owner->{username}\n"
    -        if defined $owner && $owner->{username} ne $member->{username};
    -    }
    -  }
    +  $yaml = read_members_yaml;
    +  my $members = $yaml->{"members"};
    +  my $member = $members->{$user};
    +  die "$user: does not exist\n"
    +    if !defined $member && $type ne "campus";
     
    -  die "Secret/CA: no certificate authority found"
    -    if ! -d "Secret/CA/pki/issued";
    +  my @campus_peers # [ name, hostnum, type, pubkey, user|"" ]
    +     = map { [ (split / /), "" ] } @{$yaml->{"clients"}};
     
    -  if (! -f "Secret/CA/pki/issued/$name.crt") {
    -    mysystem "cd Secret/CA; ./easyrsa build-client-full $name nopass";
    -  } else {
    -    print "Using existing key/cert...\n";
    +  my @member_peers = ();
    +  for my $u (sort keys %$members) {
    +    push @member_peers,
    +         map { [ (split / /), $u ] } @{$members->{$u}->{"clients"}};
       }
     
    -  if ($type ne "campus") {
    -    my $clients = $member->{"clients"};
    -    if (! grep { $_ eq $name } @$clients) {
    -      $member->{"clients"} = [ $name, @$clients ];
    -      write_members_yaml $yaml;
    -    }
    +  my @all_peers = sort { $a->[1] <=> $b->[1] }
    +                       (@campus_peers, @member_peers);
    +
    +  for my $p (@all_peers) {
    +    my ($n, $h, $t, $k, $u) = @$p;
    +    die "$n: name already in use by $u\n"
    +        if $name eq $n && $u ne "";
    +    die "$n: name already in use on campus\n"
    +        if $name eq $n && $u eq "";
       }
     
    +  my $hostnum = (@all_peers
    +                 ? 1 + $all_peers[$#all_peers][1]
    +                 : 3);
    +
    +  push @{$type eq "campus"
    +         ? $yaml->{"clients"}
    +         : $member->{"clients"}},
    +       "$name $hostnum $type $pubkey";
    +
       umask 077;
    -  my $DEV = $type eq "android" ? "tun" : "ovpn";
    -  my $CA = read_file "Secret/CA/pki/ca.crt";
    -  my $CRT = read_file "Secret/CA/pki/issued/$name.crt";
    -  my $KEY = read_file "Secret/CA/pki/private/$name.key";
    -  my $UP = $type eq "android" ? "" : "
    -<<openvpn-up>>";
    -
    -  if ($type ne "campus") {
    -    my $TC = read_file "Secret/front-shared.key";
    -    write_template ($DEV,$UP,$CA,$CRT,$KEY,$TC, $front_addr,
    -                    $domain_name, "public.ovpn");
    -    print "Wrote public VPN configuration to public.ovpn.\n";
    +  write_members_yaml $yaml;
    +
    +  if ($type eq "campus") {
    +    push @all_peers, [ $name, $hostnum, $type, $pubkey, "" ];
    +  } else {
    +    push @member_peers, [ $name, $hostnum, $type, $pubkey, $user ];
    +    push @all_peers, [ $name, $hostnum, $type, $pubkey, $user ];
       }
    -  my $TC = read_file "Secret/gate-shared.key";
    -  write_template ($DEV,$UP,$CA,$CRT,$KEY,$TC, $gate_wild_addr,
    -                  "gate.$domain_priv", "campus.ovpn");
    -  print "Wrote campus VPN configuration to campus.ovpn.\n";
     
    -  exit;
    +  my $core_wg_addr = hostnum_to_ipaddr (2, $public_wg_net_cidr);
    +  my $extra_front_config = "
    +PostUp = resolvectl dns %i $core_addr
    +PostUp = resolvectl domain %i $domain_priv
    +
    +# Core
    +[Peer]
    +PublicKey = $core_wg_pubkey
    +AllowedIPs = $core_wg_addr
    +AllowedIPs = $private_net_cidr
    +AllowedIPs = $campus_wg_net_cidr\n";
    +
    +  write_wg_server ("private/front-wg0.conf", \@member_peers,
    +                   hostnum_to_ipaddr_cidr (1, $public_wg_net_cidr),
    +                   $public_wg_port, $extra_front_config)
    +    if $type ne "campus";
    +  write_wg_server ("private/gate-wg0.conf", \@all_peers,
    +                   hostnum_to_ipaddr_cidr (1, $campus_wg_net_cidr),
    +                   $campus_wg_port, "\n");
    +
    +  write_wg_client ("public.conf",
    +                   hostnum_to_ipaddr ($hostnum, $public_wg_net_cidr),
    +                   $type,
    +                   $front_wg_pubkey,
    +                   "$front_addr:$public_wg_port",
    +                   hostnum_to_ipaddr (1, $public_wg_net_cidr))
    +    if $type ne "campus";
    +  write_wg_client ("campus.conf",
    +                   hostnum_to_ipaddr ($hostnum, $campus_wg_net_cidr),
    +                   $type,
    +                   $gate_wg_pubkey,
    +                   "$gate_wild_addr:$campus_wg_port",
    +                   hostnum_to_ipaddr (1, $campus_wg_net_cidr));
     }
     
    -sub write_template ($$$$$$$$$) {
    -  my ($DEV,$UP,$CA,$CRT,$KEY,$TC,$ADDR,$NAME,$FILE) = @_;
    +sub write_wg_server ($$$$$) {
    +  my ($file, $peers, $addr_cidr, $port, $extra) = @_;
       my $O = new IO::File;
    -  open ($O, ">$FILE.tmp") or die "Could not open $FILE.tmp: $!\n";
    -  print $O "client
    -dev-type tun
    -dev $DEV
    -remote $ADDR
    -nobind
    -<<openvpn-drop-priv>>
    -remote-cert-tls server
    -verify-x509-name $NAME name
    -<<openvpn-crypt>>$UP
    -verb 3
    -key-direction 1
    -<ca>\n$CA</ca>
    -<cert>\n$CRT</cert>
    -<key>\n$KEY</key>
    -<tls-crypt>\n$TC</tls-crypt>\n";
    -  close $O or die "Could not close $FILE.tmp: $!\n";
    -  rename ("$FILE.tmp", $FILE)
    -    or die "Could not rename $FILE.tmp: $!\n";
    +  open ($O, ">$file.tmp") or die "Could not open $file.tmp: $!\n";
    +  print $O "[Interface]
    +Address = $addr_cidr
    +ListenPort = $port
    +PostUp = wg set %i private-key /etc/wireguard/private-key$extra";
    +  for my $p (@$peers) {
    +    my ($n, $h, $t, $k, $u) = @$p;
    +    next if $k =~ /^-/;
    +    my $ip = hostnum_to_ipaddr ($h, $addr_cidr);
    +    print $O "
    +# $n
    +[Peer]
    +PublicKey = $k
    +AllowedIPs = $ip\n";
    +  }
    +  close $O or die "Could not close $file.tmp: $!\n";
    +  rename ("$file.tmp", $file)
    +    or die "Could not rename $file.tmp: $!\n";
     }
     
    -sub read_file ($) {
    -  my ($path) = @_;
    -  my $I = new IO::File;
    -  open ($I, "<$path") or die "$path: could not read: $!\n";
    -  local $/;
    -  my $c = <$I>;
    -  close $I or die "$path: could not close: $!\n";
    -  return $c;
    +sub write_wg_client ($$$$$$) {
    +  my ($file, $addr, $type, $pubkey, $endpt, $server_addr) = @_;
    +  my $O = new IO::File;
    +  my $DNS = ($type eq "android"
    +             ? "
    +DNS=$core_addr\nDomain=$domain_priv"
    +             : "
    +PostUp = resolvectl dns %i $core_addr
    +PostUp = resolvectl domain %i $domain_priv");
    +  open ($O, ">$file.tmp") or die "Could not open $file.tmp: $!\n";
    +  print $O "[Interface]
    +Address = $addr
    +PostUp = wg set %i private-key /etc/wireguard/private-key$DNS
    +
    +[Peer]
    +PublicKey = $pubkey
    +EndPoint = $endpt
    +AllowedIPs = $server_addr
    +AllowedIPs = $private_net_cidr
    +AllowedIPs = $public_wg_net_cidr
    +AllowedIPs = $campus_wg_net_cidr\n";
    +  close $O or die "Could not close $file.tmp: $!\n";
    +  rename ("$file.tmp", $file)
    +    or die "Could not rename $file.tmp: $!\n";
    +
    +  exit;
     }
    +
    +sub hostnum_to_ipaddr ($$)
    +{
    +  my ($hostnum, $net_cidr) = @_;
    +
    +  # Assume 24bit subnet, 8bit hostnum.
    +  # Find a Perl library for more generality?
    +  die "$hostnum: hostnum too large\n" if $hostnum > 255;
    +  my ($prefix) = $net_cidr =~ m"^(\d+\.\d+\.\d+)\.\d+/24$";
    +  die if !$prefix;
    +  return "$prefix.$hostnum";
    +}
    +
    +sub hostnum_to_ipaddr_cidr ($$)
    +{
    +  my ($hostnum, $net_cidr) = @_;
    +
    +  # Assume 24bit subnet, 8bit hostnum.
    +  # Find a Perl library for more generality?
    +  die "$hostnum: hostnum too large\n" if $hostnum > 255;
    +  my ($prefix) = $net_cidr =~ m"^(\d+\.\d+\.\d+)\.\d+/24$";
    +  die if !$prefix;
    +  return "$prefix.$hostnum/24";
    +}
     
    -
    -

    12.11. Institute Command Help

    +
    +

    12.11. Institute Command Help

    This should be the last block tangled into the inst script. It @@ -7770,8 +7656,8 @@ above.

    -
    -

    13. Testing

    +
    +

    13. Testing

    The example files in this document, ansible.cfg and hosts as well @@ -7790,7 +7676,7 @@ simulation is the VirtualBox host.

    The next two sections list the steps taken to create the simulated Core, Gate and Front machines, and connect them to their networks. -The process is similar to that described in The (Actual) Hardware, but +The process is similar to that described in The (Actual) Hardware, but is covered in detail here where the VirtualBox hypervisor can be assumed and exact command lines can be given (and copied during re-testing). The remaining sections describe the manual testing @@ -7806,8 +7692,8 @@ HTML version of the latest revision can be found on the official web site at https://www.virtualbox.org/manual/UserManual.html.

    -
    -

    13.1. The Test Networks

    +
    +

    13.1. The Test Networks

    The networks used in the test: @@ -7871,15 +7757,15 @@ on the private 192.168.15.0/24 network.

    -
    -

    13.2. The Test Machines

    +
    +

    13.2. The Test Machines

    The virtual machines are created by VBoxManage command lines in the following sub-sections. They each start with a recent Debian release (e.g. debian-12.5.0-amd64-netinst.iso) in their simulated DVD -drives. As in The Hardware preparation process being simulated, a few -additional software packages are installed. Unlike in The Hardware +drives. As in The Hardware preparation process being simulated, a few +additional software packages are installed. Unlike in The Hardware preparation, machines are moved to their final networks and then remote access is authorized. (They are not accessible via ssh on the VirtualBox NAT network where they first boot.) @@ -7891,8 +7777,8 @@ privileged accounts on the virtual machines, they are prepared for configuration by Ansible.

    -
    -

    13.2.1. A Test Machine

    +
    +

    13.2.1. A Test Machine

    The following shell function contains most of the VBoxManage @@ -8023,8 +7909,8 @@ preparation (below).

    -
    -

    13.2.2. The Test Front Machine

    +
    +

    13.2.2. The Test Front Machine

    The front machine is created with 512MiB of RAM, 4GiB of disk, and @@ -8037,7 +7923,7 @@ After Debian is installed (as detailed above) front is shut down an its primary network interface moved to the simulated Internet, the NAT network premises. front also gets a second network interface, on the host-only network vboxnet1, to make it directly accessible to -the administrator's notebook (as described in The Test Networks). +the administrator's notebook (as described in The Test Networks).

    @@ -8069,13 +7955,13 @@ Note that there is no pre-provisioning for front, which is never deployed on a frontier, always in the cloud. Additional Debian packages are assumed to be readily available. Thus Ansible installs them as necessary, but first the administrator authorizes remote -access by following the instructions in the final section: Ansible +access by following the instructions in the final section: Ansible Test Authorization.

    -
    -

    13.2.3. The Test Gate Machine

    +
    +

    13.2.3. The Test Gate Machine

    The gate machine is created with the same amount of RAM and disk as @@ -8090,14 +7976,14 @@ create_vm

    -After Debian is installed (as detailed in A Test Machine) and the +After Debian is installed (as detailed in A Test Machine) and the machine rebooted, the administrator logs in and installs several additional software packages.

    sudo apt install netplan.io systemd-resolved unattended-upgrades \
    -                 ufw isc-dhcp-server postfix openvpn
    +                 ufw isc-dhcp-server postfix wireguard
     
    @@ -8191,12 +8077,12 @@ Ethernet interface is temporarily configured with an IP address.

    Finally, the administrator authorizes remote access by following the -instructions in the final section: Ansible Test Authorization. +instructions in the final section: Ansible Test Authorization.

    -
    -

    13.2.4. The Test Core Machine

    +
    +

    13.2.4. The Test Core Machine

    The core machine is created with 1GiB of RAM and 6GiB of disk. @@ -8213,14 +8099,14 @@ create_vm

    -After Debian is installed (as detailed in A Test Machine) and the +After Debian is installed (as detailed in A Test Machine) and the machine rebooted, the administrator logs in and installs several additional software packages.

    sudo apt install netplan.io systemd-resolved unattended-upgrades \
    -                 ntp isc-dhcp-server bind9 apache2 openvpn \
    +                 ntp isc-dhcp-server bind9 apache2 wireguard \
                      postfix dovecot-imapd fetchmail expect rsync \
                      gnupg
     sudo apt install mariadb-server php php-{apcu,bcmath,curl,gd,gmp}\
    @@ -8279,12 +8165,12 @@ Netplan soon.)
     
     

    Finally, the administrator authorizes remote access by following the -instructions in the next section: Ansible Test Authorization. +instructions in the next section: Ansible Test Authorization.

    -
    -

    13.2.5. Ansible Test Authorization

    +
    +

    13.2.5. Ansible Test Authorization

    To authorize Ansible's access to the three test machines, they must @@ -8350,8 +8236,8 @@ ssh-keygen -f ~/.ssh/known_hosts -R 192.168.57.3

    -
    -

    13.3. Configure Test Machines

    +
    +

    13.3. Configure Test Machines

    At this point the three test machines core, gate, and front are @@ -8369,8 +8255,8 @@ not.

    -
    -

    13.4. Test Basics

    +
    +

    13.4. Test Basics

    At this point the test institute is just core, gate and front, @@ -8432,12 +8318,12 @@ instant attention).

    -
    -

    13.5. The Test Nextcloud

    +
    +

    13.5. The Test Nextcloud

    Further tests involve Nextcloud account management. Nextcloud is -installed on core as described in Configure Nextcloud. Once +installed on core as described in Configure Nextcloud. Once /Nextcloud/ is created, ./inst config core will validate or update its configuration files.

    @@ -8454,13 +8340,13 @@ exercise the test Nextcloud.

    The process starts with enrolling the first member of the institute -using the ./inst new command and issuing client VPN keys with the -./inst client command. +using the ./inst new command and registering a client's public key +with the ./inst client command.

    -
    -

    13.6. Test New Command

    +
    +

    13.6. Test New Command

    A member must be enrolled so that a member's client machine can be @@ -8480,14 +8366,14 @@ Take note of Dick's initial password.

    -
    -

    13.7. The Test Member Notebook

    +
    +

    13.7. The Test Member Notebook

    A test member's notebook is created next, much like the servers, except with memory and disk space doubled to 2GiB and 8GiB, and a desktop. This machine is not configured by Ansible. Rather, its -desktop VPN client and web browser test the OpenVPN configurations on +WireGuard™ tunnels and web browser test the VPN configurations on gate and front, and the Nextcloud installation on core.

    @@ -8509,7 +8395,7 @@ behind) the access point.

    -Debian is installed much as detailed in A Test Machine except that +Debian is installed much as detailed in A Test Machine except that the SSH server option is not needed and the GNOME desktop option is. When the machine reboots, the administrator logs into the desktop and installs a couple additional software packages (which @@ -8517,61 +8403,77 @@ require several more).

    -
    sudo apt install network-manager-openvpn-gnome \
    -                 openvpn-systemd-resolved \
    -                 nextcloud-desktop evolution
    +
    sudo apt install wireguard nextcloud-desktop evolution
     
    -
    -

    13.8. Test Client Command

    +
    +

    13.8. Test Client Command

    -The ./inst client command is used to issue keys for the institute's -VPNs. The following command generates two .ovpn (OpenVPN -configuration) files, small.ovpn and campus.ovpn, authorizing -access by the holder, identified as dick, owned by member dick, to -the test VPNs. +The ./inst client command is used to register the public key of a +client wishing to connect to the institute's VPNs. In this test, new +member Dick wants to connect his notebook, dick, to the institute +VPNs. First he generates a pair of WireGuard™ keys by running the +following commands on Dick's notebook.

    -
    ./inst client debian dick dick
    +
    ( umask 077; wg genkey >private)
    +wg pubkey <private >public
    +
    +
    + +

    +The administrator uses the key in public to run the following +command, generating campus.conf and public.conf files. +

    + +
    +
    ./inst client debian dick dick \
    +  4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8=
     
    -
    -

    13.9. Test Campus VPN

    +
    +

    13.9. Test Campus WireGuard™ Subnet

    -The campus.ovpn OpenVPN configuration file (generated in Test Client -Command) is transferred to dick, which is at the Wi-Fi access -point's wifi_wan_addr. +The campus.conf WireGuard™ configuration file (generated in Test +Client Command) is transferred to dick, which is at the Wi-Fi access +point's IP address, host 2 on the wild Ethernet.

    -
    scp *.ovpn sysadm@192.168.57.2:
    +
    scp *.conf sysadm@192.168.57.2:
     

    -The file is installed using the Network tab of the desktop Settings -app. The administrator uses the "+" button, chooses "Import from -file…" and the campus.ovpn file. Importantly the administrator -checks the "Use this connection only for resources on its network" -checkbox in the IPv4 tab of the Add VPN dialog. The admin does the -same with the small.ovpn file, for use on the simulated Internet. +Dick then pastes his notebook's private key into the template +campus.conf file and installs the result in +/etc/wireguard/wg0.conf, doing the same to complete public.conf +and install it in /etc/wireguard/wg1.conf.

    -The administrator turns on the campus VPN on dick (which connects -instantly) and does a few basic tests in a terminal. +To connect to the campus VPN, the following command is run. +

    + +
    +
    systemctl start wg-quick@wg0
    +
    +
    + +

    +A few basic tests are then performed in a terminal.

    systemctl status
    -ping -c 1 8.8.4.4      # dns.google
    +ping -c 1 8.8.8.8      # dns.google
     ping -c 1 192.168.56.1 # core
     host dns.google
     host core.small.private
    @@ -8580,8 +8482,8 @@ host www
     
    -
    -

    13.10. Test Web Pages

    +
    +

    13.10. Test Web Pages

    Next, the administrator copies Backup/WWW/ (included in the @@ -8620,8 +8522,8 @@ will warn but allow the luser to continue.

    -
    -

    13.11. Test Web Update

    +
    +

    13.11. Test Web Update

    Modify /WWW/live/index.html on core and wait 15 minutes for it to @@ -8635,8 +8537,8 @@ Hack /home/www/index.html on front and observe the result at

    -
    -

    13.12. Test Nextcloud

    +
    +

    13.12. Test Nextcloud

    Nextcloud is typically installed and configured after the first @@ -8644,9 +8546,9 @@ Ansible run, when core has Internet access via gate. installation directory /Nextcloud/nextcloud/ appears, the Ansible code skips parts of the Nextcloud configuration. The same installation (or restoration) process used on Core is used on core -to create /Nextcloud/. The process starts with Create -/Nextcloud/, involves Restore Nextcloud or Install Nextcloud, -and runs ./inst config core again 8.23.6. When the ./inst +to create /Nextcloud/. The process starts with Create +/Nextcloud/, involves Restore Nextcloud or Install Nextcloud, +and runs ./inst config core again 8.23.6. When the ./inst config core command is happy with the Nextcloud configuration on core, the administrator uses Dick's notebook to test it, performing the following tests on dick's desktop. @@ -8724,8 +8626,8 @@ the calendar.

    -
    -

    13.13. Test Email

    +
    +

    13.13. Test Email

    With Evolution running on the member notebook dick, one second email @@ -8753,8 +8655,8 @@ Outgoing email is also tested. A message to

    -
    -

    13.14. Test Public VPN

    +
    +

    13.14. Test Public VPN

    At this point, dick can move abroad, from the campus Wi-Fi @@ -8769,12 +8671,17 @@ machine does not need to be shut down.

    -The administrator might wait to see evidence of the change in -networks. Evolution may start "Testing reachability of mail account -dick@small.example.org." Eventually, the campus VPN should -disconnect. After it does, the administrator turns on the small -VPN, which connects in a second or two. Again, some basics are -tested in a terminal. +Then the campus VPN is disconnected and the public VPN connected. +

    + +
    +
    systemctl stop wg-quick@wg0
    +systemctl start wg-quick@wg1
    +
    +
    + +

    +Again, some basics are tested in a terminal.

    @@ -8807,8 +8714,8 @@ calendar events.

    -
    -

    13.15. Test Pass Command

    +
    +

    13.15. Test Pass Command

    To test the ./inst pass command, the administrator logs in to core @@ -8855,8 +8762,8 @@ Finally, the administrator verifies that dick can login on co

    -
    -

    13.16. Test Old Command

    +
    +

    13.16. Test Old Command

    One more institute command is left to exercise. The administrator @@ -8870,22 +8777,22 @@ retires dick and his main device dick.

    The administrator tests Dick's access to core, front and -Nextcloud, and attempts to re-connect the small VPN. All of these -should fail. +Nextcloud, and attempts to access the campus VPN. All of these should +fail.

    -
    -

    14. Future Work

    +
    +

    14. Future Work

    The small institute's network, as currently defined in this doocument, is lacking in a number of respects.

    -
    -

    14.1. Deficiencies

    +
    +

    14.1. Deficiencies

    The current network monitoring is rudimentary. It could use some @@ -8906,49 +8813,21 @@ units.

    -The institute's private domain names (e.g. www.small.private) are -not resolvable on Front. Reverse domains (86.177.10.in-addr.arpa) -mapping institute network addresses back to names in the private -domain small.private work only on the campus Ethernet. These nits -might be picked when OpenVPN supports the DHCP option -rdnss-selection (RFC6731), or with hard-coded resolvectl commands. -

    - -

    -The ./inst old dick command does not break VPN connections to Dick's -clients. New connections cannot be created, but old connections can -continue to work for some time. -

    - -

    -The ./inst client android dick-phone dick command generates .ovpn -files that require the member to remember to check the "Use this -connection only for resources on its network" box in the IPv4 (and -IPv6) tab(s) of the Add VPN dialog. The command should include an -OpenVPN setting that the NetworkManager file importer recognizes as -the desired setting. -

    - -

    -The VPN service is overly complex. The OpenVPN 2.4.7 clients allow -multiple server addresses, but the openvpn(8) manual page suggests -per connection parameters are restricted to a set that does not -include the essential verify-x509-name. Use the same name on -separate certificates for Gate and Front? Use the same certificate -and key on Gate and Front? +The institute's reverse domains (e.g. 86.177.10.in-addr.arpa) are +not available on Front, yet.

    -
    -

    14.2. More Tests

    +
    +

    14.2. More Tests

    The testing process described in the previous chapter is far from complete. Additional tests are needed.

    -
    -

    14.2.1. Backup

    +
    +

    14.2.1. Backup

    The backup command has not been tested. It needs an encrypted @@ -8957,8 +8836,8 @@ partition with which to sync? And then some way to compare that to

    -
    -

    14.2.2. Restore

    +
    +

    14.2.2. Restore

    The restore process has not been tested. It might just copy Backup/ @@ -8968,8 +8847,8 @@ perhaps permissions too. It could also use an example

    -
    -

    14.2.3. Campus Disconnect

    +
    +

    14.2.3. Campus Disconnect

    Email access (IMAPS) on front is… difficult to test unless @@ -8993,8 +8872,8 @@ could be used.

    -
    -

    15. Appendix: The Bootstrap

    +
    +

    15. Appendix: The Bootstrap

    Creating the private network from whole cloth (machines with recent @@ -9014,11 +8893,11 @@ etc.: quite a bit of temporary, manual localnet configuration just to get to the additional packages.

    -
    -

    15.1. The Current Strategy

    +
    +

    15.1. The Current Strategy

    -The strategy pursued in The Hardware is two phase: prepare the servers +The strategy pursued in The Hardware is two phase: prepare the servers on the Internet where additional packages are accessible, then connect them to the campus facilities (the private Ethernet switch, Wi-Fi AP, ISP), manually configure IP addresses (while the DHCP client silently @@ -9026,8 +8905,8 @@ fails), and avoid names until BIND9 is configured.

    -
    -

    15.2. Starting With Gate

    +
    +

    15.2. Starting With Gate

    The strategy of Starting With Gate concentrates on configuring Gate's @@ -9071,8 +8950,8 @@ ansible-playbook -l core site.yml

    -
    -

    15.3. Pre-provision With Ansible

    +
    +

    15.3. Pre-provision With Ansible

    A refinement of the current strategy might avoid the need to maintain @@ -9125,7 +9004,7 @@ routes on Front and Gate, making the simulation less… similar.

    Author: Matt Birkholz

    -

    Created: 2025-05-31 Sat 22:27

    +

    Created: 2025-06-15 Sun 12:23

    Validate

    -- 2.25.1