Apache : SSLProtocol ignoré

J’ai rencontré un problème récemment. J’avais beau modifier la variable SSLProtocol dans n’importe quel fichier de /etc/apache2/sites-enabled/, ce n’étais jamais pris en compte.

En fait, en bas de la configuration de chaque vhost, Let’s Encrypt avait rajouté la ligne suivante :

Include /etc/letsencrypt/options-ssl-apache.conf

Il fallait donc modifier le SSLProtocol directement dans ce fichier.

Python : jouons avec coding

En lisant l’article Un header d’encoding plus simple pour Python et ses commentaires, j’ai voulu voir jusqu’où on pouvait aller dans la déclaration coding en Python 3.

Je commence par créer le script suivant :

#!/usr/bin/python3
# coding: Latin-1
print('é')

Comme Python 3 est par défaut en UTF-8, je créé suis obligé d’utiliser un autre coding pour voir si c’est pris en compte. Je créé donc le script en UTF-8 mais je déclare un coding en Latin-1. De cette manière, si le coding fonctionne ça affichera é, sinon ça affichera é.

J’aurais pu créer un fichier source en Latin-1, mais si le coding ne fonctionne pas ça me retourne une erreur :

SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xe9 in position 0: unexpected end of data

Je trouve ça beaucoup moins propre.

J’ai aussi choisi de ne pas utiliser le shebang préconisé (#!/usr/bin/env python3). Ça sera utile plus tard.

Je lance donc le script, et le résultat correspond à mes attentes :

$ ./coding.py
é

Le coding est bien pris en compte.

 

Maintenant je vais tester quelques exemples dans les commentaire de l’article. Je commence par celui de Biganon :

#!/usr/bin/python3
# Bonjour, je voudrais utiliser cet encoding: Latin-1 ; et sinon, la famille ça va ?
print('é')
$ ./coding.py
é

Parfait, ça marche.

 

Ensuite je passe à haypo :

#!/usr/bin/python3
# cocoricoding: Latin-1, l’encoding bien français
print('é')
$ ./coding.py
é

Ça marche aussi. On peut donc bien mettre des caractères non-ASCII sur la ligne qui déclare l’encodage.

 

D’après mgautierfr et Sam, la regex permettant de détecter le coding est coding[:=]\s*([-\w.]+). Elle est testée uniquement sur les deux premières lignes du fichier. Voyons ce qu’il est possible de faire avec ça.

 

#!/usr/bin/python3
import os # coding: Latin-1
print('é')
./coding.py
é

Le coding n’est pas pris en compte s’il y a une instruction avant sur la ligne. Dommage, j’aurais bien aimé pouvoir changer l’encodage au milieu d’un script.

 

#!/usr/bin/python3
print('coding:Latin-1')
print('é')
$ ./coding.py
coding:Latin-1
é

Si le coding fait partie de l’instruction, ça ne marche pas non plus.

 

#!/usr/bin/python3
""" coding: Latin-1 """
print('é')
$ ./coding.py
é

Si le coding est entre triple quotes, ça ne fonctionne pas non plus. Si j’ai bien compris la doc (c’est pas garanti), les triples quotes sont considérées comme des instructions par Python. Il est donc normal que ça ne fonctionne pas.

 

#!/usr/bin/python3
# coding: Latin-1 # coding: UTF-8
print('é')
$ ./coding.py
é

S’il y a plusieurs coding, c’est le premier qui est pris en compte.

 

#!/usr/bin/python3 # coding: Latin-1
print('é')
$ ./coding.py
/usr/bin/python3: can't open file '# coding: Latin-1': [Errno 2] No such file or directory

On ne peut pas mettre le coding sur la même ligne que le shebang. Mais ça a l’air d’être une limitation de Bash. Si je garde le même script mais que je le lance directement avec python3 :

$ python3 ./coding.py
é

Là ça marche.

 

Puisque le shebang est géré par Bash et le coding par Python, il est possible de faire des choses sympa. Je commence par créer un lien symbolique /usr/bin/coding:Latin-1 qui pointe vers /usr/bin/python3 :

sudo ln -s /usr/bin/python3 /usr/bin/coding:Latin-1

Ensuite je créé le script suivant :

#!/usr/bin/coding:Latin-1
print('é')
$ ./coding.py
é

Et voilà, en une seule ligne tout le monde est content ! Bash a pu lancer Python via le lien symbolique coding:Latin-1, et Python a trouvé son coding sur la première ligne du script.

 

#!/usr/bin/coding:Latin-1
# coding: UTF-8
print('é')
$ ./coding.py
é

S’il y a deux lignes coding, c’est la première qui est prise en compte.

Docker : can’t create socket (must run as root?) : Permission denied

Dans le cadre de la dockerisation de proxy Zabbix, je suis tombé sur un problème étrange.

Je fais les commandes suivantes :

docker run -it zabbix/zabbix-proxy-sqlite3:ubuntu-3.4-latest /bin/bash
[...]
root@220fab01aae4:/var/lib/zabbix# fping palc.fr
palc.fr is alive
root@220fab01aae4:/var/lib/zabbix# su - zabbix -s /bin/bash
zabbix@220fab01aae4:~$ fping palc.fr
(null): can't create socket (must run as root?) : Permission denied

Note : l’option -it /bin/bash me permets d’avoir directement un bash pour faire mes tests. Lors d’un lancement de Docker en prod, il faudrait utiliser les options -d -t à la place.

Note 2 : vous pouvez également avoir une erreur du type socket: Operation not permitted.

Dans le container Docker, la commande fping fonctionne en root mais pas avec l’utilisateur Zabbix. Pourtant sur le système host, qui utilise le même OS, ça fonctionne bien.

Pour corriger le problème il faut simplement ajouter l’option --sysctl net.ipv4.ping_group_range="0 65535" à la commande lançant le container docker. Ça permets à n’importe quel utilisateur d’accéder directement au réseau de l’hôte, ce qui est indispensable pour effectuer des requêtes ICMP, comme le ping. Dans le cas contraire, seul l’utilisateur root serait autorisé à le faire.

TeamViewer : Pas prêt. Veuillez vérifier votre connexion.

J’’ai récemment dû utiliser TeamViewer dans le cadre de mon travail. Mais il restait bloqué indéfiniment sur l’erreur « Pas prêt. Veuillez vérifier votre connexion. » :

Impossible d’entrer un ID de connexion, ou quoi que ce soit.

La cause de ce problème est simple. Au démarrage TeamViewer fait un test de connexion sur un DNS du type masterX.teamviewer.com (X étant un nombre). Mais comme les DNS sont configurés avec les pieds, si vous êtres en IPv6 il se peut que la résolution se fasse n’importe comment et échoue. La seule solution est de désactiver IPv6 sur votre ordinateur.

Sur un Ubuntu ça se fait de la manière suivante :

  • Éditez le fichier /etc/sysctl.d/99-sysctl.conf
  • Rajoutez les trois lignes suivantes à la fin :
    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1
  • Rechargez la configuration avec sudo sysctl -p
  • Relancez TeamViewer

Notez que ça désactivera complètement IPv6 pour le système d’exploitation entier.

Zabbix : invalid field name « items.jmx_endpoint »

Si vous rencontrez l’erreur suivante dans les logs d’un proxy Zabbix :

failed to update local proxy configuration copy: invalid field name "items.jmx_endpoint"

Ca veut dire que le master est en version 3.4 et que le proxy est en version 3.0. Ces deux versions ne peuvent pas travailler ensemble. Il faut donc mettre à jour le proxy en version 3.4.

Mais cette erreur à une conséquence inattendue. En apparence le proxy fonctionne normalement. Il continue à collecter des données et à les envoyer au master. Par contre il ne peut plus mettre à jour sa configuration (ajout ou modification de métriques). Celle-ci reste figée. Mais si vous relancez le service zabbix_proxy, c’est la cata et même la collecte ne fonctionne plus.

SELinux : détecter et corriger les problèmes de droits

Le problème

Dans le cadre de la supervision MySQL, l’agent Zabbix est censé exécuter cette commande en local pour s’assurer que le serveur accepte bien les connexion :

mysqladmin -h 127.0.0.1 ping

Si je lance la commande en local :

zabbix@1.2.3.4:~$ mysqladmin -h 127.0.0.1 ping
mysqld is alive

Mais quand c’est l’agent Zabbix lui-même qui lance la commande :

mysqladmin: connect to server at '127.0.0.1' failed
error: 'Can't connect to MySQL server on '127.0.0.1' (110)'
Check that mysqld is running on 127.0.0.1 and that the port is 3306.
You can check this by doing 'telnet 127.0.0.1 3306'

Pourtant les deux tests-ci-dessus ont un fonctionnement identique. C’est la même commande qui est utilisée dans les deux cas, avec les même droits. Après une heure à faire des tests et à s’arracher les cheveux pour comprendre d’où peut venir le problème, j’ai pensé à SELinux. Pour voir si SELinux est activé :

root@1.2.3.4:~# getenforce
Enforcing

Là c’est activé, sinon ça m’afficherait Permissive ou Disabled.

Je désactive temporairement SELinux pour faire des tests avec setenforce 0. Comme la supervision Zabbix se mets à fonctionner, je sais que le problème vient de là. Je réactive SELinux avec setenforce 1.

La solution

Pour désactiver définitivement SELinux il faut faire echo "0" > /selinux/enforce. Mais comme je suis sur une plateforme demandant un niveau de sécurité élevé, je ne peux pas le désactive. Il va donc falloir autoriser l’agent Zabbix à utiliser MySQL.

On installe d’abord un utilitaire qui va bien nous aider :

apt-get install policycoreutils

Ensuite on surveille le fichier audit.log :

tail -f -n 0 /var/log/audit/audit.log | audit2allow

À chaque fois que l’agent Zabbix tente de se connecter au MySQL, ca affiche quelque chose qui ressemble à ça :

#============= zabbix_agent_t ==============
allow zabbix_agent_t mysqld_etc_t:file { open read };
#!!!! The file '/var/lib/mysql/mysql.sock' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /var/lib/mysql/mysql.sock
#!!!! This avc can be allowed using the boolean 'daemons_enable_cluster_mode'
allow zabbix_agent_t mysqld_t:unix_stream_socket connectto;

On peut voir la cause du problème. L’agent Zabbix ne peut pas accéder à /var/lib/mysql/mysql.sock. Ça nous donne même l’option à activer : daemons_enable_cluster_mode.

Je lance donc les commandes suivantes :

setsebool -P daemons_enable_cluster_mode 1setsebool daemons_enable_cluster_mode 1

Il ne reste plus qu’à redémarrer l’agent Zabbix (systemctl restart zabbix-agent.service), et le problème est résolu.

Linux : créer une règle firewalld

Récemment j’ai dû créer une règle sur firewalld pour autoriser un agent Zabbix à communiquer. Comme je n’avais jamais utilisé cette solution jusque là j’ai un peu galéré. Voici ma procédure.

Faire un firewall-cmd --get-services. Ça va afficher la liste de tous les services gérés par firewalld. Normalement zabbix-agent n’est pas dedans. On va l’ajouter.

Créez le fichier /etc/firewalld/services/zabbix-agent.xml avec pour contenu :

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>ZABBIX-AGENT</short>
  <description>Flux for zabbix-agent service.</description>
  <port protocol="tcp" port="10050"/>
</service>

Ensuite il faut recharger la configuration en lançant ces quatres commandes :

firewall-cmd --reload
firewall-cmd --add-service=zabbix-agent
firewall-cmd --permanent --add-service=zabbix-agent
firewall-cmd --reload

Si l’option --permanent n’est pas présente, cette configuration ne sera pas conservée après un redémarrage. Si l’option est présente, la configuration ne sera appliquée qu’à partir du redémarrage.

Je ne sais pas pourquoi il faut faire deux fois le --reload. Mais j’ai constaté que s’il n’est fait qu’une seule fois (quelque soit son emplacement), ça ne marche pas.