Pour sécuriser un appareil IoT Raspberry Pi, il faut fermer les portes faciles que recherchent les attaquants : connexions par mot de passe, ports ouverts, paquets obsolètes, services exécutés en root et trafic non chiffré. Cette checklist parcourt chaque couche avec les commandes exactes pour Raspberry Pi OS Bookworm, et se termine par une connexion MQTT chiffrée en TLS qui ne nécessite aucun port entrant. Appliquez-la une fois, puis intégrez le résultat à votre image pour que chaque nouvel appareil démarre déjà durci.
Modèle de menace pour un Pi sur le terrain
Une passerelle Pi est un petit serveur Linux installé dans un endroit que vous ne contrôlez pas entièrement : le réseau d'un client, un atelier de production, une armoire en bord de route. Les menaces réalistes n'ont rien d'exotique. Des scanners automatisés essaient des mots de passe par défaut ou faibles via SSH. Des services non patchés sont exploités grâce à des vulnérabilités connues. Une application compromise exécutée en root prend le contrôle de tout l'appareil. Des identifiants oubliés dans un script finissent dans un dépôt Git ou un ticket de support. Le trafic MQTT non chiffré est lu ou modifié sur un réseau partagé. Quelqu'un ayant un accès physique retire la carte SD et la lit.
Chaque point de la checklist ci-dessous cible l'une de ces menaces. Aucun ne nécessite de matériel particulier.
La checklist en un coup d'œil
| # | Domaine | Action | Protège contre |
|---|---|---|---|
| 1 | Comptes | Utilisateur unique, mot de passe robuste, pas d'images partagées aux identifiants connus | Attaques par identifiants par défaut |
| 2 | SSH | Clés uniquement, pas de login root, restriction de port optionnelle | Force brute sur les mots de passe |
| 3 | Pare-feu | Refus du trafic entrant par défaut, SSH autorisé depuis les réseaux d'administration uniquement | Services exposés |
| 4 | Mises à jour | Mises à jour de sécurité automatiques, mises à niveau complètes régulières | Vulnérabilités connues |
| 5 | Services | Désactiver ce que vous n'utilisez pas | Surface d'attaque inutile |
| 6 | Moindre privilège | Utilisateur de service dédié, sandboxing systemd | Élévation de privilèges |
| 7 | Secrets | Identifiants dans un fichier d'environnement appartenant à root, pas dans le code | Fuites d'identifiants |
| 8 | MQTT | TLS sur le port 8883, identifiants uniques par appareil | Écoute, usurpation |
| 9 | Surveillance | Connexions, échecs d'authentification, santé via MQTT | Compromission non détectée |
| 10 | Physique | Boîtier, interfaces inutilisées désactivées, choix du stockage | Manipulation physique |
1. Comptes
Les images actuelles de Raspberry Pi OS ne sont plus livrées avec l'ancien utilisateur pi et son mot de passe par défaut ; vous créez un utilisateur dans Raspberry Pi Imager ou au premier démarrage. Choisissez un nom d'utilisateur peu évident et un mot de passe long, et ne distribuez jamais une image maître où tous les appareils partagent les mêmes identifiants. Si vous construisez des images pour une flotte, générez des identifiants par appareil au moment du provisionnement.
# vérifier quels comptes peuvent se connecter
grep -vE "nologin|false" /etc/passwd
# verrouiller le mot de passe de tout compte qui ne doit utiliser que des clés
sudo passwd -l someuser
2. SSH avec clés uniquement
Copiez votre clé publique sur le Pi, vérifiez que vous pouvez vous connecter avec, puis désactivez l'authentification par mot de passe via un fichier drop-in pour que les mises à jour de paquets n'écrasent pas votre modification.
# sur votre poste de travail
ssh-keygen -t ed25519 -C "admin@workstation"
ssh-copy-id admin@gateway-01.local
# sur le Pi
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
MaxAuthTries 3
EOF
sudo sshd -t && sudo systemctl reload ssh
Gardez votre session actuelle ouverte et testez une nouvelle connexion dans un second terminal avant de la fermer. Si vous n'avez pas du tout besoin de SSH sur les appareils déployés, désactivez-le avec sudo systemctl disable --now ssh et prévoyez une procédure de maintenance qui l'active temporairement.
3. Pare-feu
Une passerelle MQTT n'établit que des connexions sortantes : elle n'a besoin de presque aucune règle entrante. ufw garde la configuration lisible :
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp # sous-réseau d'administration uniquement
sudo ufw limit 22/tcp
sudo ufw enable
sudo ufw status verbose
Remplacez le sous-réseau par votre réseau d'administration. Pour des environnements plus stricts, refusez aussi le trafic sortant et n'autorisez que DNS, NTP, les miroirs de paquets et votre broker MQTT sur le port 8883. Ajoutez fail2ban si SSH doit être joignable depuis des réseaux plus larges.
4. Mises à jour
La plupart des compromissions réelles exploitent des vulnérabilités déjà corrigées. Activez les mises à jour de sécurité automatiques et planifiez des mises à niveau complètes régulières :
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
sudo unattended-upgrade --dry-run --debug | tail -n 20
Incluez vos dépendances Python dans cette routine. Figez les versions dans un requirements.txt, testez les mises à niveau d'abord sur un appareil, puis déployez-les sur la flotte.
5. Désactiver les services inutilisés
Chaque service actif est quelque chose à patcher et quelque chose à attaquer. Listez ce qui est activé et coupez ce dont votre passerelle n'a pas besoin :
systemctl list-unit-files --state=enabled --type=service
sudo systemctl disable --now avahi-daemon cups 2>/dev/null
sudo systemctl disable --now bluetooth # seulement si vous n'utilisez pas le BLE
Sur les appareils headless, vous pouvez aussi désactiver le Wi-Fi ou le Bluetooth au niveau matériel dans config.txt avec dtoverlay=disable-wifi ou dtoverlay=disable-bt lorsque l'appareil n'utilise que l'Ethernet.
6. Moindre privilège pour votre application
Exécutez le client MQTT sous un utilisateur système dédié, sans shell de connexion et avec uniquement les groupes nécessaires (par exemple gpio ou dialout). Laissez ensuite systemd le placer en bac à sable :
sudo useradd --system --home /opt/gateway --shell /usr/sbin/nologin gateway
sudo usermod -aG gpio gateway
[Service]
User=gateway
Group=gateway
EnvironmentFile=/etc/gateway/mqtt.env
ExecStart=/opt/gateway/.venv/bin/python -u /opt/gateway/gateway.py
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/gateway
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
ProtectSystem=strict rend tout le système de fichiers en lecture seule pour le service, sauf les chemins listés : un script compromis ne peut donc ni modifier les fichiers système ni s'installer durablement. Lancez systemd-analyze security gateway.service pour voir quelles options supplémentaires s'appliquent. L'unité complète, politiques de redémarrage comprises, se trouve dans lancer un script Python MQTT au démarrage.
7. Garder les secrets hors du code
Stockez les identifiants du broker dans un fichier d'environnement lisible uniquement par root (systemd le lit avant d'abandonner les privilèges) :
sudo mkdir -p /etc/gateway
sudo tee /etc/gateway/mqtt.env > /dev/null <<'EOF'
MQTT_HOST=broker.connectmq.com
MQTT_PORT=8883
MQTT_USERNAME=YOUR_USERNAME
MQTT_PASSWORD=YOUR_PASSWORD
MQTT_CLIENT_ID=YOUR_CLIENT_ID
EOF
sudo chmod 600 /etc/gateway/mqtt.env
Gardez ce fichier hors du contrôle de version et de toute image que vous partagez. Si un appareil est perdu ou retiré du service, révoquez ses identifiants côté broker.
8. Sécuriser la connexion MQTT
MQTT en clair sur le port 1883 transmet identifiants et données sans chiffrement. Utilisez TLS sur le port 8883. Les brokers ConnectMQ présentent un certificat Let's Encrypt, auquel le Pi fait déjà confiance via son magasin de CA système : aucun fichier de certificat n'est nécessaire.
import os
import paho.mqtt.client as mqtt
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=os.environ["MQTT_CLIENT_ID"])
client.username_pw_set(os.environ["MQTT_USERNAME"], os.environ["MQTT_PASSWORD"])
client.tls_set() # vérifie le certificat du serveur et le nom d'hôte
client.connect(os.environ["MQTT_HOST"], int(os.environ["MQTT_PORT"]), keepalive=60)
client.loop_forever()
N'appelez jamais tls_insecure_set(True) en production : cela désactive la vérification du nom d'hôte et annule tout l'intérêt de TLS. Vérifiez que l'horloge est correcte, car la validation du certificat échoue si le Pi démarre avec une date erronée et que NTP n'a pas encore synchronisé. Utilisez des identifiants uniques pour chaque appareil : sur ConnectMQ, les client IDs sont liés aux identifiants émis, et des échecs de connexion répétés depuis une adresse entraînent un blocage IP. Le guide Python MQTT TLS approfondit les options de certificat, et les bonnes pratiques de sécurité MQTT traitent le côté broker. Comme l'appareil ne se connecte qu'en sortie, le pare-feu de l'étape 3 reste fermé.
N'oubliez pas que le serveur MQTT public gratuit est lisible par tout le monde. Il sert uniquement aux tests et prototypes ; les appareils de production ont leur place sur un broker privé.
9. Surveillance
Un appareil durci a toujours besoin d'être surveillé. Examinez journalctl -u ssh pour repérer des connexions inattendues, publiez les événements de santé et de sécurité (tentatives SSH échouées, redémarrages de service, reboots inattendus) sur un topic MQTT, et déclenchez des alertes en cas d'anomalie. Un topic d'état Last Will retained vous signale immédiatement qu'un appareil passe hors ligne, ce qui peut être le premier signe d'une manipulation.
10. Sécurité physique
Si quelqu'un peut retirer le stockage, il peut lire tout ce qu'il contient, identifiants compris. Utilisez un boîtier verrouillable, envisagez de démarrer sur le stockage interne des appareils basés sur un Compute Module, désactivez l'USB et le HDMI inutilisés lorsque votre matériel le permet, et considérez tout appareil qui a échappé à votre contrôle comme non fiable jusqu'à sa réinstallation. La documentation Raspberry Pi explique les options de configuration concernées.
Ces étapes se combinent bien avec les conseils de fiabilité pour Raspberry Pi et constituent ensemble le socle de toute passerelle construite à partir du tutoriel Raspberry Pi MQTT.
Connectez-vous en toute sécurité avec ConnectMQ
Un appareil durci mérite un broker conçu pour la production. ConnectMQ est un broker MQTT managé avec TLS sur le port 8883, WebSocket sécurisé sur le port 8084, identifiants par appareil et protection contre le flood. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, et connectez votre premier Pi durci en TLS en quelques minutes.
Questions fréquentes
Dois-je ouvrir des ports pour MQTT sur le Raspberry Pi ?
Non. Un client MQTT se connecte en sortie vers le broker : le Pi n'a besoin d'aucun port entrant pour MQTT. N'autorisez le SSH entrant que depuis des réseaux d'administration de confiance, si tant est que vous en ayez besoin.
Le port 1883 est-il parfois acceptable ?
Uniquement pour des tests en local avec des données non sensibles. Tout ce qui traverse un réseau non fiable doit utiliser TLS sur le port 8883 afin que les identifiants et les payloads soient chiffrés.
Chaque appareil doit-il avoir ses propres identifiants MQTT ?
Oui. Des identifiants uniques vous permettent de révoquer un seul appareil perdu ou compromis sans toucher au reste de la flotte, et ils rendent les logs exploitables.
Le chiffrement du disque est-il utile sur un Raspberry Pi ?
Il protège les données si le stockage est volé, mais l'appareil doit alors pouvoir se déverrouiller au démarrage sans intervention humaine, ce qui est difficile à faire de manière sûre sur un Pi. Pour la plupart des passerelles, réduire au minimum les secrets stockés et utiliser des identifiants révocables est plus pragmatique.



