V'Ger Voyager / Gemini (OpenBSD)

Article publié, le et modifié le
6 minutes de lecture

Cet article contient 1209 mots.
Source brute de l'article :

Description

V’Ger est le projet de serveur de publication sur le protocol Gemini, écrit en C. Écrit pour OpenBSD, il bénéficie des mesures de protections, liées à pledge(4) et unveil(4).

Dans cet article, nous aborderons l’installation et la configuration de ce service. Puis nous verrons comment configurer relayd ou nginx en tant que proxy relais ; et nous finirons par quelques règles pour Packet-Filter.

OpenBSD : 6.9 → 7.1


Installation

Puisque V’Ger est disponible dans les ports, l’utilisation de l’outil pkg_add suffit :

$ doas pkg_add vger

Autrement vous pouvez toujours l’installer depuis le dépôt Git… mais là, je vous renvoie à la documention du dépôt.

Configuration

Pré-requis :

  • changez les termes ‘addresse_ipv4’, ‘addresse_ipv6’ et ’nom_domaine’, par ce qui correspond à votre contexte de serveur !

Utilisateur dédié _vger

Créons en tout premier un utilisateur dédié, nommé _vger :

$ doas useradd -d /var/gemini -s /sbin/nologin _vger

(dans la documentation officielle, le nom de l’utilisateur est _gemini).

Système

Il nous faut créer le répertoire /var/gemini puis appliquer les droits à l’utilisateur dédié :

$ doas mkdir -p /var/gemini/nom_domaine
$ doas chown -R _vger /var/gemini

inetd

  • Fichier de configuraton : /etc/inetd.conf

Le service inetd est chargé de l’écoute active sur l’interface localhost puis appelle le binaire vger pour délivrer le contenu.

Configurons maintenant le service inetd :

1965 stream tcp nowait _vger /usr/local/bin/vger vger -d /var/gemini -v 
1965 stream tcp6 nowait _vger /usr/local/bin/vger vger -d /var/gemini -v
  • le port d’écoute est le 1965 - (dans la documentation officielle, le port par défaut est 11965).
  • géré par l’utilisateur _vger, appelant le binaire vger.

⇒ activons et démarrons le service :

$ doas rcctl enable inetd && doas rcctl start inetd

certificats SSL

Cet article ne présente pas comment obtenir les certificats SSL, mais vous pouvez les obtenir, soit depuis le client acme secure, natif sous OpenBSD, soit à partir du paquet certbot.

En premier, il semble nécessaire de créer le répertoire private dans /etc/ssl.

$ doas mkdir -p /etc/ssl/private

acme

La documentation officielle informe de lier les certificats SSL, générés par le client sécurisé acme sous OpenBSD.

Si c’est votre cas :

$ doas ln -s /etc/ssl/acme/cert.pem /etc/ssl/nom_domaine.crt
$ doas ln -s /etc/ssl/acme/private/privkey.pem /etc/ssl/private/nom_domaine.key

certbot

Dans mon contexte de serveur, les certificats sont générés par le client certbot, disponible officiellement dans les ports. Une fois les certificats générés par certbot, les liens symboliques à créer sont de cette forme :

$ doas ln -s /etc/letsencrypt/live/nom_domaine/cert.pem /etc/ssl/nom_domaine.crt
$ doas ln -s /etc/letsencrypt/live/nom_domaine/privkey.pem /etc/ssl/private/nom_domaine.key

relayd

  • Fichier de configuration : /etc/relayd.conf - chmod 0600 !

relayd est le service de relais-proxy natif sous OpenBSD.

La configuration du service relayd peut se faire ainsi - dans cet exemple, à la fois pour Ipv4|6 - :

log connection
table <localhost> { 127.0.0.1, ::1 }
tcp protocol "gemini" {
    tls keypair nom_domaine
}

relay "gemini" {
    listen on nom_domaine port 1965 tls
    protocol "gemini"
    forward to <localhost> port 1965
}

⇒ Vérification de la configuration :

$ doas relayd -n              
host_dns: nom_domaine resolves to more than 1 hosts
configuration OK

⇒ activons et démarrons le service :

$ doas rcctl enable relayd && doas rcctl start relayd

nginx

  • Fichier de configuration : /etc/nginx.conf

nginx peut lui aussi servir de proxy relais, en lieu et place de relayd ; mais il est nécessaire d’installer en plus le paquet nginx-stream.

Puis il faut modifier la configuration pour y ajouter, en début de fichier, avant la directive http :
load_module "modules/ngx_stream_module.so";

Ensuite, il est nécessaire de rajouter les déclarations suivantes en utilisant la directive stream :

stream {
    log_format basic '$remote_addr $upstream_addr [$time_local] '
                     '$protocol $status $bytes_sent $bytes_received '
                     '$session_time';

    access_log logs/nom_domaine/access.gemini.log basic;

    upstream backend_ipv4 {
        hash $remote_addr consistent;
        server 127.0.0.1:1965;
    }
    
    upstream backend_ipv6 {
		hash $remote_addr consistent;
        server [::1]:1965;
    }
    
    map $server_addr $backend {
		addresse_ipv4 backend_ipv4;
		addresse_ipv6 backend_ipv6;
	}

    server {
        listen addresse_ipv4:1965 ssl;
        listen [addresse_ipv6]:1965 ssl;

        ssl_certificate /etc/letsencrypt/live/nom_domaine/fullchain.pem;
		ssl_certificate_key /etc/letsencrypt/live/nom_domaine/privkey.pem;
		ssl_ciphers TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
		ssl_ecdh_curve X25519:P-521:P-384:P-256;
		ssl_prefer_server_ciphers on;
		ssl_protocols TLSv1.3 TLSv1.2;

        proxy_pass $backend;
    }
}

Quelques petites explications :

  • en rapport avec les directives listen, si vous ne déclarez pas l’adresse IP correspondante, tel que listen 1965 ssl;, il faudra impérativement rediriger le port sur un autre numéro de port puis reconfigurer inetd.conf pour qu’il écoute sur ce même autre numéro de port. En effet, si l’adresse IP d’écoute n’est pas spécifiée dans la directive listen, nginx cherchera à écouter sur toutes les interfaces réseaux configurées et ne pourra redémarrer car inetd écoute déjà sur l’interface localhost.

  • deux directives upstream sont déclarées, chacune pour gérer correctement le protocole IPv4 ou IPv6, et sont mappées pour n’avoir qu’un seul proxy à appeler.

  • un dernier mot, concernant les directives ssl_ciphers, ssl_ecdh_curve, ssl_prefer_server_ciphers, et ssl_protocols, elles ne sont pas strictement nécessaires mais utiles pour renforcer les préférences d’utilisation. ssl_protocols permet de prioriser la version de TLS, sachant que :

Servers MUST use TLS version 1.2 or higher and SHOULD use TLS version 1.3 or higher.

PF

Voici un exemple de règles minimalistes à ajouter à PF :

host  = adresse_ipv4
host6 = adresse_ipv6

pass in quick on egress proto tcp from any to { $host $host6 } port 1965

Pensez à recharger le jeu de règles par PF :
$ doas pfctl -f /etc/pf.conf


Voilà !

Il ne vous reste plus qu’à créer votre premier fichier index.gmi et les suivants et les déposer dans le répertoire correspondant à votre répertoire de publication… en n’oubliant pas de poser les droits de l’utilisateur dédié dessus.

Surveillance

Mais qui surveille ?

⇒ L’activité est enregistrée dans les deux logs ‘daemon’ et ‘messages’.

$ grep vger /var/log/messages                                                                                                              
May  1 10:54:28 sh1 useradd[86659]: new group added: name=_vger, gid=1011
May  1 10:54:28 sh1 useradd[86659]: new user added: name=_vger, uid=1011, gid=1011, home=/var/gemini, shell=/sbin/nologin
May  1 12:09:53 sh1 vger: request gemini://huc.fr.eu.org/
May  1 13:00:59 sh1 vger: request gemini://huc.fr.eu.org/

⇒ Il est possible de surveiller l’activité de l’utilisateur _vger avec - mais dans ce cas, franchement peu utile :

  • top -U _vger
  • fstat -u _vger -n
  • ps aux -U _vger

Dépannage

⇒ Pour vérifier que le service inetd écoute en local, il est possible de lui envoyer la requête suivante :

$ printf '%s\r\n' "gemini://huc.fr.eu.org" | vger -v -d /var/gemini 
20 text/gemini; 
# huc.fr.eu.org|gemini

()
  • Si la réponse est similaire, c’est que vger écoute bien en local !
  • Si vous avez pour réponse telnet: Unable to connect to remote host: Connection refused, c’est certainement soit que le service inetd ne peut répondre - est-il actif ? ou qu’il y a un problème dans sa configuration. Vérifiez !

⇒ Vérifier que le port 1965 soit ouvert en écoute sur vos adresses IP :

$ netstat -ant | grep 1965
tcp          0      0  *.1965                 *.*                    LISTEN
tcp          0      0  46.23.90.29.1965       *.*                    LISTEN
tcp6         0      0  2a03:6000:6e65:6.1965  *.*                    LISTEN
tcp6         0      0  *.1965                 *.*                    LISTEN

⇒ Pour finir, vous pouvez vérifier avec l’outil telnet sur le port 1965, en local et depuis une autre machine que le service écoute.

Documentations

Manpages

  • pledge(4) , unveil(4)
  • une fois installé le manpage : man 8 vger
  • le fichier pkg-readme dans /usr/local/share/doc/pkg-readmes/vger