Compare commits

...

2 commits

Author SHA1 Message Date
30d6fde582 Add article on DNS challenge
All checks were successful
ci/woodpecker/push/test Pipeline was successful
2024-07-02 23:16:04 +02:00
11b1074ede Add support for clickable headers 2024-07-02 22:53:20 +02:00
9 changed files with 182 additions and 5 deletions

View file

@ -90,11 +90,11 @@ logoText = "Hello there!"
logoHomeLink = "/fr/" logoHomeLink = "/fr/"
[menu] [menu]
# [[menu.main]] [[menu.main]]
# identifier = "blog" identifier = "blog"
# name = "Blog" name = "Blog"
# url = "/posts" url = "/posts"
# weight = 1 weight = 1
[[menu.main]] [[menu.main]]
identifier = "about_me" identifier = "about_me"

View file

@ -0,0 +1,117 @@
---
title: "How to do HTTPS at home (when your infrastructure is private)"
date: 2024-07-02T21:00:50+02:00
draft: true
toc: true
images:
tags:
- self-hosting
- sysadmin
---
## The problem of having a self-hosted infrastructure
I've been maintaining a personal homelab and self-hosted infrastructure for a few years
now, but one of the most infuriating pages when starting such project is this dreaded
**Warning: Potential Security Risk Ahead** page that appears when you're using a
self-hosted certificate, or when trying to use a password on a website or app that is
served through plain HTTP.
![A screenshot of a warning from Firefox indicating that the website that is being accessed is not secure.](/images/dns_article_firefox_warning.png)
While acceptable if you're alone on your own infrastructure or dev environment, this
poses several issues if many other contexts:
- It is not acceptable to publicly expose a website presenting this issue
- It's not advisable to say "hey look, I know that your browser gives you a big red
warning, but it's okay, you can just accept" to friends/family/etc. It's just a very
bad habit to have
- After a while, it really starts to get on your nerve
Thankfully a free solution for that, which you will probably know already, has existed
for almost ten (10) years now: [Let's Encrypt and the ACME protocol](https://letsencrypt.org/)
{{< callout type="note" >}}
I promise this is not yet another Let's Encrypt tutorial, well it is, but for a more
specific use-case
{{< /callout >}}
## The Let's Encrypt solution
### What is Let's Encrypt
[Let's Encrypt](https://letsencrypt.org/) is a nonprofit certificate authority founded
in November 2014. Its main goal was to provide an easy and free way to obtain a TLS
certificate in order to make it easy to use HTTPS everywhere.
The [ACME protocol](https://letsencrypt.org/docs/client-options/) developed by Let's
Encrypt is an automated verification system aiming at doing the following:
- verifying that you own the domain for which you want a certificate
- creating and registering that certificate
- delivering the certificate to you
Most client implementation also have an automated renewal system, further reducing the
workload for sysadmins.
The current specification for the ACME protocol proposes two (2) types of challenges
to prove ownership and control over a domain: [HTTP-01](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) and [DNS-01](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) challenge.
{{< callout type="note" >}}
Actually there are two (2) others: [TLS-SNI-01](https://letsencrypt.org/docs/challenge-types/#tls-sni-01) which is now disabled, and [TLS-ALPN-01](https://letsencrypt.org/docs/challenge-types/#tls-alpn-01) which is only aimed at a very
specific category of users, which we will ignore here.
{{< /callout >}}
### The common solution: HTTP challenge
The [HTTP-01](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) challenge
is the most common type of ACME challenge, and will satisfy most use-cases.
![A schema describing the HTTP challenge workflow for the ACME protocol and the interactions between the application server, Let's Encrypt, and the DNS server, all of them public.](/images/dns_article_http_challenge.svg)
For this challenge, you need the following elements :
- A domain name and a `A record` for that domain in a public DNS server (it can be a self-hosted DNS server, your providers', etc)
- Access to a server with a public IP that can be publicly reached
When performing this type of challenge, the following happens (in a very simplified way):
1. Your ACME client will ask to start a challenge to the Let's Encrypt API
2. In return, it will get a token
3. It will then either start a standalone server, or edit the configuration for your
current web server (nginx, apache, etc) to serve a file containing the token and a fingerprint of your account key.
4. Let's Encrypt will try to resolve your domain `test.example.com`.
5. If resolution works, then it will check the url `http://test.example.com/.well-known/acme-challenge/<TOKEN>`, and verify that the file from step 3 is served with the correct
content.
If everything works as expected, then the ACME client can download the certificate and key, and you can configure your reverse proxy or server to use this valid certificate,
all is well.
{{< callout type="help" >}}
Okay, but my app contains my accounts, or my proxmox management interface, and I
don't really want to make it public, so how does it work here?
{{< /callout >}}
Well it doesn't. For this type of challenge to work, the application server **must** be
public. For this challenge you need to prove that you have control over the application
that uses the target domain (even if you don't control the domain itself). But the
DNS-01 challenge bypasses this limitation.
### When it's not enough: the DNS challenge
As we saw in the previous section, sometimes, for various reasons, your application
server is in a private zone. It must be only reachable from inside a private network,
but you still want to be able to use a free Let's Encrypt certificate.
For this purpose, the [DNS-01](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) challenge is based on proving that you have control over the **DNS
server** itself, instead of the application server.
![A schema describing the DNS challenge workflow for the ACME protocol](/images/dns_article_dns_challenge_1.svg)
## DNS challenge in practice
## 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)

View file

@ -0,0 +1,9 @@
<h{{ .Level }} id="{{ .Anchor | safeURL }}">
<a class="hash-link nohover" href="#{{ .Anchor | safeURL }}">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="red" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<title>Link to this section</title>
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
</a>&nbsp;{{ .Text | safeHTML }}
</h{{ .Level }}>

13
static/css/heading.css Normal file
View file

@ -0,0 +1,13 @@
.hash-link {
/* -webkit-transform: translateX(-100%); */
/* left: 0;
opacity: 0;
padding: 0 5px;
position: absolute;
transform: translateX(-100%);
transition: opacity .1s ease-in;
will-change: transform, opacity; */
svg {
stroke: rgb(138, 173, 244);
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 149 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -4,6 +4,7 @@
<head> <head>
{{ partial "head.html" . }} {{ partial "head.html" . }}
<link rel="stylesheet" href="/mermaid.css"> <link rel="stylesheet" href="/mermaid.css">
<link rel="stylesheet" href="/css/heading.css">
</head> </head>
{{ block "body" . }} {{ block "body" . }}