Compare commits
2 commits
ac6913b7a2
...
30d6fde582
Author | SHA1 | Date | |
---|---|---|---|
30d6fde582 | |||
11b1074ede |
9 changed files with 182 additions and 5 deletions
10
config.toml
10
config.toml
|
@ -90,11 +90,11 @@ logoText = "Hello there!"
|
|||
logoHomeLink = "/fr/"
|
||||
|
||||
[menu]
|
||||
# [[menu.main]]
|
||||
# identifier = "blog"
|
||||
# name = "Blog"
|
||||
# url = "/posts"
|
||||
# weight = 1
|
||||
[[menu.main]]
|
||||
identifier = "blog"
|
||||
name = "Blog"
|
||||
url = "/posts"
|
||||
weight = 1
|
||||
|
||||
[[menu.main]]
|
||||
identifier = "about_me"
|
||||
|
|
117
content/en/posts/dns-challenge.md
Normal file
117
content/en/posts/dns-challenge.md
Normal 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)
|
9
layouts/_default/_markup/render-heading.html
Normal file
9
layouts/_default/_markup/render-heading.html
Normal 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> {{ .Text | safeHTML }}
|
||||
</h{{ .Level }}>
|
13
static/css/heading.css
Normal file
13
static/css/heading.css
Normal 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);
|
||||
}
|
||||
}
|
8
static/images/dns_article_dns_challenge_1.svg
Normal file
8
static/images/dns_article_dns_challenge_1.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 149 KiB |
8
static/images/dns_article_dns_challenge_2.svg
Normal file
8
static/images/dns_article_dns_challenge_2.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 159 KiB |
BIN
static/images/dns_article_firefox_warning.png
Normal file
BIN
static/images/dns_article_firefox_warning.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
21
static/images/dns_article_http_challenge.svg
Normal file
21
static/images/dns_article_http_challenge.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 43 KiB |
|
@ -4,6 +4,7 @@
|
|||
<head>
|
||||
{{ partial "head.html" . }}
|
||||
<link rel="stylesheet" href="/mermaid.css">
|
||||
<link rel="stylesheet" href="/css/heading.css">
|
||||
</head>
|
||||
|
||||
{{ block "body" . }}
|
||||
|
|
Loading…
Reference in a new issue