All links of one day
in a single page.
<Previous day - Next day>

rss_feedDaily RSS Feed
floral_left The Daily Shaarli floral_right
——————————— May 22, 2020 - Friday 22, May 2020 ———————————

Lors de l'incrémentation du serial d'une zone DNS, je me trompe. Au lieu de saisir « 2020052205 », je saisis « 20200522050 » (un zéro en trop). Je demande à OpenDNSSEC de signer la zone (DNSSEC). Puis je me rends compte de mon erreur : dig SOA <domaine> affiche « 3020633059 ». Comment faire redescendre ce serial ?

Normalement, il suffit de décrémenter le serial, de redémarrer le serveur de noms (ou de forcer le chargement de la zone sans contrôle du serial) puis de faire de même sur les slaves. Mais, il y a OpenDNSSEC au milieu et, lui, a une mémoire du serial. Si je signe à nouveau la zone après avoir remis le serial comme il faut, le serial passe à 3020633060.

Essayons naïvement de préciser le serial sur la ligne de commande ?

# ods-signer sign guiguishow.info --serial 2020052206
Error: Unable to enforce serial 2020052206 for zone <CENSURE>.
Zone <CENSURE> scheduled for immediate re-sign.

Regardons les dates de modification dans /var/lib/opendnssec. Aucun fichier modifié récemment sauf une sauvegarde du fichier de zone avant sa dernière signature. Après vérification, OpenDNSSEC ne s'en sert pas comme référence pour le serial.

En fait, le serial est lu dans le fichier de zone non signé lors du démarrage du démon signer puis il est conservé en mémoire vive.

Il suffit donc de stopper le signer et l'enforcer (systemctl stop opendnssec-signer.service opendnssec-enforcer.service), puis de mettre le serial désiré dans le fichier de zone non signé puis de démarrer l'enforcer et le signer (systemctl start opendnssec-signer.service opendnssec-enforcer.service). Le journal d'OpenDNSSEC m'informe :

ods-signerd: [namedb] zone <CENSURE> unable to use datecounter as serial: 2020052200 does not increase 2020052206. Serial set to 2020052207
ods-signerd: [STATS] <CENSURE> 2020052207 RR[count=23 time=0(sec)] NSEC[count=14 time=0(sec)] RRSIG[new=37 reused=0 time=0(sec) avg=0(sig/sec)] TOTAL[time=0(sec)] 

« 2020052206 » est le serial que j'ai écrit dans le fichier de zone non signé.

Lors du chargement de la zone par OpenDNSSEC, BIND9 consigne error: zone <CENSURE>/IN: zone serial (2020052207/3020633062) has gone backwards, mais il recharge la zone.

Sur les serveurs DNS slaves, il faudra utiliser nsd-control force_transfer <nom_zone> ou rndc retransfer <nom_zone> afin de forcer le transfert de la zone réparée sans contrôle préalable du serial.

Fin de l'incident.

Je pensais qu'il y a que AppArmor et SELinux qui limitent les droits d'un logiciel sur un système de fichiers. Ben non, il y a aussi systemd, avec les directives ReadWritePaths, ReadOnlyPaths et InaccessiblePaths d'une unit de type service, donc avec les espaces de nommage Linux.

Je l'ai découvert avec le serveur de noms nsd. Alors que je lui demandais d'écrire le fichier de zone correspond à une zone pour laquelle mon serveur est slave avec nsd-control write <nom_zone>, nsd a journalisé ce qui suit :

nsd[14377]: nsd[14377]: info: writing zone <CENSURE>. to file /var/named/zones/slave/<CENSURE>
nsd[14377]: error: cannot write zone <CENSURE>. file /var/named/zones/slave/<CENSURE>~: Read-only file system
nsd[14377]: cannot write zone <CENSURE>. file /var/named/zones/slave/<CENSURE>~: Read-only file system

Hé oui, je sauvegarde mes fichiers de zone, c'est-à-dire le contenu que je publie dans le DNS, dans /var/named, tout comme on met le contenu d'un site web, c'est-à-dire ce qu'on publie, dans /var/www.

Solution :

  • systemctl edit nsd.service ;

  • Le fichier doit avoir le contenu suivant :

    [Service]
    ReadWritePaths=/var/lib/nsd /etc/nsd /run /var/named/zones/slave


  • systemctl daemon-reload ;

  • systemctl restart nsd.service.

Résumé : activation de HTTP/2 sur ce serveur, donc migration vers mpm_event (car HTTP/2 = requêtes en parallèle dans une même connexion ce que ne peut pas gérer mpm_prefork), donc migration du module PHP pour Apache httpd (on rappellera que la fondation Apache publie d'autres logiciels que httpd : Tomcat, Storm, Ant, Kafka, Hadoop, etc.) vers PHP-FPM (car le module n'est pas multithreadé), donc suppression du chroot Apache httpd devenu inutile, donc suppression du chroot BIND9 par homogénéité entre tous les logiciels que j'utilise. Je termine par un joli bug Apache httpd quand on utilise h2c (HTTP/2 sur une connexion non chiffrée). Je rappelle que les navigateurs web prennent en charge uniquement HTTP/2 over TLS (HTTPS/2, quoi).



Il y a quelques mois, j'ai testé l'activation de la nouvelle version du protocole qui soutient le web, HTTP/2.

J'en avais déduis que son fonctionnement « plusieurs requêtes dans une même connexion TCP / HTTP » nécessite plutôt un module de traitement Apache httpd qui gère réellement les requêtes parallèles. Exit mpm_prefork, bonjour mpm_event (recommandé par la doc' officielle d'Apache httpd). Sauf que, le module PHP pour Apache n'est pas utilisable avec mpm_event, justement car il n'est pas multi-tâches. Il faut donc passer à PHP-FPM.

Par défaut, PHP-FPM n'est pas chrooté. Il peut l'être. Vu les emmerdes que ça m'a apporté au fil des ans (voir ici et là), ça en m'intéresse pas. Puisque PHP n'est plus un module d'Apache httpd, est-il encore utile de chrooter ce dernier ? Apache httpd va uniquement manipuler des fichiers statiques, pas de code dynamique avec des saisies utilisateur… Un chroot aura environ aucun intérêt.

J'ai déjà dé-chrooté MySQL car c'était la galère. Si je dé-chroote Apache httpd, il restera BIND9. Chrooter BIND9 m'a posé aucun souci pendant 10 ans. Mais, d'une part, il n'est pas chrooté par défaut, et, d'autre part, je ne l'ai pas totalement chrooté dans les règles de l'art (un chroot doit être hermétique et auto-suffisant, sans lien vers l'extérieur). Virer le chroot de BIND9, c'est assurer l'homogénéité de fonctionnement entre les logiciels que j'utilise, ce qui simplifie la mémorisation de l'architecture technique. Le seul logiciel encore chrooté sera Postfix, mais il est livré ainsi et le chroot m'a jamais posé problème.

Mon chroot MySQL aura tenu 7 ans, mes chroots Apache httpd et BIND9 auront tenu 10 ans. Le module PHP pour Apache httpd aura tenu plus de 10 ans. Pas si mal.

Au final, j'ai :

  • Dé-chrooté BIND9 ;

  • Dé-chrooté Apache httpd ;

  • Migré du module PHP d'Apache httpd à PHP-FPM ;

  • Activé HTTP/2 dans Apache httpd ;


Dé-chroot-er BIND9

Aucune difficulté : il suffit de copier (cp -a) les fichiers de zone, les clés, les journaux de transferts de zones, etc. du chroot vers l'emplacement hors chroot (/etc/bind par défaut, mais j'ai l'habitude de séparer la configuration du contenu en mettant la conf' dans /etc et le contenu dans /var/named comme l'on sépare le contenu d'un site web dans /var/www de la configuration d'un serveur web dans /etc∕) puis de retirer l'option « -t » dans /etc/default/bind9 puis de redémarrer BIND9. Si aucune erreur est consignée dans le journal, on peut supprimer le chroot avec un rm -r.


Dé-chroot-er Apache httpd

Il faut copier (cp -a) le contenu des sites web (les DocumentRoot) depuis l'emplacement du chroot vers /var/www puis retirer les directives de configuration ChrootDir et LoadFile du fichier /etc/apache2/apache2.conf. Dans chaque hôte virtuel (aka virtualhost), il faut s'assurer que les directives DocumentRoot et Directory sont toujours valables (si le chroot était bien fait, elles devraient l'être).

Côté module PHP pour Apache httpd, il faut annuler la bidouille du script de nettoyage régulier des sessions PHP et virer le paramétrage d'un magasin de certificats x509 interne au chroot plutôt que le magasin par défaut du système.

Enfin, on redémarre Apache httpd. Si aucune erreur est consignée dans le journal, on peut supprimer le chroot avec un rm -r.


Migrer du module PHP d'Apache httpd à PHP-FPM

J'ai déjà tout écrit dans mon shaarli sur mon test de HTTP/2 donc je vais faire court.

Il faut…

Installer PHP-FPM avec apt-get install php-fpm.

Dans la configuration des hôtes virtuels (aka virtualhosts) d'Apache httpd, il faut retirer les directives php_admin_value. Si l'on veut les conserver et que leur valeur est commune à tous les hôtes virtuels, on les déplace dans le php.ini (/etc/php/7.3/fpm/php.ini). Si non, il faut créer autant de pools que de virtualhosts et mettre les directives php_admin_value dans la définition d'un pool (/etc/php/7.3/fpm/pool.d/www.conf, par exemple).

Remplacer prefork par event : a2dismod mpm_prefork && a2enmod mpm_event.

Désactiver le module PHP et activer l'utilisation de PHP-FPM : a2dismod php7.3 && a2enconf php7.3-fpm. Si t'as plusieurs pools, il ne faut pas activer cette conf' généraliste, mais ajouter une directive de proxy fcgi spécifique (socket différente) à l'intérieur de chaque hôte virtuel.

Redémarrer Apache httpd. Si aucune erreur est consignée dans le journal, on peut désinstaller le module PHP pour Apache httpd : apt-get autoremove --purge libapache2-mod-php libapache2-mod-php7.3 && rm -r /etc/php/7.3/apache2.

Les erreurs / avertissements / notifications liées au code PHP (oubli d'un point virgule, mauvais échappement d'une chaîne de caractères, etc.) sont toujours consignées dans le fichier error.log d'un hôte virtuel. Les erreurs liées à PHP-FPM toutes pools confondus (nombre maximum de processus atteint, etc.) sont consignées dans le journal d'erreur de PHP, /var/log/php7.3-fpm.log). Il est possible d'avoir un journal par pool en surchargeant error_log dans la définition du pool.

Par défaut, le pool www est éxecuté sous le compte utilisateur www-data, c'est-à-dire… celui du serveur web. Comme avec le module PHP pour Apache httpd. On peut changer ça (ainsi que les droits sur les fichiers des sites web) mais, boarf, la motivation me manque.


Activer HTTP/2 dans Apache httpd

J'ai déjà tout écrit dans mon shaarli sur mon test de HTTP/2 donc je vais faire court : a2enmod http2 && systemctl restart apache2.

Je rappelle viteuf qu'il y a trois manières d'initier une connexion HTTP/2 : extension TLS ALPN, entête HTTP/1.1 « Upgrade: h2c » sur connexion non chiffrée ou entête HTTP/1.1 « HTTP Alternative Services ». **Les navigateurs web, notamment Mozilla Firefox, prennent en charge exclusivement la première méthode (HTTP/2 over TLS, HTTPS).


Lulz

On notera un truc rigolo dans le journal Apache httpd access.log de l'hôte virtuel lors d'un accès h2c (HTTP/2 sur une connexion en clair, non TLS, non chiffrée) :

2001:db8::1 - - [01/Jan/1970:01:00:00 +0100] "GET / HTTP/2.0" 200 132608 "-" "curl/7.64.0"
2001:db8::1 - - [15/Feb/2020:17:56:05 +0100] "GET / HTTP/1.1" 101 132733 "-" "curl/7.64.0"

La connexion HTTP/2 qui a forcément eu lieu après la connexion HTTP/1.1 est consignée avant… et avec un horodatage inexact.

Cette erreur se retrouve dans les entêtes transmis au client web :

HTTP/1.1 101 Switching Protocols
Upgrade: h2c
Connection: Upgrade

HTTP/2 200 
date: Thu, 01 Jan 1970 00:00:00 GMT
server: Apache
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
pragma: no-cache
last-modified: Sat, 15 Feb 2020 17:08:49 GMT
vary: Accept-Encoding,User-Agent
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: text/html; charset=utf-8

Évidemment, cela a un impact sur la durée du cache côté client web et sur tout ce qui utilise la date… ÉDIT DU 23/11/2020 À 22 H 40 : Cela impacte le calcul de la date dans l'entête « Expire » sur une image, par exemple, mais, dans cet exemple précis, la date qui apparaît dans l'entête « Expires » n'est pas une erreur de calcul liée à la date faussée par le bug h2c, mais une date symbolique passée choisie par les développeurs de PHP pour désactiver la mise en cache lors de l'ouverture d'une session sur un site web. FIN DE L'ÉDIT.

-