Nel mondo Fortinet convivono due stili di API, e il blueprint dell’esame ti chiede esplicitamente di confrontarli. Vale la pena farlo bene, perché la domanda più probabile non è «che cos’è JSON-RPC» ma «quale prodotto parla quale lingua».

JSON-RPC in due parole: il verbo sta nel corpo

JSON-RPC è un protocollo di chiamata a procedura remota codificato in JSON. La richiesta non descrive una risorsa: nomina una procedura, le passa dei parametri e porta un identificatore che riaggancia la risposta alla domanda. Il trasporto è quasi un dettaglio, perché tutto ciò che conta viaggia nel corpo del messaggio: nome del metodo, parametri, esito. Anche gli errori tornano lì dentro, non nello stato del trasporto.

È l’API di FortiManager: la sua JSON API è basata su JSON-RPC e serve a configurare e monitorare l’appliance — gestione dispositivi, policy, oggetti, esecuzione di task — con richieste JSON strutturate su HTTPS.

Il confronto, riga per riga

Cosa nomini. L’API di FortiSOAR è REST: nomina risorse. Una collezione e un record hanno un percorso, e l’azione la dichiara il metodo HTTP. JSON-RPC nomina procedure: il percorso è quasi irrilevante, il metodo HTTP pure, perché l’operazione è scritta nel payload.

Dove sta l’operazione. In REST leggere e cancellare lo stesso alert sono la stessa URL con due verbi diversi. In JSON-RPC sono due corpi diversi sullo stesso canale. Conseguenza pratica: sui log di un proxy, il traffico REST è leggibile a colpo d’occhio, quello JSON-RPC no.

Se l’API si racconta da sola. L’API di FortiSOAR è JSON-LD combinato con la specifica Hydra: partendo dalla radice, un client scopre struttura e contesto senza conoscenza pregressa, perché i collegamenti sono incorporati nelle risposte. JSON-RPC non ha nulla del genere: l’elenco dei metodi lo dà solo la documentazione. Sottigliezza che vale il punto: nemmeno tutto FortiSOAR è discoverable, perché le rotte create con un Custom API Endpoint Trigger sono escluse apposta dalla definizione JSON-LD/Hydra.

Come dice che è andata male. REST usa i codici HTTP, e in FortiSOAR li usa con precisione: 201 alla creazione, 204 senza corpo alla cancellazione, 207 quando un’operazione massiva riesce solo in parte. In JSON-RPC lo stato del trasporto può essere 200 anche quando la procedura è fallita, e devi guardare il payload.

Come ti identifichi. FortiSOAR accetta token JWT, HMAC con coppia di chiavi, oppure API key nell’header Authorization.

L’errore che ti costa il punto intero

Detto in modo che non si dimentichi: JSON-RPC non è l’API di FortiSOAR. L’API di FortiSOAR è REST, in formato JSON-LD/Hydra, con radice /api/3. JSON-RPC è l’API di FortiManager. Sono due prodotti diversi con due modelli diversi, e una risposta che attribuisce JSON-RPC a FortiSOAR è sbagliata anche se tutto il resto della frase è corretto. Poiché l’esame non assegna punteggio parziale, quel singolo scambio annulla l’intera domanda.

Costruire un connettore: i passi del wizard

Il percorso guidato parte da Content Hub o da Automation e poi Connectors, scheda Create, quindi Create e New Connector.

Nella schermata About Connector si danno nome, loghi, versione nel formato x.y.z, publisher, categoria e un template, che precarica azioni e campi tipici della famiglia scelta (Threat Intel, Ticketing e simili). Tre dettagli decidono se il connettore nascerà sano: l’API Identifier è la variabile con cui il codice referenzia il connettore, deve essere alfanumerico, non può iniziare con un numero, non può coincidere col nome di un connettore già in Content Hub e non è più modificabile una volta impostato; anche nome e versione, una volta salvati, non si cambiano; e nel publisher non si scrive «Fortinet» — lasciandolo vuoto diventa «Community».

Nella schermata Configuration si costruiscono i campi che l’utente vedrà. Trappola secca: non puoi creare campi chiamati name o default, sono parole riservate.

Nella schermata Actions si definiscono le azioni, ciascuna con i suoi metadati — titolo, categoria fra Investigation, Remediation, Utilities e simili, descrizione — e i suoi parametri di input. Un’azione senza input è legittima.

Chiudendo con Save & Create Connector si arriva al Summary e da lì al code editor, dove si testa e si pubblica. Due pulsanti fanno il lavoro vero: Test Configuration esegue l’health check e restituisce Available o Disconnected, Test Actions esegue una singola azione con i parametri che gli passi. Solo Publish Connector rende il connettore disponibile agli altri utenti: prima resta in stato Draft.

Il connettore scritto a mano

La struttura minima è una cartella col nome del connettore.

connectorname/
  info.json
  connector.py
  images/
  playbooks/playbooks.json
  requirements.txt
  packages/

Il vincolo che fa fallire l’import in silenzio: il valore di name dentro info.json deve coincidere esattamente col nome della cartella. Il file connector.py estende la classe base Connector e implementa due funzioni, execute e check_health; per far fallire davvero un health check devi sollevare ConnectorError, importandola dal modulo del framework — restituire False non basta. Esistono anche funzioni facoltative agganciate al ciclo di vita della configurazione, come on_add_config e on_update_config.

Finito, si impacchetta in .tgz e si importa dalla scheda Manage. Ultimo dettaglio operativo: le modifiche ai file Python si riflettono da sole alla chiamata successiva, ma le modifiche a info.json richiedono un reimport del connettore da CLI. E la funzione dev_execute, che ricarica il codice a ogni esecuzione, va usata solo in sviluppo: è lenta, e va rimossa prima di pubblicare.