From: Matt Birkholz Date: Sat, 14 Jun 2025 23:34:14 +0000 (-0600) Subject: Remove OpenVPN. Add pubkeys to the institute "client" command args. X-Git-Url: https://birchwood-abbey.net/git?a=commitdiff_plain;h=5c742e609f70d195e657c10cf23b915976adb333;p=Institute Remove OpenVPN. Add pubkeys to the institute "client" command args. Replaced "revoked" with "clients" in private/members.yml. Use a PostUp command to install peer private keys from the local /etc/wireguard/private-key file, thus keeping it out of the WireGuard™ and Ansible configurations. Moved e.g Secret/gate-wg0.conf to private/. Provide the example private keys in a table (as they appear nowhere else!). Treat gate-wg0.conf and front-wg0.conf like members.yml: do not tangle them and thus wipe out a test state(?). --- diff --git a/.gitignore b/.gitignore index 122f718..fd8a137 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ /roles/ /private/vars.pl +/private/members.yml +/private/front-wg0.conf +/private/gate-wg0.conf +/public.conf* +/campus.conf* diff --git a/README.org b/README.org index 59e92a0..3f234aa 100644 --- a/README.org +++ b/README.org @@ -63,7 +63,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. @@ -355,108 +355,6 @@ Note that authenticating to a non-HTTPS URL like domain name is private and the service is on a directly connected private network. -** The VPN Services - -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][The Front Role]] and [[*The Gate Role][The Gate Role]], as well as the -matching client configurations in [[*The Core Role][The Core Role]] and the =.ovpn= files -generated by [[*The Client Command][The Client Command]]. The configurations are based on the -documentation for OpenVPN v2.4: the ~openvpn(8)~ manual page and [[https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/][this -web page]]. - -*** 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. - -#+NAME: openvpn-dev-mode -#+CAPTION: ~openvpn-dev-mode~ -#+BEGIN_SRC conf -dev-type tun -dev ovpn -topology subnet -client-to-client -#+END_SRC - -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. - -#+NAME: openvpn-keepalive -#+CAPTION: ~openvpn-keepalive~ -#+BEGIN_SRC conf -keepalive 10 120 -#+END_SRC - -As mentioned in [[*The Name Service][The Name Service]], the institute uses a campus name -server. OpenVPN is instructed to push its address and the campus -search domain. - -#+NAME: openvpn-dns -#+CAPTION: ~openvpn-dns~ -#+BEGIN_SRC conf -push "dhcp-option DOMAIN {{ domain_priv }}" -push "dhcp-option DNS {{ core_addr }}" -#+END_SRC - -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. - -#+NAME: openvpn-drop-priv -#+CAPTION: ~openvpn-drop-priv~ -#+BEGIN_SRC conf -user nobody -group nogroup -persist-key -persist-tun -#+END_SRC - -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~. - -#+NAME: openvpn-crypt -#+CAPTION: ~openvpn-crypt~ -#+BEGIN_SRC conf -cipher AES-256-GCM -auth SHA256 -#+END_SRC - -Finally, a ~max-client~ limit was chosen to frustrate flooding while -accommodating a few members with a handful of devices each. - -#+NAME: openvpn-max -#+CAPTION: ~openvpn-max~ -#+BEGIN_SRC conf -max-clients 20 -#+END_SRC - -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). - -#+NAME: openvpn-debug -#+CAPTION: ~openvpn-debug~ -#+BEGIN_SRC conf -ifconfig-pool-persist ipp.txt -status openvpn-status.log -verb 3 -#+END_SRC - ** Accounts A small institute has just a handful of members. For simplicity (and @@ -525,32 +423,22 @@ institute's SSH keys: /not/ used. (Thus Core's configuration does not depend on 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 [[file:Secret/CA/][=Secret/CA/=]]. +The institute uses a couple X.509 certificates to authenticate +servers. They are created by the EasyRSA Certificate Authority stored +in [[file:Secret/CA/][=Secret/CA/=]]. - [[file:Secret/CA/pki/ca.crt][=Secret/CA/pki/ca.crt=]] :: The institute CA certificate, used to sign the other certificates. - - [[file:Secret/CA/pki/issued/small.example.org.crt][=Secret/CA/pki/issued/small.example.org.crt=]] :: The public Apache, - Postfix, and OpenVPN servers on Front. - - - [[file:Secret/CA/pki/issued/gate.small.private.crt][=Secret/CA/pki/issued/gate.small.private.crt=]] :: The campus - OpenVPN server on Gate. + - [[file:Secret/CA/pki/issued/small.example.org.crt][=Secret/CA/pki/issued/small.example.org.crt=]] :: The public + Postfix, Dovecot and Apache servers on Front. - [[file:Secret/CA/pki/issued/core.small.private.crt][=Secret/CA/pki/issued/core.small.private.crt=]] :: The campus - Apache (thus Nextcloud), and Dovecot-IMAPd servers. - - - [[file:Secret/CA/pki/issued/core.crt][=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=. Finally, the institute uses an OpenPGP key to secure sensitive emails (containing passwords or private keys) to Core. @@ -562,8 +450,8 @@ Finally, the institute uses an OpenPGP key to secure sensitive emails - [[file:Secret/root-sec.pem][=Secret/root-sec.pem=]] :: The ASCII armored OpenPGP secret key. 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. : rsync -a Secret/ Secret2/ : rsync -a Secret/ Secret3/ @@ -750,9 +638,9 @@ domain_priv: small.private ** Subnets -The small institute uses a private Ethernet, two VPNs, and an +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 +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 @@ -813,14 +701,12 @@ configuration using mostly-default VirtualBoxes (described [[*Testing][here]]). private_net_cidr: 192.168.56.0/24 wild_net_cidr: 192.168.57.0/24 -public_vpn_net_cidr: 10.177.86.0/24 public_wg_net_cidr: 10.177.87.0/24 -campus_vpn_net_cidr: 10.84.138.0/24 campus_wg_net_cidr: 10.84.139.0/24 #+END_SRC The network addresses are needed in several additional formats, e.g. -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~. @@ -838,24 +724,12 @@ wild_net_mask: wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}" wild_net_broadcast: "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}" -public_vpn_net: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('network') }}" -public_vpn_net_mask: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}" -public_vpn_net_and_mask: - "{{ public_vpn_net }} {{ public_vpn_net_mask }}" public_wg_net: "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}" public_wg_net_mask: "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}" public_wg_net_and_mask: "{{ public_wg_net }} {{ public_wg_net_mask }}" -campus_vpn_net: - "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('network') }}" -campus_vpn_net_mask: - "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}" -campus_vpn_net_and_mask: - "{{ campus_vpn_net }} {{ campus_vpn_net_mask }}" campus_wg_net: "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}" campus_wg_net_mask: @@ -880,15 +754,13 @@ virtual machines and networks, and the VirtualBox user manual uses ~192.168.15.0~ in its example configuration of a "NAT Network" (simulating Front's ISP's network). -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, ~front_vpn_addr~. The following -code block picks the obvious IP addresses for Core (host 1) and Gate -(host 2) on the private Ethernet, Gate and a Wi-Fi access point on the -wild Ethernet, and Front on the public VPN. +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). #+CAPTION: [[file:private/vars.yml][=private/vars.yml=]] #+BEGIN_SRC conf :tangle private/vars.yml @@ -896,44 +768,15 @@ core_addr_cidr: "{{ private_net_cidr | ansible.utils.ipaddr('1') }}" 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_vpn_addr_cidr: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('1') }}" -front_wg_port: 39608 front_wg_addr_cidr: "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}" -core_wg_addr_cidr: - "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}" -wg_client_front_addr_cidr: - "{{ public_wg_net_cidr | ansible.utils.ipaddr('3') }}" -campus_wg_port: 51820 -campus_wg_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('1') }}" -wg_appl_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('2') }}" -wg_client_gate_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('3') }}" core_addr: "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}" gate_addr: "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}" gate_wild_addr: "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}" -wifi_wan_addr: - "{{ wifi_wan_addr_cidr | ansible.utils.ipaddr('address') }}" -front_vpn_addr: - "{{ front_vpn_addr_cidr | ansible.utils.ipaddr('address') }}" front_wg_addr: "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -core_wg_addr: - "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_client_front_addr: - "{{ wg_client_front_addr_cidr | ansible.utils.ipaddr('address') }}" -gate_wg_addr: - "{{ campus_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_appl_addr: - "{{ wg_appl_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_client_gate_addr: - "{{ wg_client_gate_addr_cidr | ansible.utils.ipaddr('address') }}" #+END_SRC @@ -1109,9 +952,9 @@ packages. The administrator temporarily plugged Core into a cable 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 wireguard +: _ gnupg openssh-server The Nextcloud configuration requires Apache2, MariaDB and a number of PHP modules. Installing them while Core was on a cable modem sped up @@ -1263,8 +1106,8 @@ software packages. The administrator temporarily plugged Gate into a cable modem and installed them as shown below. : $ sudo apt install netplan.io systemd-resolved unattended-upgrades \ -: _ ufw isc-dhcp-server postfix openvpn \ -: _ openssh-server wireguard +: _ ufw isc-dhcp-server postfix wireguard \ +: _ openssh-server Next, the administrator concatenated a personal public ssh key and the key found in [[file:Secret/ssh_admin/][=Secret/ssh_admin/=]] (created by [[*The CA Command][The CA Command]]) into an @@ -1434,10 +1277,6 @@ 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. - ** Include Particulars The first task, as in [[*The All Role][The All Role]], is to include the institute @@ -1685,15 +1524,14 @@ times, the relaying configuration, and the common path to incoming emails. These and a few Front-specific Postfix configurations 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. #+NAME: postfix-front-networks #+CAPTION: ~postfix-front-networks~ #+BEGIN_SRC conf - p: mynetworks v: >- - {{ public_vpn_net_cidr }} {{ public_wg_net_cidr }} 127.0.0.0/8 [::ffff:127.0.0.0]/104 @@ -1833,7 +1671,7 @@ created by a more specialized role. abuse: root webmaster: root admin: root - monkey: monkey@{{ front_vpn_addr }} + monkey: monkey@{{ front_wg_addr }} root: {{ ansible_user }} path: /etc/aliases marker: "# {mark} INSTITUTE MANAGED BLOCK" @@ -2171,187 +2009,42 @@ the users' =~/Public/HTML/= directories. tags: accounts #+END_SRC -** Configure OpenVPN - -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. +** Configure Public WireGuard™ Subnet -#+NAME: openvpn-ccd-core -#+CAPTION: ~openvpn-ccd-core~ -#+BEGIN_SRC conf -iroute {{ private_net_and_mask }} -iroute {{ campus_vpn_net_and_mask }} -#+END_SRC +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. -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=][=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. -#+NAME: openvpn-front-routes -#+CAPTION: ~openvpn-front-routes~ +#+CAPTION: =private/front-wg0.conf= #+BEGIN_SRC conf -route {{ private_net_and_mask }} -route {{ campus_vpn_net_and_mask }} -push "route {{ private_net_and_mask }}" -push "route {{ campus_vpn_net_and_mask }}" -#+END_SRC - -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 VPN Service]]. - -#+NAME: openvpn-front -#+CAPTION: ~openvpn-front~ -#+BEGIN_SRC conf :noweb no-export -server {{ public_vpn_net_and_mask }} -client-config-dir /etc/openvpn/ccd -<> -<> -<> -<> -<> -<> -<> -<> -ca /usr/local/share/ca-certificates/{{ domain_name }}.crt -cert server.crt -key server.key -dh dh2048.pem -tls-crypt shared.key -#+END_SRC - -Finally, here are the tasks (and handler) required to install and -configure the OpenVPN server on Front. - -#+CAPTION: [[file:roles_t/front/tasks/main.yml][=roles_t/front/tasks/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/front/tasks/main.yml :noweb no-export - -- 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: | - <> - dest: /etc/openvpn/ccd/core - notify: Restart OpenVPN. - -- name: Disable former VPN clients. - become: yes - copy: - content: "disable\n" - dest: /etc/openvpn/ccd/{{ item }} - loop: "{{ revoked }}" - tags: accounts - -- name: Install OpenVPN server certificate/key. - 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 }} - 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: | - <> - dest: /etc/openvpn/server.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. - -- name: Enable/Start OpenVPN. - become: yes - systemd: - service: openvpn@server - enabled: yes - state: started -#+END_SRC - -#+CAPTION: [[file:roles_t/front/handlers/main.yml][=roles_t/front/handlers/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/front/handlers/main.yml - -- name: Restart OpenVPN. - become: yes - systemd: - service: openvpn@server - state: restarted -#+END_SRC - -** Configure Public WireGuard™ - -Front uses WireGuard™ to provide a public VPN service. Core has an -interface on this VPN (address: ~core_wg_addr~) and is expected to -forward packets between it and the institute's other private networks. - -The following example [[file:Secret/front-wg0.conf][=Secret/front-wg0.conf=]] configuration recognizes -Core by its public key, ~lGhC51~, and routes the institute's private -networks to it. It also recognizes a member client, Dick's Notebook, -by its public key ~4qd4xd...~ assigning it host number 4 on the VPN. - -#+CAPTION: [[file:Secret/front-wg0.conf][=Secret/front-wg0.conf=]] -#+BEGIN_SRC conf :tangle Secret/front-wg0.conf [Interface] Address = 10.177.87.1/24 -PrivateKey = AJkzVxfTm/KvRjzTN/9X2jYy+CAugiwZfN5F3JTegms= ListenPort = 39608 -PostUp = resolvectl dns wg0 192.168.56.1 -PostUp = resolvectl domain wg0 small.private +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 OpenVPN has this route. -AllowedIPs = 10.84.138.0/24, 10.84.139.0/24 +AllowedIPs = 192.168.56.0/24 +AllowedIPs = 10.84.139.0/24 -# dicks-note +# dick [Peer] PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= AllowedIPs = 10.177.87.4 + +# dicks-razr +[Peer] +PublicKey = zho0qMxoLclJSQu4GeJEcMkk0hx4Q047OcNc8vOejVw= +AllowedIPs = 10.177.87.6 #+END_SRC The configuration used on Dick's notebook when it is abroad looks like @@ -2361,9 +2054,9 @@ this: #+BEGIN_SRC conf [Interface] Address = 10.177.87.3 -PrivateKey = WAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs= -PostUp = resolvectl dns wg0 192.168.56.1 -PostUp = resolvectl domain wg0 small.private +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] @@ -2371,12 +2064,11 @@ PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4= AllowedIPs = 10.177.87.1 AllowedIPs = 10.177.87.0/24 AllowedIPs = 192.168.56.0/24 -AllowedIPs = 10.84.138.0/24, 10.84.139.0/24 -AllowedIPs = 10.177.86.0/24 +AllowedIPs = 10.84.139.0/24 #+END_SRC The following tasks install WireGuard™, configure it with -=Secret/front-wg0.conf=, and enable the service. +[[=private/front-wg0.conf=][=private/front-wg0.conf=]], and enable the service. #+CAPTION: [[file:roles_t/front/tasks/main.yml][=roles_t/front/tasks/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/front/tasks/main.yml @@ -2388,12 +2080,12 @@ The following tasks install WireGuard™, configure it with - name: Configure WireGuard™. become: yes copy: - src: ../Secret/front-wg0.conf + src: ../private/front-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes @@ -2406,9 +2098,11 @@ The following tasks install WireGuard™, configure it with #+CAPTION: [[file:roles_t/front/handlers/main.yml][=roles_t/front/handlers/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/front/handlers/main.yml -- name: Reload WireGuard™. +- name: Restart WireGuard™. become: yes - command: wg setconf wg0 + systemd: + service: wg-quick@wg0 + state: restarted #+END_SRC ** Configure Kamailio @@ -2426,12 +2120,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_vpn_addr~. +specifies the actual IP, known here as ~front_wg_addr~. #+NAME: kamailio #+CAPTION: ~kamailio~ #+BEGIN_SRC conf -listen=udp:{{ front_vpn_addr }}:5060 listen=udp:{{ front_wg_addr }}:5060 #+END_SRC @@ -2451,9 +2144,9 @@ The first step is to install Kamailio. #+END_SRC Now the configuration drop concerns the network device on which -Kamailio will be listening, the ~ovpn~ device created by OpenVPN. The -added configuration settings inform Systemd that Kamailio should not -be started before the ~ovpn~ 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. #+CAPTION: [[file:roles_t/front/tasks/main.yml][=roles_t/front/tasks/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/front/tasks/main.yml @@ -2464,13 +2157,13 @@ be started before the ~ovpn~ 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. #+END_SRC @@ -2620,9 +2313,7 @@ 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. Core's Netplan needs the name of its main (only) Ethernet interface, an example of which is given here. (A clever way to extract that name @@ -2705,8 +2396,7 @@ subnet 192.168.56.0 netmask 255.255.255.0 { 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, - 24, 10,177,87, 192,168,56,1, + option rfc3442-routes 24, 10,177,87, 192,168,56,1, 0, 192,168,56,2; } @@ -2829,9 +2519,7 @@ probably be used as forwarders rather than Google. acl "trusted" { {{ private_net_cidr }}; {{ wild_net_cidr }}; - {{ public_vpn_net_cidr }}; {{ public_wg_net_cidr }}; - {{ campus_vpn_net_cidr }}; {{ campus_wg_net_cidr }}; localhost; }; @@ -2871,13 +2559,13 @@ zone "{{ private_net_cidr | ansible.utils.ipaddr('revdns') 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"; @@ -2906,7 +2594,7 @@ www IN CNAME core.small.private. 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 @@ -3136,7 +2824,6 @@ themselves to institute clients. They share the =/etc/server.crt= and notify: - Restart Postfix. - Restart Dovecot. - - Restart OpenVPN. #+END_SRC ** Install NTP @@ -3178,9 +2865,7 @@ Core relays messages from any institute network. - p: mynetworks v: >- {{ private_net_cidr }} - {{ public_vpn_net_cidr }} {{ public_wg_net_cidr }} - {{ campus_vpn_net_cidr }} {{ campus_wg_net_cidr }} 127.0.0.0/8 [::ffff:127.0.0.0]/104 @@ -3192,7 +2877,7 @@ Core uses Front to relay messages to the Internet. #+NAME: postfix-core-relayhost #+CAPTION: ~postfix-core-relayhost~ #+BEGIN_SRC conf -- { p: relayhost, v: "[{{ front_vpn_addr }}]" } +- { p: relayhost, v: "[{{ front_wg_addr }}]" } #+END_SRC Core uses a Postfix transport file, =/etc/postfix/transport=, to @@ -3283,7 +2968,7 @@ enable the service. Whenever =/etc/postfix/transport= is changed, the ** 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 @@ -3393,7 +3078,7 @@ set no spambounce set no syslog #set logfile /home/{{ item }}/.fetchmail.log -poll {{ front_vpn_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 }} @@ -3407,8 +3092,8 @@ The Systemd service description. [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 }} @@ -3769,116 +3454,22 @@ provided [[webupdate][here]]. user: monkey #+END_SRC -** Configure OpenVPN Connection to Front - -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'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~. - -#+NAME: openvpn-core -#+CAPTION: ~openvpn-core~ -#+BEGIN_SRC conf :noweb no-export -client -dev-type tun -dev ovpn -remote {{ front_addr }} -nobind -<> -<> -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 -#+END_SRC - -The tasks that install and configure the OpenVPN client configuration -for Core. - -#+CAPTION: [[file:roles_t/core/tasks/main.yml][=roles_t/core/tasks/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/core/tasks/main.yml :noweb no-export - -- 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: Install OpenVPN secret. - become: yes - copy: - src: ../Secret/front-shared.key - dest: /etc/openvpn/shared.key - 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: | - <> - dest: /etc/openvpn/front.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. - -- name: Enable/Start OpenVPN. - become: yes - systemd: - service: openvpn@front - state: started - enabled: yes -#+END_SRC - -#+CAPTION: [[file:roles_t/core/handlers/main.yml][=roles_t/core/handlers/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/core/handlers/main.yml - -- name: Restart OpenVPN. - become: yes - systemd: - service: openvpn@front - state: restarted -#+END_SRC - ** Configure Core WireGuard™ Interface Core connects to Front's WireGuard™ service to provide members abroad -with a route to the campus networks. As described in [[*Configure Public WireGuard™][Configure -Public WireGuard™]] for Front, Core is expected to forward packets from/to the +with a route to the campus networks. As described in [[*Configure Public WireGuard™][Configure Public +WireGuard™]] for Front, Core is expected to forward packets from/to the private networks. -The following example [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]] configuration recognizes +The following example [[file:private/core-wg0.conf][=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. -#+CAPTION: [[file:Secret/core-wg0.conf][=Secret/core-wg0.conf=]] -#+BEGIN_SRC conf :tangle Secret/core-wg0.conf +#+CAPTION: [[file:private/core-wg0.conf][=private/core-wg0.conf=]] +#+BEGIN_SRC conf :tangle private/core-wg0.conf [Interface] Address = 10.177.87.2 -PrivateKey = AI+KhwnsHzSPqyIyAObx7EBBTBXFZPiXb2/Qcts8zEI= +PostUp = wg set %i private-key /etc/wireguard/private-key # Front [Peer] @@ -3887,9 +3478,10 @@ PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4= AllowedIPs = 10.177.87.1 AllowedIPs = 10.177.87.0/24 #+END_SRC +# TODO: Make this a template? The following tasks install WireGuard™, configure it with -=Secret/core-wg0.conf=, and enable the service. +[[file:private/core-wg0.conf][=private/core-wg0.conf=]], and enable the service. #+CAPTION: [[file:roles_t/core/tasks/main.yml][=roles_t/core/tasks/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/core/tasks/main.yml @@ -3901,12 +3493,12 @@ The following tasks install WireGuard™, configure it with - name: Configure WireGuard™. become: yes copy: - src: ../Secret/core-wg0.conf + src: ../private/core-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes @@ -3919,9 +3511,11 @@ The following tasks install WireGuard™, configure it with #+CAPTION: [[file:roles_t/core/handlers/main.yml][=roles_t/core/handlers/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/core/handlers/main.yml -- name: Reload WireGuard™. +- name: Restart WireGuard™. become: yes - command: wg setconf wg0 + systemd: + service: wg-quick@wg0 + state: restarted #+END_SRC ** Configure NAGIOS @@ -4967,7 +4561,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: @@ -5019,8 +4613,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=. NAT is enabled per the ~ufw-framework(8)~ manual page, by introducing ~nat~ table rules in a block at the end of =/etc/ufw/before.rules=. @@ -5063,23 +4657,20 @@ If "the standard ~iptables-restore~ syntax" as it is described in the know! Forwarding rules are also needed to route packets from the campus VPN -(the ~ovpn~ tunnel device) or WireGuard™ subnet (the ~wg0~ tunnel -device) to the institute's LAN and back. The public VPN on Front will -also be included since its packets arrive at Gate's ~lan~ interface, -coming from Core. Thus forwarding between public and campus VPNs is -also allowed. +(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. #+NAME: ufw-forward-private #+CAPTION: ~ufw-forward-private~ #+BEGIN_SRC conf --A FORWARD -i lan -o ovpn -j ACCEPT --A FORWARD -i ovpn -o lan -j ACCEPT -A FORWARD -i lan -o wg0 -j ACCEPT -A FORWARD -i wg0 -o lan -j ACCEPT #+END_SRC Note that there are no forwarding rules to allow packets to pass from -the ~wild~ device to the ~lan~ device, just the ~ovpn~ device. +the ~wild~ device to the ~lan~ device, just the ~wg0~ device. ** Install UFW @@ -5249,133 +4840,6 @@ and not rebooted, the following command would also be executed. If physically moved or rebooted for some other reason, the above command would not be necessary. -** Install Server Certificate - -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. - -#+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml - -- name: Install 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. -#+END_SRC - -** 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. - -#+NAME: openvpn-gate-routes -#+CAPTION: ~openvpn-gate-routes~ -#+BEGIN_SRC conf -push "route {{ private_net_and_mask }}" -push "route {{ public_vpn_net_and_mask }}" -#+END_SRC - -The complete OpenVPN configuration for Gate includes a ~server~ -option, the pushed routes mentioned above, and the common options -discussed in [[*The VPN Services][The VPN Services]]. - -#+NAME: openvpn-gate -#+CAPTION: ~openvpn-gate~ -#+BEGIN_SRC conf :noweb no-export -server {{ campus_vpn_net_and_mask }} -client-config-dir /etc/openvpn/ccd -<> -<> -<> -<> -<> -<> -<> -<> -ca /usr/local/share/ca-certificates/{{ domain_name }}.crt -cert /etc/server.crt -key /etc/server.key -dh dh2048.pem -tls-crypt shared.key -#+END_SRC - -Finally, here are the tasks (and handler) required to install and -configure the OpenVPN server on Gate. - -#+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml :noweb no-export - -- 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: 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. - become: yes - copy: - src: ../Secret/{{ item.src }} - dest: /etc/openvpn/{{ item.dest }} - mode: u=r,g=,o= - loop: - - { src: gate-dh2048.pem, dest: dh2048.pem } - - { src: gate-shared.key, dest: shared.key } - notify: Restart OpenVPN. - -- name: Configure OpenVPN. - become: yes - copy: - content: | - <> - dest: /etc/openvpn/server.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. -#+END_SRC - -#+CAPTION: [[file:roles_t/gate/handlers/main.yml][=roles_t/gate/handlers/main.yml=]] -#+BEGIN_SRC conf :tangle roles_t/gate/handlers/main.yml - -- name: Restart OpenVPN. - become: yes - systemd: - service: openvpn@server - state: restarted -#+END_SRC - ** Configure Campus WireGuard™ Gate uses WireGuard™ to provide a campus VPN service. Gate's routes @@ -5385,31 +4849,34 @@ institute's private networks: the private Ethernet and the public VPN. additional route Gate needs is to the public VPN via Core. The rest (private Ethernet and campus VPN) are directly connected. -The following example [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]] configuration recognizes -a wired IoT appliance (public key ~LdsCsg~) and a member client, -Dick's Notebook (public key ~4qd4xd~), assigning them the host numbers -3 and 4 respectively. (Dick's Notebook's host number is /not -coincidentally/ 4 here as well as on Front's WireGuard™ subnet.) +The following example [[=private/gate-wg0.conf=][=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. -#+CAPTION: [[file:Secret/gate-wg0.conf][=Secret/gate-wg0.conf=]] -#+BEGIN_SRC conf :tangle Secret/gate-wg0.conf +#+CAPTION: =private/gate-wg0.conf= +#+BEGIN_SRC conf [Interface] Address = 10.84.139.1/24 -PrivateKey = yOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U= ListenPort = 51820 +PostUp = wg set %i private-key /etc/wireguard/private-key -# IoT appliance +# thing [Peer] PublicKey = LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ= AllowedIPs = 10.84.139.3 -# dicks-note +# dick [Peer] PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= AllowedIPs = 10.84.139.4 + +# dicks-razr +[Peer] +PublicKey = zho0qMxoLclJSQu4GeJEcMkk0hx4Q047OcNc8vOejVw= +AllowedIPs = 10.84.139.6 #+END_SRC -The configuration used on the IoT appliance looks like this: +The configuration used on ~thing~, the IoT appliance, looks like this: #+CAPTION: WireGuard™ tunnel on an IoT appliance #+BEGIN_SRC conf @@ -5423,9 +4890,7 @@ PublicKey = y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI= AllowedIPs = 10.84.139.1 AllowedIPs = 10.84.139.0/24 AllowedIPs = 192.168.56.0/24 -AllowedIPs = 10.177.86.0/24 AllowedIPs = 10.177.87.0/24 -AllowedIPs = 10.84.138.0/24 #+END_SRC And the configuration used on Dick's notebook when it is on campus @@ -5435,7 +4900,7 @@ looks like this: #+BEGIN_SRC conf [Interface] Address = 10.84.139.3 -PrivateKey = WAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs= +PostUp = wg set %i private-key /etc/wireguard/private-key PostUp = resolvectl dns wg0 192.168.56.1 PostUp = resolvectl domain wg0 small.private @@ -5445,13 +4910,11 @@ PublicKey = y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI= AllowedIPs = 10.84.139.1 AllowedIPs = 10.84.139.0/24 AllowedIPs = 192.168.56.0/24 -AllowedIPs = 10.177.86.0/24 AllowedIPs = 10.177.87.0/24 -AllowedIPs = 10.84.138.0/24 #+END_SRC The following tasks install WireGuard™, configure it with -=Secret/gate-wg0.conf=, and enable the service. +[[=private/gate-wg0.conf=][=private/gate-wg0.conf=]], and enable the service. #+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml @@ -5463,12 +4926,12 @@ The following tasks install WireGuard™, configure it with - name: Configure WireGuard™. become: yes copy: - src: ../Secret/gate-wg0.conf + src: ../private/gate-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes @@ -5481,9 +4944,11 @@ The following tasks install WireGuard™, configure it with #+CAPTION: [[file:roles_t/gate/handlers/main.yml][=roles_t/gate/handlers/main.yml=]] #+BEGIN_SRC conf :tangle roles_t/gate/handlers/main.yml -- name: Reload WireGuard™. +- name: Restart WireGuard™. become: yes - command: wg setconf wg0 + systemd: + service: wg-quick@wg0 + state: restarted #+END_SRC @@ -5496,9 +4961,8 @@ server, sync with the campus time server, trust the institute certificate authority, and deliver email addressed to ~root~ to the 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. ** Include Particulars @@ -6107,7 +5571,12 @@ sub mysystem (@) { 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"; #+END_SRC @@ -6124,12 +5593,57 @@ The playbook that updates [[file:private/vars.pl][=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= #+END_SRC +Most of these settings are already in =private/vars.yml=. The +following few provide the servers' public keys and ports. + +#+CAPTION: [[file:private/vars.yml][=private/vars.yml]] +#+BEGIN_SRC conf :tangle 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= +#+END_SRC + +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 Host | WireGuard™ Private Key | +|---------------+----------------------------------------------| +| ~front~ | AJkzVxfTm/KvRjzTN/9X2jYy+CAugiwZfN5F3JTegms= | +| ~gate~ | yOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U= | +| ~core~ | AI+KhwnsHzSPqyIyAObx7EBBTBXFZPiXb2/Qcts8zEI= | +| ~thing~ | KIwQT5eGOl9w1qOa5I+2xx5kJH3z4xdpmirS/eGdsXY= | +| ~dick~ | WAhrlGccPf/BaFS5bRtBE4hEyt3kDxCavmwZfVTsfGs= | +| ~dicks-phone~ | oG/Kou9HOBCBwHAZGypPA1cZWUL6nR6WoxBiXc/OQWQ= | +| ~dicks-razr~ | IGNcF0VpkIBcJQAcLZ9jgRmk0SYyUr/WwSNXZoXXUWQ= | + ** The CA Command The next code block implements the ~CA~ sub-command, which creates a @@ -6182,14 +5696,8 @@ if (defined $ARGV[0] && $ARGV[0] eq "CA") { 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", @@ -6278,15 +5786,17 @@ A new member's record in the ~members~ mapping will have the ~status~ key value ~current~. That key gets value ~former~ when the member leaves.[fn: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.) #+CAPTION: =private/members.yml= #+BEGIN_SRC conf @@ -6295,9 +5805,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: @@ -6311,8 +5821,8 @@ members: 6535633263656434393030333032343533626235653332626330666166613833 usernames: - dick -revoked: -- dick-phone +clients: +- thing 3 LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ= #+END_SRC The test campus starts with the empty membership roll found in @@ -6326,7 +5836,7 @@ is used instead. --- members: usernames: [] -revoked: [] +clients: [] #+END_SRC Both locations go on the ~membership_rolls~ variable used by the @@ -6384,7 +5894,7 @@ sub dump_members_yaml ($$) { 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"}}) { @@ -6394,13 +5904,13 @@ sub dump_members_yaml ($$) { 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"; } @@ -6420,10 +5930,9 @@ each record. #+CAPTION: [[file:inst][=inst=]] #+BEGIN_SRC perl :tangle 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"; @@ -6441,7 +5950,7 @@ sub print_member ($$) { 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 @@ -6487,14 +5996,11 @@ if (defined $ARGV[0] && $ARGV[0] eq "new") { 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; @@ -6818,7 +6324,7 @@ configuration so that the email to root can be encrypted. ** 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). #+CAPTION: [[file:inst][=inst=]] #+BEGIN_SRC perl :tangle inst @@ -6833,9 +6339,7 @@ if (defined $ARGV[0] && $ARGV[0] eq "old") { 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; @@ -6860,158 +6364,227 @@ if (defined $ARGV[0] && $ARGV[0] eq "old") { ** 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 [[file:Secret/][=Secret/=]]. The generated configuration -is slightly different depending on the type of host, given as the -first argument to the command. - -- ~./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 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. - -#+NAME: openvpn-up -#+CAPTION: ~openvpn-up~ -#+BEGIN_SRC conf -script-security 2 -up /etc/openvpn/update-systemd-resolved -up-restart -#+END_SRC +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). + +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 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. + +- ~./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.) #+CAPTION: [[file:inst][=inst=]] #+BEGIN_SRC perl :tangle inst :noweb no-export -sub write_template ($$$$$$$$$); -sub read_file ($); -sub add_client ($$$); +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"; } 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" ? "" : " -<>"; - - 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 -<> -remote-cert-tls server -verify-x509-name $NAME name -<>$UP -verb 3 -key-direction 1 -\n$CA -\n$CRT -\n$KEY -\n$TC\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"; } #+END_SRC @@ -7274,7 +6847,7 @@ additional software packages. #+BEGIN_SRC sh sudo apt install netplan.io systemd-resolved unattended-upgrades \ - ufw isc-dhcp-server postfix openvpn + ufw isc-dhcp-server postfix wireguard #+END_SRC Again, the Postfix installation prompts for a couple settings. The @@ -7340,7 +6913,7 @@ additional software packages. #+BEGIN_SRC sh 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}\ @@ -7507,8 +7080,8 @@ name server). Its browser can then connect to ~core.small.private~ to 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. ** Test New Command @@ -7529,7 +7102,7 @@ Take note of Dick's initial password. 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~. #+BEGIN_SRC sh @@ -7553,46 +7126,56 @@ desktop and installs a couple additional software packages (which require several more). #+BEGIN_SRC -sudo apt install network-manager-openvpn-gnome \ - openvpn-systemd-resolved \ - nextcloud-desktop evolution +sudo apt install wireguard nextcloud-desktop evolution #+END_SRC ** 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. #+BEGIN_SRC sh -./inst client debian dick dick +( umask 077; wg genkey >private) +wg pubkey public #+END_SRC -** Test Campus VPN +The administrator uses the key in =public= to run the following +command, generating =campus.conf= and =public.conf= files. -The =campus.ovpn= OpenVPN configuration file (generated in [[*Test Client Command][Test Client -Command]]) is transferred to ~dick~, which is at the Wi-Fi access -point's ~wifi_wan_addr~. +#+BEGIN_SRC sh +./inst client debian dick dick \ + 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= +#+END_SRC + +** Test Campus WireGuard™ Subnet + +The =campus.conf= WireGuard™ configuration file (generated in [[*Test Client Command][Test +Client Command]]) is transferred to ~dick~, which is at the Wi-Fi access +point's IP address, host 2 on the wild Ethernet. #+BEGIN_SRC sh -scp *.ovpn sysadm@192.168.57.2: +scp *.conf sysadm@192.168.57.2: #+END_SRC -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. + +#+BEGIN_SRC sh +systemctl start wg-quick@wg0 +#+END_SRC + +A few basic tests are then performed in a terminal. #+BEGIN_SRC sh 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 @@ -7745,12 +7328,14 @@ machine does not need to be shut down. VBoxManage modifyvm dick --nic1 natnetwork --natnetwork1 premises #+END_SRC -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. + +#+BEGIN_SRC sh +systemctl stop wg-quick@wg0 +systemctl start wg-quick@wg1 +#+END_SRC + +Again, some basics are tested in a terminal. #+BEGIN_SRC sh ping -c 1 8.8.4.4 # dns.google @@ -7818,8 +7403,8 @@ retires ~dick~ and his main device ~dick~. #+END_SRC 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. * Future Work @@ -7841,30 +7426,8 @@ non-trivial task that must ignore intentional changes. Monkey's ~cron~ jobs on Core should be ~systemd.timer~ and ~.service~ 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. ** More Tests diff --git a/Secret/CA/pki/certs_by_serial/5BC4C03F376A8688415E10F3BCAD905E.pem b/Secret/CA/pki/certs_by_serial/5BC4C03F376A8688415E10F3BCAD905E.pem deleted file mode 100644 index 5fe5605..0000000 --- a/Secret/CA/pki/certs_by_serial/5BC4C03F376A8688415E10F3BCAD905E.pem +++ /dev/null @@ -1,88 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 5b:c4:c0:3f:37:6a:86:88:41:5e:10:f3:bc:ad:90:5e - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Small Institute LLC - Validity - Not Before: Dec 28 00:41:53 2023 GMT - Not After : Apr 1 00:41:53 2026 GMT - Subject: CN=gate.small.private - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a7:da:84:ff:f6:57:28:31:8d:d3:2b:53:ea:d0: - 0e:55:67:c4:bd:48:b5:50:e2:e0:46:ab:71:ff:45: - bf:cc:7d:64:01:63:6b:80:2d:8b:7b:3f:2b:17:5b: - e5:4c:c4:6a:59:6e:b8:04:3c:5e:df:ab:d1:54:4b: - 7e:88:fc:8f:74:c0:c6:ca:6c:b5:31:12:f0:6b:8f: - 63:2c:b8:01:e7:d0:c3:c2:76:f3:42:f2:c4:e6:b0: - a0:75:00:41:bb:83:35:5f:15:fc:f7:ba:2a:5a:92: - 6f:f4:17:09:e1:66:e6:05:23:1c:40:97:24:07:3f: - 48:1d:23:60:04:90:1f:bc:4e:38:1d:05:35:2c:a9: - 36:2b:b7:3d:b4:ea:3f:f5:2e:02:14:70:4b:56:52: - 3d:c9:2b:c8:e2:5c:9a:bf:cb:9a:9b:22:d3:85:c1: - a8:bf:c6:7e:c9:57:b9:7a:04:5b:9a:22:60:f4:c8: - 0e:fe:ea:f4:8c:4e:f4:c4:06:00:be:9d:7e:13:b9: - e0:87:b7:37:78:8b:f5:e3:d3:7d:d8:eb:5a:a4:f4: - 9b:b0:fe:1f:f7:8d:2b:f8:27:1d:5b:aa:c0:5b:c5: - f4:a1:91:34:49:cd:47:69:ad:0c:d4:92:fa:d0:1b: - d9:f8:e7:e7:de:a0:3e:d1:75:d3:d3:9c:d8:df:db: - 6c:97 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - X509v3 Subject Key Identifier: - 67:47:45:12:EA:0F:59:B8:34:4E:B1:E7:D6:8D:2A:09:18:67:F7:61 - X509v3 Authority Key Identifier: - keyid:1F:BA:80:AC:5A:8B:8B:25:4E:BF:23:64:A2:AE:A9:51:03:7C:B1:3B - DirName:/CN=Small Institute LLC - serial:66:16:EF:1C:05:B8:67:63:85:57:20:2D:DC:FB:36:A6:16:97:DC:33 - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Key Usage: - Digital Signature, Key Encipherment - X509v3 Subject Alternative Name: - DNS:gate.small.private - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 73:47:a3:51:15:cd:44:5e:67:79:dd:68:32:f3:32:e6:35:4e: - 0a:da:a4:c5:eb:07:12:f9:41:72:a0:95:e6:34:5c:66:e9:7a: - 53:be:1c:87:9f:b3:b2:5c:65:9a:5f:a1:31:62:90:bb:3d:a2: - 9a:84:ef:f8:5a:7c:e1:c8:13:67:df:50:ae:9b:6d:e4:3b:31: - 80:1f:f6:34:83:31:6f:fe:0f:9a:15:d4:85:ab:dd:a5:30:2e: - 35:85:72:01:9a:fb:4a:ab:49:5e:e4:68:ef:11:d4:20:81:9e: - f0:be:6a:e8:ed:0c:8f:2c:20:38:93:be:f3:b9:31:f2:3b:c4: - 7f:80:5a:a8:bb:03:76:95:1b:74:93:76:ef:60:9f:29:ae:fa: - d0:79:18:dd:e4:c8:f2:d6:9b:93:3d:d6:a6:07:ef:7c:ed:c7: - 77:91:35:36:bb:ec:47:75:f5:fd:41:92:aa:fe:a5:fa:02:c7: - 0c:7c:b6:8a:c5:be:02:df:52:ae:5c:a9:9a:c0:88:7e:f3:9a: - cc:c2:a7:ec:b9:48:47:c7:9c:39:6e:08:2d:2a:0f:c8:18:36: - ed:9b:ff:9e:0a:ea:2d:ee:66:89:28:7b:56:aa:a5:b7:61:6f: - eb:79:97:e0:3b:0e:70:12:f3:3b:5f:d5:4e:79:64:e3:a7:32: - ec:c2:35:1f ------BEGIN CERTIFICATE----- -MIIDjzCCAnegAwIBAgIQW8TAPzdqhohBXhDzvK2QXjANBgkqhkiG9w0BAQsFADAe -MRwwGgYDVQQDDBNTbWFsbCBJbnN0aXR1dGUgTExDMB4XDTIzMTIyODAwNDE1M1oX -DTI2MDQwMTAwNDE1M1owHTEbMBkGA1UEAwwSZ2F0ZS5zbWFsbC5wcml2YXRlMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp9qE//ZXKDGN0ytT6tAOVWfE -vUi1UOLgRqtx/0W/zH1kAWNrgC2Lez8rF1vlTMRqWW64BDxe36vRVEt+iPyPdMDG -ymy1MRLwa49jLLgB59DDwnbzQvLE5rCgdQBBu4M1XxX897oqWpJv9BcJ4WbmBSMc -QJckBz9IHSNgBJAfvE44HQU1LKk2K7c9tOo/9S4CFHBLVlI9ySvI4lyav8uamyLT -hcGov8Z+yVe5egRbmiJg9MgO/ur0jE70xAYAvp1+E7ngh7c3eIv149N92OtapPSb -sP4f940r+CcdW6rAW8X0oZE0Sc1Haa0M1JL60BvZ+Ofn3qA+0XXT05zY39tslwID -AQABo4HJMIHGMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGdHRRLqD1m4NE6x59aNKgkY -Z/dhMFkGA1UdIwRSMFCAFB+6gKxai4slTr8jZKKuqVEDfLE7oSKkIDAeMRwwGgYD -VQQDDBNTbWFsbCBJbnN0aXR1dGUgTExDghRmFu8cBbhnY4VXIC3c+zamFpfcMzAT -BgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwHQYDVR0RBBYwFIISZ2F0 -ZS5zbWFsbC5wcml2YXRlMA0GCSqGSIb3DQEBCwUAA4IBAQBzR6NRFc1EXmd53Wgy -8zLmNU4K2qTF6wcS+UFyoJXmNFxm6XpTvhyHn7OyXGWaX6ExYpC7PaKahO/4Wnzh -yBNn31Cum23kOzGAH/Y0gzFv/g+aFdSFq92lMC41hXIBmvtKq0le5GjvEdQggZ7w -vmro7QyPLCA4k77zuTHyO8R/gFqouwN2lRt0k3bvYJ8prvrQeRjd5Mjy1puTPdam -B+987cd3kTU2u+xHdfX9QZKq/qX6AscMfLaKxb4C31KuXKmawIh+85rMwqfsuUhH -x5w5bggtKg/IGDbtm/+eCuot7maJKHtWqqW3YW/reZfgOw5wEvM7X9VOeWTjpzLs -wjUf ------END CERTIFICATE----- diff --git a/Secret/CA/pki/certs_by_serial/B0C65C6B0A978A7897BA90C7E68C7FF0.pem b/Secret/CA/pki/certs_by_serial/B0C65C6B0A978A7897BA90C7E68C7FF0.pem deleted file mode 100644 index df14768..0000000 --- a/Secret/CA/pki/certs_by_serial/B0C65C6B0A978A7897BA90C7E68C7FF0.pem +++ /dev/null @@ -1,85 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - b0:c6:5c:6b:0a:97:8a:78:97:ba:90:c7:e6:8c:7f:f0 - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Small Institute LLC - Validity - Not Before: Dec 28 00:41:54 2023 GMT - Not After : Apr 1 00:41:54 2026 GMT - Subject: CN=core - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:9e:e1:f0:02:7e:fa:74:8b:03:8a:64:70:6b:18: - 2d:c8:60:4a:ce:88:f3:4c:ab:76:33:c0:1d:8c:0f: - 97:62:08:2e:3e:46:83:af:66:98:7d:cd:fb:3e:a7: - 3c:96:9e:c9:a1:f9:54:1f:90:c0:db:1b:31:9d:be: - d7:fc:b9:8b:26:ae:34:9e:aa:d5:ef:3b:7e:ee:b3: - 7e:dc:88:07:be:cd:38:19:7d:d4:97:6a:db:12:85: - ce:11:a2:2c:79:aa:2f:cc:4f:67:cf:94:ab:82:cc: - 76:9f:95:18:f2:96:a7:36:25:07:5b:29:61:c3:20: - f8:9d:ff:cd:35:fc:43:bf:dc:4b:fe:ab:c1:bc:68: - b1:f9:db:5d:35:f9:04:28:88:e0:76:74:6f:8b:d5: - c1:f9:20:a3:f3:cb:1f:12:e5:6f:77:0a:ce:c1:31: - e6:e1:c4:10:d1:9a:64:e4:a8:7c:16:4b:84:ed:30: - e5:3e:e4:6f:b6:27:b8:4c:36:2f:44:76:00:75:83: - 5e:ab:91:cc:82:98:c7:57:51:ca:55:5f:2c:a4:f2: - bc:b5:2a:2d:ea:41:8e:93:d9:80:b2:49:af:98:6d: - 94:e2:c4:f1:f0:14:0f:7e:bb:5b:15:9a:30:df:83: - b2:21:7a:3c:6d:58:05:d3:62:fd:f4:f3:f5:d5:42: - 53:53 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - X509v3 Subject Key Identifier: - C1:1F:16:6C:BD:1B:9C:46:D9:41:1F:A3:5B:C7:5B:13:94:6C:A6:DF - X509v3 Authority Key Identifier: - keyid:1F:BA:80:AC:5A:8B:8B:25:4E:BF:23:64:A2:AE:A9:51:03:7C:B1:3B - DirName:/CN=Small Institute LLC - serial:66:16:EF:1C:05:B8:67:63:85:57:20:2D:DC:FB:36:A6:16:97:DC:33 - X509v3 Extended Key Usage: - TLS Web Client Authentication - X509v3 Key Usage: - Digital Signature - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 9a:51:d3:7e:b5:3e:6c:6d:c1:49:f9:14:7a:c2:8b:ae:af:0a: - 72:7e:ac:fd:fe:72:75:fd:e7:79:23:da:03:2e:65:83:d6:b2: - 62:05:5e:88:18:e9:c9:47:26:07:54:9e:c6:50:98:22:72:f3: - 34:1e:d3:c0:3e:73:b2:0a:96:5c:a7:0e:81:54:01:01:ff:86: - 61:4d:20:d7:00:bd:36:5a:09:cc:f3:8e:94:b4:32:18:13:a9: - 34:bf:7f:be:64:d0:c6:2c:3a:4f:64:31:d5:e8:0a:ed:7a:3d: - 99:2a:79:1e:00:20:44:92:e5:82:ee:43:f9:83:cd:1f:fb:75: - cf:af:5e:f7:a7:2c:98:af:e8:07:f6:22:72:a0:b9:84:01:0a: - 7c:3c:57:f8:b1:db:33:b7:13:cf:57:25:72:10:88:49:c7:9f: - 70:8a:59:ea:71:5c:ac:94:07:cf:05:ce:b5:0f:57:3c:4c:47: - f2:1a:d0:f7:d7:bb:a5:04:57:33:85:c5:8d:2c:05:b9:7d:f6: - a0:24:69:eb:86:94:25:88:78:0e:a6:a8:80:10:5b:5b:84:c1: - a2:2e:42:fd:9e:00:dc:db:5f:ba:b4:8c:0d:34:43:06:0d:d8: - 7e:06:4e:51:64:2a:5e:1b:03:64:ce:a2:fd:41:9c:01:de:d6: - 45:fb:42:72 ------BEGIN CERTIFICATE----- -MIIDYzCCAkugAwIBAgIRALDGXGsKl4p4l7qQx+aMf/AwDQYJKoZIhvcNAQELBQAw -HjEcMBoGA1UEAwwTU21hbGwgSW5zdGl0dXRlIExMQzAeFw0yMzEyMjgwMDQxNTRa -Fw0yNjA0MDEwMDQxNTRaMA8xDTALBgNVBAMMBGNvcmUwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQCe4fACfvp0iwOKZHBrGC3IYErOiPNMq3YzwB2MD5di -CC4+RoOvZph9zfs+pzyWnsmh+VQfkMDbGzGdvtf8uYsmrjSeqtXvO37us37ciAe+ -zTgZfdSXatsShc4Roix5qi/MT2fPlKuCzHaflRjylqc2JQdbKWHDIPid/801/EO/ -3Ev+q8G8aLH52101+QQoiOB2dG+L1cH5IKPzyx8S5W93Cs7BMebhxBDRmmTkqHwW -S4TtMOU+5G+2J7hMNi9EdgB1g16rkcyCmMdXUcpVXyyk8ry1Ki3qQY6T2YCySa+Y -bZTixPHwFA9+u1sVmjDfg7IhejxtWAXTYv308/XVQlNTAgMBAAGjgaowgacwCQYD -VR0TBAIwADAdBgNVHQ4EFgQUwR8WbL0bnEbZQR+jW8dbE5Rspt8wWQYDVR0jBFIw -UIAUH7qArFqLiyVOvyNkoq6pUQN8sTuhIqQgMB4xHDAaBgNVBAMME1NtYWxsIElu -c3RpdHV0ZSBMTEOCFGYW7xwFuGdjhVcgLdz7NqYWl9wzMBMGA1UdJQQMMAoGCCsG -AQUFBwMCMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAmlHTfrU+bG3B -SfkUesKLrq8Kcn6s/f5ydf3neSPaAy5lg9ayYgVeiBjpyUcmB1SexlCYInLzNB7T -wD5zsgqWXKcOgVQBAf+GYU0g1wC9NloJzPOOlLQyGBOpNL9/vmTQxiw6T2Qx1egK -7Xo9mSp5HgAgRJLlgu5D+YPNH/t1z69e96csmK/oB/YicqC5hAEKfDxX+LHbM7cT -z1clchCIScefcIpZ6nFcrJQHzwXOtQ9XPExH8hrQ99e7pQRXM4XFjSwFuX32oCRp -64aUJYh4DqaogBBbW4TBoi5C/Z4A3NtfurSMDTRDBg3YfgZOUWQqXhsDZM6i/UGc -Ad7WRftCcg== ------END CERTIFICATE----- diff --git a/Secret/CA/pki/index.txt b/Secret/CA/pki/index.txt index 6542964..dc137de 100644 --- a/Secret/CA/pki/index.txt +++ b/Secret/CA/pki/index.txt @@ -1,4 +1,2 @@ V 260401004153Z 1D7FC1A54BC58C35B3E300C337CABFA8 unknown /CN=small.example.org -V 260401004153Z 5BC4C03F376A8688415E10F3BCAD905E unknown /CN=gate.small.private V 260401004154Z C9AC3501E1D4CEF58E104B8674B99987 unknown /CN=core.small.private -V 260401004154Z B0C65C6B0A978A7897BA90C7E68C7FF0 unknown /CN=core diff --git a/Secret/CA/pki/index.txt.old b/Secret/CA/pki/index.txt.old index c22d05c..dc137de 100644 --- a/Secret/CA/pki/index.txt.old +++ b/Secret/CA/pki/index.txt.old @@ -1,3 +1,2 @@ V 260401004153Z 1D7FC1A54BC58C35B3E300C337CABFA8 unknown /CN=small.example.org -V 260401004153Z 5BC4C03F376A8688415E10F3BCAD905E unknown /CN=gate.small.private V 260401004154Z C9AC3501E1D4CEF58E104B8674B99987 unknown /CN=core.small.private diff --git a/Secret/CA/pki/issued/core.crt b/Secret/CA/pki/issued/core.crt deleted file mode 100644 index df14768..0000000 --- a/Secret/CA/pki/issued/core.crt +++ /dev/null @@ -1,85 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - b0:c6:5c:6b:0a:97:8a:78:97:ba:90:c7:e6:8c:7f:f0 - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Small Institute LLC - Validity - Not Before: Dec 28 00:41:54 2023 GMT - Not After : Apr 1 00:41:54 2026 GMT - Subject: CN=core - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:9e:e1:f0:02:7e:fa:74:8b:03:8a:64:70:6b:18: - 2d:c8:60:4a:ce:88:f3:4c:ab:76:33:c0:1d:8c:0f: - 97:62:08:2e:3e:46:83:af:66:98:7d:cd:fb:3e:a7: - 3c:96:9e:c9:a1:f9:54:1f:90:c0:db:1b:31:9d:be: - d7:fc:b9:8b:26:ae:34:9e:aa:d5:ef:3b:7e:ee:b3: - 7e:dc:88:07:be:cd:38:19:7d:d4:97:6a:db:12:85: - ce:11:a2:2c:79:aa:2f:cc:4f:67:cf:94:ab:82:cc: - 76:9f:95:18:f2:96:a7:36:25:07:5b:29:61:c3:20: - f8:9d:ff:cd:35:fc:43:bf:dc:4b:fe:ab:c1:bc:68: - b1:f9:db:5d:35:f9:04:28:88:e0:76:74:6f:8b:d5: - c1:f9:20:a3:f3:cb:1f:12:e5:6f:77:0a:ce:c1:31: - e6:e1:c4:10:d1:9a:64:e4:a8:7c:16:4b:84:ed:30: - e5:3e:e4:6f:b6:27:b8:4c:36:2f:44:76:00:75:83: - 5e:ab:91:cc:82:98:c7:57:51:ca:55:5f:2c:a4:f2: - bc:b5:2a:2d:ea:41:8e:93:d9:80:b2:49:af:98:6d: - 94:e2:c4:f1:f0:14:0f:7e:bb:5b:15:9a:30:df:83: - b2:21:7a:3c:6d:58:05:d3:62:fd:f4:f3:f5:d5:42: - 53:53 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - X509v3 Subject Key Identifier: - C1:1F:16:6C:BD:1B:9C:46:D9:41:1F:A3:5B:C7:5B:13:94:6C:A6:DF - X509v3 Authority Key Identifier: - keyid:1F:BA:80:AC:5A:8B:8B:25:4E:BF:23:64:A2:AE:A9:51:03:7C:B1:3B - DirName:/CN=Small Institute LLC - serial:66:16:EF:1C:05:B8:67:63:85:57:20:2D:DC:FB:36:A6:16:97:DC:33 - X509v3 Extended Key Usage: - TLS Web Client Authentication - X509v3 Key Usage: - Digital Signature - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 9a:51:d3:7e:b5:3e:6c:6d:c1:49:f9:14:7a:c2:8b:ae:af:0a: - 72:7e:ac:fd:fe:72:75:fd:e7:79:23:da:03:2e:65:83:d6:b2: - 62:05:5e:88:18:e9:c9:47:26:07:54:9e:c6:50:98:22:72:f3: - 34:1e:d3:c0:3e:73:b2:0a:96:5c:a7:0e:81:54:01:01:ff:86: - 61:4d:20:d7:00:bd:36:5a:09:cc:f3:8e:94:b4:32:18:13:a9: - 34:bf:7f:be:64:d0:c6:2c:3a:4f:64:31:d5:e8:0a:ed:7a:3d: - 99:2a:79:1e:00:20:44:92:e5:82:ee:43:f9:83:cd:1f:fb:75: - cf:af:5e:f7:a7:2c:98:af:e8:07:f6:22:72:a0:b9:84:01:0a: - 7c:3c:57:f8:b1:db:33:b7:13:cf:57:25:72:10:88:49:c7:9f: - 70:8a:59:ea:71:5c:ac:94:07:cf:05:ce:b5:0f:57:3c:4c:47: - f2:1a:d0:f7:d7:bb:a5:04:57:33:85:c5:8d:2c:05:b9:7d:f6: - a0:24:69:eb:86:94:25:88:78:0e:a6:a8:80:10:5b:5b:84:c1: - a2:2e:42:fd:9e:00:dc:db:5f:ba:b4:8c:0d:34:43:06:0d:d8: - 7e:06:4e:51:64:2a:5e:1b:03:64:ce:a2:fd:41:9c:01:de:d6: - 45:fb:42:72 ------BEGIN CERTIFICATE----- -MIIDYzCCAkugAwIBAgIRALDGXGsKl4p4l7qQx+aMf/AwDQYJKoZIhvcNAQELBQAw -HjEcMBoGA1UEAwwTU21hbGwgSW5zdGl0dXRlIExMQzAeFw0yMzEyMjgwMDQxNTRa -Fw0yNjA0MDEwMDQxNTRaMA8xDTALBgNVBAMMBGNvcmUwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQCe4fACfvp0iwOKZHBrGC3IYErOiPNMq3YzwB2MD5di -CC4+RoOvZph9zfs+pzyWnsmh+VQfkMDbGzGdvtf8uYsmrjSeqtXvO37us37ciAe+ -zTgZfdSXatsShc4Roix5qi/MT2fPlKuCzHaflRjylqc2JQdbKWHDIPid/801/EO/ -3Ev+q8G8aLH52101+QQoiOB2dG+L1cH5IKPzyx8S5W93Cs7BMebhxBDRmmTkqHwW -S4TtMOU+5G+2J7hMNi9EdgB1g16rkcyCmMdXUcpVXyyk8ry1Ki3qQY6T2YCySa+Y -bZTixPHwFA9+u1sVmjDfg7IhejxtWAXTYv308/XVQlNTAgMBAAGjgaowgacwCQYD -VR0TBAIwADAdBgNVHQ4EFgQUwR8WbL0bnEbZQR+jW8dbE5Rspt8wWQYDVR0jBFIw -UIAUH7qArFqLiyVOvyNkoq6pUQN8sTuhIqQgMB4xHDAaBgNVBAMME1NtYWxsIElu -c3RpdHV0ZSBMTEOCFGYW7xwFuGdjhVcgLdz7NqYWl9wzMBMGA1UdJQQMMAoGCCsG -AQUFBwMCMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAmlHTfrU+bG3B -SfkUesKLrq8Kcn6s/f5ydf3neSPaAy5lg9ayYgVeiBjpyUcmB1SexlCYInLzNB7T -wD5zsgqWXKcOgVQBAf+GYU0g1wC9NloJzPOOlLQyGBOpNL9/vmTQxiw6T2Qx1egK -7Xo9mSp5HgAgRJLlgu5D+YPNH/t1z69e96csmK/oB/YicqC5hAEKfDxX+LHbM7cT -z1clchCIScefcIpZ6nFcrJQHzwXOtQ9XPExH8hrQ99e7pQRXM4XFjSwFuX32oCRp -64aUJYh4DqaogBBbW4TBoi5C/Z4A3NtfurSMDTRDBg3YfgZOUWQqXhsDZM6i/UGc -Ad7WRftCcg== ------END CERTIFICATE----- diff --git a/Secret/CA/pki/issued/gate.small.private.crt b/Secret/CA/pki/issued/gate.small.private.crt deleted file mode 100644 index 5fe5605..0000000 --- a/Secret/CA/pki/issued/gate.small.private.crt +++ /dev/null @@ -1,88 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 5b:c4:c0:3f:37:6a:86:88:41:5e:10:f3:bc:ad:90:5e - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Small Institute LLC - Validity - Not Before: Dec 28 00:41:53 2023 GMT - Not After : Apr 1 00:41:53 2026 GMT - Subject: CN=gate.small.private - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a7:da:84:ff:f6:57:28:31:8d:d3:2b:53:ea:d0: - 0e:55:67:c4:bd:48:b5:50:e2:e0:46:ab:71:ff:45: - bf:cc:7d:64:01:63:6b:80:2d:8b:7b:3f:2b:17:5b: - e5:4c:c4:6a:59:6e:b8:04:3c:5e:df:ab:d1:54:4b: - 7e:88:fc:8f:74:c0:c6:ca:6c:b5:31:12:f0:6b:8f: - 63:2c:b8:01:e7:d0:c3:c2:76:f3:42:f2:c4:e6:b0: - a0:75:00:41:bb:83:35:5f:15:fc:f7:ba:2a:5a:92: - 6f:f4:17:09:e1:66:e6:05:23:1c:40:97:24:07:3f: - 48:1d:23:60:04:90:1f:bc:4e:38:1d:05:35:2c:a9: - 36:2b:b7:3d:b4:ea:3f:f5:2e:02:14:70:4b:56:52: - 3d:c9:2b:c8:e2:5c:9a:bf:cb:9a:9b:22:d3:85:c1: - a8:bf:c6:7e:c9:57:b9:7a:04:5b:9a:22:60:f4:c8: - 0e:fe:ea:f4:8c:4e:f4:c4:06:00:be:9d:7e:13:b9: - e0:87:b7:37:78:8b:f5:e3:d3:7d:d8:eb:5a:a4:f4: - 9b:b0:fe:1f:f7:8d:2b:f8:27:1d:5b:aa:c0:5b:c5: - f4:a1:91:34:49:cd:47:69:ad:0c:d4:92:fa:d0:1b: - d9:f8:e7:e7:de:a0:3e:d1:75:d3:d3:9c:d8:df:db: - 6c:97 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - X509v3 Subject Key Identifier: - 67:47:45:12:EA:0F:59:B8:34:4E:B1:E7:D6:8D:2A:09:18:67:F7:61 - X509v3 Authority Key Identifier: - keyid:1F:BA:80:AC:5A:8B:8B:25:4E:BF:23:64:A2:AE:A9:51:03:7C:B1:3B - DirName:/CN=Small Institute LLC - serial:66:16:EF:1C:05:B8:67:63:85:57:20:2D:DC:FB:36:A6:16:97:DC:33 - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Key Usage: - Digital Signature, Key Encipherment - X509v3 Subject Alternative Name: - DNS:gate.small.private - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 73:47:a3:51:15:cd:44:5e:67:79:dd:68:32:f3:32:e6:35:4e: - 0a:da:a4:c5:eb:07:12:f9:41:72:a0:95:e6:34:5c:66:e9:7a: - 53:be:1c:87:9f:b3:b2:5c:65:9a:5f:a1:31:62:90:bb:3d:a2: - 9a:84:ef:f8:5a:7c:e1:c8:13:67:df:50:ae:9b:6d:e4:3b:31: - 80:1f:f6:34:83:31:6f:fe:0f:9a:15:d4:85:ab:dd:a5:30:2e: - 35:85:72:01:9a:fb:4a:ab:49:5e:e4:68:ef:11:d4:20:81:9e: - f0:be:6a:e8:ed:0c:8f:2c:20:38:93:be:f3:b9:31:f2:3b:c4: - 7f:80:5a:a8:bb:03:76:95:1b:74:93:76:ef:60:9f:29:ae:fa: - d0:79:18:dd:e4:c8:f2:d6:9b:93:3d:d6:a6:07:ef:7c:ed:c7: - 77:91:35:36:bb:ec:47:75:f5:fd:41:92:aa:fe:a5:fa:02:c7: - 0c:7c:b6:8a:c5:be:02:df:52:ae:5c:a9:9a:c0:88:7e:f3:9a: - cc:c2:a7:ec:b9:48:47:c7:9c:39:6e:08:2d:2a:0f:c8:18:36: - ed:9b:ff:9e:0a:ea:2d:ee:66:89:28:7b:56:aa:a5:b7:61:6f: - eb:79:97:e0:3b:0e:70:12:f3:3b:5f:d5:4e:79:64:e3:a7:32: - ec:c2:35:1f ------BEGIN CERTIFICATE----- -MIIDjzCCAnegAwIBAgIQW8TAPzdqhohBXhDzvK2QXjANBgkqhkiG9w0BAQsFADAe -MRwwGgYDVQQDDBNTbWFsbCBJbnN0aXR1dGUgTExDMB4XDTIzMTIyODAwNDE1M1oX -DTI2MDQwMTAwNDE1M1owHTEbMBkGA1UEAwwSZ2F0ZS5zbWFsbC5wcml2YXRlMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp9qE//ZXKDGN0ytT6tAOVWfE -vUi1UOLgRqtx/0W/zH1kAWNrgC2Lez8rF1vlTMRqWW64BDxe36vRVEt+iPyPdMDG -ymy1MRLwa49jLLgB59DDwnbzQvLE5rCgdQBBu4M1XxX897oqWpJv9BcJ4WbmBSMc -QJckBz9IHSNgBJAfvE44HQU1LKk2K7c9tOo/9S4CFHBLVlI9ySvI4lyav8uamyLT -hcGov8Z+yVe5egRbmiJg9MgO/ur0jE70xAYAvp1+E7ngh7c3eIv149N92OtapPSb -sP4f940r+CcdW6rAW8X0oZE0Sc1Haa0M1JL60BvZ+Ofn3qA+0XXT05zY39tslwID -AQABo4HJMIHGMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGdHRRLqD1m4NE6x59aNKgkY -Z/dhMFkGA1UdIwRSMFCAFB+6gKxai4slTr8jZKKuqVEDfLE7oSKkIDAeMRwwGgYD -VQQDDBNTbWFsbCBJbnN0aXR1dGUgTExDghRmFu8cBbhnY4VXIC3c+zamFpfcMzAT -BgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwHQYDVR0RBBYwFIISZ2F0 -ZS5zbWFsbC5wcml2YXRlMA0GCSqGSIb3DQEBCwUAA4IBAQBzR6NRFc1EXmd53Wgy -8zLmNU4K2qTF6wcS+UFyoJXmNFxm6XpTvhyHn7OyXGWaX6ExYpC7PaKahO/4Wnzh -yBNn31Cum23kOzGAH/Y0gzFv/g+aFdSFq92lMC41hXIBmvtKq0le5GjvEdQggZ7w -vmro7QyPLCA4k77zuTHyO8R/gFqouwN2lRt0k3bvYJ8prvrQeRjd5Mjy1puTPdam -B+987cd3kTU2u+xHdfX9QZKq/qX6AscMfLaKxb4C31KuXKmawIh+85rMwqfsuUhH -x5w5bggtKg/IGDbtm/+eCuot7maJKHtWqqW3YW/reZfgOw5wEvM7X9VOeWTjpzLs -wjUf ------END CERTIFICATE----- diff --git a/Secret/CA/pki/private/core.key b/Secret/CA/pki/private/core.key deleted file mode 100644 index e1218d3..0000000 --- a/Secret/CA/pki/private/core.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCe4fACfvp0iwOK -ZHBrGC3IYErOiPNMq3YzwB2MD5diCC4+RoOvZph9zfs+pzyWnsmh+VQfkMDbGzGd -vtf8uYsmrjSeqtXvO37us37ciAe+zTgZfdSXatsShc4Roix5qi/MT2fPlKuCzHaf -lRjylqc2JQdbKWHDIPid/801/EO/3Ev+q8G8aLH52101+QQoiOB2dG+L1cH5IKPz -yx8S5W93Cs7BMebhxBDRmmTkqHwWS4TtMOU+5G+2J7hMNi9EdgB1g16rkcyCmMdX -UcpVXyyk8ry1Ki3qQY6T2YCySa+YbZTixPHwFA9+u1sVmjDfg7IhejxtWAXTYv30 -8/XVQlNTAgMBAAECggEAAcV9uKsAxBIVHbkyXBQeoo7MSew5LKAp+h677zO9s0A2 -TJR0FtCoH5lcO6qyrSOjfOGIrUdrlww0RYPhgmkkYryFGRKV8XJlrAFzulkiUpLI -LtfHA7jGk4WXzBa75zYqDUQClMwEDSCWRZlseBWM7LiFK5OIPWkD/8/HBafErs8G -w3Q1LzD1ImC4D0pdGc4vzwVtz29hOIj7QNO6hSuXaQAApXWTQK7n9i7OGyBjj5/2 -ry+zmIK2/tjtAMo1sgbNBMI6EaFL2w8VsjLZcSnr++0TjJP5xXOxGhffKpE4uTIX -I6X1OrHG1HlMQYnewA6sgvb3EKJINNwa4wApO5VhsQKBgQDfOK8c2aA0fii8aHlb -esIzQypvbahcEacP5Kf70TCHlzLkWnP8hMiybl9RyXJ78YXSq+8Y4d3a+sERta8M -Z5TndHmEbJMF/ft6cxVikT4QiJm4QL528LCHy+XoAaNMtgrUnVcQNrIk8ABOkc0q -I/PV1diAuKZ7NnxOgHeaZ8p8YwKBgQC2NqJYgpkCScEekx9Q5GZcVkaXTlqS0FDo -LMh8YsaJALybcjDTZRbj8cymCBVsJsK3En2KAMZuERbA5MqVYRE4RPSKqXGFDbEc -X8DJuBcJvFS3f8NswuPUgt84ZoU2I4LCvsGNjU52m//G40MHG8JkSZKoZuZKND9y -j/ivLjCoUQKBgCtRZrokiXBmYyVc6OAVzIYCLMP+9cMYMeFlsCuwBsjpUJj77LI+ -Wmw1+w12GF9xGVUuxHGBs3oBW2JCbbvshfr8oXBPWaC6DwlOOAIuyWqP97TH665N -OxS/PthtKPGECkoEVpbw5lVAte6JYNUisPj4TNF+A+C5TBo31/4A0kydAoGAW8Rc -MtNjGAHpHurdhLHi03IoDx/JAdOkS6nyNqLQdkNGucriyDRLOPWYKa48i8Fhoy3O -x+foB5rXqMIRPPYr4/jmZ8c6gtYIcs/Omkj6YU7WI6xW0bm9YFOg9Bi90ixEOKw1 -coLOF3IteQ8PvM7AMh3TnLhmFs0Ffz7+8csDemECgYEAw69eauRzYj24Q//1vIEk -0AVtERZmgqRAwNaNJTFgwukJtb0+1sKbAkObRy3yuBJmtX9dk20gdNi7MWjbTRWl -aEKKeSERyfbzTdOovxgAAUZk9sjlvbel78B+HhjG5p5/AseGVEnHHzDHEVVGEd9v -bXuMYBr+pIEcsxtk4t0qXQ0= ------END PRIVATE KEY----- diff --git a/Secret/CA/pki/private/gate.small.private.key b/Secret/CA/pki/private/gate.small.private.key deleted file mode 100644 index 176d4b0..0000000 --- a/Secret/CA/pki/private/gate.small.private.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCn2oT/9lcoMY3T -K1Pq0A5VZ8S9SLVQ4uBGq3H/Rb/MfWQBY2uALYt7PysXW+VMxGpZbrgEPF7fq9FU -S36I/I90wMbKbLUxEvBrj2MsuAHn0MPCdvNC8sTmsKB1AEG7gzVfFfz3uipakm/0 -FwnhZuYFIxxAlyQHP0gdI2AEkB+8TjgdBTUsqTYrtz206j/1LgIUcEtWUj3JK8ji -XJq/y5qbItOFwai/xn7JV7l6BFuaImD0yA7+6vSMTvTEBgC+nX4TueCHtzd4i/Xj -033Y61qk9Juw/h/3jSv4Jx1bqsBbxfShkTRJzUdprQzUkvrQG9n45+feoD7RddPT -nNjf22yXAgMBAAECggEAGWx9QaHH0MQ0tZv18XaC/Uei4oKtR+udScb1FNO1Od1y -NM2gvkDnxAqs1bRrFkYXz6T4BVg5jIpjQe/PYiNS/T2nvohZp221ca09ucvDKiAS -TpWiweywizqMizw3OJYmktjrQIB3otFUWLXWnsftpjCLunLKF7jrjNJLXFWSIPy/ -MkWT1TFTIJsrjhvfPbh+f+OO1Jtdb9V9NOQdtAzvZMB2lK1BLPEJjEEpoy5ryvir -dKbPBRD9r06zp4NyubOXXxxBhevwR1NfJ3AQAfKgZTs6pi6OLWVMoxIuJOcyZO0K -YXMSeAM5Y1//JOBWy+d2BKh/K+GOUTMHK9FAub3iyQKBgQDPwcG3RkMjta319bbw -yIyVAOhM0J+qHYjrSaCeCJ2P2NPCgVrzcg6SuSydEBg3e+v1knITcrsqDq3OYapd -eCQVIaUaKkZ6c4fxFde3fOgA6Kr6N7Vb8+goZXRAnFKTkudgD4hKUlWbQpTnh2gG -R32M9zNkDBCotwQ+PRnL7sONbwKBgQDO1K/K1g6V8CEUcbsBP7IlGcVUOsYcfeZ8 -GjCHGRYZDfQL646lq4kMxQm6rOV5o5JCCQHGedZOwfY7DIpjWh4jim39iYQGFmTb -65JIubCvqDUNxDKXHaq2bUuvhfd+wOpBTyNPyBmYQOZVK40yMLH0Vs9uQ/2I9Pm3 -w1lZBWZPWQKBgQDC2SyukBY98pHiAX5/GwhGYyB7kpp8eNDGIzqhnODxXWFVpe5A -LnOehk9iSwr7Vpz5p0yYEt2Y10WJLy4SFbB5pSFshcOt6pbPtDWp4FrTJ2Pb4s2U -HRBaerRqOHJ196xK+qZPViL1x59R+jvEz93fjKTFK0+gfG1dVf7QtfDvvwKBgCrA -F13LhNRE//Fj2I1XhxDYFMtmIpC9DSjVmPYznzeqhKj6FU/09qznBS3KktvjjVWM -2wsVH9DDkot9+hSzCcu6zyU6iUlg05QJSwExMG3+TIj95p8JiMGQMbaj8BYI9eJt -4xSYfYHU2Eb+a37WRdIFJ3bZIsxuJjdvb0ZRMWZxAoGAdEflKm0SdtpHzRUKZjLF -jl319XN2ZkJd/Lm47jBDiDP39G3h/0Qs2x7O1kEVFHT/ylZrlu9yFPT6xa4b686r -FTzNS7xmi4kGZ/VACaBB57yF7pBnXj+Bgcb/9gZNAdSJA7zi/4xaU7c8X1udgK+T -0WQ46DtKSF9UfmXdgZUjtA0= ------END PRIVATE KEY----- diff --git a/Secret/CA/pki/reqs/core.req b/Secret/CA/pki/reqs/core.req deleted file mode 100644 index 37920d8..0000000 --- a/Secret/CA/pki/reqs/core.req +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICVDCCATwCAQAwDzENMAsGA1UEAwwEY29yZTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAJ7h8AJ++nSLA4pkcGsYLchgSs6I80yrdjPAHYwPl2IILj5G -g69mmH3N+z6nPJaeyaH5VB+QwNsbMZ2+1/y5iyauNJ6q1e87fu6zftyIB77NOBl9 -1Jdq2xKFzhGiLHmqL8xPZ8+Uq4LMdp+VGPKWpzYlB1spYcMg+J3/zTX8Q7/cS/6r -wbxosfnbXTX5BCiI4HZ0b4vVwfkgo/PLHxLlb3cKzsEx5uHEENGaZOSofBZLhO0w -5T7kb7YnuEw2L0R2AHWDXquRzIKYx1dRylVfLKTyvLUqLepBjpPZgLJJr5htlOLE -8fAUD367WxWaMN+DsiF6PG1YBdNi/fTz9dVCU1MCAwEAAaAAMA0GCSqGSIb3DQEB -CwUAA4IBAQAGg6ZVBzd70SvsfDilCFTWEFhaMpvgZ73UdiEpxxGaRQuN7wFzQipa -KCxdFunQ4lPMoVj7JFM4yu6JvG7ba0B7VqG9HTXV2TpFxBOYeqfEX6Y3xFf/HX0W -uNVTuZTbwKu2/4C/yylWdiN3znm2tZ/+zs28Xy8bCPCOAgWg5BVgWST8EGfNvL3B -InG0fwwXxwYRJEdyT+dUbfH9YKLzrKmlVO33vpxR7u6pIYk7AAL1R5XAkHxdSZJG -3W7TQJEaZf+OKquMbNcBKwNhzLMEeCO3RIVRmmw2xyoPkeivlbG1HGeImnLeA2xm -YDdDPjRy0H61kNPyvhp8EGCsNBebD3D4 ------END CERTIFICATE REQUEST----- diff --git a/Secret/CA/pki/reqs/gate.small.private.req b/Secret/CA/pki/reqs/gate.small.private.req deleted file mode 100644 index b1dc2e2..0000000 --- a/Secret/CA/pki/reqs/gate.small.private.req +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICYjCCAUoCAQAwHTEbMBkGA1UEAwwSZ2F0ZS5zbWFsbC5wcml2YXRlMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp9qE//ZXKDGN0ytT6tAOVWfEvUi1 -UOLgRqtx/0W/zH1kAWNrgC2Lez8rF1vlTMRqWW64BDxe36vRVEt+iPyPdMDGymy1 -MRLwa49jLLgB59DDwnbzQvLE5rCgdQBBu4M1XxX897oqWpJv9BcJ4WbmBSMcQJck -Bz9IHSNgBJAfvE44HQU1LKk2K7c9tOo/9S4CFHBLVlI9ySvI4lyav8uamyLThcGo -v8Z+yVe5egRbmiJg9MgO/ur0jE70xAYAvp1+E7ngh7c3eIv149N92OtapPSbsP4f -940r+CcdW6rAW8X0oZE0Sc1Haa0M1JL60BvZ+Ofn3qA+0XXT05zY39tslwIDAQAB -oAAwDQYJKoZIhvcNAQELBQADggEBAFSpfB5tiD6s9+hzasMy7hJC49SlX4zrZZga -uLgebvtwepPCBclfk8dsI7hr0YtQ8hf/e7sTdNvRUuhv0QetjQV42nP8zV23y20L -E7O65+o1erx3FdFs3ruetZaPsMYdwsZvpnxLKFgb8OEd0VQ6E5bjZzLhxD0JYDjC -D8MBPW8wC3AcR6ZPdCSdmoYl6Y+sFmeoeHLMnXivdSkKcnKR/gcIKdspotoshRp7 -3ZVr73uR8xUKKxslLXvjy3eDT1GcBaD89FUWJcEiG4ylF4hFcrhd/EkfDbNcEDIA -XAnVURPJ3NYIKmSJ7nVurj3mlQLBgig6AH+dpqMn6BLTJ0m80a0= ------END CERTIFICATE REQUEST----- diff --git a/Secret/core-wg0.conf b/Secret/core-wg0.conf deleted file mode 100644 index 0b2a980..0000000 --- a/Secret/core-wg0.conf +++ /dev/null @@ -1,14 +0,0 @@ -[Interface] -Address = 10.177.87.2 -PrivateKey = AI+KhwnsHzSPqyIyAObx7EBBTBXFZPiXb2/Qcts8zEI= -PostUp = iptables -A FORWARD -i %i -j ACCEPT -PostUp = iptables -A FORWARD -o %i -j ACCEPT -PostDown = iptables -D FORWARD -i %i -j ACCEPT -PostDown = iptables -D FORWARD -o %i -j ACCEPT - -# Front -[Peer] -PublicKey = S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4= -AllowedIPs = 10.177.87.1 -AllowedIPs = 10.177.87.0/24 -EndPoint = 192.168.15.5:39608 diff --git a/Secret/front-dh2048.pem b/Secret/front-dh2048.pem deleted file mode 100644 index 4c70ed0..0000000 --- a/Secret/front-dh2048.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEAjBSxtr3Eq9dSD4S7cCewQ0ojCDq0+ZfodrCNacwlAFJWGJPCatjf -6DgFmEf8M2MDYIHq2VhNxhmArWfd6D6Y44NZnYZa537pSD7gYO/Al0g2Wn2O57on -Sn9Dt4vmob2N2L3HxUYITXcc3Cq8q93kMTnEINLChwqwsFmRdeGFWCVBDMMJMX4E -dcRtsv9pWvrps34CZ8jIWwJ9x3n6uhNAfW4Argt7LCI+/wguWnH4b54Ya3QrgveQ -+H0Qi+Zr36HyNuHREzbqYHO1PNbzpAo1BfcvuZyoW6AuF17FaHSOFBpgT0ojmYOw -7NTWRHNuiuhFNOmNPLq1eRt7CWHCfERbiwIBAg== ------END DH PARAMETERS----- diff --git a/Secret/front-shared.key b/Secret/front-shared.key deleted file mode 100644 index 2d8517f..0000000 --- a/Secret/front-shared.key +++ /dev/null @@ -1,21 +0,0 @@ -# -# 2048 bit OpenVPN static key -# ------BEGIN OpenVPN Static key V1----- -38bb9f2e2ecf092249801644212b9546 -9eee27dad596e738c3b290f814e87136 -4e571cf3cfe990c6e2423c6583f00c4a -37c4c11bea6c7b70947dd3473792e973 -6106f6a0b0eb96861ade6b2f641e39ca -59829de1d1d0455afa8510183f6eda5d -2df99306c448d5d4a52699fdced9d45f -5cd650e057eeac3b8ee134dfda4a3f36 -dda2fae254a8fffb2a4aafe5b1f9b505 -7087da1a362df472cf27f7b5690eaac5 -4476c76635f9919506e3922aca44ea72 -5d6ea54559619f85b7b6c830a66e8d95 -be0c0b73830784ea463aa1f4b1a837ba -3f9b90057e30941c6d8ad1ab49a6e4d5 -8215cbe4865e4d0b30f60223dd72b30a -5c2940c22b1cdc3778d060a3cedbc4d4 ------END OpenVPN Static key V1----- diff --git a/Secret/front-wg0.conf b/Secret/front-wg0.conf deleted file mode 100644 index f73fdd6..0000000 --- a/Secret/front-wg0.conf +++ /dev/null @@ -1,21 +0,0 @@ -[Interface] -Address = 10.177.87.1/24 -PrivateKey = AJkzVxfTm/KvRjzTN/9X2jYy+CAugiwZfN5F3JTegms= -ListenPort = 39608 -PostUp = iptables -A FORWARD -i %i -j ACCEPT -PostUp = iptables -A FORWARD -o %i -j ACCEPT -PostDown = iptables -D FORWARD -i %i -j ACCEPT -PostDown = iptables -D FORWARD -o %i -j ACCEPT - -# Core -[Peer] -PublicKey = lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c= -AllowedIPs = 10.177.87.2 -AllowedIPs = 10.177.87.0/24 -AllowedIPs = 192.168.56.0/24 -AllowedIPs = 10.84.138.0/24, 10.84.139.0/24 - -# dicks-note -[Peer] -PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= -AllowedIPs = 10.177.87.4 diff --git a/Secret/gate-dh2048.pem b/Secret/gate-dh2048.pem deleted file mode 100644 index c5e982d..0000000 --- a/Secret/gate-dh2048.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEAlgb0GzS0P+nJEuJ1y4WawxY6/eeO8pUvestFoq+8VbDvm+6xd2WF -mq8X6MpMqwnmqrEbftqRUvAZ+tO/J14AhPGVL9JLXkpOIXkCGR63jpI34UOD9Np7 -XUpNJyHVLcj/pnlOiPEuhiXFFBEez1kXQx8JxEqx1HofO699/8NmlSBxqFPJefCC -6dNYSYfIiF0odZVB+7N0FyHsw5ukCWh+lJAQU3nz9q2WP2+KdtLUCsEyz+w0kI1B -CWAmsekbF05D4vcOTMQ2W1UVthBMJObU2IHg/xfA/9ZUBRFguQzo0H/0AUxM9Fo7 -8AYeoFtNJnw/ZhHXKhGKJQGctcbncCpa4wIBAg== ------END DH PARAMETERS----- diff --git a/Secret/gate-shared.key b/Secret/gate-shared.key deleted file mode 100644 index fec95dc..0000000 --- a/Secret/gate-shared.key +++ /dev/null @@ -1,21 +0,0 @@ -# -# 2048 bit OpenVPN static key -# ------BEGIN OpenVPN Static key V1----- -c5ceb7e1cb1c786f5ad2afd2cc62b2c8 -45fb74fe0116d0e2aad97a9b9066eb30 -6127c851931a6bd97b3e6cf896f09a44 -b0f68b3656d1fa46a73202c0bec5368b -20f23e743d09826169ffbee8328974ea -5134e6c1c9050e31aa02f29722e1df2e -cce6bea69c8ec5d3cf6c1b1b15afcf78 -fad7f12c48436006bab293aba68840cb -88a358378f326a9f99bf09f21028ddf9 -b85b158bce9745663d74f8fd0b217738 -ae90d4da0d151ea458a961dbfeb8e3e5 -59ccd15678a90fa8da9d567e47e1ca10 -80d8706c7cbf6f10a2055258ec337105 -f567a4be6b758438b74f48a54ce86bdd -556abbef5bed0c07cd4fc305b22a3195 -6a6e9093ca2efffc299aa94906e95fc4 ------END OpenVPN Static key V1----- diff --git a/Secret/gate-wg0.conf b/Secret/gate-wg0.conf deleted file mode 100644 index 41f6f70..0000000 --- a/Secret/gate-wg0.conf +++ /dev/null @@ -1,18 +0,0 @@ -[Interface] -Address = 10.84.139.1/24 -PrivateKey = yOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U= -ListenPort = 51820 -PostUp = iptables -A FORWARD -i %i -j ACCEPT -PostUp = iptables -A FORWARD -o %i -j ACCEPT -PostDown = iptables -D FORWARD -i %i -j ACCEPT -PostDown = iptables -D FORWARD -o %i -j ACCEPT - -# IoT appliance -[Peer] -PublicKey = LdsCsgfjKCfd5+VKS+Q/dQhWO8NRNygByDO2VxbXlSQ= -AllowedIPs = 10.84.139.3 - -# dicks-note -[Peer] -PublicKey = 4qd4xdRztZBKhFrX9jI/b4fnMzpKQ5qhg691hwYSsX8= -AllowedIPs = 10.84.139.4 diff --git a/inst b/inst index 43ee139..62cb803 100755 --- a/inst +++ b/inst @@ -58,7 +58,12 @@ sub mysystem (@) { 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"; if (defined $ARGV[0] && $ARGV[0] eq "CA") { @@ -75,14 +80,8 @@ if (defined $ARGV[0] && $ARGV[0] eq "CA") { 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", @@ -177,7 +176,7 @@ sub dump_members_yaml ($$) { 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"}}) { @@ -187,21 +186,20 @@ sub dump_members_yaml ($$) { 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"; } -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"; @@ -219,7 +217,7 @@ sub print_member ($$) { 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 @@ -250,14 +248,11 @@ if (defined $ARGV[0] && $ARGV[0] eq "new") { 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; @@ -350,126 +345,187 @@ if (defined $ARGV[0] && $ARGV[0] eq "old") { 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; } -sub write_template ($$$$$$$$$); -sub read_file ($); -sub add_client ($$$); +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"; } 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" ? "" : " -script-security 2 -up /etc/openvpn/update-systemd-resolved -up-restart"; - - 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 -user nobody -group nogroup -persist-key -persist-tun -remote-cert-tls server -verify-x509-name $NAME name -cipher AES-256-GCM -auth SHA256$UP -verb 3 -key-direction 1 -\n$CA -\n$CRT -\n$KEY -\n$TC\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"; } die "usage: $0 [CA|config|new|pass|old|client] ...\n"; diff --git a/playbooks/check-inst-vars.yml b/playbooks/check-inst-vars.yml index a3215e9..81a29ec 100644 --- a/playbooks/check-inst-vars.yml +++ b/playbooks/check-inst-vars.yml @@ -7,7 +7,22 @@ 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= diff --git a/private/core-dhcpd.conf b/private/core-dhcpd.conf index 72601a8..88a44a7 100644 --- a/private/core-dhcpd.conf +++ b/private/core-dhcpd.conf @@ -17,8 +17,7 @@ subnet 192.168.56.0 netmask 255.255.255.0 { 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, - 24, 10,177,87, 192,168,56,1, + option rfc3442-routes 24, 10,177,87, 192,168,56,1, 0, 192,168,56,2; } diff --git a/private/core-wg0.conf b/private/core-wg0.conf new file mode 100644 index 0000000..c0138d8 --- /dev/null +++ b/private/core-wg0.conf @@ -0,0 +1,10 @@ +[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 diff --git a/private/db.domain b/private/db.domain index d830023..626dc4b 100644 --- a/private/db.domain +++ b/private/db.domain @@ -18,7 +18,7 @@ www IN CNAME core.small.private. 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 diff --git a/private/members-empty.yml b/private/members-empty.yml index 60e422a..5635a85 100644 --- a/private/members-empty.yml +++ b/private/members-empty.yml @@ -1,4 +1,4 @@ --- members: usernames: [] -revoked: [] +clients: [] diff --git a/private/vars.yml b/private/vars.yml index d8e7e72..60ca651 100644 --- a/private/vars.yml +++ b/private/vars.yml @@ -3,9 +3,7 @@ domain_priv: small.private private_net_cidr: 192.168.56.0/24 wild_net_cidr: 192.168.57.0/24 -public_vpn_net_cidr: 10.177.86.0/24 public_wg_net_cidr: 10.177.87.0/24 -campus_vpn_net_cidr: 10.84.138.0/24 campus_wg_net_cidr: 10.84.139.0/24 private_net: @@ -19,24 +17,12 @@ wild_net_mask: wild_net_and_mask: "{{ wild_net }} {{ wild_net_mask }}" wild_net_broadcast: "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}" -public_vpn_net: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('network') }}" -public_vpn_net_mask: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}" -public_vpn_net_and_mask: - "{{ public_vpn_net }} {{ public_vpn_net_mask }}" public_wg_net: "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}" public_wg_net_mask: "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}" public_wg_net_and_mask: "{{ public_wg_net }} {{ public_wg_net_mask }}" -campus_vpn_net: - "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('network') }}" -campus_vpn_net_mask: - "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('netmask') }}" -campus_vpn_net_and_mask: - "{{ campus_vpn_net }} {{ campus_vpn_net_mask }}" campus_wg_net: "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}" campus_wg_net_mask: @@ -48,44 +34,15 @@ core_addr_cidr: "{{ private_net_cidr | ansible.utils.ipaddr('1') }}" 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_vpn_addr_cidr: - "{{ public_vpn_net_cidr | ansible.utils.ipaddr('1') }}" -front_wg_port: 39608 front_wg_addr_cidr: "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}" -core_wg_addr_cidr: - "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}" -wg_client_front_addr_cidr: - "{{ public_wg_net_cidr | ansible.utils.ipaddr('3') }}" -campus_wg_port: 51820 -campus_wg_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('1') }}" -wg_appl_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('2') }}" -wg_client_gate_addr_cidr: - "{{ campus_wg_net_cidr | ansible.utils.ipaddr('3') }}" core_addr: "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}" gate_addr: "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}" gate_wild_addr: "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}" -wifi_wan_addr: - "{{ wifi_wan_addr_cidr | ansible.utils.ipaddr('address') }}" -front_vpn_addr: - "{{ front_vpn_addr_cidr | ansible.utils.ipaddr('address') }}" front_wg_addr: "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -core_wg_addr: - "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_client_front_addr: - "{{ wg_client_front_addr_cidr | ansible.utils.ipaddr('address') }}" -gate_wg_addr: - "{{ campus_wg_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_appl_addr: - "{{ wg_appl_addr_cidr | ansible.utils.ipaddr('address') }}" -wg_client_gate_addr: - "{{ wg_client_gate_addr_cidr | ansible.utils.ipaddr('address') }}" core_ethernet: enp0s3 @@ -97,6 +54,14 @@ gate_lan_mac: 08:00:27:f3:16:79 gate_wild_mac: 08:00:27:4a:de:d2 gate_isp_mac: 08:00:27:3d:42:e5 +front_wg_pubkey: S+6HaTnOwwhWgUGXjSBcPAvifKw+j8BDTRfq534gNW4= +public_wg_port: 39608 + +gate_wg_pubkey: y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI= +campus_wg_port: 51820 + +core_wg_pubkey: lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c= + membership_rolls: - "../private/members.yml" - "../private/members-empty.yml" diff --git a/roles_t/core/handlers/main.yml b/roles_t/core/handlers/main.yml index 3fd628e..d804487 100644 --- a/roles_t/core/handlers/main.yml +++ b/roles_t/core/handlers/main.yml @@ -59,16 +59,12 @@ service: apache2 state: restarted -- name: Restart OpenVPN. +- name: Restart WireGuard™. become: yes systemd: - service: openvpn@front + service: wg-quick@wg0 state: restarted -- name: Reload WireGuard™. - become: yes - command: wg setconf wg0 - - name: Reload NAGIOS4. become: yes systemd: diff --git a/roles_t/core/tasks/main.yml b/roles_t/core/tasks/main.yml index e4ba27d..2710d73 100644 --- a/roles_t/core/tasks/main.yml +++ b/roles_t/core/tasks/main.yml @@ -94,9 +94,7 @@ acl "trusted" { {{ private_net_cidr }}; {{ wild_net_cidr }}; - {{ public_vpn_net_cidr }}; {{ public_wg_net_cidr }}; - {{ campus_vpn_net_cidr }}; {{ campus_wg_net_cidr }}; localhost; }; @@ -138,13 +136,13 @@ 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"; @@ -277,7 +275,6 @@ notify: - Restart Postfix. - Restart Dovecot. - - Restart OpenVPN. - name: Install NTP. become: yes @@ -306,14 +303,12 @@ - p: mynetworks v: >- {{ private_net_cidr }} - {{ public_vpn_net_cidr }} {{ public_wg_net_cidr }} - {{ campus_vpn_net_cidr }} {{ campus_wg_net_cidr }} 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 - - { p: relayhost, v: "[{{ front_vpn_addr }}]" } + - { p: relayhost, v: "[{{ front_wg_addr }}]" } - { p: inet_interfaces, v: "127.0.0.1 {{ core_addr }}" } - { p: transport_maps, v: "hash:/etc/postfix/transport" } notify: Restart Postfix. @@ -385,7 +380,7 @@ set no syslog #set logfile /home/{{ item }}/.fetchmail.log - poll {{ front_vpn_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 }} @@ -406,8 +401,8 @@ [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 }} @@ -596,69 +591,6 @@ name: webupdate user: monkey -- 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: Install OpenVPN secret. - become: yes - copy: - src: ../Secret/front-shared.key - dest: /etc/openvpn/shared.key - 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: | - client - dev-type tun - dev ovpn - remote {{ front_addr }} - nobind - user nobody - group nogroup - persist-key - persist-tun - cipher AES-256-GCM - auth SHA256 - 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 - dest: /etc/openvpn/front.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. - -- name: Enable/Start OpenVPN. - become: yes - systemd: - service: openvpn@front - state: started - enabled: yes - - name: Install WireGuard™. become: yes apt: pkg=wireguard @@ -666,12 +598,12 @@ - name: Configure WireGuard™. become: yes copy: - src: ../Secret/core-wg0.conf + src: ../private/core-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes diff --git a/roles_t/front/handlers/main.yml b/roles_t/front/handlers/main.yml index b5aa9de..0db39f3 100644 --- a/roles_t/front/handlers/main.yml +++ b/roles_t/front/handlers/main.yml @@ -38,16 +38,12 @@ service: apache2 state: restarted -- name: Restart OpenVPN. +- name: Restart WireGuard™. become: yes systemd: - service: openvpn@server + service: wg-quick@wg0 state: restarted -- name: Reload WireGuard™. - become: yes - command: wg setconf wg0 - - name: Reload Systemd. become: yes systemd: diff --git a/roles_t/front/tasks/main.yml b/roles_t/front/tasks/main.yml index 95f52ec..1203e7d 100644 --- a/roles_t/front/tasks/main.yml +++ b/roles_t/front/tasks/main.yml @@ -133,7 +133,6 @@ - { p: smtpd_tls_key_file, v: /etc/server.key } - p: mynetworks v: >- - {{ public_vpn_net_cidr }} {{ public_wg_net_cidr }} 127.0.0.0/8 [::ffff:127.0.0.0]/104 @@ -178,7 +177,7 @@ abuse: root webmaster: root admin: root - monkey: monkey@{{ front_vpn_addr }} + monkey: monkey@{{ front_wg_addr }} root: {{ ansible_user }} path: /etc/aliases marker: "# {mark} INSTITUTE MANAGED BLOCK" @@ -353,108 +352,6 @@ when: members[item].status != 'current' tags: accounts -- 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: | - iroute {{ private_net_and_mask }} - iroute {{ campus_vpn_net_and_mask }} - dest: /etc/openvpn/ccd/core - notify: Restart OpenVPN. - -- name: Disable former VPN clients. - become: yes - copy: - content: "disable\n" - dest: /etc/openvpn/ccd/{{ item }} - loop: "{{ revoked }}" - tags: accounts - -- name: Install OpenVPN server certificate/key. - 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 }} - 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: | - server {{ public_vpn_net_and_mask }} - client-config-dir /etc/openvpn/ccd - route {{ private_net_and_mask }} - route {{ campus_vpn_net_and_mask }} - push "route {{ private_net_and_mask }}" - push "route {{ campus_vpn_net_and_mask }}" - dev-type tun - dev ovpn - topology subnet - client-to-client - keepalive 10 120 - push "dhcp-option DOMAIN {{ domain_priv }}" - push "dhcp-option DNS {{ core_addr }}" - user nobody - group nogroup - persist-key - persist-tun - cipher AES-256-GCM - auth SHA256 - max-clients 20 - ifconfig-pool-persist ipp.txt - status openvpn-status.log - verb 3 - ca /usr/local/share/ca-certificates/{{ domain_name }}.crt - cert server.crt - key server.key - dh dh2048.pem - tls-crypt shared.key - dest: /etc/openvpn/server.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. - -- name: Enable/Start OpenVPN. - become: yes - systemd: - service: openvpn@server - enabled: yes - state: started - - name: Install WireGuard™. become: yes apt: pkg=wireguard @@ -462,12 +359,12 @@ - name: Configure WireGuard™. become: yes copy: - src: ../Secret/front-wg0.conf + src: ../private/front-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes @@ -486,13 +383,13 @@ 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. @@ -500,7 +397,6 @@ become: yes copy: content: | - listen=udp:{{ front_vpn_addr }}:5060 listen=udp:{{ front_wg_addr }}:5060 dest: /etc/kamailio/kamailio-local.cfg notify: Restart Kamailio. diff --git a/roles_t/gate/handlers/main.yml b/roles_t/gate/handlers/main.yml index bcb43a3..857346d 100644 --- a/roles_t/gate/handlers/main.yml +++ b/roles_t/gate/handlers/main.yml @@ -14,12 +14,8 @@ systemd: daemon-reload: yes -- name: Restart OpenVPN. +- name: Restart WireGuard™. become: yes systemd: - service: openvpn@server + service: wg-quick@wg0 state: restarted - -- name: Reload WireGuard™. - become: yes - command: wg setconf wg0 diff --git a/roles_t/gate/tasks/main.yml b/roles_t/gate/tasks/main.yml index 908fa09..5f062ad 100644 --- a/roles_t/gate/tasks/main.yml +++ b/roles_t/gate/tasks/main.yml @@ -29,7 +29,7 @@ addresses: [ {{ core_addr }} ] search: [ {{ domain_priv }} ] routes: - - to: {{ public_vpn_net_cidr }} + - to: {{ public_wg_net_cidr }} via: {{ core_addr }} wild: match: @@ -95,8 +95,6 @@ -A FORWARD -i wild -o isp -j ACCEPT -A FORWARD -i isp -o lan {{ ACCEPT_RELATED }} -A FORWARD -i isp -o wild {{ ACCEPT_RELATED }} - -A FORWARD -i lan -o ovpn -j ACCEPT - -A FORWARD -i ovpn -o lan -j ACCEPT -A FORWARD -i lan -o wg0 -j ACCEPT -A FORWARD -i wg0 -o lan -j ACCEPT COMMIT @@ -137,91 +135,6 @@ enabled: yes state: started -- 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. - -- 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: 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. - become: yes - copy: - src: ../Secret/{{ item.src }} - dest: /etc/openvpn/{{ item.dest }} - mode: u=r,g=,o= - loop: - - { src: gate-dh2048.pem, dest: dh2048.pem } - - { src: gate-shared.key, dest: shared.key } - notify: Restart OpenVPN. - -- name: Configure OpenVPN. - become: yes - copy: - content: | - server {{ campus_vpn_net_and_mask }} - client-config-dir /etc/openvpn/ccd - push "route {{ private_net_and_mask }}" - push "route {{ public_vpn_net_and_mask }}" - dev-type tun - dev ovpn - topology subnet - client-to-client - keepalive 10 120 - push "dhcp-option DOMAIN {{ domain_priv }}" - push "dhcp-option DNS {{ core_addr }}" - user nobody - group nogroup - persist-key - persist-tun - cipher AES-256-GCM - auth SHA256 - max-clients 20 - ifconfig-pool-persist ipp.txt - status openvpn-status.log - verb 3 - ca /usr/local/share/ca-certificates/{{ domain_name }}.crt - cert /etc/server.crt - key /etc/server.key - dh dh2048.pem - tls-crypt shared.key - dest: /etc/openvpn/server.conf - mode: u=r,g=r,o= - notify: Restart OpenVPN. - - name: Install WireGuard™. become: yes apt: pkg=wireguard @@ -229,12 +142,12 @@ - name: Configure WireGuard™. become: yes copy: - src: ../Secret/gate-wg0.conf + src: ../private/gate-wg0.conf dest: /etc/wireguard/wg0.conf mode: u=r,g=,o= owner: root group: root - notify: Reload WireGuard™. + notify: Restart WireGuard™. - name: Enable/Start WireGuard™ on boot. become: yes