Naar de inhoud
Avanet

Sophos Switch beheren via CLI, lokale REST API en Fusion API

De lokale CLI en REST API benaderen rechtstreeks één Sophos Switch. De Sophos Fusion Switch Management API staat hiervan los: deze gebruikt service-principalgegevens op tenantniveau en distribueert centraal beleid naar switches. Dit runbook vermeldt voor beide routes de juiste identiteit, basis-URL en validatie.

Toepassingsgebied en uitgangspunten

Dit runbook omvat het volgende:

  • lokale CLI-toegang via een beheerpad dat voor het apparaat is vrijgegeven, met name SSH;
  • oriëntatie en diagnose in de CLI;
  • inloggen op de lokale REST API van het apparaat;
  • de levenscyclus van het sessietoken;
  • een gedocumenteerde API-test zonder wijzigingen met GET /api/ports;
  • veilig onderzoek, probleemoplossing, rollback en beëindiging van de sessie.

Dit is bewust geen volledige catalogus van API-eindpunten of CLI-commando’s. De centrale documentatie biedt richtlijnen, maar controleer vóór gebruik of de API op het doelapparaat beschikbaar is. De daarin vermelde paden, zoals /ports, zijn relatief ten opzichte van de serverbasis /api; het volledige aanroeppad is dus /api/ports. Ook CLI-commando’s, modi en parameters kunnen per model en firmware verschillen. De vereiste beoordeling staat in Variabiliteit van firmware en model.

Stel vóór toegang het volgende vast:

  1. Is Sophos Fusion of lokaal beheer het leidende systeem?
  2. Om welke switch, welk model, welke firmware en welk beheer-IP-adres gaat het?
  3. Is leestoegang genoeg, of is een goedgekeurde wijziging vereist?
  4. Wat zijn de beginsituatie, het succescriterium en het rollbackplan?
  5. Is er een onafhankelijk beheerpad als de wijziging de normale toegang onderbreekt?

Vermeng identiteiten en rollen niet

De accounts onder People zijn lokale switchaccounts:

Lokaal privilegetypeRechten op de switchTypisch gebruik
AdminAlle switchfuncties bekijken en wijzigenGoedgekeurd lokaal beheer en schrijvende API-aanroepen
UserInstellingen bekijken, maar niet wijzigenDiagnose en controle volgens het beginsel van minimale bevoegdheden

Deze lokale rollen zijn niet hetzelfde als de beheerdersrollen in Sophos Fusion. Een Fusion-rol verleent niet automatisch lokale CLI- of API-rechten en lokale referenties zijn geen Fusion-referenties. De aanmeldgegevens van een lokaal switchaccount worden naar /api/system/login verzonden.

Lokale accounts worden beheerd in de lokale interface onder People:

  1. Selecteer Add om een account aan te maken, of kies Edit naast een account.
  2. Stel Username, Password en Privilege type in.
  3. Selecteer Privilege type als Admin of User.
  4. Opslaan met Apply.

Een lokaal wachtwoord moet aan alle volgende eisen voldoen:

  • ten minste 10 en ten hoogste 32 tekens;
  • ten minste één letter en één cijfer;
  • ten minste één van deze speciale tekens: @ ~ % * # + - =.

Een lokaal Admin-account kan wachtwoorden van andere accounts wijzigen, maar niet het wachtwoord van het standaardaccount admin. Alleen admin zelf of Sophos Fusion kan dat wachtwoord wijzigen. Gebruik voor reguliere werkzaamheden persoonlijke lokale accounts in plaats van een gedeeld admin-account.

Toegang voorbereiden

Vóór een sessie:

  • Vergelijk beheer-IP-adres, model, firmwarestatus, locatie en serienummer met het wijzigingsticket.
  • Verleen alleen toegang vanaf een administratief beheernetwerk en een geautoriseerde beheerhost.
  • Maak beheerdiensten niet toegankelijk via VLAN’s of internet.
  • Controleer de tijdbron en de tijd op de beheerhost; een onjuiste tijd bemoeilijkt de beoordeling van logs en API-resultaten.
  • Zorg bij een wijziging voor een actuele configuratieback-up en een onafhankelijk terugkeerpad.
  • Leg bij Fusion-beheer de centrale doeltoestand vast en documenteer de lokale uitzondering expliciet.
  • Sla toegangsgegevens of tokens nooit op in tickettekst, chat, schermafbeeldingen, shellgeschiedenis of broncode.

Vervang de volgende plaatshouders:

PlaatshoudersBetekenis
<Switch-IP address>Beheer-IP-adres of een vertrouwde beheernaam van het doelapparaat
<LOCAL-USERNAME>Lokaal switchaccount, geen Fusion-gebruiker
your-passwordlokaal wachtwoord; alleen een plaatshouder, nooit als echt wachtwoord gebruiken
xxxxxxxx.yyyyyyyy.zzzzzzgemaskeerd voorbeeld van een bearer-token, geen echt token

Gebruik CLI veilig

Verbindingen maken

SSH is een lokale beheerdienst. Deze moet in de gebruikte firmware zijn geconfigureerd en vanaf het beheernetwerk bereikbaar zijn. Een algemene clientaanroep is:

ssh <LOCAL-USERNAME>@<Switch-IP-address>

De syntaxis is een clientvoorbeeld: vervang <LOCAL-USERNAME> en <Switch-IP-address> volledig, inclusief de punthaken. Vergelijk de vingerafdruk op een onafhankelijke, betrouwbare manier voordat u de hostsleutel bevestigt. Negeer een waarschuwing over een gewijzigde hostsleutel nooit; onderzoek eerst of sprake is van vervanging van het apparaat, een fabrieksreset, een IP-conflict of een mogelijke man-in-the-middle-aanval.

Als het specifieke model fysieke consoletoegang biedt, kan die als onafhankelijk onderhoudspad dienen. De verbindings- en seriële parameters moeten bij het model passen; neem ze niet over van een ander Sophos Switch-model.

Oriëntatie in de CLI

Bekijk eerst de huidige prompt en bepaal zo de actieve commandomodus. Ga er niet van uit dat een commando in elke modus beschikbaar is. De gedocumenteerde hulp en toetsen zijn:

InvoerEffecten
?Beschikbare commando’s tonen
TABCommando voltooien
Pijl omhoog / omlaagEerder uitgevoerde commando’s tonen
Pijl naar links/rechtsNavigeren in de huidige regel
Backspace of Ctrl + HEen teken verwijderen
HistoryLijst met commandogeschiedenis tonen
QUitvoer verlaten en terugkeren naar de switchprompt

Controleer hoofdlettergebruik en exacte beschikbaarheid met ? of TAB op het doelapparaat. Q beëindigt gepagineerde of actieve uitvoer, maar niet automatisch de SSH-sessie.

Veilige CLI-sequentie

  1. Begin met een lokaal User-account als alleen-lezen toegang voldoende is.
  2. Controleer het doelapparaat, de prompt en de commandomodus.
  3. Geef met ? de beschikbare commando’s voor deze modus weer.
  4. Voer eerst alleen status- of weergavebewerkingen uit.
  5. Leg vóór een wijziging de volledige actuele toestand en de exacte rollback vast.
  6. Wijzig slechts één technische stap tegelijk en controleer het resultaat onmiddellijk.
  7. Keer bij gepagineerde uitvoer met Q terug naar de prompt.
  8. Sluit de sessie correct af met het exit-/logoutcommando dat ? op het doelapparaat aangeeft en controleer daarna of de SSH-verbinding is beëindigd.

Behandel de commandogeschiedenis als gevoelige informatie: deze kan beheeradressen, gebruikersnamen of ingevoerde parameters bevatten. Geef wachtwoorden en tokens nooit als CLI-parameters op; voer ze alleen interactief in wanneer de switch daarom vraagt.

REST API: gedocumenteerde aanmelding

De API is via HTTPS bereikbaar op het beheeradres van de switch. De switch maakt voor elke sessie een nieuw bearer-token aan. Wanneer de huidige sessie wordt gesloten, moet een nieuw token worden aangevraagd.

De gedocumenteerde aanmelding gebruikt PATCH /api/system/login. Het volgende voorbeeld toont de gepubliceerde syntaxis ongewijzigd met neutrale plaatshouders:

curl -k https://<Switch-IP address>/api/system/login -X PATCH -H 'Content-Type:application/json' -d '{"user":"admin","password":"your-password"}'

Een geslaagd voorbeeldantwoord heeft deze structuur:

{
  "restful_res": {
    "token": "xxxxxxxx.yyyyyyyy.zzzzzz",
    "utctimestamp": "##########",
    "timeout": 900,
    "errCode": 0,
    "message": "OK"
  }
}

De volgende bepalingen zijn van toepassing:

  • token is een geheim met dezelfde beschermingseisen als een wachtwoord.
  • utctimestamp en timeout maken deel uit van de specifieke sessie.
  • De gedocumenteerde voorbeeldrespons toont timeout: 900; de statische beschrijving vermeldt de eenheid niet. Controleer vóór automatisering de betekenis in de gepubliceerde API-help, valideer die voor de gebruikte firmware en leg de waarde niet hard vast.
  • errCode: 0 en message: "OK" duiden in de getoonde respons op succes. Controleer daarnaast de HTTP-status.
  • Vraag een nieuw token aan nadat de sessie is beëindigd, afgewezen of verlopen; hergebruik geen oud token.

Veiliger cURL-patroon

Het volgende patroon voorkomt dat wachtwoorden en tokens in de procesargumenten staan, controleert het TLS-certificaat en schrijft geen bestand met geheimen. Het vereist curl, jq en een shell die here strings ondersteunt:

read -r -p 'Lokale switchgebruiker: ' SW_USER
read -r -s -p 'Lokaal switchwachtwoord: ' 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-aanmelding mislukt.' >&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-aanmelding heeft geen geldig bearer-token opgeleverd.' >&2
    unset SW_TOKEN SW_USER
    exit 1
    ;;
esac

Vervang /path/to/switch-ca.pem en <Switch-IP-address>. Gebruik de hostnaam waarvoor het certificaat is uitgegeven. Zorg dat in een interactieve shell geen debugtracing zoals set -x actief is. Maak variabelen niet zichtbaar via env, export, debuguitvoer of kerndumps.

REST API: aanroep en verificatie

De gedocumenteerde voorbeeldaanroep leest de poorten en geeft het token door in de Authorization-header:

curl -k https://<Switch IP Address>/api/ports -H 'authorization:Bearer <Token>'

<Token> is hier bewust alleen een plaatshouder voor het bearer-token. Dit gepubliceerde voorbeeld is daarom niet uitvoerbaar: vervang <Token> niet door het echte token en voer zo’n opdracht niet in de shellgeschiedenis in. De uitvoerbare aanroep hieronder gebruikt de variabele SW_TOKEN die tijdens het aanmelden is ingesteld.

Gebruik voor een echte sessie het al beschermde token en certificaatvalidatie. --config - leest de cURL-configuratie van de standaardinvoer; daardoor wordt de Authorization-header niet als procesargument doorgegeven en ontstaat geen tijdelijk bestand:

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 is de geschikte eerste functietest omdat de gedocumenteerde oproep status vraagt in plaats van een configuratiewijziging aan te tonen. De test is alleen succesvol als:

  1. TLS-validatie en de verbinding slagen;
  2. geen HTTP-fout terugkomt;
  3. de respons syntactisch en technisch aannemelijk is;
  4. poortnummer, poortnaam en verwachte statussen overeenkomen met het juiste doelapparaat;
  5. geen toegangsgegevens of tokens in de uitvoer of in logs verschijnen.

curl --fail-with-body retourneert een foutstatus bij HTTP-fouten, maar behoudt de responstekst voor lokale diagnose. Controleer deze responstekst op tokens, adressen, serienummers en andere interne gegevens voordat u hem deelt.

Schrijvende API-aanroepen

Voer schrijvende aanroepen alleen uit voor goedgekeurde, beperkte en omkeerbare wijzigingen. Gebruik een payload van een ander model, andere firmware of een oud script nooit zonder controle.

Voor elke schrijvende aanroep:

  1. Controleer de methode, het pad, de parameters, de datatypes en het responsschema in het Swagger-/OpenAPI-schema van het doelapparaat en bevestig de beschikbaarheid voor de actieve firmware.
  2. Lees de betrokken toestand onmiddellijk vooraf met een geschikte leesbewerking uit en sla deze veilig op.
  3. Verstuur alleen de minimaal vereiste velden; raad niet naar onbekende standaardwaarden.
  4. Werk op precies één switch en met een kleine, omkeerbare scope.
  5. Beoordeel de HTTP-status en toepassingsspecifieke velden zoals errCode en message.
  6. Bevestig de toestand met een onafhankelijke GET en, indien relevant, met een functietest.
  7. Stop bij een afwijking; stuur geen verdere wijzigingen in een herhaallus.

Alleen een geslaagde HTTP-verbinding bewijst niet dat de wijziging is geslaagd. Ook een aannemelijke JSON-body bewijst niet dat het beoogde datapad blijft werken. Test bijvoorbeeld wijzigingen aan poorten, VLAN’s of beheer ook vanuit het betrokken netwerksegment.

Bearer-tokens veilig beheren gedurende hun levenscyclus

  1. Genereren: Vraag voor elke API-sessie via PATCH /api/system/login een nieuw token aan.
  2. Controleren: Controleer het HTTP-resultaat, errCode, message, het tokenveld en de sessiewaarden zonder het token weer te geven.
  3. Gebruiken: Stuur het token alleen in de header Authorization: Bearer <token> en uitsluitend naar de bedoelde switch. <Token> is hier alleen een niet-uitvoerbare plaatshouder; de uitvoerbare voorbeelden stellen de header samen op basis van SW_TOKEN.
  4. Beperken: Exporteer, bewaar of deel tokens niet en schrijf ze niet naar bestanden, Git, CI-logs of tickets. Gebruik voor elke parallelle taak een eigen gecontroleerde sessie.
  5. Vernieuwen: Werk niet verder met hetzelfde token nadat de sessie is beëindigd of afgewezen, maar start een nieuwe sessie. Vermijd eindeloze automatische heraanmeldlussen.
  6. Sluiten: Roep de gedocumenteerde uitlogbewerking PATCH /api/system/logout aan. Ook hier komt de header via de standaardinvoer in plaats van via de procesargumenten van 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'
  1. Lokaal verwijderen: Verwijder na het afmelden de lokale variabelen. Als afmelden door een verbroken verbinding of een al ongeldige sessie niet meer mogelijk is, verwijder de geheimen dan toch lokaal en controleer de sessiebeëindiging volgens de specificaties van de gebruikte firmware:
unset SW_TOKEN SW_USER LOGIN_RESPONSE SW_PASSWORD
  1. Controleren: Controleer de shellgeschiedenis, tijdelijke bestanden en taaklogs op onbedoeld gelekte geheimen. Behandel een openbaar geworden token als gecompromitteerd, beëindig de sessie en stuur er geen verdere aanroepen mee.

Sophos Fusion Switch Management API op tenantniveau

Dit gedeelte gebruikt niet https://<Switch-IP-address>/api/.... De Fusion API authenticeert een service principal bij de regionale Sophos Fusion-host (voorheen Sophos Central) en werkt op de opgegeven tenant. Lokale People-accounts, Admin/User-rollen, lokale sessietokens en het Swagger-schema van het apparaat zijn niet van toepassing.

Vereisten, rollen en referenties

De switch moet in de juiste tenant zijn geregistreerd en door Sophos Fusion worden beheerd. De volgende uitvoerbare procedure geldt uitsluitend voor rechtstreekse API-referenties van deze tenant (client_id en client_secret). Alleen een Super Admin van de rechtstreekse tenant maakt deze aan onder Global Settings > Access Control > API Credentials; de toegewezen service-principalrol moet de vereiste lees- en schrijftoegang bieden. Gebruik bij deze shellvoorbeelden geen Partner- of Enterprise-referenties. Volg daarvoor eerst de afzonderlijke tenantselectieprocedure in Sophos Fusion API Credentials veilig beheren en keer pas terug naar deze procedure met referenties die specifiek voor de geselecteerde rechtstreekse tenant zijn uitgegeven en gecontroleerd.

Bewaar het client secret en de JWT in een geheimenkluis, nooit in scripts, tickets, shellgeschiedenis of CI-uitvoer. Vereist zijn curl, jq, Bash, een goedgekeurd wijzigingsvenster en een vastgelegde tenant-ID, regio, actuele lijst, volledige doellijst en rollback. Referenties vervangen geen licentie of Support Subscription.

Service principal verifiëren en regionale host bepalen

De IDP verstrekt de JWT via POST https://id.sophos.com/api/v2/oauth2/token. Voor de hier vereiste rechtstreekse tenantreferenties retourneert GET https://api.central.sophos.com/whoami/v1 de velden id en apiHosts.dataRegion. De procedure breekt af als whoami geen tenantidentiteit retourneert. Stuur nooit een Partner- of Organization-ID als X-Tenant-ID; probeer de regionale host niet te raden en kopieer deze niet van een andere tenant.

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

Elke switchaanroep vereist de twee headers Authorization: Bearer <token> en X-Tenant-ID: <tenant-id>, plus de volledig vastgestelde <data-region>-host. De gedocumenteerde successtatussen zijn 200 en 201; ze bewijzen alleen dat de aanroep is geaccepteerd.

MAC-filters veilig lezen en volledig vervangen

GET /switch/v1/settings/mac-filtering leest de tenantbrede blokkeerlijst. PUT /switch/v1/settings/mac-filtering voegt niets toe: macAddresses moet de volledige gewenste lijst bevatten en vervangt de bestaande lijst. {"macAddresses":[]} wist alle blokkades.

Het voorbeeld voegt een fictief, lokaal beheerd 02:-adres toe. Publiceer geen echt MAC-adres van een client. Bescherm de werkbestanden met operationele gegevens.

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

Schrijf pas nadat de volledige diff is goedgekeurd. Vanaf het vastleggen van de uitgangssituatie voor taken tot het opslaan van de eenduidig gecorreleerde taak-ID mag niemand in de tenant een andere wijziging van macFilters uitvoeren:

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

Teruglezen, taakpolling en validatie

Een geslaagde PUT bewijst niet dat elke switch het beleid heeft toegepast. Lees de instelling exact terug en vraag daarna GET /switch/v1/tasks op. Taken worden na 30 dagen verwijderd en vormen geen permanent auditarchief. De gedocumenteerde filters zijn type, pageSize en pageTotal. Omdat deze procedure geen andere, niet-gedocumenteerde paginaparameter veronderstelt, verwerkt zij maximaal de eerste volledige pagina van 50 taken. Bij pages.total > 1 breekt zij af in plaats van volgende pagina’s stilzwijgend te negeren.

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("meerdere overeenkomende taken") 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

De procedure correleert precies één nieuwe taak aan de hand van CHANGE_STARTED_AT, type: "macFilters" en de vóór de PUT opgeslagen taak-ID’s. Vervolgens vraagt zij de verzameling maximaal 30 keer op, met tussenpozen van tien seconden, en selecteert zij uitsluitend de opgeslagen taak-ID. Voor succes zijn zowel een geslaagde totaalstatus als de eindstatus succeeded voor elk item in switches[] vereist. Dubbelzinnigheid, paginering, een time-out, fouten en noSupportSubscription leiden tot afbreken. De PUT wordt niet herhaald.

Fusion API-fouten nauwkeurig afhandelen

  • 401/403: Controleer de vervaldatum van de JWT, de service principal, de tenantcontext en de headers; lokale rollen zijn hier niet van toepassing.
  • Verkeerde tenant of regionale host: Bepaal ID en host opnieuw via whoami of de lijst met beheerde tenants.
  • HTTP 200/201 zonder effect: Controleer de teruggelezen gegevens en de taak; blijf binnen de ingestelde grens pollen, maar herhaal de PUT niet blindelings.
  • noSupportSubscription: Corrigeer Support Subscription en apparaatstatus in de juiste tenant; geen lokale omweg.
  • Code 10905 – Duplicate MAC filter policy: Controleer switches[].error, lees opnieuw en los een dubbele of verouderde aanvraag op; probeer het niet blindelings opnieuw.
  • Code 10906 – MAC filter list is exhausted: Stop en keur een kleinere, volledige lijst goed; stuur nooit een deelverzameling om die als toevoeging te gebruiken.
  • Code 10908 – MAC address already allowed in the static MAC table: Los het conflict en het beveiligingseffect op; verwijder toegestane items niet zonder controle.

Leg bij fouten HTTP-status, taak-ID, switch-ID, status, error, message en code samen vast en maskeer gevoelige gegevens.

Grenzen van rollback en herstel

Een rollback is opnieuw een volledige PUT van de opgeslagen lijst. Lees eerst de huidige toestand terug en sluit gelijktijdige wijzigingen uit; voer daarna dezelfde teruglees- en taakvalidatie uit totdat elke switch een eindstatus heeft.

# Zorg vóór deze nieuwe uitlezing voor een exclusief wijzigingsvenster.
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("meerdere overeenkomende rollbacktaken") 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 is slechts een momentopname en geen volledige switchback-up. Gebruik bij verlies nooit een lege lijst als reset: daarmee wist u alle blokkades. Deze API herstelt geen lokale CLI-/REST-configuratie en heft geen Active Threat Response-isolatie op. Wis tokenvariabelen, bescherm of verwijder bestanden op een veilige manier en documenteer het taakresultaat.

Problemen per symptoom oplossen

TLS- of certificaatfout

  • Controleer de beheernaam, IP, geldigheid, certificaatketen en systeemtijd.
  • Geef met --cacert de juiste CA op of vervang het apparaatcertificaat via het daarvoor bestemde beheerproces.
  • Gebruik -k niet als permanente oplossing. Het versleutelt het transport, maar verifieert de identiteit van de switch niet.
  • Als het certificaat of de SSH-hostsleutel is gewijzigd, bevestig dan eerst dat u daadwerkelijk de bedoelde switch hebt benaderd.

Verbinding geweigerd, time-out of geen route

  • Controleer het beheer-IP-adres, beheer-VLAN, de routering, ACL en beschikbaarheid van de dienst.
  • Test vanaf een geautoriseerde host in het bedoelde beheernetwerk.
  • Omzeil het probleem niet door de dienst voor alle netwerken of voor internet open te stellen.
  • Als een zojuist uitgevoerde wijziging de toegang heeft onderbroken, gebruik dan het onafhankelijke beheerpad en voer de voorbereide rollback uit.

Aanmelding mislukt

  • Zorg ervoor dat een lokaal switchaccount wordt gebruikt, geen Sophos Fusion-account.
  • Controleer gebruikersnaam, wachtwoordvereisten, accountstatus en lokale rol.
  • Probeer niet herhaaldelijk automatisch wachtwoorden te raden; dit kan tot accountvergrendeling leiden en de oorzaak verhullen.
  • Houd er bij het standaardaccount admin rekening mee dat alleen admin zelf of Sophos Fusion het wachtwoord kan wijzigen.

HTTP 401 of 403

  • Controleer bij 401 het token en of de sessie is verlopen; meld daarna opnieuw aan.
  • Controleer bij 403 de lokale rol en of de bewerking is toegestaan; verhoog bevoegdheden niet zonder afzonderlijke goedkeuring.
  • Probeer hooguit één gecontroleerd nieuw token. Leg de fout, respons en firmwarestatus veilig vast, raadpleeg de gepubliceerde API-help en controleer model en firmware van het doelapparaat.

HTTP 400, 404 of 405

  • Vergelijk pad, methode, headers en JSON met de gepubliceerde API-help en valideer deze voor het model en de firmware van het doelapparaat.
  • Controleer het hoofdlettergebruik en het voorvoegsel /api.
  • Een 404 of 405 kan duiden op een niet-beschikbaar eindpunt of op een eindpunt dat in deze firmware anders is gedefinieerd. Probeer dit niet te omzeilen met vergelijkbare schrijfbewerkingen.

HTTP-fout ondanks respons of een andere errCode dan 0

  • Leg de HTTP-status en de responsbody vast.
  • Documenteer message, maskeer interne informatie voordat u gegevens deelt en herhaal een identieke wijziging niet blindelings.
  • Als onduidelijk is of een wijziging gedeeltelijk is toegepast, bepaal dan eerst de werkelijke toestand met een GET, CLI-uitvoer en een functietest.

CLI-opdracht ontbreekt of wordt afgewezen

  • Controleer met ? of het commando in de huidige modus bestaat.
  • Voltooi met TAB de syntaxis die het apparaat aanbiedt.
  • Controleer lokale rol, commandomodus, model en firmware.
  • Neem geen vergelijkbaar klinkende commando’s van andere firmware over.

Rollback en sessiebeëindiging

Een zuivere test met GET /api/ports wijzigt geen configuratie en vereist geen technische rollback. De API-aanmelding maakt echter wel een sessie aan; beëindig die volgens de tokenlevenscyclus en verwijder de lokale variabelen.

Bij een configuratiewijziging moet de rollback vooraf zijn voorbereid:

  1. Exporteer de actuele toestand en de betrokken objecten of leg deze met leesbewerkingen vast.
  2. Bereid de exacte omgekeerde bewerking voor op basis van de gepubliceerde API-help en valideer deze voor de gebruikte firmware, of gebruik de CLI-help van het doelapparaat.
  3. Bepaal criteria voor onmiddellijke rollback, zoals verlies van beheer, uplink, VLAN-bereikbaarheid of PoE-levering.
  4. Probeer bij een fout niet verder te optimaliseren, maar herstel de vorige waarde via het nog werkende pad.
  5. Controleer daarna de beheertoegang, poortstatus, uplinks en betrokken diensten.
  6. Als het normale pad wegvalt, voer de rollback dan uit via het vooraf geverifieerde onafhankelijke beheerpad, eventueel via de modelafhankelijke consoletoegang. Een fabrieksreset is geen normale rollback, omdat deze de configuratie verwijdert.

Voor een switch die via Sophos Fusion wordt beheerd, volstaat alleen een lokale rollback niet. Controleer de gezaghebbende doeltoestand in Sophos Fusion en verwerk een goedgekeurde noodwijziging daar correct, of draai deze lokaal volledig terug. Wissel niet ongecontroleerd tussen lokale en centrale beheerkanalen.

Tot slot:

  • CLI-uitvoer afsluiten met Q en het exit-/logoutcommando gebruiken dat op de prompt van het apparaat wordt aangegeven;
  • sluit de API-sessie af met de gedocumenteerde PATCH /api/system/logout;
  • lokale token- en wachtwoordvariabelen met unset weggooien;
  • controleren of er geen tijdelijke bestanden of debuglogs geheimen bevatten;
  • resultaat, firmware, gebruikt beheerpad, verificatie en eventuele rollback in het ticket documenteren.

Beveiliging versterken

  • Gebruik een afzonderlijk beheer-VLAN met ACL’s die de toegang beperken tot enkele beheerhosts en de vereiste protocollen.
  • Activeer HTTPS en SSH alleen wanneer nodig; schakel onveilige of ongebruikte beheerdiensten uit.
  • Gebruik vertrouwde certificaten en geverifieerde SSH-hostsleutels.
  • Gebruik persoonlijke lokale accounts, User voor pure weergave en Admin alleen voor goedgekeurde wijzigingen.
  • Vervang het standaardwachtwoord onmiddellijk; vermijd gedeelde wachtwoorden en roteer ze na personeelswisselingen of een verandering van serviceprovider.
  • Houd API-geheimen buiten broncode, .env-bestanden, shellgeschiedenis, procesargumenten en CI-uitvoer.
  • Voer API-clients nooit uit met uitgebreide headerdebugging zolang een Authorization-header is ingesteld.
  • Houd sessies kort, gebruik een nieuw token per sessie en verwijder vervolgens variabelen.
  • Bewaar beschermde en herstelbare configuratieback-ups buiten de switch.
  • Correleer lokale logs, centrale gebeurtenissen en tickets tijdig; controleer de tijdinstelling van de switch.
  • Herbeoordeel regelmatig lokale accounts, beheer-ACL’s, certificaten, SSH-sleutels en automatiseringstoegang.

Variabiliteit van firmware en model

De statische REST API-pagina documenteert het aanmeldpad /api/system/login, de leestest /api/ports en de Authorization-header; de gepubliceerde API-help vermeldt ook het afmeldpad /api/system/logout. Deze centrale bronnen bieden voorbeelden en houvast, maar geen schema dat universeel op alle apparaten van toepassing is. Het specifieke Swagger-/OpenAPI-schema wordt door de actieve doelswitch gegenereerd en weerspiegelt het model en de firmwarestatus. De gepubliceerde CLI-documenten bevestigen de bovengenoemde CLI-help, maar garanderen evenmin dat elk aanvullend commando op elke firmware identiek is.

Voor de productie dus per model en firmware:

  • documenteer de exacte firmwareversie en het hardwaremodel;
  • controleer de CLI-modus en syntaxis met ? en TAB;
  • controleer in het Swagger-/OpenAPI-schema welke methoden, paden en schema’s het doelapparaat voor de actieve firmware aanbiedt;
  • test de aanmelding en GET /api/ports eerst in een gecontroleerde sessie;
  • valideer elke schrijfautomatisering exact tegen dit doelschema en daarnaast in een niet-productieomgeving of een duidelijk beperkte omgeving;
  • test na firmware-updates opnieuw de aanmelding, certificaatcontrole, het responsschema, de tokenverwerking en alle gebruikte eindpunten;
  • pas bij afwijkingen het script niet aan voordat de nieuwe semantiek en rollback volledig zijn begrepen.

Eindcontrole

  • Juist model, juiste firmware en juist beheer-IP-adres bevestigd.
  • Leidend systeem, Sophos Fusion of lokaal beheer, gedocumenteerd.
  • Lokaal User- of Admin-account gebruikt dat bij de opdracht past.
  • TLS-certificaat of SSH-hostsleutel geverifieerd; geen permanente optie gebruikt die deze controle uitschakelt.
  • Token alleen voor de betreffende sessie gebruikt en nooit openbaar gemaakt.
  • HTTP-status, errCode, message en technische status gecontroleerd.
  • Voor wijzigingen zijn de actuele toestand, rollback en onafhankelijke toegang beschikbaar.
  • Resultaat geverifieerd via GET, CLI-uitvoer en de vereiste functietest.
  • Sessie gesloten, variabelen verwijderd en logs gecontroleerd op geheimen.
  • Lokale uitzondering in Sophos Fusion verwerkt en volledig in het ticket gedocumenteerd.