Przejdz do tresci
Avanet

Eksport i import Sophos Firewall przez Central API

Od wersji Sophos Central Firewall Management 2026.29 konfiguracje zapór z systemem SFOS 22.0 MR2 lub nowszym można eksportować i importować przez REST API. Proces składa się z kilku kroków: uwierzytelnienia dostępu do API, ustalenia identyfikatora zapory, uruchomienia eksportu lub wysyłania pliku oraz sprawdzania zwróconej transakcji aż do jej zakończenia.

Import zmienia zaporę docelową i nie jest odtworzeniem kopii zapasowej. Najpierw należy utworzyć aktualną kopię zapasową zapory, przetestować proces na zaporze testowej, a następnie lokalnie zweryfikować jego rezultat.

Przygotowanie wymagań i zmiennych API

Potrzebne są:

  • zapora połączona z Sophos Central i zarządzana przez tę platformę, z systemem co najmniej SFOS 22.0 MR2;
  • aktywna płatna subskrypcja zapory wykraczająca poza Base License lub aktywna umowa wsparcia;
  • osobne poświadczenie API z wymaganymi uprawnieniami;
  • curl, jq, a do importu także md5 lub md5sum;
  • identyfikator tenanta, regionalny host API i identyfikator zapory;
  • okno serwisowe i przetestowana droga odzyskania dostępu na potrzeby importu.

Poświadczenia API tworzy się w Sophos Central w obszarze Global Settings > Access Control > API Credentials. Dla tenanta Sophos zaleca rolę Service Principal Firewall. W Partner Dashboard funkcja znajduje się w Global Settings > APIs & Integrations > API Credentials Management; dostępne są tam inne role i należy wybrać rolę o najmniejszym zakresie uprawnień zapewniającą dostęp do docelowego tenanta. Client Secret, JWT, Secure Storage Master Key oraz wydane później adresy URL pobierania i wysyłania nie powinny trafiać do zgłoszeń, czatów ani zrzutów ekranu.

Przykłady działają w Bash i zakładają użycie poświadczenia tenanta. Poświadczenia partnera i organizacji Enterprise muszą najpierw rozpoznać docelowego tenanta wraz z jego regionalnym hostem API. Różnicę tę Sophos wyjaśnia w dokumencie Jak działają nasze interfejsy API.

Wprowadzić Client ID i Client Secret bez zapisywania sekretu w historii powłoki:

read -r -p "Client ID: " CLIENT_ID
read -r -s -p "Client Secret: " CLIENT_SECRET
printf '\n'

Następnie zażądać ograniczonego czasowo tokena JWT:

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

Proste przykłady z curl przekazują krótkotrwały JWT jako argument nagłówka. Dlatego należy je uruchamiać na zaufanej stacji administracyjnej, na której inni lokalni użytkownicy nie mogą odczytywać argumentów procesów.

Wywołanie whoami zwraca dla poświadczenia tenanta jego identyfikator oraz regionalny host 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"

Jeśli jq przerwie działanie na tym etapie, poświadczenie prawdopodobnie jest przypisane do partnera lub organizacji Enterprise. Nie należy wtedy używać ich identyfikatora jako X-Tenant-ID, lecz ustalić zarządzanego tenanta i jego apiHost.

Ustalenie identyfikatora zapory

Lista zapór pokazuje nazwę, hostname, numer seryjny, firmware i 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'

Należy przejąć UUID właściwej zapory i nie wybierać jej wyłącznie na podstawie podobnej nazwy wyświetlanej:

FIREWALL_ID="<firewall-uuid>"

Jeśli brakuje zapory, najpierw należy sprawdzić tenanta, region, połączenie z Central i zezwolenie na zarządzanie. Rejestrację opisuje artykuł Łączenie Sophos Firewall z Sophos Central.

Eksport konfiguracji

Uruchomienie pełnego eksportu

Eksport jest wykonywany asynchronicznie. Pierwsze wywołanie zwraca więc tylko identyfikator transakcji:

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"

Po kilku sekundach ponownie pobrać status:

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"

Powtarzać żądanie mniej więcej co dziesięć sekund, aż status osiągnie stan końcowy finished. Wartości pending i started nie oznaczają jeszcze błędu.

Dopiero przy status: "finished" i result: "success" pole response.url zawiera ograniczony czasowo adres pobierania:

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

Plik TAR może zawierać poufne dane sieciowe, użytkowników, VPN i polityk. Należy przechowywać go w bezpiecznym miejscu lub usunąć po analizie. Do przygotowania czytelnego raportu albo porównania stanu przed zmianą i po niej można użyć zawartego pliku Entities.xml w Sophos Firewall Config Studio.

Eksport tylko wybranych konfiguracji

Przy eksporcie selektywnym nazwy encji trzeba podać dokładnie i z zachowaniem wielkości liter. Poniższy przykład eksportuje reguły zapory i NAT wraz z obiektami zależnymi:

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"

Prawidłowe nazwy encji znajdują się w aktualnym punkcie końcowym eksportu Sophos Firewall API. Dla eksportu selektywnego domyślna wartość includeDependency to false; opcję należy ustawić świadomie i mimo to sprawdzić wynikowy pakiet.

Import konfiguracji

Import składa się z zażądania adresu URL wysyłania, przesłania pliku TAR, potwierdzenia danych pliku i sprawdzenia transakcji. Przykład używa wyłącznie zapory testowej i celowo ustawia performPartialImport na false. Domyślna wartość API to true i dopuszcza częściowy import dla każdej zapory.

Najpierw należy sprawdzić zgodność: zapora docelowa wymaga co najmniej tej samej wersji firmware i Pattern. Importy selektywne pomiędzy różnymi modelami Sophos obsługuje tylko z modelu niższego do wyższego; sprzęt docelowy musi mieć co najmniej tyle samo portów Ethernet. Przy innych nazwach portów trzeba odpowiednio dostosować Entities.xml przed wysłaniem.

Przygotowanie pliku importu i sumy kontrolnej

Przygotować plik docelowy, sumę kontrolną i rozmiar pliku:

FILE="sophos-firewall-config-2026-08-03.tar"
FILE_SIZE=$(wc -c <"$FILE" | tr -d ' ')

W systemie macOS:

CHECKSUM_MD5=$(md5 -q "$FILE")

W systemie Linux:

CHECKSUM_MD5=$(md5sum "$FILE" | awk '{print $1}')

Żądanie sesji wysyłania i przesłanie pliku

Zażądać sesji wysyłania i wyświetlić tylko pola, które nie są poufne:

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"

Przed wygaśnięciem Pre-signed URL przesłać plik metodą PUT zwróconą przez API. Do tego adresu URL nie wysyłać nagłówka JWT ani tenanta:

curl --fail-with-body --silent --show-error \
  --request PUT \
  --upload-file "$FILE" \
  "$UPLOAD_URL"
unset UPLOAD_URL

Zakończenie importu i sprawdzenie statusu

Jeśli pakiet zawiera informacje poufne i jest importowany na inną lub ponownie wdrożoną zaporę, potrzebny jest właściwy Secure Storage Master Key. Bez niego SFOS nie zaimportuje informacji poufnych ani zależnych od nich konfiguracji. Poniższy monit nie wyświetla sekretu; naciśnięcie Enter pozostawia pole puste:

read -r -s -p "Secure Storage Master Key lub Enter, aby pominąć: " SSMK
printf '\n'

Zakończyć wysyłanie i przypisać pakiet do zapory docelowej:

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"

Jedno żądanie przyjmuje od 1 do 25 unikalnych identyfikatorów zapór. Dla kolejnych zapór pakiet trzeba przesłać ponownie; nie wolno ponownie używać tego samego Pre-signed URL ani identyfikatora transakcji.

Sprawdzić status importu przez ten sam punkt końcowy transakcji:

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"

Także to żądanie należy powtarzać mniej więcej co dziesięć sekund, aż pojawi się status: "finished". Dopiero wtedy ocenić result, a przy wielu zaporach docelowych także każdy element w response.items.

Wartość success potwierdza przetworzenie przez API, a nie merytoryczny rezultat.

Lokalna weryfikacja importu

Po uzyskaniu finished na każdej zaporze docelowej należy sprawdzić:

  1. Czy znajdują się na niej dokładnie oczekiwane reguły, obiekty i ustawienia?
  2. Czy z powodu brakującego lub nieprawidłowego SSMK brakuje użytkowników, haseł, certyfikatów albo obiektów zależnych?
  3. Czy interfejsy, strefy, bramy, firmware, wersja Pattern i model sprzętowy pasują do pakietu?
  4. Czy routing, NAT, VPN, uwierzytelnianie i dostęp administracyjny działają zgodnie ze zdefiniowanymi przypadkami testowymi?
  5. Czy Audit Trail i logi konfiguracji pokazują nieoczekiwane zmiany?
  6. Czy ponowny eksport lub porównanie w Config Studio pokazuje wyłącznie planowane różnice?

Import/Export aktualizuje istniejącą konfigurację i nie usuwa automatycznie wszystkiego, czego brakuje w pakiecie. Plik TAR nie jest więc ani pełnym stanem docelowym, ani zamiennikiem kopii zapasowej, rollbacku i testu działania.

Rozwiązywanie problemów

Eksport pozostaje bez adresu pobierania

Adres URL pojawia się dopiero przy status: "finished" i result: "success". Przy error lub partialSuccess należy sprawdzić pola w response i nie kontynuować z pustym albo wygasłym adresem URL.

HTTP 401 lub 403

Kod 401 zwykle oznacza, że JWT wygasł lub jest nieprawidłowy. Należy uwierzytelnić się ponownie. Przy 403 sprawdzić rolę Central, kontekst tenanta, X-Tenant-ID i regionalny host API. Lokalne zezwolenie XML API pod /webconsole/APIController nie ma tu zastosowania; opisano je osobno w artykule Zabezpieczanie dostępu do XML API w Sophos Firewall.

Upload-complete zwraca 400 lub 409

Sprawdzić identyfikator transakcji, czas wygaśnięcia adresu wysyłania, rzeczywisty rozmiar pliku, szesnastkową sumę kontrolną MD5 oraz unikalność identyfikatorów zapór. Po wysłaniu pliku nie wolno go zmieniać. Przy kolejnej próbie należy utworzyć nową sesję wysyłania.

Import kończy się statusem error lub partialSuccess

Zapisać response, a przy wielu zaporach docelowych także response.items. Jeśli wywołanie API zwraca oddzielną odpowiedź błędu 4xx lub 5xx, dodatkowo udokumentować error, message, code, correlationId i requestId. Następnie lokalnie sprawdzić wersję docelową, Pattern, model, porty, zależności i SSMK. Jeśli odpowiedź Central jest niewystarczająca, sprawdzić na zaporze plik fwcm-api-executor.log zgodnie z artykułem Usługi i pliki logów Sophos Firewall.

Dla statusu API miarodajny jest punkt końcowy transakcji; nie należy zakładać, że zadanie pojawi się w kolejce zadań Sophos Central Firewall.

Bardzo duży import zostaje przerwany

Sophos wymienia Known Issue NR-19066: import z bardzo dużą liczbą obiektów może przekroczyć dwugodzinny limit przetwarzania. Zamiast ponawiać niezmieniony pełny import, należy tworzyć mniejsze pakiety selektywne, importować je osobno i weryfikować każdy krok.

Na końcu sesji usunąć zmienne zawierające dane poufne:

unset JWT CLIENT_ID TENANT_ID API_HOST FIREWALL_ID TARGET_FIREWALL_ID
unset EXPORT_TX IMPORT_TX CHECKSUM_MD5 FILE_SIZE