Compare commits
1 commit
ea8aedd0d6
...
f4f2771ab3
Author | SHA1 | Date | |
---|---|---|---|
f4f2771ab3 |
2 changed files with 6 additions and 179 deletions
|
@ -15,6 +15,9 @@ dataDir = "data"
|
|||
layoutDir = "layouts"
|
||||
publishDir = "public"
|
||||
|
||||
[author]
|
||||
name = "Melora Hugues"
|
||||
|
||||
[taxonomies]
|
||||
category = "blog"
|
||||
tags = "tags"
|
||||
|
@ -53,9 +56,6 @@ author = true
|
|||
logoText = "Hello there!"
|
||||
logoHomeLink = "/"
|
||||
|
||||
[params.author]
|
||||
name = "Melora Hugues"
|
||||
|
||||
[[params.social]]
|
||||
name = "git"
|
||||
url = "https://git.faercol.me"
|
||||
|
|
|
@ -142,185 +142,12 @@ server for that.
|
|||
|
||||
### Configuring the DNS server
|
||||
|
||||
The first step is configuring the DNS server. For this, I'll just use a [bind](https://bind9.readthedocs.io/en/v9.18.27/)
|
||||
server installed from my usual package manager.
|
||||
|
||||
```bash
|
||||
# example on Debian 12
|
||||
sudo apt install bind9
|
||||
```
|
||||
|
||||
Most of the configuration happens in the `/etc/bind` directory, mostly in `/etc/bind/named.conf.local`
|
||||
|
||||
```text
|
||||
root@dns-server: ls /etc/bind/
|
||||
bind.keys db.127 db.empty named.conf named.conf.local rndc.key
|
||||
db.0 db.255 db.local named.conf.default-zones named.conf.options zones.rfc1918
|
||||
```
|
||||
|
||||
Let's declare a first zone, for `internal.example.com`. Add the following config to
|
||||
`/etc/bind/named.conf.local`
|
||||
|
||||
```text
|
||||
zone "internal.example.com." IN {
|
||||
type master;
|
||||
file "/var/lib/bind/internal.example.com.zone";
|
||||
```
|
||||
|
||||
This simply declares a new zone which is described in the file `/var/lib/bind/internal.example.com.zone`
|
||||
|
||||
Let's now create the zone itself. A DNS zone has a base structure that you must follow
|
||||
|
||||
```dns
|
||||
$ORIGIN .
|
||||
$TTL 7200 ; 2 hours
|
||||
internal.example.com IN SOA ns.internal.example.com. admin.example.com. (
|
||||
2024070301 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
600 ; retry (10 minutes)
|
||||
86400 ; expire (1 day)
|
||||
600 ; minimum (10 minutes)
|
||||
)
|
||||
NS ns.internal.example.com.
|
||||
|
||||
$ORIGIN internal.example.com.
|
||||
ns A 1.2.3.4
|
||||
test A 192.168.1.2
|
||||
```
|
||||
|
||||
This file declares a zone `internal.example.com` which master is `ns.internal.example.com`.
|
||||
It also sets the parameters (time to live for the records, and the current serial for the
|
||||
zone config).
|
||||
|
||||
Finally, two (2) A records are created, associating the name `ns.internal.example.com` to
|
||||
the IP address `1.2.3.4`, and `test.internal.example.com` (the domain for which we want
|
||||
a certificate) to a local IP address `192.168.1.2`.
|
||||
|
||||
A simple `systemctl restart bind9` would be enough to apply the modification, but we still
|
||||
have one thing to do, which is allowing remote modifications to the zone.
|
||||
|
||||
### Enabling remote DNS zone modification
|
||||
|
||||
To allow remote modification of our DNS zone, we are going to use [TSIG](https://www.ibm.com/docs/en/aix/7.3?topic=ssw_aix_73/network/bind9_tsig.htm)
|
||||
which stands for **Transaction signature**. It's a way to secure server to server operations
|
||||
to edit a DNS zone, and is preferred to access control based on IP addresses.
|
||||
|
||||
Let's start with creating a key using the command `tsig-keygen <keyname>`
|
||||
|
||||
```shell
|
||||
➜ tsig-keygen letsencrypt
|
||||
key "letsencrypt" {
|
||||
algorithm hmac-sha256;
|
||||
secret "oK6SqKRvGNXHyNyIEy3hijQ1pclreZw4Vn5v+Q4rTLs=";
|
||||
};
|
||||
```
|
||||
|
||||
This creates a key with the given name using the default algorithm (which is `hmac-sha256`).
|
||||
The entire output of this command is actually a code block that you can add to your bind9
|
||||
configuration.
|
||||
|
||||
Finally, using `update-policy`, allow this key to be used to update the zone.
|
||||
|
||||
```text
|
||||
update-policy {
|
||||
grant letsencrypt. zonesub txt;
|
||||
};
|
||||
```
|
||||
|
||||
{{< callout type="note" >}}
|
||||
Doing so allows users to update everything in your zone using this key. In fact
|
||||
you would only need to update `_acme-challenge.test.internal.example.com` as seen
|
||||
in the DNS challenge description.
|
||||
|
||||
If you want a better restriction, then you can use the following configuration instead
|
||||
|
||||
```text
|
||||
update-policy {
|
||||
grant letsencrypt. name _acme-challenge.test.internal.example.com. txt;
|
||||
};
|
||||
```
|
||||
|
||||
{{< /callout >}}
|
||||
|
||||
This means your entire `named.conf.local` would become something like this
|
||||
|
||||
```text
|
||||
key "letsencrypt" {
|
||||
algorithm hmac-sha256;
|
||||
secret "oK6SqKRvGNXHyNyIEy3hijQ1pclreZw4Vn5v+Q4rTLs=";
|
||||
};
|
||||
|
||||
zone "internal.example.com." IN {
|
||||
type master;
|
||||
file "/var/lib/bind/internal.example.com.zone";
|
||||
update-policy {
|
||||
grant letsencrypt. zonesub txt;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
Be **very cautious** about the `.` at the end of the zone name and the key name, they are
|
||||
easy to miss, and forgetting them will cause issues that would be hard to detect.
|
||||
{{< /callout >}}
|
||||
|
||||
With that being done, you can restart the DNS server and everything is ready server side,
|
||||
the only remaining thing to do would be the DNS challenge itself.
|
||||
|
||||
### Performing the challenge
|
||||
|
||||
Start by installing the certbot with the RFC2136 plugin (to perform the DNS challenge).
|
||||
|
||||
```shell
|
||||
apt install python3-certbot-dns-rfc2136
|
||||
```
|
||||
|
||||
It's handled using a `.ini` configuration file, let's put it in `/etc/certbot/credentials.ini`
|
||||
|
||||
```ini
|
||||
dns_rfc2136_server = <you_dns_ip>
|
||||
dns_rfc2136_port = 53
|
||||
dns_rfc2136_name = letsencrypt.
|
||||
dns_rfc2136_secret = oK6SqKRvGNXHyNyIEy3hijQ1pclreZw4Vn5v+Q4rTLs=
|
||||
dns_rfc2136_algorithm = HMAC-SHA512
|
||||
```
|
||||
|
||||
Finally, run the challenge using certbot (if it's the first time you're using certbot on
|
||||
that machine, it might ask for an email to handle admin stuff).
|
||||
|
||||
```shell
|
||||
root@toolbox:~# certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /etc/certbot/credentials.ini -d 'test.internal.example.com'
|
||||
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
Requesting a certificate for test.internal.example.com
|
||||
Waiting 60 seconds for DNS changes to propagate
|
||||
|
||||
Successfully received certificate.
|
||||
Certificate is saved at: /etc/letsencrypt/live/test.internal.example.com/fullchain.pem
|
||||
Key is saved at: /etc/letsencrypt/live/test.internal.example.com/privkey.pem
|
||||
This certificate expires on 2024-09-30.
|
||||
These files will be updated when the certificate renews.
|
||||
Certbot has set up a scheduled task to automatically renew this certificate in the background.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
If you like Certbot, please consider supporting our work by:
|
||||
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
|
||||
* Donating to EFF: https://eff.org/donate-le
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
```
|
||||
|
||||
And that's done, you have a certificate, and a no point in time did you need to
|
||||
actually expose your application to the outside world.
|
||||
|
||||
Now because I like to go way too far, I can propose two (2) improvements to this
|
||||
setup:
|
||||
|
||||
- Using ACL in addition to the TSIG key to secure operations on the DNS server
|
||||
- Using a second DNS server only locally accessible for your private records, and
|
||||
using the public server to only perform challenges
|
||||
|
||||
## Bonus 1: adding a second layer of authentication to connect to the DNS
|
||||
|
||||
## Bonus 2: completely hiding your private domains from outside
|
||||
## Bonus: completely hiding your private domains from outside
|
||||
|
||||
![A schema describing the DNS challenge workflow for the ACME protocol using a public and private DNS servers](/images/dns_article_dns_challenge_2.svg)
|
||||
|
||||
![alt text](image.png)
|
||||
|
|
Loading…
Reference in a new issue