Sophos Switch über CLI, lokale REST API und Fusion API verwalten
Die lokale CLI und die lokale REST API greifen direkt auf einen Sophos Switch zu. Die Sophos Fusion Switch Management API ist davon getrennt: Sie nutzt Service-Principal-Zugangsdaten auf Tenant-Ebene und verteilt zentrale Richtlinien an Switches. Dieses Runbook beschreibt für beide Verwaltungswege die jeweilige Identität, Basis-URL und Prüfung.
Geltungsbereich und sichere Grundentscheidung
Dieses Runbook deckt Folgendes ab:
- lokalen CLI-Zugriff über einen für das Gerät freigegebenen Managementweg, insbesondere SSH;
- Orientierung und Diagnose in der CLI;
- Anmeldung an der gerätelokalen REST API;
- Lebenszyklus des sitzungsbezogenen Bearer-Tokens;
- einen dokumentierten, nicht verändernden API-Test mit
GET /api/ports; - sichere Prüfung, Fehlerbehebung, Rücknahme und Sitzungsende.
Es bildet bewusst keinen vollständigen API-Endpunkt- oder CLI-Befehlskatalog ab. Die zentrale Dokumentation bietet Orientierung; vor API-Arbeiten ist jedoch die Verfügbarkeit auf dem Zielgerät zu prüfen. Dort ausgewiesene Pfade wie /ports sind relativ zur Serverbasis /api, der vollständige Aufrufpfad lautet also /api/ports. Auch CLI-Befehle, Modi und Parameter können sich nach Modell und Firmware unterscheiden. Die verbindliche Einordnung folgt im Abschnitt Firmware- und Modellvariabilität.
Vor dem Zugriff festlegen:
- Ist Sophos Fusion oder die lokale Verwaltung das führende System?
- Welcher konkrete Switch, welches Modell, welche Firmware und welche Management-IP sind betroffen?
- Reicht Lesezugriff, oder ist eine genehmigte Änderung erforderlich?
- Wie sehen Ist-Zustand, Erfolgskriterium und Rücknahme aus?
- Gibt es einen unabhängigen Managementweg, falls die Änderung den normalen Zugang unterbricht?
Identitäten und Rollen nicht vermischen
Die Konten unter People sind lokale Konten des Switches:
| Lokaler Privilege type | Rechte auf dem Switch | Typischer Einsatz |
|---|---|---|
| Admin | alle Switchfunktionen anzeigen und ändern | genehmigte lokale Administration und schreibende API-Aufrufe |
| User | Einstellungen anzeigen, aber nicht ändern | Diagnose und Kontrolle nach dem Least-Privilege-Prinzip |
Diese lokalen Rollen sind nicht dasselbe wie Administratorrollen in Sophos Fusion. Eine Fusion-Rolle verleiht nicht automatisch ein lokales CLI- oder API-Recht, und lokale Zugangsdaten sind keine Fusion-Anmeldedaten. An /api/system/login werden die Zugangsdaten eines lokalen Switch-Kontos gesendet.
Lokale Konten werden in der lokalen Oberfläche unter People verwaltet:
- Add wählen, um ein Konto anzulegen, oder Edit neben einem Konto wählen.
- Username, Password und Privilege type festlegen.
- Als Privilege type entweder Admin oder User wählen.
- Mit Apply speichern.
Ein lokales Passwort muss alle folgenden Anforderungen erfüllen:
- mindestens 10 und höchstens 32 Zeichen;
- mindestens einen Buchstaben und eine Zahl;
- mindestens eines dieser Sonderzeichen:
@ ~ % * # + - =.
Ein lokales Admin-Konto kann Passwörter anderer Konten ändern, nicht aber das Passwort des Standardkontos admin. Dieses ändert nur das Konto admin selbst oder Sophos Fusion. Für den Regelbetrieb persönliche lokale Konten statt eines gemeinsam verwendeten admin-Kontos einsetzen.
Zugriff vorbereiten
Vor einer Sitzung:
- Management-IP, Modell, Firmwarestand, Standort und Seriennummer gegen das Change-Ticket prüfen.
- Zugriff nur aus einem administrativen Managementnetz und von einem autorisierten Admin-Host erlauben.
- Managementdienste nicht aus Benutzer-VLANs oder dem Internet erreichbar machen.
- Zeitquelle und Administrator-Host prüfen; falsche Zeit erschwert Log- und API-Auswertung.
- Bei einer Änderung ein aktuelles Konfigurationsbackup und einen unabhängigen Rückweg bereithalten.
- Bei Fusion-Verwaltung den zentralen Sollzustand sichern und die lokale Ausnahme ausdrücklich dokumentieren.
- Nie Zugangsdaten oder Bearer-Token in Tickettext, Chat, Screenshot, Shell-History oder Quellcode ablegen.
Die folgenden Platzhalter müssen ersetzt werden:
| Platzhalter | Bedeutung |
|---|---|
<Switch-IP address> | Management-IP oder ein vertrauenswürdig aufgelöster Managementname des Zielgeräts |
<LOCAL-USERNAME> | lokales Switch-Konto, nicht Fusion-Benutzer |
your-password | lokales Passwort; nur ein Platzhalter, nie als echtes Passwort verwenden |
xxxxxxxx.yyyyyyyy.zzzzzz | maskiertes Beispiel eines Bearer-Tokens, kein echtes Token |
CLI sicher verwenden
Verbindung herstellen
SSH ist Teil der lokalen Managementdienste. Es muss auf der eingesetzten Firmware konfiguriert und aus dem Managementnetz erreichbar sein. Ein allgemeiner Client-Aufruf lautet:
ssh <LOCAL-USERNAME>@<Switch-IP-address>
Der Aufruf ist ein Client-Beispiel: <LOCAL-USERNAME> und <Switch-IP-address> vollständig ersetzen, einschliesslich der spitzen Klammern. Vor dem Bestätigen des Host Keys dessen Fingerprint über einen unabhängigen, vertrauenswürdigen Weg vergleichen. Eine Warnung über einen geänderten Host Key nicht ungeprüft übergehen; zuerst einen Gerätetausch, Factory Reset, IP-Konflikt oder möglichen Man-in-the-Middle-Angriff ausschliessen.
Falls das konkrete Modell einen physischen Konsolenzugang besitzt, eignet sich dieser als unabhängiger Wartungsweg. Anschluss und serielle Parameter müssen zum Modell passen; nicht von einem anderen Sophos-Switch-Modell übernehmen.
In der CLI orientieren
Zuerst den aktuellen Prompt und damit den aktuellen Befehlsmodus beachten. Nicht davon ausgehen, dass ein Befehl in jedem Modus verfügbar ist. Die dokumentierten Hilfen und Tasten sind:
| Eingabe | Wirkung |
|---|---|
? | verfügbare Befehle auflisten |
TAB | Befehl vervollständigen |
| Pfeil nach oben / unten | zuvor ausgeführte Befehle anzeigen |
| Pfeil nach links / rechts | in der aktuellen Zeile navigieren |
Backspace oder Ctrl + H | ein Zeichen löschen |
History | Liste des Befehlsverlaufs anzeigen |
Q | eine Ausgabe verlassen und zum Switch-Prompt zurückkehren |
Gross-/Kleinschreibung und genaue Verfügbarkeit mit ? beziehungsweise TAB auf dem Zielgerät prüfen. Q beendet eine paginierte oder aktive Ausgabe und ist nicht automatisch das Ende der SSH-Sitzung.
Sicherer CLI-Ablauf
- Mit einem lokalen User-Konto beginnen, wenn Anzeigen genügen.
- Zielgerät, Prompt und Befehlsmodus prüfen.
- Mit
?die in diesem Modus verfügbaren Befehle anzeigen. - Zuerst ausschliesslich Status- beziehungsweise Anzeigeoperationen ausführen.
- Vor einer Änderung den vollständigen Ist-Zustand und die exakte Rücknahme erfassen.
- Nur einen fachlichen Schritt auf einmal ändern und unmittelbar kontrollieren.
- Bei seitenweiser Ausgabe mit
Qzum Prompt zurückkehren. - Die Sitzung mit dem auf dem Zielgerät unter
?ausgewiesenen Exit-/Logout-Befehl sauber beenden und danach die SSH-Verbindung kontrollieren.
Den Befehlsverlauf als sensible Information behandeln: Er kann Managementadressen, Benutzernamen oder eingegebene Parameter enthalten. Passwörter und Token nie als CLI-Parameter eingeben, sofern der Switch sie nicht verdeckt interaktiv abfragt.
REST API: dokumentierte Anmeldung
Die API ist per HTTPS unter der Managementadresse des Switches erreichbar. Der Switch erstellt für jede Sitzung ein neues Bearer-Token. Wird die aktuelle Sitzung geschlossen, muss ein neues Token bezogen werden.
Die dokumentierte Anmeldung verwendet PATCH /api/system/login. Das folgende Beispiel zeigt die veröffentlichte Syntax unverändert mit neutralen Platzhaltern:
curl -k https://<Switch-IP address>/api/system/login -X PATCH -H 'Content-Type:application/json' -d '{"user":"admin","password":"your-password"}'
Eine erfolgreiche Beispielantwort hat diese Struktur:
{
"restful_res": {
"token": "xxxxxxxx.yyyyyyyy.zzzzzz",
"utctimestamp": "##########",
"timeout": 900,
"errCode": 0,
"message": "OK"
}
}
Dabei gilt:
tokenist ein Geheimnis mit denselben Schutzanforderungen wie ein Passwort.utctimestampundtimeoutgehören zur konkreten Sitzung.- Die dokumentierte Beispielantwort zeigt
timeout: 900; die statische Beschreibung legt die Einheit nicht fest. Für Automation die Bedeutung in der veröffentlichten API-Hilfe prüfen, für die tatsächlich eingesetzte Firmware validieren und nicht hart codieren. errCode: 0undmessage: "OK"kennzeichnen die gezeigte erfolgreiche Antwort. Zusätzlich den HTTP-Status prüfen.- Nach Sitzungsende oder einer abgewiesenen, abgelaufenen Sitzung ein neues Token anfordern; ein altes Token nicht wiederverwenden.
Gehärtetes cURL-Muster
Das folgende Muster vermeidet Passwort und Token in den Prozessargumenten, prüft das TLS-Zertifikat und schreibt keine Geheimnisdatei. Es benötigt curl, jq und eine Shell mit Here-Strings:
read -r -p 'Lokaler Switch-Benutzer: ' SW_USER
read -r -s -p 'Lokales Switch-Passwort: ' 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' 'API-Anmeldung fehlgeschlagen.' >&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' 'API-Anmeldung lieferte kein gültiges Bearer-Token.' >&2
unset SW_TOKEN SW_USER
exit 1
;;
esac
/path/to/switch-ca.pem und <Switch-IP-address> ersetzen. Den Hostnamen verwenden, für den das Zertifikat ausgestellt ist. In einer interaktiven Shell zuvor sicherstellen, dass kein Debug-Tracing wie set -x aktiv ist. Variablen nicht mit env, export, Debug-Ausgaben oder Core Dumps offenlegen.
REST API: Aufruf und Prüfung
Der dokumentierte Beispielaufruf liest die Ports und übergibt das Token im Authorization-Header:
curl -k https://<Switch IP Address>/api/ports -H 'authorization:Bearer <Token>'
<Token> ist hier bewusst nur ein Platzhalter für das Bearer-Token. Dieses veröffentlichte Beispiel ist daher nicht ausführbar: <Token> weder durch das echte Token ersetzen noch einen solchen Befehl in die Shell-History eingeben. Der folgende ausführbare Aufruf verwendet stattdessen direkt die bereits beim Login gesetzte Variable SW_TOKEN.
Für eine echte Sitzung das bereits geschützte Token und die Zertifikatsprüfung verwenden. --config - liest die curl-Konfiguration aus der Standardeingabe; dadurch wird der Authorization-Header nicht als Prozessargument übergeben und es entsteht keine temporäre Datei:
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 ist der geeignete erste Funktionstest, weil der dokumentierte Aufruf Status abfragt, statt eine Konfigurationsänderung zu demonstrieren. Erfolgreich ist der Test erst, wenn:
- TLS-Prüfung und Verbindung erfolgreich sind;
- kein HTTP-Fehler zurückkommt;
- die Antwort syntaktisch und fachlich plausibel ist;
- Portzahl, Portnamen und erwartete Zustände zum richtigen Zielgerät passen;
- keine Zugangsdaten oder Token in der Ausgabe oder in Logs erscheinen.
curl --fail-with-body liefert bei HTTP-Fehlern einen Fehlerstatus, behält aber den Antworttext für die lokale Diagnose. Diesen Antworttext vor einer Weitergabe auf Token, Adressen, Seriennummern und andere interne Daten prüfen.
Schreibende API-Aufrufe kontrollieren
Schreibende Aufrufe nur als genehmigte, begrenzte und reversible Änderungen ausführen. Keine Payload aus einem anderen Modell, einer anderen Firmware oder einem alten Skript ungeprüft wiederverwenden.
Für jeden schreibenden Aufruf gilt:
- Im Swagger-/OpenAPI-Schema des Zielgeräts Methode, Pfad, Parameter, Datentypen und Antwortschema prüfen und die Verfügbarkeit für dessen laufende Firmware bestätigen.
- Den betroffenen Zustand unmittelbar davor mit einer passenden Leseoperation erfassen und sicher ablegen.
- Nur die minimal erforderlichen Felder senden; keine unbekannten Defaults erraten.
- Genau einen Switch und einen kleinen, reversiblen Scope verwenden.
- HTTP-Status sowie anwendungsspezifische Felder wie
errCodeundmessageauswerten. - Den Zustand mit einem unabhängigen
GETund, wo relevant, durch einen Funktionstest bestätigen. - Bei Abweichung stoppen; nicht in einer Wiederholungsschleife weitere Änderungen senden.
Eine erfolgreiche HTTP-Verbindung allein beweist keine erfolgreiche Änderung. Ebenso beweist ein plausibler JSON-Body nicht, dass der beabsichtigte Datenpfad weiterhin funktioniert. Beispielsweise müssen Port-, VLAN- oder Managementänderungen zusätzlich aus dem betroffenen Netzsegment getestet werden.
Bearer-Token sicher über den Lebenszyklus führen
- Erzeugen: Für jede API-Sitzung über
PATCH /api/system/loginein neues Token beziehen. - Prüfen: HTTP-Erfolg,
errCode,message, Tokenfeld und die Sitzungswerte prüfen, ohne das Token auszugeben. - Verwenden: Das Token nur im
Authorization-Header mit dem SchemaBearerund nur an den erwarteten Switch senden.<Token>bezeichnet hier ausschliesslich einen nicht ausführbaren Platzhalter; die ausführbaren Beispiele erzeugen den Header ausSW_TOKEN. - Begrenzen: Token nicht exportieren, persistieren, teilen oder in Dateien, Git, CI-Logs und Tickets schreiben. Pro parallelem Job eine eigene kontrollierte Sitzung verwenden.
- Erneuern: Nach Sitzungsende oder Zurückweisung nicht mit demselben Token weiterarbeiten, sondern eine neue Sitzung aufbauen. Endlose automatische Re-Login-Schleifen vermeiden.
- Schliessen: Die dokumentierte Logout-Operation authentifiziert als
PATCH /api/system/logoutaufrufen. Auch hier gelangt der Header über die Standardeingabe statt über die Prozessargumente zu curl:
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'
- Lokal verwerfen: Nach dem Logout die lokalen Variablen entfernen. Ist der Logout wegen einer unterbrochenen Verbindung oder bereits ungültigen Sitzung nicht mehr möglich, die Geheimnisse trotzdem lokal verwerfen und das Sitzungsende nach den Vorgaben der eingesetzten Firmware kontrollieren:
unset SW_TOKEN SW_USER LOGIN_RESPONSE SW_PASSWORD
- Kontrollieren: Shell-Verlauf, temporäre Dateien und Job-Logs auf versehentliche Geheimnisse prüfen. Ein offengelegtes Token als kompromittiert behandeln, Sitzung beenden und keine weiteren Aufrufe damit senden.
Tenantweite Sophos Fusion Switch Management API
Dieser Abschnitt verwendet nicht https://<Switch-IP-address>/api/.... Die Fusion API authentifiziert einen Service Principal am regionalen Sophos-Fusion-Host (ehemals Sophos Central) und führt Operationen für den angegebenen Tenant aus. Lokale People-Konten, Rollen Admin/User, lokale Sitzungstoken und das gerätespezifische Swagger-Schema gelten hier nicht.
Voraussetzungen, Rollen und Zugangsdaten
Der Switch muss im richtigen Tenant registriert sein und von Sophos Fusion verwaltet werden. Der folgende ausführbare Ablauf gilt ausschliesslich für direkte API Credentials dieses Tenants (client_id und client_secret). Nur ein Super Admin des direkten Tenants erstellt sie unter Global Settings > Access Control > API Credentials; die zugewiesene Service-Principal-Rolle muss den benötigten Lese- und Schreibzugriff erlauben. Partner- oder Enterprise-Credentials dürfen mit diesen Shell-Beispielen nicht verwendet werden. Für diese Credentials zuerst das separate Tenant-Auswahlverfahren unter Sophos Fusion API-Zugangsdaten sicher verwalten durchführen. Erst danach mit Zugangsdaten zu diesem Ablauf zurückkehren, die eigens für den ausgewählten direkten Tenant ausgestellt und geprüft wurden.
Client Secret und JWT gehören in einen Secret Store, nie in Skripte, Tickets, Shell-History oder CI-Ausgaben. Benötigt werden curl, jq, eine Bash-Shell, ein genehmigtes Change-Fenster sowie eine dokumentierte Tenant-ID, Region, aktuelle Liste, vollständige Zielliste und Rücknahme. API Credentials ersetzen weder eine Lizenz noch eine Support Subscription.
Service Principal authentifizieren und Regionshost bestimmen
Der Identity Provider (IDP) stellt das JWT über POST https://id.sophos.com/api/v2/oauth2/token aus. Bei den hier vorausgesetzten direkten Tenant-Credentials liefert GET https://api.central.sophos.com/whoami/v1 die Felder id und apiHosts.dataRegion. Der Ablauf bricht ab, wenn whoami keine Tenant-Identität liefert. Niemals eine Partner- oder Organization-ID als X-Tenant-ID senden; den Regionshost weder erraten noch aus einem anderen Tenant übernehmen.
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
Jeder Switch-Aufruf benötigt die Header Authorization: Bearer <token> und X-Tenant-ID: <tenant-id> sowie den vollständig ermittelten <data-region>-Host. Die dokumentierten Erfolgsstatus sind 200 oder 201; sie belegen nur, dass der Aufruf angenommen wurde.
MAC-Filter sicher lesen und vollständig ersetzen
GET /switch/v1/settings/mac-filtering liest die tenantweite Blockliste. PUT /switch/v1/settings/mac-filtering fügt keine Einträge an: macAddresses muss die vollständige gewünschte Liste enthalten und ersetzt die bestehende Liste. {"macAddresses":[]} löscht alle Blockeinträge.
Das Beispiel ergänzt eine synthetische, lokal verwaltete 02:-Adresse. Keine reale Client-MAC offenlegen. Die Arbeitsdateien enthalten Betriebsdaten und müssen geschützt werden.
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
Erst nach Freigabe des vollständigen Diffs schreiben. Vom Erfassen des Task-Ausgangszustands bis zum Speichern der eindeutig zugeordneten Task-ID darf im Tenant keine andere macFilters-Änderung laufen:
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
Rücklesen, Task-Abfrage und Validierung
Ein erfolgreicher PUT beweist nicht, dass alle Switches die Richtlinie angewendet haben. Die Einstellung exakt zurücklesen und danach GET /switch/v1/tasks abfragen. Tasks werden nach 30 Tagen gelöscht und sind kein dauerhaftes Auditarchiv. Die dokumentierten Filter sind type, pageSize und pageTotal. Da hier kein weiterer dokumentierter Seitenparameter vorausgesetzt wird, verarbeitet der Ablauf höchstens die erste vollständige Seite mit 50 Tasks und bricht bei pages.total > 1 ab, statt weitere Seiten stillschweigend zu ignorieren.
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("mehrere passende Tasks") 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
Der Ablauf ordnet anhand von CHANGE_STARTED_AT, type: "macFilters" und den vor dem PUT gesicherten Task-IDs genau einen neuen Task zu. Danach fragt er die Sammlung höchstens 30-mal im Abstand von zehn Sekunden ab und wählt ausschliesslich die gespeicherte Task-ID. Erfolg setzt sowohl einen erfolgreichen Gesamtstatus als auch für jeden Eintrag in switches[] den abschliessenden Status succeeded voraus. Mehrdeutigkeit, Pagination, Timeout, Fehler und noSupportSubscription führen zum Abbruch. Der PUT wird dabei nicht wiederholt.
Fusion-API-Fehler gezielt behandeln
- 401/403: JWT-Ablauf, Service Principal, Tenant-Kontext und Header prüfen; lokale Rollen helfen nicht.
- Falscher Tenant oder Regionshost: Tenant-ID und Host erneut aus
whoamibeziehungsweise der verwalteten Tenant-Liste ermitteln. - HTTP 200/201 ohne Wirkung: Rückleseergebnis und passenden Task prüfen; die Abfrage begrenzt fortsetzen, aber den PUT nicht ungeprüft wiederholen.
noSupportSubscription: Support Subscription und Gerätestatus im richtigen Tenant korrigieren; kein lokaler Workaround.- Code
10905–Duplicate MAC filter policy:switches[].errorprüfen, Zustand erneut lesen und doppelte oder veraltete Anforderung klären; den Aufruf nicht ungeprüft wiederholen. - Code
10906–MAC filter list is exhausted: Stoppen und eine kleinere vollständige Liste genehmigen; nie eine Teilliste zum Anfügen senden. - Code
10908–MAC address already allowed in the static MAC table: Konflikt und Sicherheitswirkung klären; statische Allow-Einträge nicht ungeprüft entfernen.
Bei Fehlern HTTP-Status, Task-ID, Switch-ID, status, error, message und code gemeinsam erfassen und sensible Daten redigieren.
Rücknahme und Wiederherstellungsgrenzen
Die Rücknahme ist ein weiterer vollständiger PUT der gesicherten Liste. Vorher erneut lesen und Paralleländerungen ausschliessen; anschliessend dieselbe Rückleseprüfung und denselben Task-Ablauf bis zum Endstatus jedes Switches durchführen.
# Vor dem erneuten Lesen ein exklusives Änderungsfenster sicherstellen.
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("mehrere passende Rücknahme-Tasks") 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 ist nur eine Momentaufnahme dieser Einstellung, kein vollständiges Switch-Backup. Bei verlorener Baseline nie eine leere Liste als Reset senden: Sie löscht alle Blockeinträge. Diese API stellt keine lokale CLI-/REST-Konfiguration wieder her und hebt keine Active-Threat-Response-Isolierung auf. Zum Abschluss Tokenvariablen löschen, Dateien schützen oder sicher löschen und das Task-Ergebnis dokumentieren.
Fehler nach Symptom behandeln
TLS- oder Zertifikatsfehler
- Managementname, IP, Gültigkeit, Zertifikatskette und Systemzeit prüfen.
- Die korrekte CA mit
--cacerthinterlegen oder das Gerätezertifikat über den vorgesehenen Verwaltungsprozess ersetzen. -knicht als dauerhafte Fehlerbehebung verwenden. Es verschlüsselt zwar den Transport, authentifiziert den Switch aber nicht.- Bei geändertem Zertifikat oder SSH Host Key zuerst bestätigen, dass wirklich der vorgesehene Switch angesprochen wird.
Verbindung abgelehnt, Timeout oder keine Route
- Management-IP, Management-VLAN, Routing, ACL und Freigabe des Dienstes prüfen.
- Von einem autorisierten Host im vorgesehenen Managementnetz testen.
- Nicht durch Öffnen des Dienstes für alle Netze oder das Internet umgehen.
- Wenn eine eben ausgeführte Änderung den Zugang unterbrochen hat, den unabhängigen Managementweg und den vorbereiteten Rollback verwenden.
Anmeldung schlägt fehl
- Sicherstellen, dass ein lokales Switch-Konto verwendet wird, kein Sophos-Fusion-Konto.
- Benutzername, Passwortanforderungen, Kontostatus und lokale Rolle prüfen.
- Nicht wiederholt automatisiert raten; dies kann Sperren auslösen und verdeckt die Ursache.
- Beim Standardkonto
adminbeachten, dass dessen Passwort nur durchadminselbst oder Sophos Fusion geändert wird.
HTTP 401 oder 403
- Bei
401Token, Sitzungsende und neue Anmeldung prüfen. - Bei
403die lokale Rolle und die Berechtigung für die Operation prüfen; Rechte nicht pauschal erhöhen. - Ein neues Token höchstens kontrolliert beziehen. Bleibt der Fehler, Antwort und Firmwarestand sichern, die veröffentlichte API-Hilfe prüfen und Modell sowie Firmware des Zielgeräts abgleichen.
HTTP 400, 404 oder 405
- Pfad, Methode, Header und JSON gegen die veröffentlichte API-Hilfe vergleichen und für Modell sowie Firmware des Zielgeräts validieren.
- Gross-/Kleinschreibung und den Präfix
/apiprüfen. - Ein
404oder405kann auf einen nicht verfügbaren beziehungsweise in dieser Firmware anders definierten Endpunkt hindeuten. Nicht durch Probieren ähnlicher Schreiboperationen umgehen.
HTTP-Fehler trotz Antwort oder errCode ungleich 0
- HTTP-Status und Antwortbody gemeinsam auswerten.
messagedokumentieren, interne Angaben vor Weitergabe redigieren und keine identische Änderung blind wiederholen.- Ist unklar, ob eine Änderung teilweise übernommen wurde, zuerst per
GET, CLI-Anzeige und Funktionstest den tatsächlichen Zustand bestimmen.
CLI-Befehl fehlt oder wird abgewiesen
- Mit
?prüfen, ob der Befehl im aktuellen Modus existiert. - Mit
TABdie auf dem Gerät angebotene Syntax vervollständigen. - Lokale Rolle, Befehlsmodus, Modell und Firmware kontrollieren.
- Keinen ähnlich klingenden Befehl aus einer anderen Firmware übernehmen.
Rücknahme, Abbruch und Sitzungsende
Ein reiner GET /api/ports-Test ändert keine Konfiguration und benötigt keine fachliche Rücknahme. Die API-Anmeldung erzeugt jedoch eine Sitzung; diese gemäss Token-Lebenszyklus beenden und die lokalen Variablen löschen.
Bei einer Konfigurationsänderung ist der Rollback vorher festzulegen:
- Ist-Zustand und betroffene Objekte exportieren oder mit Leseoperationen erfassen.
- Die exakte inverse Operation anhand der veröffentlichten API-Hilfe und ihrer Validierung für die eingesetzte Firmware beziehungsweise anhand der CLI-Hilfe des Zielgeräts vorbereiten.
- Kriterien definieren, bei denen sofort abgebrochen wird, etwa Verlust von Management, Uplink, VLAN-Erreichbarkeit oder PoE-Versorgung.
- Bei einem Fehler keine weiteren Optimierungen versuchen, sondern den vorherigen Wert über den noch funktionierenden Weg wiederherstellen.
- Danach Managementzugriff, Portstatus, Uplinks und betroffene Dienste erneut prüfen.
- Ist der normale Weg verloren, über den vorher verifizierten unabhängigen Managementweg, gegebenenfalls den modellabhängigen Konsolenzugang, zurücknehmen. Ein Factory Reset ist kein normaler Rollback, weil er die Konfiguration löscht.
Für einen in Sophos Fusion verwalteten Switch reicht eine lokale Rücknahme allein nicht. Den autoritativen Sollzustand in Sophos Fusion prüfen und eine genehmigte Notfalländerung dort sauber nachführen oder lokal vollständig entfernen. Nicht zwischen lokalem und zentralem Kanal hin- und herkonfigurieren.
Zum Abschluss:
- eine CLI-Ausgabe mit
Qverlassen und am Prompt den auf dem Gerät ausgewiesenen Exit-/Logout-Befehl verwenden; - die API-Sitzung mit dem dokumentierten
PATCH /api/system/logoutschliessen; - lokale Token- und Passwortvariablen mit
unsetverwerfen; - prüfen, dass keine temporären Dateien oder Debug-Logs Geheimnisse enthalten;
- Ergebnis, Firmware, verwendeten Verwaltungsweg, Verifikation und allfällige Rücknahme im Ticket dokumentieren.
Sicherheits-Hardening
- Dediziertes Management-VLAN mit ACLs auf wenige Admin-Hosts und benötigte Protokolle beschränken.
- HTTPS und SSH nur aktivieren, wenn benötigt; unsichere oder ungenutzte Managementdienste deaktivieren.
- Vertrauenswürdige Zertifikate und verifizierte SSH Host Keys verwenden.
- Persönliche lokale Konten einsetzen, User für reine Sicht und Admin nur für genehmigte Änderungen.
- Standardpasswort sofort ersetzen; gemeinsame Passwörter vermeiden und nach Personal- oder Dienstleisterwechsel rotieren.
- API-Geheimnisse aus Quellcode,
.env-Dateien, Shell-History, Prozessargumenten und CI-Ausgaben fernhalten. - API-Clients niemals mit ausführlichem Header-Debugging betreiben, solange ein Authorization-Header gesetzt ist.
- Sitzungen kurz halten, pro Sitzung ein neues Token verwenden und Variablen danach löschen.
- Konfigurationsbackups ausserhalb des Switches geschützt und wiederherstellbar aufbewahren.
- Lokale Logs, zentrale Ereignisse und Change-Tickets zeitlich korrelieren; Uhrzeit des Switches kontrollieren.
- Regelmässig lokale Konten, Management-ACLs, Zertifikate, SSH Keys und Automationszugänge rezertifizieren.
Firmware- und Modellvariabilität
Die statische REST-API-Seite belegt den Anmeldepfad /api/system/login, den Lesetest /api/ports und den Authorization-Header; die veröffentlichte API-Hilfe dokumentiert auch den Logout-Pfad /api/system/logout. Diese zentralen Hilfen liefern Beispiele und Orientierung, aber kein für alle Geräte universell gültiges Schema. Das konkrete Swagger-/OpenAPI-Schema wird vom laufenden Ziel-Switch erzeugt und bildet dessen Modell- und Firmwarestand ab. Die veröffentlichten CLI-Unterlagen belegen die genannten CLI-Hilfen; auch sie garantieren nicht, dass jeder weitere Befehl auf jeder Firmware identisch ist.
Vor Produktionseinsatz deshalb pro Modell und Firmware:
- exakte Firmwareversion und Hardwaremodell dokumentieren;
- CLI-Modus und Syntax mit
?undTABprüfen; - das vom Zielgerät für die laufende Firmware bereitgestellte Swagger-/OpenAPI-Schema für Methoden, Pfade und Schemas prüfen;
- Login und
GET /api/portszuerst in einer kontrollierten Sitzung testen; - jede schreibende Automation gegen genau dieses Zielschema und zusätzlich in einer nicht produktiven oder klar begrenzten Umgebung validieren;
- nach Firmwareupdates Login, Zertifikatsprüfung, Antwortschema, Tokenbehandlung und alle verwendeten Endpunkte erneut testen;
- bei Abweichungen nicht das Skript «passend machen», bevor die neue Semantik und die Rücknahme verstanden sind.
Abschlusskontrolle
- Richtiges Modell, richtige Firmware und richtige Management-IP bestätigt.
- Führendes System Sophos Fusion oder lokal dokumentiert.
- Lokales User- beziehungsweise Admin-Konto passend zum Auftrag verwendet.
- TLS-Zertifikat oder SSH Host Key geprüft; keine dauerhafte Unsicherheitsoption eingesetzt.
- Token nur sitzungsbezogen verwendet und nie offengelegt.
- HTTP-Status,
errCode,messageund fachlicher Zustand geprüft. - Bei Änderungen Ist-Zustand, Rücknahme und unabhängiger Zugriff vorhanden.
- Ergebnis über
GET, CLI-Anzeige und erforderlichen Funktionstest verifiziert. - Sitzung geschlossen, Variablen gelöscht und Logs auf Geheimnisse geprüft.
- Lokale Ausnahme gegenüber Sophos Fusion bereinigt und im Ticket abgeschlossen.