Architecture Sécurisée pour Accès Distants : Zero-Trust avec Raspberry Pi 3, WireGuard et OPNsense

Cet article présente un guide pas à pas pour déployer un hotspot wifi en mode Zero-Trust, cela permet de déployer un point d’accès rendant possible l’accès à des données ultra-sensibles de son système d’information. Il fait parti d’un ensemble de cinq articles pour un système d’information de voyage.

Cet article en particulier ne s’applique pas seulement au cas de la conception d’un SI nomade. Un accès distant Zero-Trust est un élément qui vous permettra de renforcer votre sécurité et de réduire les risques de vol de données dans le cloud, par exemple pour une situation de télétravail.

Introduction : Contexte et objectifs

Face à la montée des menaces cyber et aux exigences croissantes des entreprises en matière d’accès distant sécurisé, il devient indispensable de mettre en place une solution qui combine :

  • Isolation réseau et chiffrement multi-couches
  • Supervision centralisée pour le suivi des ressources et la détection d’anomalies
  • Matériel résilient et jetable : le Raspberry Pi 3, équipé d’un écran tactile, sert de borne Wi-Fi sécurisée.

L’objectif est de permettre à plusieurs utilisateurs sur un site distant d’accéder à des ressources critiques sur le réseau interne, tout en limitant la surface d’attaque grâce à une architecture Zero-Trust. La solution repose sur :

  • Un hotspot Wi-Fi géré par un Raspberry Pi 3 capable de choisir la connexion (Ethernet ou USB).
  • Une double encapsulation VPN via WireGuard avec deux passerelles OPNsense.
  • Une mise à jour centralisée des configurations.
  • Des mécanismes de vérification d’intégrité et l’utilisation de TPM/swtpm pour sécuriser le matériel.

Architecture globale

Flux de Contrôle :

  1. Authentification 802.1X et vérification TPM sur le Raspberry Pi.
  2. Double tunnel VPN WireGuard pour encapsuler et chiffrer le trafic.
  3. Gestion des configurations et des accès via OPNsense (règles strictes Zero-Trust).
  4. Mise à jour centralisée via SSH et vérification d’intégrité (checksum).
  5. Supervision continue des Raspberry Pi et des mobiles via Prometheus/Grafana.

1. Configuration du Raspberry Pi 3 et de l’écran tactile

1.1. Préparation d’une image sécurisée

Pour limiter les risques d’altération, préparez une image de base en mode read-only et désactivez les services inutiles.

# Passage en mode overlay (lecture seule)
sudo raspi-config nonint do_overlayfs
sudo apt purge --auto-remove triggerhappy logrotate
sudo systemctl mask apt-daily.service apt-daily-upgrade.service

# Désactivation des services non essentiels
sudo systemctl stop bluetooth.service
sudo systemctl disable bluetooth.service

1.2. Interface tactile et choix de connexion

L’écran tactile permet de choisir le mode de connexion (Ethernet, USB, ou Wi-Fi via hotspot).

Exemple d’interface avec Tkinter (ne pas réutiliser) :

import tkinter as tk
from tkinter import messagebox

def select_connection(mode):
    if mode == "Ethernet":
        messagebox.showinfo("Connexion", "Configuration Ethernet sélectionnée.")
        subprocess.run(["/usr/local/bin/setup_network.sh", "ethernet"])
    elif mode == "USB":
        messagebox.showinfo("Connexion", "Configuration USB sélectionnée.")
        subprocess.run(["/usr/local/bin/setup_network.sh", "usb"])
    elif mode == "Wi-Fi":
        messagebox.showinfo("Connexion", "Activation du Hotspot Wi-Fi sécurisé.")
        subprocess.run(["/usr/local/bin/wifi_manager.py"])
        
root = tk.Tk()
root.title("Sélection de la connexion")
root.geometry("480x320")

label = tk.Label(root, text="Choisissez votre mode de connexion :", font=("Helvetica", 16))
label.pack(pady=20)

tk.Button(root, text="Ethernet", command=lambda: select_connection("Ethernet"), width=20, height=2).pack(pady=10)
tk.Button(root, text="USB", command=lambda: select_connection("USB"), width=20, height=2).pack(pady=10)
tk.Button(root, text="Wi-Fi (Hotspot)", command=lambda: select_connection("Wi-Fi"), width=20, height=2).pack(pady=10)

root.mainloop()

1.3. Point d’accès Wi-Fi avec QRCode dynamique

Un script génère un nouveau SSID et mot de passe à chaque rotation, met à jour le fichier de configuration de hostapd, et génère un QRCode pour une connexion rapide.

Script /usr/local/bin/wifi_manager.py :

import random
import string
import subprocess
from datetime import datetime

def generate_credentials():
    date_str = datetime.now().strftime("%m%d")
    ssid = f"CAMPING-{date_str}"
    password = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(12))
    return ssid, password

def update_hostapd(ssid, password):
    config = f"""interface=wlan0
driver=nl80211
ssid={ssid}
hw_mode=g
channel=6
wpa=2
wpa_passphrase={password}
wpa_key_mgmt=WPA-PSK
"""
    with open('/etc/hostapd/hostapd.conf', 'w') as f:
        f.write(config)
    subprocess.run(['systemctl', 'restart', 'hostapd'])

def create_qrcode(ssid, password):
    auth_string = f'WIFI:T:WPA;S:{ssid};P:{password};;'
    subprocess.run(f'qrencode -o /tmp/wifi_qr.png -s 10 "{auth_string}"', shell=True)

if __name__ == "__main__":
    ssid, password = generate_credentials()
    update_hostapd(ssid, password)
    create_qrcode(ssid, password)

1.4. Intégration de la connexion réseau (Ethernet/USB)

Un script simple configure la connexion réseau en fonction du choix effectué via l’interface tactile.

Script /usr/local/bin/setup_network.sh :

#!/bin/bash
if [ "$1" == "ethernet" ]; then
    echo "Configuration Ethernet..."
    sudo dhclient eth0
elif [ "$1" == "usb" ]; then
    echo "Configuration USB..."
    sudo ifconfig usb0 up
    sudo dhclient usb0
fi

2. Mise en place du VPN et intégration OPNsense

2.1. Configuration WireGuard sur le Raspberry Pi

Le tunnel VPN protège le trafic du Pi vers la passerelle externe.

Exemple de configuration (/etc/wireguard/wg0.conf) :

[Interface]
PrivateKey = CLÉ_PRIVÉE_PI
Address = 10.100.0.2/32
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PreDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = CLÉ_PUBLIQUE_OPNSENSE
AllowedIPs = 0.0.0.0/0
Endpoint = opnsense.example.com:51820
PersistentKeepalive = 25

2.2. Intégration dans OPNsense et Configuration du Pare-feu

Les règles OPNsense doivent limiter l’accès au réseau interne.

Exemple de configuration OPNsense (extrait XML) :

<rule>
  <description>Autoriser le trafic VPN du Raspberry Pi vers FW interne</description>
  <type>pass</type>
  <interface>wg1</interface>
  <direction>in</direction>
  <ipprotocol>inet</ipprotocol>
  <statetype>keep state</statetype>
  <source>10.100.0.0/24</source>
  <destination>192.168.100.2</destination>
  <protocol>udp</protocol>
  <destination_port>51830</destination_port>
</rule>

3. Mise à jour centralisée, Vérification d’intégrité et Sécurité matérielle

3.1. Mise à jour centralisée des configurations

Chaque Raspberry Pi récupère sa configuration depuis un serveur central via SSH. Un mécanisme de fallback permet de continuer à fonctionner en cas d’indisponibilité du serveur.

Exemple de script de mise à jour (/usr/local/bin/config_update.sh) :

#!/bin/bash
GPG_KEY="/usr/share/keys/entreprise-pub.gpg"
CONFIG_URL="https://config.entreprise.com/rpi/${HOSTNAME}.tar.gz.sig"

# Tenter de récupérer la configuration
if curl -s "${CONFIG_URL}" | gpgv --keyring "${GPG_KEY}" - | tar xz -C /etc --overwrite-dir; then
    echo "Configuration mise à jour depuis le serveur central."
else
    echo "Serveur central indisponible, utilisation de la configuration de secours."
    cp /etc/config_backup/* /etc/
fi

systemctl daemon-reload

3.2. Vérification d’intégrité par checksum

Pour garantir que le système n’a pas été modifié de manière non autorisée, un script calcule et vérifie les checksums des fichiers critiques.

Script (/usr/local/bin/integrity_check.sh) :

#!/bin/bash
DIRS=("/etc/hostapd" "/etc/wireguard")
TMP_FILE="/tmp/$(hostname)_checksums.txt"

{
  echo "# $(date)"
  for dir in "${DIRS[@]}"; do
    find $dir -type f -exec sha256sum {} \;
  done
} > "$TMP_FILE"

# Vous pouvez comparer ce fichier à une version attendue ou le transmettre pour audit

3.3. Sécurité matérielle avec TPM/swtpm

L’utilisation d’un module TPM (ou swtpm pour simulation) permet de protéger les clés sensibles et de garantir l’intégrité matérielle lors du boot.

Exemple de commandes TPM :

# Création d'un Endorsement Key et d'un Attestation Key
tpm2_createek -C e -c ek.ctx -G rsa -u ek.pub
tpm2_createak -C ek.ctx -c ak.ctx -G rsa -s rsassa -u ak.pub -n ak.name

# Attestation de Boot : enregistrement des événements dans les PCR
tpm2_pcrevent 0 /boot/vmlinuz
tpm2_pcrevent 1 /boot/initrd.img

# Vérification de l'intégrité via quote (simulation d'extraction d'un quote)
if ! tpm2_checkquote -u ak.pub -m pcr.bin -s quote.sig; then
    echo "Alerte : Altération détectée !" | mail -s "TPM Alert" security@entreprise.com
    sudo systemctl stop networking
fi

4. Supervision et Gestion des Incidents

4.1. Monitoring centralisé avec Prometheus et Grafana

Chaque Raspberry Pi et chaque mobile connecté transmet des métriques (état du VPN, charge système, intégrité, etc.) pour une supervision centralisée.

Exemple d’alerte Prometheus :

- alert: VPNMobileInactive
  expr: up{job="mobile",vpn_status="down"} == 1
  for: 1m
  labels:
    severity: warning
  annotations:
    summary: "Un mobile est connecté sans VPN actif"

4.2. Procédures de réponse aux incidents et reprise d’activité

En cas d’incident, une procédure automatique révoque les accès, bloque l’IP concernée et capture les logs pour analyse.

Exemple de procédure en Python :

def incident_response(pi_ip):
    steps = [
        ("Révocation de la clé WG", revoke_wireguard_key(pi_ip)),
        ("Blocage IP via OPNsense", opnsense_api.block_ip(pi_ip)),
        ("Capture de logs", capture_forensic_logs(pi_ip)),
        ("Notification", send_alert(f"Incident détecté sur {pi_ip}"))
    ]
    for description, result in steps:
        if not result:
            escalate_to_human()
            break

4.3. Plan de Reprise d’Activité

Un script de basculement active le tunnel VPN secondaire si un incident est détecté.

#!/bin/bash
# failover.sh
case "$1" in
  start)
    nmcli con up "Backup_VPN" ifname wg1
    ip route add 10.100.0.0/16 via 192.168.100.1 metric 100
    ;;
  stop)
    nmcli con down "Backup_VPN"
    ;;
esac

Conclusion et perspectives

Cette architecture Zero-Trust offre une solution robuste et résiliente pour sécuriser l’accès distant aux ressources internes dans des environnements non maîtrisés. Grâce à :

  • Un Raspberry Pi 3 équipé d’un écran tactile permettant de choisir le mode de connexion (Ethernet, USB ou Hotspot Wi-Fi),
  • Une rotation automatique des identifiants du hotspot via QRCode,
  • Une double encapsulation VPN (WireGuard) avec des règles strictes gérées par OPNsense,
  • Une mise à jour centralisée des configurations avec mécanisme de fallback,
  • Une vérification d’intégrité régulière et l’utilisation de TPM pour protéger le matériel,
  • Une surveillance centralisée via Prometheus et Grafana et des procédures de réponse aux incidents,

vous obtenez une infrastructure de sécurité, résiliente même en cas de défaillance d’un Raspberry Pi ou de vol de l’un d’eux. Cette solution est une approche transportable et low-cost d’un point d’accès ultra sécurisé.

Notre série sur un SI de voyage hautement sécurisé

Si vous ne les avez pas encore lu, retrouvez notre série d’articles sur la conception un Système d’Information transportable :