Gestire in sicurezza le API Credential di Sophos Central
Sophos Central può essere automatizzato tramite API e collegato a piattaforme SIEM, RMM, di reporting o assicurative. Non si usano account amministratore personali, ma API Credential dedicate formate da Client ID e Client Secret.
Queste credenziali sono identità macchina. Chi possiede il secret può eseguire tutte le azioni API consentite dal ruolo Service Principal assegnato. Il secret va quindi trattato come una password privilegiata e non deve finire in script, ticket, e-mail o repository Git.
Distinguere API Credentials e Integration Credential Manager
In Global Settings > Access Control esistono due aree dal nome simile:
| Area | Compito |
|---|---|
| API Credentials | identità tecnica con cui un’applicazione richiama le API Sophos Central |
| Integration Credential Manager | credenziali di prodotti terzi usate da Sophos per integrazioni come Data Ingestion o Response Actions |
Per uno script proprio, una query SIEM o un client API si creano API Credential. Le credenziali di un prodotto terzo che Sophos Central deve usare appartengono invece all’Integration Credential Manager.
Non tutte le automazioni richiedono API Credential generiche: utenti e gruppi si sincronizzano tramite un servizio di directory, mentre il software può essere distribuito con uno script di installazione eseguito localmente su ciascun dispositivo. Per AD Sync si crea un’identità API solo se il flusso di sincronizzazione previsto lo richiede, assegnandole esclusivamente il ruolo Service Principal Directory Sync.
Prerequisiti e responsabilità
Solo un Super Admin può creare e gestire API Credential. L’applicazione si autentica con il proprio Client ID e Client Secret, non con l’account personale dell’amministratore.
Prima della creazione si documentano scopo, proprietario, sistema di destinazione, ruolo necessario, scadenza e contatto di emergenza. Si usa una Credential distinta per ogni applicazione e ambiente. Un secret condiviso tra script di backup, SIEM e fornitori esterni impedisce un blocco mirato e complica l’analisi delle cause.
Scegliere il ruolo Service Principal corretto
Sophos offre diversi ruoli:
- Service Principal Read-Only legge i dati del tenant, ma non può modificarli né eseguire query Live Discover.
- Service Principal Management può leggere, creare, modificare ed eliminare utenti e gruppi, leggere e gestire alert, leggere Endpoint ed eseguire azioni come uno scan, oltre a visualizzare e modificare impostazioni globali Endpoint Protection. Gestisce anche amministratori, ruoli e Security Policy, ma non accede alle query Live Discover.
- Service Principal Forensics crea, visualizza, esegue ed elimina query Live Discover.
- Service Principal Directory Sync è esclusivamente per la sincronizzazione Active Directory e non può svolgere altre attività API.
- Service Principal Firewall limita l’identità alla gestione Firewall e vieta attività API Central esterne a tale ambito.
- Service Principal Audit Log consente ad applicazioni esterne, strumenti SIEM e script di integrazione di recuperare gli eventi dell’Audit Log con accesso alle query in sola lettura.
- Service Principal Super Admin dispone di ampi diritti di lettura, scrittura, eliminazione e query.
La scelta parte sempre dal ruolo più ristretto. Un’integrazione di reporting o assicurazione cyber riceve Read-Only. AD Sync usa il ruolo dedicato. Super Admin si usa solo se gli endpoint API documentati richiedono davvero ampi diritti di scrittura e nessun ruolo più ristretto funziona.
Creare una Credential
Il percorso è Global Settings > Access Control > API Credentials. Al primo accesso occorre accettare le condizioni di utilizzo.
- Aprire Add Credential.
- Inserire un nome univoco e una descrizione con applicazione, ambiente e proprietario.
- Selezionare il ruolo Service Principal minimo necessario.
- Creare la Credential e acquisire subito Client ID e Client Secret.
- Conservare il secret in un secret store aziendale e cancellarlo dagli appunti temporanei.
Il Client Secret viene mostrato una sola volta e non può essere visualizzato di nuovo. Se viene perso, non si ripristina quello esistente: si crea una nuova Credential e si elimina la precedente dopo una migrazione riuscita.
Contratto API, autenticazione e regione
Il contratto comune usa POST https://id.sophos.com/api/v2/oauth2/token per OAuth2 e GET https://api.central.sophos.com/whoami/v1 per identificare la Credential. Le Credential Partner ed Enterprise leggono poi rispettivamente GET https://api.central.sophos.com/partner/v1/tenants e GET https://api.central.sophos.com/organization/v1/tenants. Per le API di prodotto usare solo l’host HTTPS restituito in apiHosts.dataRegion o apiHost; non dedurre mai la regione.
Richiedere un token di accesso in modo sicuro
read -r -p "Client ID: " SOPHOS_CLIENT_ID
read -r -s -p "Client Secret: " SOPHOS_CLIENT_SECRET; printf '\n'
TOKEN_RESPONSE=$(printf 'grant_type=client_credentials&client_id=%s&client_secret=%s&scope=token' \
"$(jq -rn --arg v "$SOPHOS_CLIENT_ID" '$v|@uri')" \
"$(jq -rn --arg v "$SOPHOS_CLIENT_SECRET" '$v|@uri')" |
curl --fail-with-body --silent --show-error --request POST \
--header 'Content-Type: application/x-www-form-urlencoded' --data-binary @- \
https://id.sophos.com/api/v2/oauth2/token)
unset SOPHOS_CLIENT_SECRET
SOPHOS_ACCESS_TOKEN=$(jq -er '
select(.token_type == "bearer") |
select((.expires_in | type) == "number" and .expires_in > 0) |
.access_token | select(type == "string" and length > 0)
' <<<"$TOKEN_RESPONSE")
unset TOKEN_RESPONSE
WHOAMI=$(printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" |
curl --fail-with-body --silent --show-error --config - https://api.central.sophos.com/whoami/v1
)
Una risposta valida contiene access_token, token_type: "bearer" e un expires_in numerico positivo; può contenere anche refresh_token, errorCode, message e trackingId. Non registrarla e richiedere un nuovo token alla scadenza.
Valutare whoami
Il contratto di risposta whoami per un tenant e la risoluzione degli altri tipi sono:
{
"id": "<tenant-uuid>",
"idType": "tenant",
"apiHosts": {
"global": "https://api.central.sophos.com",
"dataRegion": "https://api-us03.central.sophos.com"
}
}
SOPHOS_ID=$(jq -er '.id|select(type=="string" and length>0)' <<<"$WHOAMI")
SOPHOS_ID_TYPE=$(jq -er '.idType|select(.=="tenant" or .=="partner" or .=="organization")' <<<"$WHOAMI")
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}$'
if [[ "$SOPHOS_ID_TYPE" == tenant ]]; then
SOPHOS_TENANT_ID=$(jq -er --arg re "$UUID_RE" '.id|select(type=="string" and test($re))' <<<"$WHOAMI")
SOPHOS_API_HOST=$(jq -er '.apiHosts.dataRegion|select(type=="string" and test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$"))' <<<"$WHOAMI")
else
case "$SOPHOS_ID_TYPE" in
partner) TENANTS_URL='https://api.central.sophos.com/partner/v1/tenants'; CONTEXT_HEADER="X-Partner-ID: ${SOPHOS_ID}" ;;
organization) TENANTS_URL='https://api.central.sophos.com/organization/v1/tenants'; CONTEXT_HEADER="X-Organization-ID: ${SOPHOS_ID}" ;;
*) exit 1 ;;
esac
TENANTS_FILE=$(mktemp); printf '[]\n' >"$TENANTS_FILE"; page=1; max_pages=1000; expected_pages=
while (( page <= max_pages )); do
PAGE_RESPONSE=$(printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" | curl --fail-with-body --silent --show-error --get --config - --header "$CONTEXT_HEADER" --data-urlencode "page=${page}" --data-urlencode 'pageSize=100' --data-urlencode 'pageTotal=true' "$TENANTS_URL")
page_total=$(jq -er 'select((.items|type)=="array")|.pages.total|select(type=="number" and floor==. and .>=1 and .<=1000)' <<<"$PAGE_RESPONSE")
if [[ -z "$expected_pages" ]]; then expected_pages=$page_total; fi; [[ "$page_total" == "$expected_pages" ]] || exit 1
jq -e --argjson page "$PAGE_RESPONSE" '.+$page.items' "$TENANTS_FILE" >"${TENANTS_FILE}.new"; mv "${TENANTS_FILE}.new" "$TENANTS_FILE"
(( page >= expected_pages )) && break; ((page++))
done
(( page == expected_pages )) || exit 1
read -r -p 'UUID del tenant di destinazione dalla mappatura approvata: ' TARGET_TENANT_ID
TARGET_TENANT=$(jq -cer --arg id "$TARGET_TENANT_ID" --arg re "$UUID_RE" '[.[]|select((.id|type)=="string" and (.id|test($re)) and (.id|ascii_downcase)==($id|ascii_downcase))|select((.apiHost|type)=="string" and (.apiHost|test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$")))]|select(length==1)|.[0]' "$TENANTS_FILE")
SOPHOS_TENANT_ID=$(jq -r .id <<<"$TARGET_TENANT"); SOPHOS_API_HOST=$(jq -r .apiHost <<<"$TARGET_TENANT"); rm -f "$TENANTS_FILE"
fi
export SOPHOS_TENANT_ID SOPHOS_API_HOST
Ogni richiesta di prodotto del tenant associa esattamente Authorization: Bearer <token-di-accesso>, X-Tenant-ID: <uuid-tenant> e l’apiHost regionale dello stesso tenant. L’host globale non sostituisce un’API di prodotto regionale.
whoami restituisce id, idType e apiHosts. Per Partner/Enterprise l’ID non è un Tenant ID: il ciclo richiede header di autorizzazione e contesto, è limitato a 1.000 pagine, segue il valore reale pages.total ed esporta solo una corrispondenza UUID univoca con apiHost regionale valido.
Validazione e ripristino controllato
Prima di scrivere verificare idType, UUID, formato HTTPS dell’host, JSON, paginazione e oggetti attesi con una lettura innocua. scope=token non concede diritti funzionali: contano anche ruolo, accesso tenant, licenza e operazione. Per 400 controllare il form; 401 Credential/scadenza/secret; 403 ruolo e accesso; 404 host/versione/percorso; 429 Retry-After e Backoff; 5xx Request ID o trackingId e tentativi limitati. Non inviare mai Token o secret al supporto.
Se tenant o host sono errati, interrompere le scritture e isolare i dati ricevuti. Eliminare la Credential blocca chiamate future ma non annulla modifiche: usare il rollback specifico preparato e rimuovere dalla sessione token, ID, tenant, host e WHOAMI con unset.
unset SOPHOS_ACCESS_TOKEN SOPHOS_CLIENT_ID SOPHOS_ID SOPHOS_ID_TYPE
unset SOPHOS_TENANT_ID SOPHOS_API_HOST WHOAMI
Risolvere i problemi dell’accesso API comune
Per 400 controllare form e campi; 401 Credential, scadenza, secret, token e sintassi Bearer; 403 ruolo, accesso tenant e operazione; 404 host globale/regionale, versione e percorso; 429 rispettare Retry-After e riprovare entro un limite con backoff e jitter; 5xx conservare Request ID o trackingId e riprovare entro un limite. Con idType inatteso o apiHost mancante non costruire header tenant. Non inviare mai token o secret al supporto.
Testare l’autenticazione in modo controllato
Il primo test non deve essere un’azione di scrittura in produzione. Si ottiene innanzitutto un OAuth Access Token dall’endpoint Sophos Identity. L’endpoint whoami restituisce poi Tenant ID, API Host e tipo di account. Solo allora si esegue una chiamata di lettura innocua contro l’API Host fornito per il tenant.
L’API Host non va copiato da un esempio. Sophos utilizza più regioni dati e occorre quindi usare l’URL restituito da whoami. Anche Tenant ID e Organization ID non sono intercambiabili.
Il test documenta almeno:
- l’autenticazione con la nuova identità funziona,
- viene restituito il tenant previsto,
- le operazioni di lettura autorizzate funzionano,
- un’operazione non consentita viene rifiutata con
403 Forbidden, - il sistema di destinazione registra il test in modo tracciabile senza memorizzare il Client Secret.
Gestire scadenza e rotazione
Sophos non invia avvisi quando una API Credential scade. Dopo la scadenza non può più autenticarsi e viene rimossa automaticamente da Central. Il monitoraggio deve quindi avvenire fuori da Central.
Una rotazione corretta usa una breve sovrapposizione:
- Creare una nuova Credential con ruolo identico o più ristretto.
- Configurare l’applicazione con Client ID e secret nuovi.
- Testare autenticazione e funzione operativa.
- Eliminare la vecchia Credential.
- Verificare la modifica nel registro dei secret e nella documentazione operativa.
La vecchia Credential non va lasciata attiva per mesi come precauzione. Se un’applicazione supporta un solo set di secret, si pianifica una finestra di manutenzione.
Sostituire i vecchi token SIEM API
API Token Management è la precedente autenticazione della SIEM Integration API. Sophos non emette più nuovi token e non estende la durata di quelli esistenti, che funzionano solo fino alla scadenza.
Un’integrazione che li usa non va lasciata invariata fino all’ultimo giorno. Si inventariano token, sistema di destinazione, scadenza ed endpoint usati, si crea una API Credential appropriata, si migra l’applicazione e si verifica l’intero flusso dati. Il vecchio token viene rimosso solo dopo un controllo parallelo riuscito.
Il passaggio da token legacy ad API Credential non è una semplice rinomina. L’integrazione deve supportare autenticazione OAuth, whoami, host regionale e modello dei ruoli. Un connettore SIEM si configura quindi secondo la documentazione attuale del produttore, non con un vecchio esempio di token.
Fornitori esterni e accesso di terzi
Per un soggetto esterno si crea un’identità Service Principal Read-Only dedicata, se bastano diritti di lettura. Client ID e secret vengono trasferiti su canali cifrati separati. L’accesso riceve una data di fine e viene eliminato alla conclusione del progetto.
Via API, questo accesso può leggere soprattutto Alerts ed Events, risultati dell’Account Health Check, dettagli dei dispositivi e configurazioni delle policy. Read-Only impedisce aggiunte, modifiche ed eliminazioni in Central, ma non limita automaticamente quali dati leggibili vengano prelevati o conservati dalla piattaforma terza. Prima dell’autorizzazione si chiariscono contrattualmente ambito, scopo, luogo di archiviazione, conservazione ed eliminazione dei dati.
La creazione segue Global Settings > Access Control > API Credentials > Add Credential. Al primo accesso si accettano condizioni d’uso e privacy, si sceglie Service Principal Read-Only e si acquisiscono in sicurezza Client ID e Client Secret visibile una sola volta. Il trasferimento avviene tramite un canale cifrato approvato, come il portale HTTPS del fornitore, non via e-mail o ticket.
L’API Host non viene copiato da una tabella regionale statica. L’applicazione usa whoami per determinare l’host valido proprio per quel tenant. La documentazione resta così corretta anche se Sophos modifica regioni o endpoint. Quando il fornitore non necessita più dell’accesso, si elimina la Credential revocando immediatamente l’autorizzazione API.
Non sono accettabili l’esportazione dell’account Super Admin personale, un’identità API condivisa tra più clienti o un secret nel ticket di supporto. Il fornitore deve inoltre dichiarare dove conserva il secret, come lo protegge e quando lo elimina.
Individuare gli errori
401 Unauthorized
Di norma Client ID, secret, endpoint token o richiesta OAuth sono errati. Anche una Credential scaduta e già rimossa causa questo errore. Verificare prima che esista ancora in Central e che l’applicazione usi davvero il set di secret più recente.
403 Forbidden
L’autenticazione è riuscita, ma il ruolo non consente l’azione. Invece di assegnare subito Super Admin, si associa l’endpoint API necessario al ruolo Service Principal appropriato.
Token corretto, regione dati errata
L’Access Token non determina da solo l’API Host operativo. L’applicazione deve usare l’host regionale restituito da whoami. Un host fisso di un’altra regione causa errori o query contro il confine di piattaforma errato.
L’integrazione si interrompe senza preavviso
Se Central non mostra un alert aperto, si verificano scadenza, ultima chiamata API riuscita e versione del secret nel sistema di destinazione. Il monitoraggio della scadenza appartiene al sistema esterno.
Controllo periodico
Almeno ogni trimestre si verificano nome, proprietario, ruolo, ultimo utilizzo, scadenza e destinazione di ogni Credential. Le identità non attribuibili o inutilizzate vengono eliminate. In caso di sospetta fuoriuscita del secret, la Credential interessata viene eliminata immediatamente e sostituita con una nuova. In seguito si esaminano i log del sistema di destinazione e dell’integrazione alla ricerca di chiamate API insolite.
I diritti degli amministratori personali vengono controllati separatamente secondo Assegnare correttamente i ruoli amministrativi di Sophos Central. Le API Credential non sostituiscono né MFA né un accesso amministrativo personale tracciabile.