Skip to content

Commit

Permalink
Create DNS Chalange for Kubernetes Post
Browse files Browse the repository at this point in the history
  • Loading branch information
53845714nF committed Sep 22, 2024
1 parent ab8962f commit 02067df
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
164 changes: 164 additions & 0 deletions content/blog/let_s_encrypt_dns_challenge_for_kubernetes/index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
title: "DNS Challenge for Kubernetes 📃"
date: 2024-03-31T01:28:22+01:00
draft: false
hideLastModified: true
summaryImage: "img/kubernetes.jpg"
keepImageRatio: true
summary: "Learn how to set up the DNS Challenge for Let's Encrypt in your k3s cluster."
showInMenu: false
tags: ["k3s", "Let's Encrypt", "Kubernetes", "Ingress", "DNS Challenge", "Hetzner DNS"]
---

I have been running a k3s cluster for some time and now I want to expand my Ingress resource to allow accessing my applications with valid Let's Encrypt certificates.
The DNS Challenge for Let's Encrypt seems to be the ideal solution for this, as it does not require opening ports to the outside world, thus maintaining the security of my network.
In this article, I'll walk you through step-by-step on how to set up the DNS Challenge for Let's Encrypt in your k3s cluster, using the Hetzner DNS provider.

## Requirements 📋
- k3s cluster
- kubectl
- helm
- DNS provider (In my case Hetzner DNS, the provider must provide the API to change the DNS entries)

## Setting up the DNS name 📡
First, we need to create the DNS entries for our domain. These entries can point to a local IP address.

![DNS entries](img/hetzner.png)

Although this may seem unusual at first and poses a certain security risk in the DNS system - known as DNS rebinding attacks. Most routers provide protection against rebinding, preventing external requests from being forwarded to the local IP address.

To configure the DNS records, you may need to disable the rebinding protection in your router. Please note that you should only enter your domain there, as wildcards can pose a security risk. In the user interface of the Fritzbox, you can find the rebinding protection under:

`Home Network` -> `Network` -> `Network Settings` -> `Rebinding Protection`

(The DNS entries have been obscured as they are not relevant for this purpose.)

## Installing cert-manager
Next, we need to install cert-manager, which is essentially a standard in the Kubernetes world for managing certificates.

{{< codeWide >}}
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml
{{< /codeWide >}}

An element that's not entirely standard is the [Cert Manager Webook Hetzner](https://github.com/vadimkim/cert-manager-webhook-hetzner) project, which enables communication with the Hetzner DNS provider.

To do this, we'll use helm, a package manager for Kubernetes:
{{< codeWide >}}
helm repo add cert-manager-webhook-hetzner https://vadimkim.github.io/cert-manager-webhook-hetzner
helm install --namespace cert-manager cert-manager-webhook-hetzner cert-manager-webhook-hetzner/cert-manager-webhook-hetzner --set groupName=hackwiki.de
{{< /codeWide >}}

## Creating the Cluster Issuer
Now we need to create a Cluster Issuer that will be used to issue the certificates. The Cluster Issuer will use the Hetzner DNS provider to create the DNS records for the DNS Challenge.

Create a file named `cluster-issuer.yaml` with the following content:
{{< codeWide >}}
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory

email: *************

privateKeySecretRef:
name: letsencrypt

solvers:
- dns01:
webhook:
groupName: **********
solverName: hetzner
config:
secretName: hetzner-secret
zoneName: *********
apiUrl: https://dns.hetzner.com/api/v1
{{< /codeWide >}}

Replace the placeholders with your data. The server URL must be the address of the ACME server. You can find the URL for the test server in the project's Readme (Cert Manager Webhook Hetzner). This is also useful if you don't want to exceed Let's Encrypt's rate limit during testing. For production systems, you should change the URL to the normal Let's Encrypt server.

To communicate with the Hetzner DNS provider, we need to store the API key in a secret. Create a file named `hetzner-secret.yaml` with the following content:
{{< codeWide >}}
---
apiVersion: v1
kind: Secret
metadata:
name: hetzner-secret
namespace: cert-manager
type: Opaque
data:
api-key: ***************************
{{< /codeWide >}}

Apply the files to your cluster:
{{< codeWide >}}
kubectl apply -f cluster-issuer.yaml
kubectl apply -f hetzner-secret.yaml
{{< /codeWide >}}

## Creating the Ingress resource
Before we create the Ingress resource, we need to create a certificate. Create a file named `certificate.yaml` with the following content:
{{< codeWide >}}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: foobar-cert
namespace: *********
spec:
commonName: foobar.**********
dnsNames:
- foobar.**************
issuerRef:
name: letsencrypt
kind: ClusterIssuer
secretName: foobar-cert
{{< /codeWide >}}

Replace the placeholders with your data. Apply the file to your cluster:
{{< codeWide >}}
kubectl apply -f certificate.yaml
{{< /codeWide >}}

Now you can create your Ingress resource. Create a file named `ingress.yaml` with the following content:
{{< codeWide >}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foobar-ingress
namespace: *******
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: traefik
rules:
- host: foobar.***********
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: foobar-service
port:
number: 80
tls:
- hosts:
- foobar.************
secretName: foobar-cert
{{< /codeWide >}}

And now you can create the Ingress resource:
{{< codeWide >}}
kubectl apply -f ingress.yaml
{{< /codeWide >}}

Here, the certificate for the domain `foobar.**********` is created.
And reach your application via `https://foobar.************`.

## Conclusion 🎉
With the DNS Challenge for Let's Encrypt, you can easily secure your applications with valid certificates without having to open ports to the outside world. This way, you can maintain the security of your network and still provide your users with a secure connection.
169 changes: 169 additions & 0 deletions content/blog/let_s_encrypt_dns_challenge_for_kubernetes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
title: "DNS Challenge für Kubernetes 📃"
date: 2024-03-31T01:28:22+01:00
draft: false
hideLastModified: true
summaryImage: "img/kubernetes.jpg"
keepImageRatio: true
summary: "Erfahren Sie, wie Sie die DNS Challenge für Let's Encrypt in Ihrem k3s Cluster einrichten können."
showInMenu: false
tags: ["k3s", "Let's Encrypt", "Kubernetes", "Ingress", "DNS Challenge", "Hetzer DNS"]
---

Seit einiger Zeit betreibe ich ein k3s Cluster und möchte nun meine Ingress Ressource erweitern,
um meine Anwendungen über gültige Let's Encrypt Zertifikate zu erreichen.
Die DNS Challenge für Let's Encrypt scheint mir hierfür die ideale Lösung zu sein,
da sie keine Öffnung von Ports nach außen erfordert und somit die Sicherheit meines Netzwerks nicht gefährdet.
In diesem Artikel zeige ich Ihnen Schritt für Schritt, wie Sie die DNS Challenge für Let's Encrypt in Ihrem k3s Cluster einrichten können,
wobei ich den DNS Provider Hetzner DNS verwende.

## Voraussetzungen 📋
- k3s Cluster
- kubectl
- helm
- DNS Provider (In meinem Fall Hetzner DNS, der Provider muss die API zur Verfügung stellen um die DNS Einträge zu ändern)

## Einrichtung des DNS Namens 📡
Zunächst müssen wir die DNS Einträge für unsere Domain erstellen. Diese Einträge können auf eine lokale IP Adresse zeigen.

![DNS Einträge](img/hetzner.png)

Das ist im ersten moment vielleicht komisch da man annehmen könnte das sowas nicht funktioniert.
Und ja das birgt ein gewisses sicherheitsrisiko im DNS System. Diese Attacken heißen DNS-Rebinding-Angriff.
Als Angreifer könnte ich eine Domain auf eine lokale IP Adresse zeigen lassen und so versuchen auf die lokale IP Adresse zuzugreifen.
Es ist aber immer noch notwendig die Seite des Angreifers zu besuchen.
Daher gibt es bei den meisten Routern einen Rebound Schutz. Dieser verhindert das Anfragen von außen auf die lokale IP Adresse weitergeleitet werden.

Sie müssen dies nun für ihre Domain im Router den Rebound Schutz deaktivieren.
Bitte beachten Sie das sie dort nur ihre Domain eintragen wildcards könnten ein Sicherheitsrisiko darstellen.

Unter der Fritzbox finden sie den Rebound Schutz unter:

`Heimnetzwerk` -> `Netzwerk` -> `Netzwerkeinstellungen` -> `Rebound Schutz`

![Benutzeroberfläche der Fritzbox](img/fritz_box.png)

(Mir ist bewust das man die DNS Eintäge einsehen kann, trotzdem habe ich sie unkenntlich gemacht da sie hierfür nicht relevant sind.)

## Installation von cert-manager

Als nächstes müssen wir den cert-manager installieren, der quasi ein Standard in der Kubernetes Welt zur Verwaltung von Zertifikaten ist

{{< codeWide >}}
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml
{{< /codeWide >}}

Eine nicht ganz standardmäßige Komponente ist das Projekt [Cert Manager Webook Hetzner](https://github.com/vadimkim/cert-manager-webhook-hetzner), das die Kommunikation mit dem Hetzner DNS Provider ermöglicht.

Dafür verwenden wir helm, einen Paketmanager für Kubernetes:

{{< codeWide >}}
helm repo add cert-manager-webhook-hetzner https://vadimkim.github.io/cert-manager-webhook-hetzner
helm install --namespace cert-manager cert-manager-webhook-hetzner cert-manager-webhook-hetzner/cert-manager-webhook-hetzner --set groupName=hackwiki.de
{{< /codeWide >}}

## Erstellen des Cluster Issuer
Um die DNS Challenge nutzen zu können, müssen wir einen Cluster Issuer erstellen.

{{< codeWide >}}
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory

email: *************

privateKeySecretRef:
name: letsencrypt

solvers:
- dns01:
webhook:
groupName: **********
solverName: hetzner
config:
secretName: hetzner-secret
zoneName: *********
apiUrl: https://dns.hetzner.com/api/v1
{{< /codeWide >}}
Bei der Server-URL muss die Adresse des ACME Servers angegeben werden.
In der Readme des Projekts (Cert Manager Webhook Hetzner) finden Sie die URL für den Testserver.
Dies ist auch sinnvoll, wenn Sie beim Testen das Rate Limit von Let's Encrypt nicht überschreiten möchten.
Für Produktivsysteme sollten Sie die URL auf den normalen Let's Encrypt Server ändern.

Um mit dem Hetzner DNS Provider kommunizieren zu können, müssen wir den API-Key in einem Secret speichern.
{{< codeWide >}}
---
apiVersion: v1
kind: Secret
metadata:
name: hetzner-secret
namespace: cert-manager
type: Opaque
data:
api-key: ***************************
{{< /codeWide >}}


## Erstellen des Ingress

Bevor wir den Ingress erstellen, müssen wir noch ein Zertifikat erstellen.

{{< codeWide >}}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: foobar-cert
namespace: *********
spec:
commonName: foobar.**********
dnsNames:
- foobar.**************
issuerRef:
name: letsencrypt
kind: ClusterIssuer
secretName: foobar-cert
{{< /codeWide >}}

Hier wird das Zertifikat für die Domain foobar.********** erstellt.

Nun können wir den Ingress erstellen.

{{< codeWide >}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foobar-ingress
namespace: *******
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: traefik
rules:
- host: foobar.***********
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: foobar-service
port:
number: 80
tls:
- hosts:
- foobar.************
secretName: foobar-cert
{{< /codeWide >}}

Der Ingress leitet nun alle Anfragen an die Domain `foobar.**********` an den Service `foobar-service` weiter.

## Fazit 🎉
Die Verwendung der DNS Challenge für Let's Encrypt bietet eine sehr sichere Methode zur Erlangung von Zertifikaten für Ihre Anwendungen.
Ich hoffe, dieser Post hat Ihnen geholfen, die DNS Challenge für Let's Encrypt in Ihrem k3s Cluster einzurichten.

0 comments on commit 02067df

Please sign in to comment.