#9 Wrote ns and bind installation instructions
parent
279a461659
commit
28cf55061b
376
INSTALL.md
376
INSTALL.md
|
@ -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.
|
Loading…
Reference in New Issue