Zarządzanie Sophos Switch przez CLI, lokalne REST API i Fusion API
Lokalne interfejsy CLI i REST API zapewniają bezpośredni dostęp do jednego przełącznika Sophos Switch. Sophos Fusion Switch Management API jest odrębnym interfejsem: korzysta z poświadczeń jednostki usługi (service principal) na poziomie tenanta i rozsyła centralne polityki do przełączników. Ten runbook wskazuje właściwą tożsamość, bazowy adres URL i sposób walidacji dla obu ścieżek.
Zakres i podstawowe decyzje
Ten runbook obejmuje:
- lokalny dostęp do CLI za pośrednictwem ścieżki zarządzania udostępnionej dla urządzenia, w szczególności SSH;
- orientację i diagnostykę w CLI;
- logowanie do lokalnego REST API urządzenia;
- cykl życia tokenu Bearer powiązanego z sesją;
- udokumentowany, niemodyfikujący test API za pomocą
GET /api/ports; - bezpieczne testowanie, rozwiązywanie problemów, wycofywanie zmian i kończenie sesji.
Celowo nie przedstawiono tu pełnego katalogu punktów końcowych API ani poleceń CLI. Dokumentacja centralna stanowi materiał orientacyjny, jednak przed rozpoczęciem pracy z API należy sprawdzić jego dostępność na urządzeniu docelowym. Wskazane tam ścieżki, takie jak /ports, są względne wobec bazowej ścieżki serwera /api, dlatego pełna ścieżka wywołania to /api/ports. Polecenia, tryby i parametry CLI mogą się różnić zależnie od modelu i oprogramowania układowego. Wiążące informacje zawiera sekcja Zmienność oprogramowania układowego i modeli.
Przed uzyskaniem dostępu ustal:
- Czy systemem nadrzędnym jest Sophos Fusion, czy konfiguracja lokalna?
- Którego przełącznika dotyczy zadanie: jaki to model, jaka wersja oprogramowania układowego i jaki adres IP zarządzania?
- Czy dostęp do odczytu jest wystarczający, czy też wymagana jest zatwierdzona zmiana?
- Jaki jest stan początkowy, kryterium powodzenia i plan wycofania?
- Czy istnieje niezależna ścieżka zarządzania, jeśli zmiana przerywa normalny dostęp?
Rozdzielenie tożsamości i ról
Konta w ramach People są lokalnymi kontami przełącznika:
| Typ przywileju lokalnego | Prawa do przełącznika | Typowe zastosowanie |
|---|---|---|
| Admin | Wyświetlanie i zmiana wszystkich funkcji przełącznika | Zatwierdzona administracja lokalna i wywołania API z prawem zapisu |
| User | Wyświetlanie ustawień bez możliwości ich zmiany | Diagnostyka i kontrola zgodnie z zasadą najmniejszych uprawnień |
Te role lokalne nie są tym samym co role administratora w Sophos Fusion. Rola w Fusion nie nadaje automatycznie lokalnych uprawnień CLI ani API, a lokalne dane uwierzytelniające nie są danymi logowania do Fusion. Do /api/system/login wysyłane są dane lokalnego konta przełącznika.
Konta lokalne są zarządzane w lokalnym interfejsie w ramach People:
- Wybierz Add, aby utworzyć konto lub wybierz Edit obok konta.
- Ustaw Username, Password i Privilege type.
- Jako Privilege type wybierz Admin lub User.
- Zapisz ustawienia przyciskiem Apply.
Lokalne hasło musi spełniać wszystkie następujące wymagania:
- co najmniej 10 i nie więcej niż 32 znaków;
- co najmniej jedną literę i jedną cyfrę;
- co najmniej jeden z tych znaków specjalnych:
@ ~ % * # + - =.
Lokalne konto Admin może zmieniać hasła innych kont, ale nie hasło domyślnego konta admin. Hasło tego konta może zmienić wyłącznie sam użytkownik admin albo Sophos Fusion. Do codziennej pracy zamiast współdzielonego konta admin używaj imiennych kont lokalnych.
Przygotowanie dostępu
Przed rozpoczęciem sesji:
- Porównaj adres IP, model, wersję oprogramowania układowego, lokalizację i numer seryjny ze zgłoszeniem zmiany.
- Zezwól na dostęp wyłącznie z administracyjnej sieci zarządzania i autoryzowanego hosta administratora.
- Nie udostępniaj usług zarządzania w produkcyjnych sieciach VLAN ani w Internecie.
- Sprawdź źródło czasu i czas na hoście administratora; nieprawidłowy czas utrudnia analizę dzienników i odpowiedzi API.
- Jeśli planujesz zmianę, przygotuj aktualną kopię zapasową konfiguracji i niezależną ścieżkę dostępu na potrzeby wycofania.
- Jeśli urządzeniem zarządza system centralny, zabezpiecz zapis jego stanu docelowego i wyraźnie udokumentuj lokalny wyjątek.
- Nigdy nie przechowuj danych dostępowych ani tokenów Bearer w treści zgłoszenia, na czacie, na zrzucie ekranu, w historii powłoki ani w kodzie źródłowym.
W przykładach należy zastąpić następujące symbole zastępcze:
| Symbol zastępczy | Znaczenie |
|---|---|
<Switch-IP address> | Adres IP zarządzania lub zaufana nazwa urządzenia docelowego |
<LOCAL-USERNAME> | Lokalne konto przełącznika, a nie użytkownik Fusion |
your-password | Hasło lokalne; jest to tylko symbol zastępczy, którego nie należy używać jako rzeczywistego hasła |
xxxxxxxx.yyyyyyyy.zzzzzz | Zamaskowany przykład tokenu Bearer, a nie rzeczywisty token |
Bezpieczne stosowanie CLI
Nawiązywanie połączeń
SSH jest jedną z lokalnych usług zarządzania. Musi być skonfigurowane na używanym modelu urządzenia i dostępne z sieci zarządzania. Ogólna postać polecenia klienta:
ssh <LOCAL-USERNAME>@<Switch-IP-address>
To jest przykładowe polecenie klienta: zastąp całe wartości <LOCAL-USERNAME> i <Switch-IP-address>, łącznie z nawiasami ostrymi. Przed zaakceptowaniem klucza hosta porównaj jego odcisk niezależnym, zaufanym kanałem. Nie ignoruj ostrzeżenia o zmianie klucza hosta; najpierw wyklucz wymianę urządzenia, reset fabryczny, konflikt adresów IP lub możliwy atak typu man-in-the-middle.
Jeśli dany model ma fizyczny port konsoli, może on służyć jako niezależna ścieżka dostępu podczas konserwacji. Parametry połączenia szeregowego muszą odpowiadać konkretnemu modelowi; nie przenoś ustawień z innego modelu Sophos Switch.
Orientacja w CLI
Najpierw sprawdź bieżący znak zachęty, a tym samym aktywny tryb poleceń. Nie zakładaj, że każde polecenie jest dostępne w każdym trybie. Udokumentowane funkcje pomocy i klawisze to:
| Wpis | Działanie |
|---|---|
? | Lista dostępnych poleceń |
TAB | Uzupełnij polecenie |
| Strzałka w górę / w dół | Pokaż wcześniej wykonane polecenia |
| Strzałka w lewo / w prawo | Nawiguj w bieżącej linii |
Backspace lub Ctrl + H | Usuń znak |
History | Wyświetl historię poleceń |
Q | Zamknij wyświetlane dane i wróć do znaku zachęty przełącznika |
Sprawdź wielkość liter i dokładną dostępność polecenia za pomocą ? lub TAB na urządzeniu docelowym. Q zamyka stronicowane lub aktywne wyjście, ale nie kończy automatycznie sesji SSH.
Bezpieczna sekwencja CLI
- Zacznij od lokalnego konta User, jeśli wystarczy dostęp tylko do odczytu.
- Sprawdź urządzenie docelowe, tryb znaku zachęty i dostępne polecenia.
- Za pomocą
?wyświetl polecenia dostępne w tym trybie. - Najpierw wykonuj wyłącznie operacje wyświetlania lub odczytu stanu.
- Przed zmianą zapisz pełny stan bieżący i przygotuj dokładną operację wycofania.
- Zmień tylko jeden krok techniczny na raz i natychmiast go kontroluj.
- Jeśli wyjście jest stronicowane, wróć do znaku zachęty klawiszem
Q. - Prawidłowo zakończ sesję poleceniem wyjścia lub wylogowania wskazanym przez
?na urządzeniu docelowym, a następnie sprawdź, czy połączenie SSH zostało zamknięte.
Traktuj historię poleceń jako informację wrażliwą: może zawierać adresy zarządzania, nazwy użytkowników lub wprowadzone parametry. Nigdy nie podawaj haseł ani tokenów jako parametrów CLI; wprowadzaj je wyłącznie wtedy, gdy przełącznik poprosi o nie interaktywnie.
REST API: udokumentowane logowanie
API jest dostępne przez HTTPS pod adresem zarządzania przełącznika. Przełącznik tworzy nowy token Bearer dla każdej sesji. Po zamknięciu bieżącej sesji należy uzyskać nowy token.
Udokumentowane logowanie wykorzystuje PATCH /api/system/login. Poniższy przykład zachowuje opublikowaną składnię, zastępując jedynie wartości neutralnymi symbolami:
curl -k https://<Switch-IP address>/api/system/login -X PATCH -H 'Content-Type:application/json' -d '{"user":"admin","password":"your-password"}'
Prawidłowa odpowiedź ma następującą strukturę:
{
"restful_res": {
"token": "xxxxxxxx.yyyyyyyy.zzzzzz",
"utctimestamp": "##########",
"timeout": 900,
"errCode": 0,
"message": "OK"
}
}
Stosuje się następujące zasady:
tokenjest tajemnicą z tymi samymi wymaganiami ochrony co hasło.utctimestampitimeoutsą częścią konkretnej sesji.- Udokumentowana odpowiedź zawiera
timeout: 900; opis statyczny nie określa jednostki. Przed automatyzacją sprawdź znaczenie tej wartości w opublikowanej pomocy API, potwierdź je dla rzeczywistego oprogramowania układowego i nie wpisuj go na stałe do kodu. errCode: 0imessage: "OK"wskazują powodzenie. Dodatkowo sprawdź status HTTP.- Po zakończeniu sesji albo odrzuceniu wygasłej sesji uzyskaj nowy token; nie używaj ponownie starego.
Utwardzony wzór cURL
Poniższy wzorzec nie umieszcza hasła ani tokenu w argumentach procesu, weryfikuje certyfikat TLS i nie zapisuje sekretu w pliku. Wymaga programów curl i jq oraz powłoki obsługującej here-string:
read -r -p 'Lokalny użytkownik przełącznika: ' SW_USER
read -r -s -p 'Lokalne hasło przełącznika: ' SW_PASSWORD
printf '\n'
LOGIN_RESPONSE="$({
printf '%s\n%s\n' "$SW_USER" "$SW_PASSWORD" |
jq -Rn '[inputs] | {user: .[0], password: .[1]}' |
curl --disable --silent --show-error --fail-with-body \
--cacert /path/to/switch-ca.pem \
--request PATCH \
--header 'Content-Type:application/json' \
--data-binary @- \
'https://<Switch-IP-address>/api/system/login'
})"
unset SW_PASSWORD
if [ "$(jq -r '.restful_res.errCode' <<<"$LOGIN_RESPONSE")" != "0" ]; then
printf '%s\n' 'Logowanie do API nie powiodło się.' >&2
unset LOGIN_RESPONSE SW_USER
exit 1
fi
SW_TOKEN="$(jq -er '.restful_res.token' <<<"$LOGIN_RESPONSE")" || exit 1
unset LOGIN_RESPONSE
case "$SW_TOKEN" in
''|*[!A-Za-z0-9._~+/=-]*)
printf '%s\n' 'Logowanie do API nie zwróciło prawidłowego tokenu Bearer.' >&2
unset SW_TOKEN SW_USER
exit 1
;;
esac
Zastąp /path/to/switch-ca.pem i <Switch-IP-address> właściwymi wartościami. Użyj nazwy hosta, dla której wydano certyfikat. W powłoce interaktywnej upewnij się, że nie jest aktywne śledzenie debugowania, na przykład set -x. Nie ujawniaj zmiennych za pomocą poleceń env lub export, danych debugowania ani zrzutów pamięci.
REST API: wywołanie i weryfikacja
Udokumentowane wywołanie próbne odczytuje porty i przekazuje token w nagłówku Authorization:
curl -k https://<Switch IP Address>/api/ports -H 'authorization:Bearer <Token>'
<Token> jest niewykonywalnym symbolem zastępczym tokenu Bearer. Opublikowany przykład jest więc wyłącznie ilustracją: nie zastępuj <Token> rzeczywistym tokenem ani nie wpisuj takiego polecenia do historii powłoki. Poniższe wykonywalne wywołanie korzysta bezpośrednio ze zmiennej SW_TOKEN ustawionej podczas logowania.
W rzeczywistej sesji użyj zabezpieczonego tokenu i weryfikuj certyfikat. Opcja --config - przekazuje konfigurację programu curl przez standardowe wejście; dzięki temu nagłówek Authorization nie trafia do argumentów procesu i nie powstaje plik tymczasowy:
printf 'header = "Authorization: Bearer %s"\n' "$SW_TOKEN" |
curl --disable --silent --show-error --fail-with-body \
--config - \
--cacert /path/to/switch-ca.pem \
'https://<Switch-IP-address>/api/ports'
GET /api/ports jest odpowiednim pierwszym testem działania, ponieważ udokumentowane wywołanie odczytuje stan zamiast zmieniać konfigurację. Test jest udany tylko wtedy, gdy:
- połączenie i weryfikacja TLS kończą się powodzeniem;
- nie jest zwracany błąd HTTP;
- odpowiedź jest poprawna składniowo i wiarygodna technicznie;
- numery i nazwy portów oraz oczekiwane stany odpowiadają właściwemu urządzeniu docelowemu;
- w wyniku ani w dziennikach nie pojawiają się dane dostępowe lub tokeny.
Opcja curl --fail-with-body zwraca kod błędu przy błędach HTTP, ale zachowuje treść odpowiedzi do lokalnej diagnostyki. Przed udostępnieniem odpowiedzi sprawdź, czy nie zawiera ona tokenów, adresów, numerów seryjnych ani innych danych wewnętrznych.
Kontrola wywołań API z prawem zapisu
Wywołania z prawem zapisu wykonuj wyłącznie w ramach zatwierdzonych, ograniczonych i odwracalnych zmian. Nie używaj ładunku przeznaczonego dla innego modelu lub wersji oprogramowania układowego ani starego, niezweryfikowanego skryptu.
Dla każdego wywołania z prawem zapisu:
- Sprawdź metodę, ścieżkę, parametry, typy danych i schemat odpowiedzi w schemacie Swagger/OpenAPI urządzenia docelowego oraz potwierdź ich dostępność w używanej wersji oprogramowania układowego.
- Bezpośrednio przed zmianą odczytaj stan bieżący i bezpiecznie go zachowaj.
- Wyślij tylko minimalny zestaw wymaganych pól; nie zgaduj nieznanych wartości domyślnych.
- Ogranicz operację do dokładnie jednego przełącznika i małego, odwracalnego zakresu.
- Oceń status HTTP i pola specyficzne dla aplikacji, takie jak
errCodeimessage. - Potwierdź stan za pomocą niezależnego żądania
GEToraz, w stosownych przypadkach, testu funkcjonalnego. - W razie rozbieżności zatrzymaj się; nie wysyłaj kolejnych zmian w pętli ponawiania.
Pomyślne wywołanie HTTP samo w sobie nie dowodzi, że zmiana się powiodła. Podobnie poprawna treść JSON nie dowodzi, że zamierzona ścieżka danych nadal działa. Na przykład zmiany dotyczące portu, sieci VLAN lub zarządzania trzeba również przetestować z odpowiedniego segmentu sieci.
Bezpieczny cykl życia tokenu Bearer
- Utwórz: Dla każdej sesji API uzyskaj nowy token przez
PATCH /api/system/login. - Sprawdź: Zweryfikuj wynik HTTP,
errCode,message, pole tokena i wartości sesji bez wyświetlania tokena. - Użyj: Wysyłaj token wyłącznie w nagłówku
Authorization, zgodnie ze schematemBearer, i tylko do oczekiwanego przełącznika. Wartość tokenu jest tu celowo pominięta; przykłady wykonywalne tworzą nagłówek ze zmiennejSW_TOKEN. - Ogranicz: Nie eksportuj, nie zapisuj ani nie udostępniaj tokenów; nie umieszczaj ich w plikach, Git, dziennikach CI ani zgłoszeniach. Dla każdego zadania równoległego używaj odrębnej kontrolowanej sesji.
- Odnów: Po zakończeniu lub odrzuceniu sesji nie używaj ponownie tego samego tokena, lecz utwórz nową sesję. Unikaj nieskończonych automatycznych pętli ponownego logowania.
- Zamknij: Wywołaj uwierzytelnioną operację wylogowania
PATCH /api/system/logout. Także tutaj nagłówek jest przekazywany do curl przez standardowe wejście, a nie przez argumenty procesu:
printf 'header = "Authorization: Bearer %s"\n' "$SW_TOKEN" |
curl --disable --silent --show-error --fail-with-body \
--config - \
--cacert /path/to/switch-ca.pem \
--request PATCH \
'https://<Switch-IP-address>/api/system/logout'
- Usuń lokalnie: Po wylogowaniu usuń zmienne lokalne. Jeśli wylogowanie nie jest już możliwe z powodu zerwania połączenia lub nieważnej sesji, mimo to usuń lokalne sekrety i potwierdź zakończenie sesji w sposób właściwy dla używanego oprogramowania układowego:
unset SW_TOKEN SW_USER LOGIN_RESPONSE SW_PASSWORD
- Skontroluj: Sprawdź historię powłoki, pliki tymczasowe i dzienniki zadań pod kątem przypadkowo ujawnionych sekretów. Ujawniony token traktuj jako przejęty, zakończ sesję i nie wysyłaj za jego pomocą kolejnych wywołań.
Sophos Fusion Switch Management API na poziomie tenanta
Ta sekcja nie używa https://<Switch-IP-address>/api/.... Fusion API uwierzytelnia jednostkę usługi (service principal) na regionalnym hoście Sophos Fusion (dawniej Sophos Central) i działa w podanym tenancie. Lokalne konta People, role Admin/User, lokalne tokeny sesji i schemat Swagger urządzenia nie mają tu zastosowania.
Wymagania wstępne, role i poświadczenia
Przełącznik musi być zarejestrowany we właściwym tenancie i zarządzany przez Sophos Fusion. Poniższa wykonywalna procedura dotyczy wyłącznie bezpośrednich poświadczeń API tego tenanta (client_id i client_secret). Może je utworzyć tylko Super Admin bezpośredniego tenanta w sekcji Global Settings > Access Control > API Credentials. Rola przypisana do jednostki usługi (service principal) musi zapewniać wymagane uprawnienia do odczytu i zapisu. W tych przykładach powłoki nie wolno używać poświadczeń partnera ani organizacji Enterprise. W takim przypadku najpierw wykonaj odrębną procedurę wyboru tenanta opisaną w artykule Bezpieczne zarządzanie poświadczeniami API Sophos Fusion, a następnie wróć tutaj z poświadczeniami wystawionymi i zweryfikowanymi specjalnie dla wybranego bezpośredniego tenanta.
Sekret i token JWT przechowuj w sejfie sekretów, nigdy w skryptach, zgłoszeniach, historii powłoki ani wynikach CI. Potrzebne są programy curl i jq, powłoka Bash, zatwierdzone okno zmian oraz zapisane: ID tenanta, region, lista bieżąca, pełna lista docelowa i plan wycofania. Poświadczenia nie zastępują licencji ani subskrypcji pomocy technicznej (Support Subscription).
Uwierzytelnienie jednostki usługi i ustalenie hosta regionalnego
Dostawca tożsamości (IDP) wystawia token JWT przez POST https://id.sophos.com/api/v2/oauth2/token. W przypadku wymaganych tutaj bezpośrednich poświadczeń tenanta żądanie GET https://api.central.sophos.com/whoami/v1 zwraca pola id i apiHosts.dataRegion. Procedura kończy się błędem, jeśli whoami nie zwróci tożsamości tenanta. Nigdy nie wysyłaj ID partnera ani organizacji jako X-Tenant-ID; nie zgaduj hosta regionalnego i nie kopiuj go z innego tenanta.
read -r -p 'Service principal client ID: ' SP_CLIENT_ID
read -r -s -p 'Service principal client secret: ' SP_CLIENT_SECRET
printf '\n'
TOKEN_RESPONSE="$({
jq -rn --arg id "$SP_CLIENT_ID" --arg secret "$SP_CLIENT_SECRET" \
'"grant_type=client_credentials&client_id=\($id|@uri)&client_secret=\($secret|@uri)&scope=token"' |
curl --disable --silent --show-error --fail-with-body \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-binary @- \
'https://id.sophos.com/api/v2/oauth2/token'
})"
unset SP_CLIENT_SECRET
FUSION_TOKEN="$(jq -er '
select(.token_type == "bearer") |
.access_token | select(type == "string" and length > 0)
' <<<"$TOKEN_RESPONSE")" || exit 1
unset TOKEN_RESPONSE
WHOAMI_RESPONSE="$(
printf 'header = "Authorization: Bearer %s"\n' "$FUSION_TOKEN" |
curl --disable --silent --show-error --fail-with-body \
--config - \
'https://api.central.sophos.com/whoami/v1'
)"
UUID_RE='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$'
FUSION_TENANT_ID="$(jq -er --arg re "$UUID_RE" \
'select(.idType == "tenant") | .id | select(type == "string" and test($re))' \
<<<"$WHOAMI_RESPONSE")" || exit 1
FUSION_DATA_REGION="$(jq -er \
'.apiHosts.dataRegion | select(type == "string" and test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$"))' \
<<<"$WHOAMI_RESPONSE")" || exit 1
unset WHOAMI_RESPONSE UUID_RE
Każde żądanie dotyczące przełączników wymaga dwóch nagłówków — Authorization: Bearer <token> oraz X-Tenant-ID: <tenant-id> — a także w pełni ustalonego hosta <data-region>. Udokumentowane statusy powodzenia to 200 i 201; potwierdzają one wyłącznie przyjęcie żądania.
Bezpieczny odczyt i pełna zamiana filtrów MAC
GET /switch/v1/settings/mac-filtering odczytuje listę blokad tenanta. PUT /switch/v1/settings/mac-filtering nie dopisuje elementów: pole macAddresses musi zawierać pełną listę docelową, która zastępuje dotychczasowy stan. {"macAddresses":[]} usuwa wszystkie blokady.
Przykład dodaje fikcyjny, lokalnie administrowany adres zaczynający się od 02:. Nie publikuj rzeczywistego adresu MAC klienta. Chroń pliki robocze zawierające dane operacyjne.
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-before.json
jq -e '.macAddresses | type == "array"' mac-filter-before.json >/dev/null || exit 1
jq '{macAddresses: (.macAddresses + ["02:00:00:00:00:51"] | unique)}' \
mac-filter-before.json > mac-filter-desired.json
jq -S '.macAddresses' mac-filter-before.json mac-filter-desired.json
Zapis wykonaj dopiero po zatwierdzeniu pełnych różnic. Od pobrania bazowej listy zadań do zapisania ID jednoznacznie skorelowanego zadania nie wolno wykonywać w tym tenancie żadnej innej zmiany typu macFilters:
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/tasks?type=macFilters&pageSize=50&pageTotal=true" \
> mac-filter-tasks-before.json
jq -e '
(.items | type == "array") and
(.pages.current == 1) and
(.pages.total >= 0) and (.pages.total <= 1) and
((.items | length) <= 50)
' mac-filter-tasks-before.json >/dev/null || exit 1
CHANGE_STARTED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
--request PUT \
--header 'Content-Type: application/json' \
--data-binary @mac-filter-desired.json \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-put-response.json
Odczyt zwrotny, odpytywanie zadań i walidacja
Pomyślne żądanie PUT nie dowodzi, że wszystkie przełączniki zastosowały politykę. Odczytaj dokładnie ustawienie, a następnie wywołaj GET /switch/v1/tasks. Zadania są usuwane po 30 dniach i nie stanowią trwałego archiwum audytowego. Udokumentowane filtry to type, pageSize i pageTotal. Ponieważ procedura nie zakłada istnienia innego udokumentowanego parametru stronicowania, przetwarza najwyżej jedną pełną stronę zawierającą 50 zadań i kończy się błędem przy pages.total > 1, zamiast po cichu ignorować kolejne strony.
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-after.json
jq -e '.macAddresses | type == "array"' mac-filter-after.json >/dev/null || exit 1
diff -u \
<(jq -S '.macAddresses' mac-filter-desired.json) \
<(jq -S '.macAddresses' mac-filter-after.json) || exit 1
CHANGE_TASK_ID=''
CHANGE_TASK_DONE=false
for CHANGE_POLL_ATTEMPT in $(seq 1 30); do
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/tasks?type=macFilters&pageSize=50&pageTotal=true" \
> mac-filter-tasks.json
jq -e '
(.items | type == "array") and
(.pages.current == 1) and
(.pages.total >= 0) and (.pages.total <= 1) and
((.items | length) <= 50)
' mac-filter-tasks.json >/dev/null || exit 1
if [ -z "$CHANGE_TASK_ID" ]; then
jq -e -s --arg started "$CHANGE_STARTED_AT" '
def epoch: sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601;
[.[0].items[].id] as $before |
[.[1].items[] |
select(
.type == "macFilters" and
(.id as $id | ($before | index($id) | not)) and
((.createdAt | epoch) >= ($started | epoch)) and
((.updatedAt | epoch) >= ($started | epoch))
)
] | if length > 1 then error("wiele pasujących zadań") else . end
' mac-filter-tasks-before.json mac-filter-tasks.json \
> mac-filter-task-matches.json || exit 1
if jq -e 'length == 1' mac-filter-task-matches.json >/dev/null; then
CHANGE_TASK_ID="$(jq -er '.[0].id | strings | select(length > 0)' \
mac-filter-task-matches.json)" || exit 1
fi
fi
if [ -n "$CHANGE_TASK_ID" ]; then
jq -e --arg id "$CHANGE_TASK_ID" '
[.items[] | select(.id == $id)] |
select(length == 1) | .[0]
' mac-filter-tasks.json > mac-filter-task-current.json || exit 1
if jq -e '.status.pending > 0' mac-filter-task-current.json >/dev/null; then
:
else
jq -e '
(.status.total | type == "number") and (.status.total > 0) and
(.status.pending == 0) and (.status.failed == 0) and
((.status.noSupportSubscription // 0) == 0) and
(.status.succeeded == .status.total) and
(.switches | type == "array") and
((.switches | length) == .status.total) and
all(.switches[];
(.id | type == "string" and length > 0) and
(.status == "succeeded") and
(.error == null)
)
' mac-filter-task-current.json >/dev/null || exit 1
CHANGE_TASK_DONE=true
break
fi
fi
[ "$CHANGE_POLL_ATTEMPT" -lt 30 ] && sleep 10
done
[ "$CHANGE_TASK_DONE" = true ] || exit 1
jq '{id, type, createdAt, updatedAt, status, switches}' mac-filter-task-current.json
Procedura koreluje dokładnie jedno nowe zadanie na podstawie CHANGE_STARTED_AT, typu macFilters i identyfikatorów zadań zapisanych przed żądaniem PUT. Następnie odpytuje kolekcję najwyżej 30 razy w odstępach dziesięciu sekund i wybiera wyłącznie zadanie o zapisanym ID. Powodzenie wymaga zarówno poprawnego statusu zbiorczego, jak i końcowego statusu succeeded dla każdego wpisu w switches[]. Niejednoznaczność, stronicowanie, przekroczenie czasu, błąd lub noSupportSubscription powodują przerwanie procedury. Żądanie PUT nie jest ponawiane.
Precyzyjna obsługa błędów Fusion API
- 401/403: Sprawdź ważność tokenu JWT, jednostkę usługi (service principal), kontekst tenanta i nagłówki; role lokalne nie mają tu zastosowania.
- Zły tenant lub host regionalny: Ustal ponownie ID i host przez
whoamilub listę zarządzanych tenantów. - HTTP 200/201 bez efektu: Sprawdź odczyt i zadanie; odpytuj z limitem, lecz nie ponawiaj żądania PUT w ciemno.
noSupportSubscription: Popraw Support Subscription i stan urządzenia we właściwym tenancie; bez lokalnego obejścia.- Kod
10905–Duplicate MAC filter policy: Sprawdźswitches[].error, odczytaj stan i rozwiąż duplikat lub stare żądanie; bez ślepych prób. - Kod
10906–MAC filter list is exhausted: Zatrzymaj się i zatwierdź mniejszą pełną listę; nigdy nie wysyłaj podzbioru jako dopisania. - Kod
10908–MAC address already allowed in the static MAC table: Wyjaśnij konflikt i wpływ; nie usuwaj statycznych zezwoleń bez analizy.
W razie błędu zapisz razem status HTTP, ID zadania, ID przełącznika oraz pola status, error, message i code; dane wrażliwe zamaskuj.
Granice wycofania i odtwarzania
Wycofanie polega na wysłaniu kolejnego pełnego żądania PUT z zapisaną listą. Najpierw ponownie odczytaj stan i wyklucz równoległe zmiany, a następnie wykonaj ten sam odczyt zwrotny oraz procedurę obsługi zadań aż do osiągnięcia stanu końcowego przez każdy przełącznik.
# Przed ponownym odczytem zapewnij wyłączne okno zmian.
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-pre-restore.json
jq -e '.macAddresses | type == "array"' mac-filter-pre-restore.json >/dev/null || exit 1
diff -u \
<(jq -S '.macAddresses' mac-filter-desired.json) \
<(jq -S '.macAddresses' mac-filter-pre-restore.json) || exit 1
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/tasks?type=macFilters&pageSize=50&pageTotal=true" \
> mac-filter-restore-tasks-before.json
jq -e '
(.items | type == "array") and
(.pages.current == 1) and
(.pages.total >= 0) and (.pages.total <= 1) and
((.items | length) <= 50)
' mac-filter-restore-tasks-before.json >/dev/null || exit 1
jq '{macAddresses}' mac-filter-before.json > mac-filter-restore.json
RESTORE_STARTED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
--request PUT \
--header 'Content-Type: application/json' \
--data-binary @mac-filter-restore.json \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-restore-response.json
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/settings/mac-filtering" \
> mac-filter-restored.json
jq -e '.macAddresses | type == "array"' mac-filter-restored.json >/dev/null || exit 1
diff -u \
<(jq -S '.macAddresses' mac-filter-restore.json) \
<(jq -S '.macAddresses' mac-filter-restored.json) || exit 1
RESTORE_TASK_ID=''
RESTORE_TASK_DONE=false
for RESTORE_POLL_ATTEMPT in $(seq 1 30); do
printf 'header = "Authorization: Bearer %s"\nheader = "X-Tenant-ID: %s"\n' \
"$FUSION_TOKEN" "$FUSION_TENANT_ID" |
curl --disable --silent --show-error --fail-with-body \
--config - \
"$FUSION_DATA_REGION/switch/v1/tasks?type=macFilters&pageSize=50&pageTotal=true" \
> mac-filter-restore-tasks.json
jq -e '
(.items | type == "array") and
(.pages.current == 1) and
(.pages.total >= 0) and (.pages.total <= 1) and
((.items | length) <= 50)
' mac-filter-restore-tasks.json >/dev/null || exit 1
if [ -z "$RESTORE_TASK_ID" ]; then
jq -e -s --arg started "$RESTORE_STARTED_AT" '
def epoch: sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601;
[.[0].items[].id] as $before |
[.[1].items[] |
select(
.type == "macFilters" and
(.id as $id | ($before | index($id) | not)) and
((.createdAt | epoch) >= ($started | epoch)) and
((.updatedAt | epoch) >= ($started | epoch))
)
] | if length > 1 then error("wiele pasujących zadań wycofania") else . end
' mac-filter-restore-tasks-before.json mac-filter-restore-tasks.json \
> mac-filter-restore-task-matches.json || exit 1
if jq -e 'length == 1' mac-filter-restore-task-matches.json >/dev/null; then
RESTORE_TASK_ID="$(jq -er '.[0].id | strings | select(length > 0)' \
mac-filter-restore-task-matches.json)" || exit 1
fi
fi
if [ -n "$RESTORE_TASK_ID" ]; then
jq -e --arg id "$RESTORE_TASK_ID" '
[.items[] | select(.id == $id)] |
select(length == 1) | .[0]
' mac-filter-restore-tasks.json > mac-filter-restore-task-current.json || exit 1
if jq -e '.status.pending > 0' mac-filter-restore-task-current.json >/dev/null; then
:
else
jq -e '
(.status.total | type == "number") and (.status.total > 0) and
(.status.pending == 0) and (.status.failed == 0) and
((.status.noSupportSubscription // 0) == 0) and
(.status.succeeded == .status.total) and
(.switches | type == "array") and
((.switches | length) == .status.total) and
all(.switches[];
(.id | type == "string" and length > 0) and
(.status == "succeeded") and
(.error == null)
)
' mac-filter-restore-task-current.json >/dev/null || exit 1
RESTORE_TASK_DONE=true
break
fi
fi
[ "$RESTORE_POLL_ATTEMPT" -lt 30 ] && sleep 10
done
[ "$RESTORE_TASK_DONE" = true ] || exit 1
jq '{id, type, createdAt, updatedAt, status, switches}' \
mac-filter-restore-task-current.json
unset FUSION_TOKEN SP_CLIENT_ID FUSION_TENANT_ID FUSION_DATA_REGION \
CHANGE_STARTED_AT CHANGE_TASK_ID RESTORE_STARTED_AT RESTORE_TASK_ID
mac-filter-before.json jest migawką ustawienia, a nie pełną kopią przełącznika. Po utracie listy bazowej nie używaj pustej listy do resetowania: usunęłaby wszystkie blokady. API nie odtwarza lokalnej konfiguracji CLI/REST ani nie zwalnia izolacji Active Threat Response. Usuń zmienne zawierające token, zabezpiecz lub bezpiecznie usuń pliki i udokumentuj wynik.
Rozwiązywanie problemów według objawów
Błąd TLS lub certyfikatu
- Sprawdź nazwę zarządzania, IP, ważność, łańcuch certyfikatów i czas systemowy.
- Podaj właściwy certyfikat urzędu certyfikacji za pomocą
--cacertalbo zastąp certyfikat urządzenia zgodnie z przyjętym procesem zarządzania. - Nie używaj opcji
-kjako stałego obejścia problemu. Szyfruje ona transmisję, ale nie uwierzytelnia przełącznika. - Jeśli zmienił się certyfikat lub klucz hosta SSH, najpierw potwierdź, że połączenie rzeczywiście prowadzi do zamierzonego przełącznika.
Połączenie odrzucone, timeout lub bez trasy
- Sprawdź adres IP zarządzania, sieć VLAN zarządzania, routing, listy ACL i dostępność usługi.
- Przeprowadź test z autoryzowanego hosta w przewidzianej sieci zarządzania.
- Nie obchodź problemu przez udostępnienie usługi wszystkim sieciom lub Internetowi.
- Jeśli właśnie wprowadzona zmiana przerwała dostęp, użyj niezależnej ścieżki zarządzania i wykonaj przygotowany plan wycofania.
Logowanie nie powiodło się
- Upewnij się, że używane jest lokalne konto przełącznika, a nie konto Sophos Fusion.
- Sprawdź nazwę użytkownika, wymagania dotyczące hasła, status konta i lokalną rolę.
- Nie próbuj automatycznie kolejnych haseł; może to zablokować konto i utrudnić rozpoznanie przyczyny.
- Pamiętaj, że hasło domyślnego konta
adminmoże zmienić wyłącznie sam użytkownikadminalbo Sophos Fusion.
HTTP 401 lub 403
- Przy
401sprawdź, czy token lub sesja nie wygasły, i zaloguj się ponownie. - Przy
403sprawdź lokalną rolę oraz uprawnienia do danej operacji; nie próbuj obchodzić kontroli dostępu. - Nowy token rozwiązuje problem tylko wtedy, gdy przyczyną była nieważna sesja. Zachowaj status błędu i odpowiedź, sprawdź opublikowaną pomoc API oraz porównaj model i wersję oprogramowania układowego urządzenia docelowego.
HTTP 400, 404 lub 405
- Porównaj ścieżkę, metodę, nagłówki i JSON z opublikowaną pomocą API oraz zweryfikuj je dla modelu i wersji oprogramowania układowego urządzenia docelowego.
- Sprawdź wielkość liter i przedrostek
/api. 404lub405mogą oznaczać, że punkt końcowy jest niedostępny albo ma inną definicję w tej wersji oprogramowania. Nie próbuj na chybił trafił podobnych operacji zapisu.
Błąd HTTP mimo odpowiedzi lub errCode różny od 0
- Zapisz status HTTP i treść odpowiedzi.
- Udokumentuj pole
message, przed udostępnieniem usuń informacje wewnętrzne i nie ponawiaj w ciemno identycznej zmiany. - Jeśli nie wiadomo, czy zmiana została częściowo przyjęta, najpierw ustal stan rzeczywisty za pomocą żądania
GET, danych z CLI i testu funkcjonalnego.
Brak lub odrzucenie polecenia CLI
- Za pomocą
?sprawdź, czy polecenie istnieje w bieżącym trybie. - Klawiszem
TABuzupełnij składnię oferowaną przez urządzenie. - Sprawdź lokalną rolę, tryb poleceń, model i wersję oprogramowania układowego.
- Nie przenoś podobnie brzmiącego polecenia z innej wersji oprogramowania układowego.
Wycofanie zmian i zakończenie sesji
Sam test GET /api/ports nie zmienia konfiguracji i nie wymaga wycofania. Logowanie do API tworzy jednak sesję; zakończ ją zgodnie z opisanym cyklem życia tokenu i usuń zmienne lokalne.
W przypadku zmiany konfiguracji plan wycofania należy określić z wyprzedzeniem:
- Wyeksportuj stan bieżący i obiekty mające wpływ na środowisko albo zapisz je za pomocą operacji odczytu.
- Przygotuj dokładną operację odwrotną na podstawie opublikowanej pomocy API zweryfikowanej dla używanej wersji oprogramowania układowego albo pomocy CLI urządzenia docelowego.
- Określ kryteria natychmiastowego wycofania, takie jak utrata dostępu do zarządzania, łączności, dostępności sieci VLAN lub zasilania PoE.
- W razie błędu nie próbuj dalszych optymalizacji; przywróć poprzednią wartość, korzystając z nadal działającej ścieżki.
- Następnie ponownie sprawdź dostęp do zarządzania, stan portów, łączność i usługi objęte zmianą.
- Jeśli zwykła ścieżka dostępu została utracona, wycofaj zmianę za pomocą wcześniej zweryfikowanej, niezależnej ścieżki zarządzania, ewentualnie konsoli dostępnej w danym modelu. Reset fabryczny nie jest zwykłą metodą wycofania, ponieważ usuwa konfigurację.
W przypadku przełącznika zarządzanego przez Sophos Fusion samo lokalne wycofanie nie wystarczy. Sprawdź autorytatywny stan docelowy w Sophos Fusion, a następnie odpowiednio wprowadź tam zatwierdzoną zmianę awaryjną albo całkowicie usuń lokalny wyjątek. Nie wprowadzaj konkurencyjnych zmian kanałem lokalnym i centralnym.
Na zakończenie:
- zamknij aktywne wyjście CLI klawiszem
Qi użyj polecenia wyjścia lub wylogowania wskazanego przez pomoc urządzenia; - zamknij sesję API udokumentowanym żądaniem
PATCH /api/system/logout; - usuń lokalne zmienne tokenu i hasła za pomocą
unset; - sprawdź, czy żadne pliki tymczasowe ani dzienniki debugowania nie zawierają sekretów;
- udokumentuj w zgłoszeniu wynik, wersję oprogramowania układowego, używaną ścieżkę administracyjną, weryfikację i ewentualne wycofanie.
Utwardzanie bezpieczeństwa
- Używaj dedykowanej sieci VLAN zarządzania, a listy ACL ogranicz do niezbędnych hostów administracyjnych i protokołów.
- Włączaj HTTPS i SSH tylko wtedy, gdy są potrzebne; wyłącz niezabezpieczone lub nieużywane usługi zarządzania.
- Użyj zaufanych certyfikatów i sprawdzonych kluczy hosta SSH.
- Używaj imiennych kont lokalnych: User do samego odczytu, a Admin tylko do zatwierdzonych zmian.
- Natychmiast zmień hasło domyślne; unikaj współdzielonych haseł i rotuj je po zmianie personelu lub dostawcy usług.
- Przechowuj sekrety API poza kodem źródłowym, plikami
.env, historią powłoki, argumentami procesów i wynikami CI. - Nigdy nie uruchamiaj klienta API z rozszerzonym debugowaniem nagłówków, gdy ustawiony jest nagłówek Authorization.
- Utrzymuj krótkie sesje, dla każdej używaj nowego tokenu, a następnie usuwaj zmienne.
- Przechowuj chronione i możliwe do odtworzenia kopie zapasowe konfiguracji poza przełącznikiem.
- Koreluj w czasie lokalne dzienniki, zdarzenia centralne i zgłoszenia zmian; sprawdzaj czas przełącznika.
- Regularnie weryfikuj lokalne konta, listy ACL zarządzania, certyfikaty, klucze SSH i dostęp automatyzacji.
Zmienność oprogramowania układowego i modeli
Statyczna dokumentacja REST API opisuje ścieżkę logowania /api/system/login, test odczytu /api/ports i nagłówek autoryzacji; opublikowana pomoc API dokumentuje również ścieżkę wylogowania /api/system/logout. Te centralne materiały zawierają przykłady i wskazówki, ale nie stanowią uniwersalnego schematu dla wszystkich urządzeń. Schemat Swagger/OpenAPI jest generowany przez uruchomiony przełącznik docelowy i odpowiada jego modelowi oraz wersji oprogramowania układowego. Opublikowane materiały dotyczące CLI potwierdzają dostępność opisanych funkcji pomocy, ale nie gwarantują identyczności każdego dodatkowego polecenia we wszystkich wersjach oprogramowania układowego.
Dlatego przed użyciem produkcyjnym, osobno dla każdego modelu i każdej wersji oprogramowania układowego:
- udokumentuj dokładną wersję oprogramowania układowego i model sprzętu;
- Sprawdź tryb CLI i składnię za pomocą
?iTAB; - sprawdź schemat Swagger/OpenAPI pod kątem metod, ścieżek i schematów udostępnianych przez urządzenie docelowe z daną wersją oprogramowania układowego;
- najpierw zaloguj się i wykonaj
GET /api/portsw kontrolowanej sesji; - zatwierdź automatyzację zapisu dokładnie dla tego systemu docelowego, a dodatkowo sprawdź ją w środowisku nieprodukcyjnym lub wyraźnie ograniczonym;
- po aktualizacji oprogramowania układowego ponownie przetestuj logowanie, weryfikację certyfikatu, schemat odpowiedzi, token i wszystkie używane punkty końcowe;
- w przypadku rozbieżności nie „dostosowuj skryptu”, dopóki nie zrozumiesz nowej semantyki i sposobu wycofania.
Kontrola końcowa
- Potwierdzono właściwy model, wersję oprogramowania układowego i adres IP zarządzania.
- Udokumentowano system nadrzędny: Sophos Fusion lub zarządzanie lokalne.
- Użyto lokalnego konta User lub Admin odpowiedniego do zadania.
- Sprawdzono certyfikat TLS lub klucz hosta SSH; nie użyto trwałej opcji obniżającej bezpieczeństwo.
- Token był używany tylko w ramach sesji i nigdy nie został ujawniony.
- Sprawdzono status HTTP,
errCode,messagei stan funkcjonalny. - W przypadku zmian dostępne są stan bieżący, plan wycofania i niezależny dostęp.
- Wynik zweryfikowano przez
GET, dane CLI i wymagany test funkcjonalny. - Sesję zamknięto, zmienne usunięto, a dzienniki sprawdzono pod kątem sekretów.
- Lokalny wyjątek uzgodniono z Sophos Fusion i zamknięto w zgłoszeniu.