#9 Wrote ns and bind installation instructions

master
Keith Irwin 2023-04-07 14:40:11 -06:00
parent 279a461659
commit 28cf55061b
Signed by: ki9
GPG Key ID: DF773B3F4A88DA86
1 changed files with 370 additions and 6 deletions

View File

@ -6,7 +6,7 @@ Before installing wagon, the server needs to be set up with the following basic
- bind9
- openssl ca
Theoretically, wireguard, bind9, and wagon could all live in docker containers, or none of them. If wagon is in docker but either wireguard or bind9 *aren't*, then the wagon container has to use `host` network mode.
Theoretically, wireguard, bind9, and wagon could all live in docker containers, or none of them. If wagon is in docker but either wireguard or bind9 *aren't*, then the wagon container has to use "host" network mode.
Almost all commands in this guide need to be run as root/admin.
@ -52,7 +52,7 @@ net_num=99 # Match what's on the server
srv_listenport=58395 # Match what's on the server
srv_pubkey='XXXXXXXXXXXXXX' # The public key we copied above
psk='YYYYYYYYYYYYYY' # The psk we copied above
srv_endpoint='1.2.3.4' # The server's public IP address
public_ip='1.2.3.4' # The server's public IP address
```
Create the interface on the client and add the server as a peer:
@ -62,7 +62,7 @@ our_privkey="$(wg genkey)"
ip link add dev "${net_name}" type wireguard
ip addr add dev "${net_name}" "10.${net_num}.1.1/8"
echo "${our_privkey}" | wg set "${net_name}" private-key /dev/stdin \
peer "${srv_pubkey}" allowed-ips "10.0.0.0/8" endpoint "${srv_endpoint}:${srv_listenport}" persistent-keepalive 25
peer "${srv_pubkey}" allowed-ips "10.0.0.0/8" endpoint "${public_ip}:${srv_listenport}" persistent-keepalive 25
ip link set up dev "${net_name}"
```
@ -85,12 +85,376 @@ Make sure the client can ping the server with `ping 10.${net_num}.0.1` and the s
## 2. bind9
TODO
These instructions are adapted from [Digital Ocean: How To Configure BIND as a Private Network DNS Server on Ubuntu 22.04 (2022-08)](https://www.digitalocean.com/community/tutorials/how-to-configure-bind-as-a-private-network-dns-server-on-ubuntu-22-04)
On the server, open a root shell and [install bind9 nameserver](https://kb.isc.org/docs/aa-00648). Set some variables to make the rest easier.
```sh
tld='mynet' # The same as $net_name (see below)
net_num='99' # Match what's used with wireguard
public_ip='1.2.3.4' # The server's public IP address, as above
```
The `$tld` should match the `$net_name`, which is the wireguard interface name. Probably using a different `$tld` could be possible in a future version. Ok, let's configure bind. In older documentation, you'll see reference to `named.conf`. In newer versions of bind, this file just includes `named.conf.options` and `named.conf.local`. We will follow this convention too.
If you're already running a nameserver, you can add these configurations alongside your existing settings.
**`/etc/bind/named.conf.options`**
```named.conf
// Access control lists
acl "mynet_acl" {
// change 99 to $net_num
10.99.0.0/16;
};
acl "intervpn_acl" {
10.0.0.0/8;
};
options {
// This is bind's default location for zonefiles
// Just make sure you include it in backups.
directory "/var/cache/bind";
// https://serverfault.com/a/381923
notify explicit;
// Add listen-on-v6 if using IPv6
// Listen on your public IP too if you are
// also running a public nameserver
listen-on {
127.0.0.1; // localhost
10.99.0.1; // VPN
};
// Whom we provide nameservice to
// https://tldp.org/HOWTO/DNS-HOWTO-6.html#ss6.2
recursion yes;
allow-recursion {
localhost; localnets;
intervpn_acl; // or mynet_acl to be more restricitve
};
// Enable DNSSEC validation for forwarded queries
dnssec-validation auto;
// Keep these settings restricted and change them
// per-zone in named.conf.local.
allow-transfer { none; };
allow-query {
localhost; localnets;
};
// If we don't know a domain, forward to these nameservers
// A good list of public nameservers by country:
// https://dnschecker.org/public-dns
forwarders {
1.1.1.1;
8.8.8.8;
};
};
```
That wasn't so bad, was it? Now we'll set the per-zone settings. wagon requires reverse DNS so stop complaining and just do it. I spent a while searching for a good tool to turn IP addresses into their respective rDNS domains before I realized that `nslookup` does that. `nslookup` and `nsupdate` should have been installed with bind; if not, install them.
Ok, let's use nslookup to grab the rDNS domain for our IP:
```sh
nslookup 10.99.0.1
** server can't find 1.0.99.10.in-addr.arpa: NXDOMAIN
```
Now we know that to provide rDNS for all the IPs in `10.99.0.0/16`, we must serve on the entire zone `99.10.in-addr.arpa`. Do this for IPv6 if needed to get a zone ending in `.ip6.arpa`.
**`/etc/bind/named.conf.local`**
```named.conf
// We'll create these keys in the next step
include "/etc/bind/keys/admin.key";
include "/etc/bind/keys/wagon.key";
// mynet is your tld
zone "mynet" {
type master;
// "file" is relative to the "directory" we
// set in named.conf.options
file "mynet.db";
allow-query {
localhost; localnets;
intervpn_acl; // or mynet_acl to be more restricitve
};
// This should be include slave servers AND
// Any machine that will be running wagon
allow-transfer { localhost; 10.99.0.1; };
// This should be set to slave servers
also-notify { localhost; };
// Here we give two keys nsupdate permissions
update-policy {
grant admin zonesub ANY;
grant wagon zonesub ANY;
};
};
// The rDNS zone we got from nslookup
zone "99.10.in-addr.arpa" {
type master;
file "10.99.db"; // relative to "directory"
// The next settings can be copied verbatim from above
allow-query {localhost; localnets; intervpn_acl; };
allow-transfer { localhost; 10.99.0.1; };
update-policy {
grant admin zonesub ANY;
grant wagon zonesub ANY;
};
};
// Any existing zones will live happily alongside
// zone "example.com" {
```
Excellent. This file referenced four files that don't exist yet and must be created. Let's start with the keys. `nsupdate` uses symetric keys, so one copy will live on the bind server and the other will be copied to the nsupdate client.
I like to keep my keys in `/etc/bind/keys`. Let's create this directory and the two keys named above. Actually you should rename the "admin" key as your username and give a different key to each admin. "wagon" is of course the key our future dashboard will use to update the nameserver.
```sh
mkdir /etc/bind/keys
tsig-keygen -a hmac-sha512 admin >/etc/bind/keys/admin.key
tsig-keygen -a hmac-sha512 wagon >/etc/bind/keys/wagon.key
chown -R root:bind /etc/bind/keys
chmod 750 /etc/bind/keys
chmod 640 /etc/bind/keys/*.key
cat /etc/bind/keys/admin.key
```
Copy the key we just catted and paste it into an `admin.key` file on your pc. Now you will be able to modify DNS records by running `nsupdate -k admin.key` on your PC. When we set up wagon, we'll copy the value from `wagon.key` into the wagon config. But let's not get ahead of ourselves, we still have one more thing to do with bind: create the zonefiles.
Firstly, let's assume some variables:
- Our server's $HOSTNAME is `hn` and it's domain name will be `hn.mynet`
- The single wireguard client we set up at `10.99.1.1` is going to get the domain name `pc.myuser.mynet`.
Start with fDNS:
**`/var/cache/bind/mynet.db`**
```bind
$ORIGIN .
$TTL 604800 ; 1 week
mynet IN SOA hn.mynet. myuser.mynet. (
2 ; serial
604800 ; refresh (1 week)
86400 ; retry (1 day)
2419200 ; expire (4 weeks)
604800 ; minimum (1 week)
)
NS hn.mynet.
$ORIGIN mynet.
; Record for our servers
hn A 10.99.0.1
*.hn CNAME hn.mynet.
; Record for our user
$ORIGIN myuser.mynet.
pc A 10.99.1.1
*.pc CNAME pc.myuser.mynet.
```
In the SOA line, there are two values that require explanation:
- **`hn.mynet.`** is the default server `nsupdate` will send updates to. Of course it's our VPN domain, not a public domain name; we don't accept nsupdates from the internet.
- **`myuser.mynet.`** is actually the email `myuser@mynet` and should be set to the server admin. If you want to use a public email address, you can set it to something like `hostmaster.example.com.` for `hostmaster@example.com`.
Now do one for rDNS (same thing goes for the SOA line here):
**`/var/cache/bind/10.99.db`**
```bind
$ORIGIN .
$TTL 604800 ; 1 week
99.10.in-addr.arpa IN SOA hn.mynet. myuser.mynet. (
2 ; serial
604800 ; refresh (1 week)
86400 ; retry (1 day)
2419200 ; expire (4 weeks)
604800 ; minimum (1 week)
)
NS hn.mynet.
; Server records
$ORIGIN 0.99.10.in-addr.arpa.
1 PTR hn.mynet.
; User records
$ORIGIN 1.99.10.in-addr.arpa.
1 PTR pc.myuser.mynet.
```
See, that wasn't so hard! Now start the nameserver and check that it doesn't throw any errors:
```sh
systemctl start named
systemctl enable named
systemctl status named
```
If it's not working, fix it and then go back to your pc and check the lookups.
```sh
nslookup pc.myuser.mynet 10.99.0.1
nslookup hn.mynet 10.99.0.1
nslookup 10.99.0.1 10.99.0.1
nslookup 10.99.1.1 10.99.0.1
```
Each of these commands uses `10.99.0.1` as the nameserver by setting it as the second argument; you can also make that your default nameserver or the nameserver for the `mynet` TLD. Look into setting "search domains" for your VPN interface in your operating system. `systemd-resolved` users, for example, can run these commands:
```sh
resolvectl dns mynet 10.99.0.1
resolvectl domain mynet '~mynet' '~99.10.in-addr.arpa'
```
This will tell the OS to send `.mynet` queries to our vpn nameserver. Not all programs respect this setting though; `dig`, `ping`, and your browser will work but you'll still have to set the nameserver by hand for `nslookup` (as above) and `nsupdate` using the "server" command (even though we set it in our SOA):
```sh
nsupdate -k admin.key
> server 10.99.0.1
> add test.mynet 86400 TXT "hello"
> delete test.mynet TXT
> send
> quit
```
## 3. Certificate authority
TODO
The last major step is to set up the certificate authority. Unlike wireguard and bind, this won't require running some background service; we just generate a few files and keep them safe.
A good place to keep your SSL certs and keys is in `/etc/ssl/private/mynet`. Let's make things easier by setting some variables:
```sh
tld='mynet'
crt_dir="/etc/ssl/private/${tld}"
ca_key="${crt_dir}/_ca.key"
ca_crt="${crt_dir}/_ca.crt"
```
Now we'll create the ca key and cert. You will be asked for some details about your organization; put whatever you want. You'll also be asked to create a passphrase: create and store one using the most secure methods! You'll need this passphrase for the `wagon` config later.
Here we're setting `-days 3650` which will require re-signing and re-distributing the certificate every ten years. You can avoid that by setting it to 100 years with `-days 36500`. This field is required but I think there is no limit, so you can set it to `99999999` if you want.
```sh
openssl genrsa -des3 -out "${ca_key}" 4096
openssl req -x509 -new -nodes -key "${ca_key}" -sha256 -days 3650 -out "${ca_crt}"
ln -s "${ca_crt}" "/etc/ssl/certs/${tld}.pem"
```
The last step makes the cert available to verification from the host OS. This cert file, `/etc/ssl/private/mynet/_ca.crt` should be shared with everyone who will be accessing your network. One easy way to do this is to serve it on your public website at `https://www.example.com/ca.crt` so users can easily download it. It must be added to every user's OS and/or browser. How this is done will depend on the OS and browser... so you should provide instructions to your users! A sample of such instructions can be found at [www.gf4.pw/nebuchadnezzar/ca/](https://www.gf4.pw/nebuchadnezzar/ca/).
We can use these CA files to sign certificates for hosts using our `mynet` domain. Let's sign one for the server first:
```sh
org='My Cool Network'
tld=mynet
host=hn
domain="${host}.${tld}"
crt_dir="/etc/ssl/private/${tld}"
host_dir="${crt_dir}/${host}"
ca_crt="${crt_dir}/_ca.crt"
ca_key="${crt_dir}/_ca.key"
ips='IP:10.99.0.1'
# Create a subdirectory for the host's files
mkdir -p "${host_dir}"
# Generate the host's key
openssl genrsa -out "${host_dir}/server.key" 2048
# Set certificate configuration
# If /etc/ssl/openssl.cnf doesn't exist, look for
# openssl.cnf somewhere in your openssl installation
cat /etc/ssl/openssl.cnf \
<(printf "\n[SAN]\nsubjectAltName=DNS:${domain},DNS:*.${domain},${ips}\n") \
>"${host_dir}.cnf"
# Now we'll create the certificate signing request
openssl req -new -sha256 -reqexts SAN \
-key "${host_dir}/server.key" \
-config "${crt_dir}/${host}.cnf" \
-subj "/O=${org}/OU=${host}/CN=${domain}" \
-out "${crt_dir}/${host}.csr"
# Finally, sign the certificate
# This will request the CA passphrase set previously
# Set -days to whatever you want using the tips above
openssl x509 -req -sha256 -extensions SAN \
-CAcreateserial -days "3650"
-CA "${ca_crt}" -CAkey "${ca_key}" \
-in "${crt_dir}/${host}.csr" \
-extfile "${crt_dir}/${host}.cnf" \
-out "${host_dir}/server.crt"
```
That should do it! Let's check that the cert is valid for all domains and IPs:
```sh
openssl x509 -text -noout -in "${host_dir}/server.crt" | grep -A1 'Subject Alternative Name'
```
That should return something like:
```sh
X509v3 Subject Alternative Name:
DNS:hn.mynet, DNS:*.hn.mynet, IP Address:10.99.0.1
```
It contains our domain, wildcard domain, and IP address. Since everything went well, we can delete the CSR and cnf file:
```sh
rm -f "${crt_dir}/${host}.csr" "${crt_dir}/${host}.cnf"
```
One last thing: we need to generate a certificate and key for our pc. Everything is basically the same as with the server, except that our domain will be `pc.myuser.mynet` instead of `hn.mynet`. So let's breeze through this and check the comments from above if you get confused.
```sh
org='My Cool Network'
tld=mynet
host='pc.myuser'
domain="${host}.${tld}"
crt_dir="/etc/ssl/private/${tld}"
host_dir="${crt_dir}/${host}"
ca_crt="${crt_dir}/_ca.crt"
ca_key="${crt_dir}/_ca.key"
ips='IP:10.99.1.1'
days=3650
mkdir -p "${host_dir}"
openssl genrsa -out "${host_dir}/server.key" 2048
cat /etc/ssl/openssl.cnf \
<(printf "\n[SAN]\nsubjectAltName=DNS:${domain},DNS:*.${domain},${ips}\n") \
>"${host_dir}.cnf"
openssl req -new -sha256 -reqexts SAN \
-key "${host_dir}/server.key" \
-config "${crt_dir}/${host}.cnf" \
-subj "/O=${org}/OU=${host}/CN=${domain}" \
-out "${crt_dir}/${host}.csr"
openssl x509 -req -sha256 -extensions SAN \
-CAcreateserial -days "3650"
-CA "${ca_crt}" -CAkey "${ca_key}" \
-in "${crt_dir}/${host}.csr" \
-extfile "${crt_dir}/${host}.cnf" \
-out "${host_dir}/server.crt"
openssl x509 -text -noout -in "${host_dir}/server.crt" | grep -A1 'Subject Alternative Name'
rm -f "${crt_dir}/${host}.csr" "${crt_dir}/${host}.cnf"
```
You might be thinking, this would all be easier as a script. A script that could add clients to wireguard and bind, then generate and server the ssl files. This is what `wagon` is designed to do.
## 4. Wagon
TODO
Now that we have this all set up, we can use wagon. Wagon will help us add clients to wireguard, give them a domain name in bind, and create SSL certificates for them in a single step on a nice GUI dashboard.
TODO: Finish wagon setup instructions.