Exporter et importer Sophos Firewall via l’API Central
Depuis Sophos Central Firewall Management 2026.29, les configurations des firewalls exécutant SFOS 22.0 MR2 ou une version ultérieure peuvent être exportées et importées via l’API REST. Le processus comprend quelques étapes : authentifier l’accès à l’API, déterminer l’ID du firewall, démarrer l’exportation ou le chargement, puis vérifier la transaction renvoyée jusqu’à son terme.
Une importation modifie le firewall cible et ne constitue pas une restauration de sauvegarde. Il faut d’abord créer une sauvegarde du firewall à jour, exécuter le processus sur un firewall de test, puis valider localement le résultat.
Préparer les prérequis et les variables de l’API
Les éléments suivants sont nécessaires :
- un firewall exécutant SFOS 22.0 MR2 ou une version ultérieure, connecté à Sophos Central et géré depuis cette plateforme ;
- un abonnement payant actif pour le firewall, autre que la Base License, ou un contrat de support actif ;
- un identifiant d’API dédié disposant des autorisations nécessaires ;
curl,jqet, pour une importation,md5oumd5sum;- l’ID du tenant, l’hôte régional de l’API et l’ID du firewall ;
- une fenêtre de maintenance et une procédure de retour arrière testée pour les importations.
Les identifiants d’API sont créés dans Sophos Central sous Global Settings > Access Control > API Credentials. Pour un tenant, Sophos recommande le rôle Service Principal Firewall. Dans le Partner Dashboard, la fonction se trouve sous Global Settings > APIs & Integrations > API Credentials Management ; d’autres rôles y sont proposés et il convient d’utiliser celui qui dispose des privilèges minimaux nécessaires pour accéder au tenant cible. Le Client Secret, le JWT, le Secure Storage Master Key ainsi que les URL de téléchargement ou de chargement générées ultérieurement ne doivent pas figurer dans des tickets, chats ou captures d’écran.
Les exemples s’exécutent dans Bash et supposent l’utilisation d’un identifiant de tenant. Les identifiants Partner et Enterprise doivent d’abord résoudre le tenant cible et son hôte régional de l’API. Sophos explique cette différence dans How Our APIs Work.
Saisir le Client ID et le Client Secret sans inscrire le secret dans l’historique du shell :
read -r -p "Client ID: " CLIENT_ID
read -r -s -p "Client Secret: " CLIENT_SECRET
printf '\n'
Demander ensuite un JWT à durée limitée :
JWT=$(
printf '%s' "$CLIENT_SECRET" |
curl --fail-with-body --silent --show-error \
--request POST \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode 'client_secret@-' \
--data-urlencode 'scope=token' \
https://id.sophos.com/api/v2/oauth2/token |
jq -er '.access_token'
)
unset CLIENT_SECRET
Les exemples curl simples transmettent le JWT de courte durée comme argument d’en-tête. Ils doivent donc être exécutés sur un poste d’administration de confiance où aucun utilisateur non autorisé ne peut lire les arguments des processus locaux.
Avec un identifiant de tenant, whoami renvoie l’ID du tenant et l’hôte régional de l’API :
WHOAMI=$(
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $JWT" \
https://api.central.sophos.com/whoami/v1
)
TENANT_ID=$(jq -er 'select(.idType == "tenant") | .id' <<<"$WHOAMI")
API_HOST=$(jq -er '.apiHosts.dataRegion' <<<"$WHOAMI")
printf 'Tenant: %s\nAPI host: %s\n' "$TENANT_ID" "$API_HOST"
Si jq s’interrompt à ce stade, l’identifiant est probablement associé à un partenaire ou à une organisation Enterprise. Il ne faut alors pas continuer en utilisant son ID comme X-Tenant-ID, mais déterminer le tenant géré et son apiHost.
Déterminer l’ID du firewall
La liste des firewalls affiche le nom, le hostname, le numéro de série, le firmware et l’UUID :
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
"$API_HOST/firewall/v1/firewalls?pageSize=1000" |
jq -r '.items[] |
[.name, .hostname, .serialNumber, .firmwareVersion, .id] |
@tsv'
Utiliser l’UUID du firewall approprié et ne pas le sélectionner uniquement en fonction d’un nom d’affichage similaire :
FIREWALL_ID="<firewall-uuid>"
Si le firewall n’apparaît pas, vérifier d’abord le tenant, la région, la connexion à Central et l’approbation de la gestion. L’enregistrement est expliqué dans Connecter Sophos Firewall à Sophos Central.
Exporter la configuration
Démarrer une exportation complète
L’exportation s’exécute de manière asynchrone. Le premier appel ne renvoie donc qu’un ID de transaction :
EXPORT_RESPONSE=$(
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
--header 'Content-Type: application/json' \
--data '{"fullExport":true}' \
"$API_HOST/firewall/v1/firewall-config/firewalls/$FIREWALL_ID/export"
)
EXPORT_TX=$(jq -er '.transactionId' <<<"$EXPORT_RESPONSE")
printf 'Export transaction: %s\n' "$EXPORT_TX"
Récupérer à nouveau l’état après quelques secondes :
EXPORT_STATUS=$(
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
"$API_HOST/firewall/v1/firewall-config/firewalls/transactions/$EXPORT_TX"
)
jq '{status, result, createdAt, finishedAt, expiryAt, response}' \
<<<"$EXPORT_STATUS"
Répéter la requête environ toutes les dix secondes jusqu’à ce que status atteigne l’état final finished. pending et started ne constituent pas encore des erreurs.
Ce n’est que lorsque status: "finished" et result: "success" sont renvoyés que response.url contient l’URL de téléchargement à durée limitée :
DOWNLOAD_URL=$(
jq -er '
select(.status == "finished" and .result == "success") |
.response.url
' <<<"$EXPORT_STATUS"
)
OUTPUT="sophos-firewall-config-$(date +%F).tar"
curl --fail-with-body --location --output "$OUTPUT" "$DOWNLOAD_URL"
tar -tf "$OUTPUT"
unset DOWNLOAD_URL
Le fichier TAR peut contenir des données sensibles relatives au réseau, aux utilisateurs, aux VPN et aux stratégies. Il faut le stocker de manière sécurisée ou le supprimer après l’analyse. Pour obtenir un rapport lisible ou effectuer une comparaison avant-après, le fichier Entities.xml inclus peut être utilisé dans Sophos Firewall Config Studio.
Exporter uniquement certaines configurations
Pour une exportation sélective, les noms des entités doivent être saisis exactement et en respectant la casse. Cet exemple exporte les règles de firewall et de NAT avec les objets dépendants :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
--header 'Content-Type: application/json' \
--data '{
"fullExport": false,
"includeDependency": true,
"exportEntities": ["FirewallRule", "NATRule"]
}' \
"$API_HOST/firewall/v1/firewall-config/firewalls/$FIREWALL_ID/export"
Les noms d’entité valides sont indiqués dans l’endpoint d’exportation actuel de l’API Sophos Firewall. Pour une exportation sélective, la valeur par défaut de includeDependency est false ; cette option doit être définie de manière intentionnelle et le paquet obtenu doit tout de même être vérifié.
Importer la configuration
L’importation consiste à demander une URL de chargement, charger le fichier TAR, confirmer les métadonnées du fichier et vérifier la transaction. L’exemple n’utilise qu’un firewall de test et définit volontairement performPartialImport sur false. La valeur par défaut de l’API est true et autorise une importation partielle pour chaque firewall.
Vérifier d’abord la compatibilité : le firewall cible doit disposer au minimum de la même version du firmware et des patterns. Sophos ne prend en charge les importations sélectives entre différents modèles que d’un modèle inférieur vers un modèle supérieur ; le matériel cible doit posséder au moins autant de ports Ethernet. Si les noms des ports diffèrent, il faut adapter Entities.xml avant le chargement.
Préparer le fichier d’importation et la somme de contrôle
Préparer le fichier cible, la somme de contrôle et la taille du fichier :
FILE="sophos-firewall-config-2026-08-03.tar"
FILE_SIZE=$(wc -c <"$FILE" | tr -d ' ')
Sous macOS :
CHECKSUM_MD5=$(md5 -q "$FILE")
Sous Linux :
CHECKSUM_MD5=$(md5sum "$FILE" | awk '{print $1}')
Demander une session de chargement et charger le fichier
Demander une session de chargement et afficher uniquement les champs non secrets :
IMPORT_SESSION=$(
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
"$API_HOST/firewall/v1/firewall-config/firewalls/import"
)
IMPORT_TX=$(jq -er '.transactionId' <<<"$IMPORT_SESSION")
UPLOAD_URL=$(jq -er '.url' <<<"$IMPORT_SESSION")
jq '{transactionId, method, expiresAt}' <<<"$IMPORT_SESSION"
Charger le fichier avec la méthode PUT renvoyée avant l’expiration de l’URL présignée. Ne pas envoyer d’en-tête JWT ou de tenant à cette URL :
curl --fail-with-body --silent --show-error \
--request PUT \
--upload-file "$FILE" \
"$UPLOAD_URL"
unset UPLOAD_URL
Terminer l’importation et vérifier l’état
Si le paquet contient des informations sensibles et qu’il est importé sur un firewall différent ou nouvellement déployé, le Secure Storage Master Key correspondant est nécessaire. Sans cette clé, SFOS n’importe pas les informations sensibles ni les configurations qui en dépendent. L’invite suivante n’affiche pas le secret ; appuyer sur Entrée permet de l’omettre :
read -r -s -p "Secure Storage Master Key, ou appuyez sur Entrée : " SSMK
printf '\n'
Terminer le chargement et attribuer le paquet au firewall cible :
TARGET_FIREWALL_ID="$FIREWALL_ID"
COMPLETE_RESPONSE=$(
printf '%s' "$SSMK" |
jq -Rsc \
--arg firewall "$TARGET_FIREWALL_ID" \
--arg checksum "$CHECKSUM_MD5" \
--argjson size "$FILE_SIZE" '
. as $ssmk |
{
firewallIds: [$firewall],
checksumMd5: $checksum,
fileSizeBytes: $size,
performPartialImport: false
}
+ if ($ssmk | length) > 0
then {secureMasterKey: $ssmk}
else {}
end
' |
curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
--header 'Content-Type: application/json' \
--data-binary @- \
"$API_HOST/firewall/v1/firewall-config/firewalls/import/$IMPORT_TX/upload-complete"
)
unset SSMK
jq '{id, status, result}' <<<"$COMPLETE_RESPONSE"
Une requête accepte entre 1 et 25 ID de firewall uniques. Pour d’autres firewalls, le paquet doit être chargé à nouveau ; il ne faut pas réutiliser la même URL présignée ni le même ID de transaction.
Vérifier l’état de l’importation via le même endpoint de transaction :
IMPORT_STATUS=$(
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $JWT" \
--header "X-Tenant-ID: $TENANT_ID" \
"$API_HOST/firewall/v1/firewall-config/firewalls/transactions/$IMPORT_TX"
)
jq '{status, result, createdAt, finishedAt, response}' <<<"$IMPORT_STATUS"
Répéter également cette requête environ toutes les dix secondes jusqu’à ce que status: "finished" apparaisse. Ce n’est qu’ensuite qu’il faut évaluer result et, pour plusieurs cibles, chaque élément de response.items.
success confirme le traitement par l’API, et non le résultat fonctionnel.
Valider localement l’importation
Après finished, vérifier les points suivants sur chaque firewall cible :
- Les règles, objets et paramètres attendus sont-ils exactement présents ?
- Des utilisateurs, mots de passe, certificats ou objets dépendants sont-ils absents en raison d’un SSMK manquant ou incorrect ?
- Les interfaces, zones, passerelles, le firmware, la version des patterns et le modèle matériel correspondent-ils au paquet ?
- Le routage, le NAT, les VPN, l’authentification et l’accès d’administration fonctionnent-ils avec des cas de test définis ?
- L’Audit Trail et les journaux de configuration indiquent-ils des modifications inattendues ?
- Une nouvelle exportation ou comparaison avec Config Studio ne montre-t-elle que les différences prévues ?
L’importation et l’exportation mettent à jour la configuration existante et ne suppriment pas automatiquement tout ce qui est absent du paquet. Le fichier TAR ne représente donc ni un état cible complet ni un substitut à une sauvegarde, un rollback et un test fonctionnel.
Dépannage
L’exportation ne fournit pas d’URL de téléchargement
L’URL apparaît uniquement après status: "finished" et result: "success". En cas de error ou de partialSuccess, vérifier les champs de response et ne pas poursuivre avec une URL vide ou expirée.
HTTP 401 ou 403
Avec 401, le JWT est généralement expiré ou non valide. Il faut s’authentifier à nouveau. Avec 403, vérifier le rôle Central, le contexte du tenant, X-Tenant-ID et l’hôte régional de l’API. L’autorisation de l’API XML locale sous /webconsole/APIController ne s’applique pas ici ; elle est traitée séparément dans Sécuriser l’accès à l’API XML de Sophos Firewall.
Upload-complete renvoie 400 ou 409
Vérifier l’ID de transaction, l’heure d’expiration de l’URL de chargement, la taille réelle du fichier, la somme de contrôle MD5 hexadécimale et les ID de firewall uniques. Ne pas modifier le fichier après son chargement. Utiliser une nouvelle session de chargement pour une nouvelle tentative.
L’importation se termine par error ou partialSuccess
Enregistrer response et, pour plusieurs firewalls cibles, response.items. Si un appel d’API renvoie une réponse d’erreur 4xx ou 5xx distincte, consigner également error, message, code, correlationId et requestId. Vérifier ensuite localement la version cible, la version des patterns, le modèle, les ports, les dépendances et le SSMK. Si la réponse de Central ne suffit pas, contrôler fwcm-api-executor.log sur le firewall comme décrit dans Services et fichiers journaux de Sophos Firewall.
L’endpoint de transaction fait foi pour l’état de l’API ; ne pas supposer que la tâche apparaît dans la Central Firewall Task Queue.
Une importation très volumineuse s’interrompt
Sophos répertorie le Known Issue NR-19066 : une importation comportant un très grand nombre d’objets peut dépasser la limite de traitement de deux heures. Au lieu de répéter l’importation complète sans modification, créer des paquets sélectifs plus petits, les importer individuellement et valider chaque étape.
À la fin de la session, supprimer les variables sensibles :
unset JWT CLIENT_ID TENANT_ID API_HOST FIREWALL_ID TARGET_FIREWALL_ID
unset EXPORT_TX IMPORT_TX CHECKSUM_MD5 FILE_SIZE