Knockd est un outil de "portknocking":
Si un motif réseau spécifique est détecté, il peut exécuter des actions pré-déterminées

Prenons l'exemple suivant, adapté de la manpage de knockd:


[opencloseSSH]
    sequence      = 2222:tcp,3333:tcp,4444:tcp
    seq_timeout   = 15
    tcpflags      = syn
    start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --syn -j ACCEPT

Cette configuration permet d'ajouter une rêgle de firewall pour l'IP source externe qui aura généré la séquence réseau (détectée sur l'interface du serveur)

Dans ce cas, la séquence de déclenchement est la suivante:

  • Connexion TCP port 2222
  • Connexion TCP 3333
  • Connexion TCP 4444

(En réalisé, ce ne sont pas des connexions TCP établies, mais simplement un packet SYN)

Ca serait vachement bien si knockd pouvait maintenant piloter le filtrage IP de caddy.
Nous allons voir comment.

L'interface API de caddy

Caddy dispose d'une API pour interagir dynamiquement sur sa configuration.
La configuration suivante permet d'activer cette interface d'admin sur une socket unix:

{
  admin "unix//run/caddy/admin.socket" {
    origins myadmin
  }
}

Avec cette configuration, il est possible de lancer des commandes curl pour consulter la configuration:

# curl -s --unix-socket  /run/caddy/admin.socket http://myadmin/config/apps/http/servers
{
  "srv0": {
    "listen": [
      ":443"
    ],
...

Un appel a l'API en GET permet de lire la configuration.
Et un appel POST permet de modifier cette configuration.

Filtrage IP dans caddy

A présent, voyons comment  protéger notre virtual server avec les directives client_ip et handle:e

https://mon.beau.serveur.com:443 {

# IPs autorisées 
        @allowed {
                client_ip  33.32.31.30
        }

# Gestion du site pour les ip autorisées
        handle @allowed {
                reverse_proxy 1.2.3.4:443 {
                }
        }

# Gestion du site pour les ip(s) non déclarées
        handle {
                respond "Access denied" 403
        }
}

Dans cet exemple, nous déclarons que l'ip 33.32.31.30 fait partie du 'groupe' @allowed, et pourra accéder aux site 1.2.3.4:443 en mode reverse proxy.


Pour les autres, il y aura une erreur HTTP 403

Interaction knockd et caddy

La configuration knockd suivante permettra de lancer une commande de mise à jour de la configuration Caddy.

[options]
	logfile = /var/log/knockd.log

[allowedIPS]
	sequence    = 2222:udp,3333:tcp,4444:udp
	seq_timeout = 10
	command     = curl -s --unix-socket  /run/caddy/admin.socket -X POST -H "Content-Type: application/json"  -d '{"ranges": ["%IP%"]}' 'http://myadmin/config/apps/http/servers/srv0/routes/2/handle/0/routes/1/match/0/client_ip'
	tcpflags    = syn

Testons cette configuration:

# Configuration de base au démarage du serveur.
# L'API nous retourne bien l'unique IP déclarée comme autorisée dans la configuation

server $ curl -s --unix-socket  /run/caddy/admin.socket 'http://myadmin/config/apps/http/servers/srv0/routes/2/handle/0/routes/1/match/0/client_ip/ranges' | jq 
[
  "33.32.31.30"
]

# Netcat permet de générer la séquence réseau (portknocking) et déclencher les commandes associées 
laptop (130.33.45.32) $ for i in 10000 10001 1023; do nc -w 1 -v monserveur $i; done

server $ curl -s --unix-socket  /run/caddy/admin.socket 'http://myadmin/config/apps/http/servers/srv0/routes/2/handle/0/routes/1/match/0/client_ip/ranges' | jq 
[
  "130.33.45.32"
]

=> L'ip a bien été actualisée dans la configuration de caddy 

Remarques:

Le portknocking ne doit pas être l'unique moyen de sécuriser votre serveur.

Il constitue un premier niveau de protection, mais repose uniquement sur la confidentialité de la séquence de déclenchement.  

Vous pourrez ajouter, en complément, une authentification par certificats ou avec un MFA.