Hoppa till innehållet
Avanet

Hantera Sophos Switch via CLI, lokalt REST API och Fusion API

Lokalt CLI och lokalt REST API ansluter direkt till en Sophos Switch. Sophos Fusion Switch Management API är separat: det använder autentiseringsuppgifter för en service principal på tenantnivå och distribuerar centrala policyer till switchar. Den här runbooken beskriver rätt identitet, bas-URL och validering för båda metoderna.

Omfattning och säkra inledande beslut

Den här runbooken omfattar följande:

  • lokal CLI-åtkomst via en hanteringsväg som har öppnats för enheten, i synnerhet SSH;
  • orientering och diagnos i CLI;
  • inloggning i enhetens lokala REST API;
  • livscykeln för sessionens bearer-token;
  • ett dokumenterat, icke-modifierande API-test med GET /api/ports;
  • säker undersökning, felsökning, återställning och avslutning av sessionen.

Runbooken innehåller avsiktligt inte en fullständig katalog över API-endpoints eller CLI-kommandon. Den centrala dokumentationen ger vägledning, men före API-arbete måste tillgängligheten kontrolleras på målenheten. Sökvägar som /ports är relativa till serverbasen /api, så den fullständiga sökvägen är /api/ports. CLI-kommandon, lägen och parametrar kan också skilja sig mellan modeller och firmwareversioner. Den obligatoriska bedömningen beskrivs i avsnittet Variationer mellan firmware och modeller.

Fastställ följande före åtkomst:

  1. Är Sophos Fusion eller den lokala administrationen det auktoritativa systemet?
  2. Vilken switch, modell, firmwareversion och hanterings-IP berörs?
  3. Räcker läsåtkomst eller krävs en godkänd ändring?
  4. Vilket är det aktuella tillståndet, framgångskriteriet och återställningsförfarandet?
  5. Finns det en oberoende hanteringsväg om ändringen bryter den normala åtkomsten?

Blanda inte identiteter och roller

Kontona under People är lokala konton på switchen:

Lokal Privilege TypeRättigheter på switchenTypisk användning
AdminVisa och ändra alla switchfunktionerGodkänd lokal administration och skrivande API-anrop
UserVisa inställningar, men inte ändra demDiagnostik och kontroll enligt principen om minsta privilegium

Dessa lokala roller är inte samma sak som administratörsroller i Sophos Fusion. En Fusion-roll ger inte automatiskt lokal CLI- eller API-behörighet, och lokala autentiseringsuppgifter är inte Fusion-autentiseringsuppgifter. Autentiseringsuppgifterna för ett lokalt switchkonto skickas till /api/system/login.

Lokala konton hanteras i det lokala gränssnittet under People:

  1. Välj Add för att skapa ett konto eller välj Edit bredvid ett konto.
  2. Ange Username, Password och Privilege type.
  3. Välj Privilege type som antingen Admin eller User.
  4. Spara med Apply.

Ett lokalt lösenord måste uppfylla alla följande krav:

  • minst 10 och högst 32 tecken;
  • minst en bokstav och en siffra;
  • minst ett av följande specialtecken: @ ~ % * # + - =.

Ett lokalt Admin-konto kan ändra lösenord för andra konton, men inte lösenordet för standardkontot admin. Det lösenordet kan endast ändras av kontot admin självt eller via Sophos Fusion. Använd personliga lokala konton i den löpande driften i stället för ett delat admin-konto.

Förbered åtkomst

Före en session:

  • Kontrollera hanterings-IP, modell, firmwarestatus, plats och serienummer mot ändringsärendet.
  • Tillåt endast åtkomst från ett administrativt hanteringsnätverk och en behörig administrationsvärd.
  • Exponera inte hanteringstjänster för användar-VLAN eller internet.
  • Kontrollera tidskällan och administrationsvärdens tid. Felaktig tid försvårar utvärdering av loggar och API-anrop.
  • Om en ändring ska göras måste en aktuell konfigurationssäkerhetskopia och en oberoende återställningsväg finnas tillgängliga.
  • Vid hantering via Fusion ska det centrala måltillståndet säkras och det lokala undantaget dokumenteras uttryckligen.
  • Lagra aldrig autentiseringsuppgifter eller bearer-token i ärendetext, chattar, skärmbilder, skalhistorik eller källkod.

Följande platshållare ska ersättas:

PlatshållareBetydelse
<Switch-IP address>Hanterings-IP eller ett betrott hanteringsnamn för målenheten
<LOCAL-USERNAME>Lokalt switchkonto, inte en Fusion-användare
your-passwordLokalt lösenord; endast en platshållare, använd det aldrig som ett verkligt lösenord
xxxxxxxx.yyyyyyyy.zzzzzzMaskerat exempel på en bearer-token, inte en verklig token

Använd CLI säkert

Ansluta

SSH är en av de lokala hanteringstjänsterna. Tjänsten måste vara konfigurerad i den firmware som används och åtkomlig från hanteringsnätverket. Ett generellt klientanrop är:

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

Kommandot är ett klientexempel: ersätt hela <LOCAL-USERNAME> och <Switch-IP-address>, inklusive vinkelparenteserna. Jämför värdnyckelns fingeravtryck via en oberoende, betrodd kanal innan du godkänner den. Ignorera inte en varning om en ändrad värdnyckel. Undersök först om enheten har bytts eller fabriksåterställts, om det finns en IP-konflikt eller om det kan röra sig om en man-in-the-middle-attack.

Om modellen har en fysisk konsolport kan den användas som en oberoende underhållsväg. Anslutningen och de seriella parametrarna måste stämma för modellen; återanvänd inte antaganden från en annan Sophos Switch-modell.

Orientering i CLI

Kontrollera först den aktuella prompten och därmed det aktuella kommandoläget. Utgå inte från att ett kommando är tillgängligt i alla lägen. Följande hjälpmedel och tangenter är dokumenterade:

InmatningFunktion
?Lista tillgängliga kommandon
TABSlutföra kommandot
Pil upp/nedVisa tidigare utförda kommandon
Pil vänster/högerNavigera på den aktuella raden
Backspace eller Ctrl + HTa bort ett tecken
HistoryVisa kommandohistoriken
QStäng en utmatning och återgå till switchprompten

Kontrollera skiftläge och exakt tillgänglighet med ? eller TAB på målenheten. Q avslutar en sidindelad eller aktiv utmatning, inte automatiskt SSH-sessionen.

Säker CLI-sekvens

  1. Börja med ett lokalt User-konto när skrivskyddad åtkomst är tillräcklig.
  2. Kontrollera målenheten, prompten och kommandoläget.
  3. Visa med ? vilka kommandon som finns i det aktuella läget.
  4. Utför till en början endast status- eller visningsåtgärder.
  5. Dokumentera det fullständiga faktiska tillståndet och det exakta återställningsförfarandet före en ändring.
  6. Ändra endast ett tekniskt steg i taget och kontrollera det omedelbart.
  7. Återgå till prompten med Q när utmatningen visas sida för sida.
  8. Avsluta sessionen korrekt med det exit-/logout-kommando som visas med ? på målenheten och kontrollera därefter att SSH-anslutningen har stängts.

Behandla kommandohistoriken som känslig information: den kan innehålla hanteringsadresser, användarnamn eller angivna parametrar. Ange aldrig lösenord eller token som CLI-parametrar om inte switchen efterfrågar dem interaktivt.

REST API: dokumenterad inloggning

API:t nås via HTTPS på switchens hanteringsadress. Switchen skapar en ny bearer-token för varje session. När den aktuella sessionen har stängts måste en ny token hämtas.

Den dokumenterade inloggningen använder PATCH /api/system/login. Följande exempel visar den publicerade syntaxen oförändrad, med neutrala platshållare:

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

Ett exempel på ett lyckat svar har följande struktur:

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

Tänk på följande:

  • token är en hemlighet med samma skyddskrav som ett lösenord.
  • utctimestamp och timeout är en del av den specifika sessionen.
  • Det dokumenterade exempelsvaret visar timeout: 900, men den statiska beskrivningen anger inte enheten. Kontrollera betydelsen i den publicerade API-hjälpen, validera den mot den firmware som faktiskt används och hårdkoda inte värdet i automatiseringar.
  • errCode: 0 och message: "OK" anger att det visade svaret lyckades. Kontrollera även HTTP-statusen.
  • Begär en ny token när sessionen har avslutats eller när en utgången session avvisas. Återanvänd inte en gammal token.

Härdat cURL-mönster

Följande mönster undviker lösenord och token i processargumenten, verifierar TLS-certifikatet och skriver ingen fil med hemligheter. Det kräver curl, jq och ett skal med stöd för härsträngar (here strings):

read -r -p 'Lokalt switchanvändarnamn: ' SW_USER
read -r -s -p 'Lokalt switchlösenord: ' 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-inloggningen misslyckades.' >&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-inloggningen returnerade ingen giltig bearer-token.' >&2
    unset SW_TOKEN SW_USER
    exit 1
    ;;
esac

Ersätt /path/to/switch-ca.pem och <Switch-IP-address>. Använd det värdnamn som certifikatet har utfärdats för. Kontrollera i ett interaktivt skal att ingen felsökningsspårning, exempelvis set -x, är aktiv. Exponera inte variabler via env, export, felsökningsutskrifter eller kärndumpar.

REST API: anrop och verifiering

Det dokumenterade exempelanropet läser portarna och skickar token i Authorization-headern:

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

<Token> är avsiktligt bara en platshållare för bearer-token. Det publicerade exemplet är därför inte körbart: ersätt inte <Token> med en verklig token och skriv inte in ett sådant kommando så att det hamnar i skalhistoriken. Det körbara anropet nedan använder i stället variabeln SW_TOKEN, som redan har tilldelats vid inloggningen.

Använd den redan skyddade token och certifikatverifieringen i en verklig session. --config - läser cURL-konfigurationen från standardindata. Då skickas Authorization-headern inte som ett processargument och ingen temporär fil skapas:

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 är ett lämpligt första funktionstest eftersom det dokumenterade anropet begär status i stället för att göra en konfigurationsändring. Testet lyckas endast om:

  1. TLS-verifieringen och anslutningen lyckas;
  2. inget HTTP-fel returneras;
  3. svaret är syntaktiskt och tekniskt rimligt;
  4. portnummer, portnamn och förväntade tillstånd stämmer med rätt målenhet;
  5. inga autentiseringsuppgifter eller token visas i utdata eller loggar.

curl --fail-with-body ger en felstatus vid HTTP-fel men behåller svarstexten för lokal diagnostik. Kontrollera svarstexten med avseende på token, adresser, serienummer och andra interna uppgifter innan du delar den.

Kontrollera skrivande API-anrop

Utför skrivande anrop endast som godkända, begränsade och reversibla ändringar. Återanvänd inte okontrollerat en nyttolast från en annan modell, firmwareversion eller ett gammalt skript.

För varje skrivande anrop:

  1. Kontrollera metod, sökväg, parametrar, datatyper och svarsschema i målenhetens Swagger-/OpenAPI-schema och bekräfta att de är tillgängliga i den firmware som körs.
  2. Läs av det berörda tillståndet omedelbart före ändringen med en lämplig läsåtgärd och lagra det säkert.
  3. Skicka endast de minsta nödvändiga fälten; gissa inte okända standardvärden.
  4. Begränsa anropet till exakt en switch och en liten, reversibel omfattning.
  5. Utvärdera HTTP-statusen och applikationsspecifika fält som errCode och message.
  6. Bekräfta tillståndet med ett oberoende GET-anrop och, när det är relevant, med ett funktionstest.
  7. Avbryt vid en avvikelse. Skicka inte fler ändringar i en upprepande loop.

En lyckad HTTP-anslutning bevisar inte att en ändring har lyckats. På samma sätt bevisar en rimlig JSON-kropp inte att den avsedda datavägen fortfarande fungerar. Port-, VLAN- eller hanteringsändringar måste exempelvis även testas från det berörda nätverkssegmentet.

Hantera bearer-token säkert under hela livscykeln

  1. Skapa: Hämta en ny token för varje API-session via PATCH /api/system/login.
  2. Verifiera: Kontrollera HTTP-resultatet, errCode, message, tokenfältet och sessionsvärdena utan att skriva ut tokenvärdet.
  3. Använd: Skicka tokenvärdet endast i headern Authorization: Bearer <token> och endast till den avsedda switchen. <Token> är den kanoniska, icke-körbara platshållaren; de körbara exemplen skapar headern från SW_TOKEN.
  4. Begränsa: Exportera, spara eller dela inte token och skriv dem inte till filer, Git, CI-loggar eller ärenden. Använd en separat, kontrollerad session för varje parallellt jobb.
  5. Förnya: Fortsätt inte arbeta med samma token när sessionen har avslutats eller avvisats, utan skapa en ny session. Undvik oändliga automatiska loopar för ny inloggning.
  6. Stäng: Anropa den dokumenterade och autentiserade utloggningen PATCH /api/system/logout. Även här skickas headern till cURL via standardindata i stället för via processargumenten:
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. Radera lokalt: Ta bort de lokala variablerna efter utloggningen. Om utloggning inte längre är möjlig på grund av en avbruten anslutning eller en redan ogiltig session ska hemligheterna ändå raderas lokalt och sessionsavslutet verifieras enligt specifikationen för den firmwareversion som används:
unset SW_TOKEN SW_USER LOGIN_RESPONSE SW_PASSWORD
  1. Kontrollera: Kontrollera skalhistorik, temporära filer och jobbloggar efter oavsiktligt exponerade hemligheter. Betrakta en exponerad token som komprometterad, avsluta sessionen och skicka inga fler anrop.

Sophos Fusion Switch Management API på tenantnivå

Det här avsnittet använder inte https://<Switch-IP-address>/api/.... Fusion API autentiserar en service principal mot den regionala Sophos Fusion-värden (tidigare Sophos Central) och arbetar i angiven tenant. Lokala People-konton, rollerna Admin/User, lokala sessionstoken och enhetens Swagger-schema gäller inte här.

Förutsättningar, roller och autentiseringsuppgifter

Switchen måste vara registrerad i rätt tenant och hanteras av Sophos Fusion. Det körbara flödet nedan gäller endast direkta API-autentiseringsuppgifter för denna tenant (client_id och client_secret). Endast en Super Admin för den direkta tenanten kan skapa dem under Global Settings > Access Control > API Credentials. Den tilldelade rollen för service principal måste medge den läs- och skrivåtkomst som krävs. Autentiseringsuppgifter för Partner eller Enterprise får inte användas med dessa skalexempel. För sådana autentiseringsuppgifter ska du först följa det separata flödet för val av tenant i Hantera Sophos Fusion API Credentials säkert och sedan återgå till det här flödet med autentiseringsuppgifter som har utfärdats och verifierats specifikt för den valda direkta tenanten.

Förvara klienthemligheten och JWT-token i ett hemlighetsvalv, aldrig i skript, ärenden, skalhistorik eller CI-utdata. Du behöver curl, jq, Bash, ett godkänt ändringsfönster samt dokumenterat tenant-ID, region, aktuell lista, fullständig mållista och återställningsplan. Autentiseringsuppgifterna ersätter inte en licens eller Support Subscription.

Autentisera service principal och identifiera den regionala värden

Identitetsprovidern utfärdar en JWT-token via POST https://id.sophos.com/api/v2/oauth2/token. Med de direkta tenantautentiseringsuppgifter som krävs här returnerar GET https://api.central.sophos.com/whoami/v1 fälten id och apiHosts.dataRegion. Flödet avbryts om whoami inte returnerar en tenantidentitet. Skicka aldrig ett partner- eller organisations-ID som X-Tenant-ID. Gissa inte den regionala värden och kopiera den inte från en annan 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

Varje switchanrop kräver båda headerfälten Authorization: Bearer <token> och X-Tenant-ID: <tenant-id> samt den fullständigt identifierade värden <data-region>. De dokumenterade statuskoderna för lyckade anrop är 200 eller 201; de bevisar endast att anropet togs emot.

Läs och ersätt MAC-filter fullständigt och säkert

GET /switch/v1/settings/mac-filtering läser tenantens fullständiga blockeringslista. PUT /switch/v1/settings/mac-filtering lägger inte till poster: macAddresses måste innehålla hela mållistan och ersätter den befintliga listan. {"macAddresses":[]} tar bort samtliga blockeringar.

Exemplet lägger till en syntetisk, lokalt administrerad 02:-adress. Publicera inte en verklig klient-MAC-adress. Arbetsfilerna innehåller driftdata och måste skyddas.

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

Skriv först när hela diffen har godkänts. Från det att baslinjen för tasks hämtas tills det entydigt korrelerade task-ID:t har sparats får ingen annan ändring av macFilters pågå i tenanten:

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

Återläsning, avläsning av taskstatus och validering

En lyckad PUT bevisar inte att alla switchar har tillämpat policyn. Läs tillbaka inställningen exakt och anropa därefter GET /switch/v1/tasks. Tasks tas bort efter 30 dagar och utgör inte ett permanent revisionsarkiv. De dokumenterade filtren är type, pageSize och pageTotal. Eftersom flödet inte förutsätter någon ytterligare dokumenterad sidparameter behandlar det högst den första fullständiga sidan med 50 tasks och avbryter om pages.total > 1, i stället för att utan varning ignorera fler sidor.

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("flera matchande 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

Flödet korrelerar exakt en ny task med hjälp av CHANGE_STARTED_AT, type: "macFilters" och de task-ID:n som sparades före PUT-anropet. Därefter frågar det samlingen högst 30 gånger med tio sekunders intervall och väljer endast det sparade task-ID:t. Ett lyckat resultat kräver både en lyckad sammanlagd status och slutstatusen succeeded för varje post i switches[]. Tvetydighet, paginering, tidsgräns, fel och noSupportSubscription medför att flödet avbryts. PUT-anropet upprepas inte.

Hantera Fusion API-fel exakt

  • 401/403: Kontrollera JWT-tokenens giltighet, service principal, tenantkontexten och headerfälten. Lokala roller påverkar inte detta.
  • Fel tenant eller regional värd: Hämta ID och värd igen via whoami eller listan över hanterade tenants.
  • HTTP 200/201 utan effekt: Kontrollera återläsningen och motsvarande task. Fortsätt den begränsade avläsningen, men upprepa inte PUT-anropet utan kontroll.
  • noSupportSubscription: Korrigera Support Subscription och enhetsstatus i rätt tenant; ingen lokal genväg.
  • Kod 10905 – Duplicate MAC filter policy: Granska switches[].error, läs tillståndet igen och lös den dubblerade eller inaktuella begäran. Försök inte igen utan kontroll.
  • Kod 10906 – MAC filter list is exhausted: Avbryt och godkänn en mindre fullständig lista. Skicka aldrig en delmängd som ett tillägg.
  • Kod 10908 – MAC address already allowed in the static MAC table: Lös konflikten och bedöm säkerhetseffekten. Ta inte bort statiska tillåtelser utan granskning.

Vid fel ska HTTP-status, task-ID, switch-ID, status, error, message och code sparas tillsammans. Maskera känsliga uppgifter.

Gränser för återställning

En återställning är ytterligare ett fullständigt PUT-anrop med den sparade listan. Läs först om tillståndet och uteslut samtidiga ändringar. Genomför sedan samma återläsning och taskvalidering fram till slutstatus för varje switch.

# Säkerställ ett exklusivt ändringsfönster före den nya läsningen.
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("flera matchande återställnings-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 är endast en ögonblicksbild av inställningen, inte en fullständig säkerhetskopia av switchen. Om baslinjen saknas får en tom lista aldrig användas för återställning: den tar bort samtliga blockeringar. API:t återställer inte lokal CLI-/REST-konfiguration och häver inte Active Threat Response-isolering. Radera slutligen tokenvariablerna, skydda eller radera filerna på ett säkert sätt och dokumentera taskresultatet.

Felsök utifrån symptom

TLS eller certifikatfel

  • Kontrollera hanteringsnamn, IP-adress, giltighet, certifikatkedja och systemtid.
  • Ange korrekt CA-certifikat med --cacert eller ersätt enhetscertifikatet via den avsedda hanteringsprocessen.
  • Använd inte -k som en permanent lösning. Alternativet krypterar transporten men autentiserar inte switchen.
  • Om certifikatet eller SSH-värdnyckeln har ändrats ska du först bekräfta att du verkligen ansluter till den avsedda switchen.

Anslutningen avvisas, tidsgränsen överskrids eller ingen rutt finns

  • Kontrollera hanterings-IP, hanterings-VLAN, routning, ACL och att tjänsten är aktiverad.
  • Testa från en behörig värd i det avsedda hanteringsnätverket.
  • Kringgå inte problemet genom att öppna tjänsten för alla nätverk eller internet.
  • Om en ändring som du just har gjort har brutit åtkomsten ska du använda den oberoende hanteringsvägen och den förberedda återställningen.

Inloggningen misslyckas

  • Kontrollera att ett lokalt switchkonto används, inte ett Sophos Fusion-konto.
  • Kontrollera användarnamn, lösenordskrav, kontostatus och lokal roll.
  • Gör inte upprepade automatiska gissningar. Det kan utlösa kontolåsning och dölja grundorsaken.
  • För standardkontot admin noterar du att lösenordet endast ändras av admin själv eller Sophos Fusion.

HTTP 401 eller 403

  • Vid 401 ska du kontrollera om token eller sessionen har löpt ut och därefter logga in på nytt.
  • Vid 403 ska du kontrollera den lokala rollen och behörigheten för åtgärden. Höj inte behörigheterna generellt.
  • En ny token är endast en av kontrollerna. Bevara felet, svaret och firmwarestatusen på ett säkert sätt, kontrollera den publicerade API-hjälpen och jämför målenhetens modell och firmwareversion.

HTTP 400, 404 eller 405

  • Jämför sökväg, metod, headerfält och JSON med den publicerade API-hjälpen och validera dem mot målenhetens modell och firmwareversion.
  • Kontrollera skiftläget och prefixet /api.
  • 404 eller 405 kan tyda på att en endpoint saknas eller är definierad på ett annat sätt i den aktuella firmwareversionen. Felsök inte genom att prova liknande skrivåtgärder.

HTTP-fel trots svar eller ett errCode som inte är 0

  • Spara HTTP-statusen och svarskroppen tillsammans.
  • Dokumentera message, maskera interna uppgifter innan informationen delas och upprepa inte en identisk ändring utan kontroll.
  • Om det är oklart huruvida en ändring har genomförts delvis ska du först fastställa det faktiska tillståndet med GET, CLI-utmatning och ett funktionstest.

CLI-kommandot som saknas eller avvisas

  • Kontrollera med ? om kommandot finns i det aktuella läget.
  • Slutför med TAB den syntax som enheten erbjuder.
  • Kontrollera den lokala rollen, kommandoläget, modellen och firmwareversionen.
  • Använd inte ett kommando från en annan firmwareversion bara för att det låter likartat.

Återställning och avslutning av sessionen

Ett rent GET /api/ports-test ändrar ingen konfiguration och kräver ingen teknisk återställning. API-inloggningen skapar dock en session. Avsluta den och ta bort de lokala variablerna enligt tokenlivscykeln.

Vid en konfigurationsändring måste återställningen definieras i förväg:

  1. Exportera det faktiska tillståndet och de berörda objekten eller dokumentera dem med läsåtgärder.
  2. Förbered den exakta omvända åtgärden utifrån den publicerade API-hjälpen och valideringen för den firmwareversion som används, eller utifrån CLI-hjälpen på målenheten.
  3. Definiera kriterier för omedelbart avbrott, exempelvis förlust av hantering, upplänk, VLAN-åtkomst eller PoE-försörjning.
  4. Vid fel ska du inte försöka göra ytterligare optimeringar, utan återställa det tidigare värdet via den väg som fortfarande fungerar.
  5. Kontrollera därefter hanteringsåtkomst, portstatus, upplänkar och berörda tjänster igen.
  6. Om den normala vägen förloras ska du återställa via den tidigare verifierade, oberoende hanteringsvägen, eventuellt den modellberoende konsolåtkomsten. En fabriksåterställning är inte en normal återställningsmetod eftersom den raderar konfigurationen.

För en switch som hanteras i Sophos Fusion räcker inte en lokal återställning. Kontrollera det auktoritativa måltillståndet i Sophos Fusion och inför den godkända nödändringen korrekt där eller ta bort den lokala ändringen helt. Gör inte motstridiga konfigurationsändringar via lokala och centrala kanaler.

Avslutningsvis ska du:

  • lämna en CLI-utmatning med Q och använda det exit-/logout-kommando som visas på enheten vid prompten;
  • Stäng API-sessionen med den dokumenterade PATCH /api/system/logout;
  • ta bort lokala token- och lösenordsvariabler med unset;
  • kontrollera att inga tillfälliga filer eller felloggar innehåller hemligheter;
  • dokumentera resultat, firmwareversion, använd administrationsväg, verifiering och eventuell återställning i ärendet.

Säkerhetshärdning

  • Använd ett dedikerat hanterings-VLAN med ACL:er som begränsar åtkomsten till ett fåtal administrationsvärdar och nödvändiga protokoll.
  • Aktivera HTTPS och SSH endast vid behov. Inaktivera osäkra eller oanvända hanteringstjänster.
  • Använd betrodda certifikat och verifierade SSH-värdnycklar.
  • Använd personliga lokala konton: User för ren läsåtkomst och Admin endast för godkända ändringar.
  • Byt ut standardlösenord omedelbart; undvik vanliga lösenord och rotera efter personal eller tjänsteleverantörsändringar.
  • Håll API-hemligheter borta från källkod, .env-filer, skalhistorik, processargument och CI-utdata.
  • Kör aldrig API-klienter med omfattande headerfelsökning när en Authorization-header är inställd.
  • Håll sessionerna korta, använd en ny token per session och ta därefter bort variablerna.
  • Håll konfigurationssäkerhetskopior skyddade och återställningsbara utanför switchen.
  • Korrelera lokala loggar, centrala händelser och ändringsärenden tidsmässigt. Kontrollera switchens tid.
  • Granska regelbundet lokala konton, hanterings-ACL:er, certifikat, SSH-nycklar och automatiseringsåtkomster på nytt.

Variationer mellan firmware och modeller

Den statiska REST API-sidan dokumenterar inloggningssökvägen /api/system/login, lästestet /api/ports och Authorization-headern. Den publicerade API-hjälpen dokumenterar även utloggningssökvägen /api/system/logout. Dessa centrala resurser ger exempel och vägledning, men inte ett schema som gäller generellt för alla enheter. Det specifika Swagger-/OpenAPI-schemat genereras av målswitchen som körs och motsvarar dess modell och firmwareversion. De publicerade CLI-dokumenten belägger de CLI-hjälpmedel som nämns ovan, men garanterar inte heller att alla andra kommandon är identiska i varje firmwareversion.

Gör därför följande före produktionssättning för varje modell och firmwareversion:

  • dokumentera den exakta firmwareversionen och hårdvarumodellen;
  • Kontrollera CLI-läge och syntax med ? och TAB;
  • kontrollera Swagger-/OpenAPI-schemat för de metoder, sökvägar och scheman som målenhetens aktiva firmwareversion tillhandahåller;
  • testa först inloggningen och GET /api/ports i en kontrollerad session;
  • validera all skrivande automatisering mot exakt detta målschema och dessutom i en icke-produktiv eller tydligt begränsad miljö;
  • testa efter firmwareuppdateringar på nytt inloggning, certifikatverifiering, svarsschema, tokenhantering och alla endpoints som används;
  • anpassa inte skriptet vid avvikelser förrän den nya semantiken och återställningsmetoden är förstådda.

Slutrevision

  • Rätt modell, firmwareversion och hanterings-IP har bekräftats.
  • Det auktoritativa systemet – Sophos Fusion eller lokal hantering – har dokumenterats.
  • Ett lokalt User- eller Admin-konto som motsvarar uppgiften har använts.
  • TLS-certifikatet eller SSH-värdnyckeln har verifierats. Inget permanent osäkert alternativ har använts.
  • Token har endast använts för sin session och aldrig exponerats.
  • HTTP-status, errCode, message och funktionstillstånd har kontrollerats.
  • För ändringar finns aktuellt tillstånd, återställningsplan och oberoende åtkomst tillgängliga.
  • Resultatet har verifierats via GET, CLI-utmatning och eventuella nödvändiga funktionstest.
  • Sessionen har stängts, variablerna har raderats och loggarna har kontrollerats efter hemligheter.
  • Det lokala undantaget har stämts av mot Sophos Fusion och avslutats i ärendet.