\n\n\n\n Agent Sandboxing: Un Tutorial Pratico per Sviluppo Sicuro dell'AI - BotSec \n

Agent Sandboxing: Un Tutorial Pratico per Sviluppo Sicuro dell’AI

📖 14 min read2,749 wordsUpdated Apr 4, 2026

Introduzione al Sandboxing degli Agenti

Con il crescere della sofisticatezza e dell’autonomia degli agenti di intelligenza artificiale, la necessità di solidi sistemi di sicurezza diventa fondamentale. Una delle tecniche più critiche per garantire un funzionamento sicuro degli agenti AI, in particolare quelli che interagiscono con sistemi esterni o dati sensibili, è il sandboxing degli agenti. Il sandboxing fornisce un ambiente isolato in cui un agente può eseguire i propri compiti senza rappresentare una minaccia per il sistema host o per altre risorse della rete. Questo tutorial esplorerà gli aspetti pratici del sandboxing degli agenti, offrendo esempi concreti e indicazioni passo a passo per implementare ambienti sicuri per l’AI.

Il principio fondamentale alla base del sandboxing è il principio del minimo privilegio: un agente dovrebbe avere accesso solo alle risorse strettamente necessarie per il suo funzionamento e nient’altro. Questo minimizza la superficie di attacco e limita i potenziali danni che un agente errante o malevolo potrebbe infliggere. Che tu stia sviluppando agenti per transazioni finanziarie, analisi dei dati o interazione con dispositivi IoT, comprendere e implementare il sandboxing non è più un’opzione: è essenziale.

Perché il Sandboxing è Cruciale per gli Agenti AI

  • Sicurezza contro Agenti Malevoli: Un agente, se compromesso o progettato con intento malevolo, potrebbe tentare di accedere a file sensibili, lanciare attacchi alla rete o sfruttare vulnerabilità di sistema. Il sandboxing previene queste azioni.
  • Protezione contro Bug ed Errori: Anche un agente ben intenzionato può avere bug che portano a effetti collaterali indesiderati, come un consumo eccessivo di risorse o corruzione dei dati. Il sandboxing contiene questi errori.
  • Gestione delle Risorse: I sandbox possono imporre limiti sull’uso di CPU, memoria e rete, impedendo a un agente fuori controllo di monopolizzare le risorse di sistema.
  • Privacy e Isolamento dei Dati: Per agenti che gestiscono informazioni sensibili, il sandboxing garantisce che i dati elaborati da un agente non possano essere accessibili o trapelati da un altro, né dal sistema host stesso senza esplicita autorizzazione.
  • Ambiente Controllato per Sperimentazioni: Gli sviluppatori possono testare in sicurezza nuovi comportamenti degli agenti, algoritmi o interazioni con API esterne in un ambiente controllato senza rischiare il sistema di produzione.

Concetti Fondamentali del Sandboxing

Prima di esplorare esempi pratici, comprendiamo i meccanismi fondamentali utilizzati per il sandboxing:

  • Isolamento dei Processi: Eseguire l’agente in un processo separato con permessi limitati.
  • Virtualizzazione: Utilizzare macchine virtuali (VM) o container (ad es. Docker) per fornire un ambiente operativo completamente isolato.
  • Filtraggio delle Chiamate di Sistema (Seccomp): Limitare l’insieme delle chiamate di sistema che un agente può fare al kernel, limitando così la sua interazione con l’OS sottostante.
  • Isolamento della Rete: Controllare le connessioni di rete in entrata e in uscita, spesso utilizzando firewall o reti virtuali.
  • Permessi del File System: Fornire accesso in lettura/scrittura solo a directory e file specifici, spesso con accesso di sola lettura alla maggior parte del sistema.
  • Limiti delle Risorse (cgroups): Limitare l’uso di CPU, memoria, I/O e larghezza di banda di rete.

Esempio Pratico 1: Sandboxing di Base a Livello di Processo (Python)

Per agenti più semplici o quelli che richiedono un isolamento meno rigoroso, il sandboxing di base a livello di processo all’interno di un linguaggio di scripting come Python può essere un buon punto di partenza. Questo implica eseguire l’agente in un subprocesso con privilegi utente ridotti e gestire attentamente il suo ambiente.

Scenari: Un Agente Python che Elabora Codice Fornito dall’Utente

Immagina un agente progettato per eseguire piccoli frammenti di codice Python forniti dall’utente per l’analisi. Eseguire codice arbitrario è intrinsecamente pericoloso, quindi il sandboxing è cruciale.

Passi di Implementazione:

  1. Creare un Utente Dedicato a Basso Privilegio:
    Su Linux, crea un utente specificamente per eseguire i processi dell’agente. Questo utente dovrebbe avere permessi minimi.
    sudo adduser --system --no-create-home --shell /bin/false agent_sandbox_user
    Questo crea un utente di sistema senza directory home e senza shell di login, limitando severamente le sue capacità.
  2. Subprocesso Python con Cambio Utente:
    Utilizzeremo il modulo subprocess di Python per eseguire il codice dell’agente come `agent_sandbox_user`. Limiteremo anche il suo ambiente.

import subprocess
import os
import pwd # Per ottenere l'ID utente

def run_sandboxed_code(code_to_execute: str):
 # Ottieni l'UID dell'utente a basso privilegio
 try:
 user_info = pwd.getpwnam('agent_sandbox_user')
 uid = user_info.pw_uid
 gid = user_info.pw_gid # Spesso lo stesso dell'UID per utenti di sistema
 except KeyError:
 print("Errore: 'agent_sandbox_user' non trovato. Per favore, crealo prima.")
 return

 # Prepara il file di script dell'agente
 agent_script_path = '/tmp/agent_script.py'
 with open(agent_script_path, 'w') as f:
 f.write(code_to_execute)
 
 # Cambia i permessi affinché l'utente sandboxed possa leggerlo
 os.chmod(agent_script_path, 0o400) # Solo lettura per il proprietario, accesso negato per altri
 
 # Comando per eseguire lo script Python come utente sandboxed
 # Impostiamo anche esplicitamente un ambiente minimo per prevenire l'ereditarietà di variabili sensibili
 command = [
 'sudo', '-u', 'agent_sandbox_user',
 'python3', agent_script_path
 ]

 try:
 print(f"Esecuzione del codice sandboxed come utente {user_info.pw_name} (UID: {uid})...")
 # Usa preexec_fn per setuid/setgid prima di exec (più solido di sudo per alcuni scenari)
 # Tuttavia, per semplicità e compatibilità tra piattaforme (se sudo è disponibile), ci atteniamo a sudo qui.
 # Per un vero setuid/setgid da Python, è necessario os.setuid/os.setgid e una attenta rimozione dei privilegi.
 
 # Utilizzando subprocess.run con utente specifico (tramite sudo) e ambiente limitato
 result = subprocess.run(
 command,
 capture_output=True,
 text=True,
 check=True, # Solleva un'eccezione per codici di uscita non zero
 env={'PATH': '/usr/bin:/bin'}, # PATH minimo
 timeout=10 # Aggiungi un timeout per prevenire loop infiniti
 )
 print("Output:")
 print(result.stdout)
 if result.stderr:
 print("Errori:")
 print(result.stderr)

 except subprocess.CalledProcessError as e:
 print(f"Il processo sandboxed è fallito con codice di errore {e.returncode}:")
 print(f"Stdout: {e.stdout}")
 print(f"Stderr: {e.stderr}")
 except subprocess.TimeoutExpired:
 print("Il processo sandboxed ha impiegato troppo tempo.")
 except FileNotFoundError:
 print("Errore: comando 'python3' o 'sudo' non trovato.")
 finally:
 # Pulisci il file di script
 if os.path.exists(agent_script_path):
 os.remove(agent_script_path)


# --- Casi di Test ---

# 1. Codice sicuro
safe_code = """
print('Ciao dal sandbox!')
x = 10 + 20
print(f'Risultato: {x}')
"""
run_sandboxed_code(safe_code)

print("\n" + "-"*30 + "\n")

# 2. Tentativo di accesso a un file riservato (dovrebbe fallire)
restricted_access_code = """
import os
try:
 with open('/etc/shadow', 'r') as f:
 print(f.read())
except PermissionError:
 print('Accesso negato come previsto!')
except FileNotFoundError:
 print('File non trovato (anche previsto per un utente sandboxed)!')
"""
run_sandboxed_code(restricted_access_code)

print("\n" + "-"*30 + "\n")

# 3. Tentativo di creare un file in una directory riservata (dovrebbe fallire)
file_creation_code = """
import os
try:
 with open('/root/malicious.txt', 'w') as f:
 f.write('Contenuto malevolo!')
 print('File creato (inaspettato)!')
except PermissionError:
 print('Accesso negato per creare file in /root come previsto!')
except Exception as e:
 print(f'Si è verificato un errore: {e}')
"""
run_sandboxed_code(file_creation_code)

print("\n" + "-"*30 + "\n")

# 4. Tentativo di richiesta di rete (potrebbe riuscire o fallire a seconda della configurazione di rete per agent_sandbox_user)
# Per un vero sandbox, l'uscita di rete dovrebbe essere limitata a livello di firewall.
network_request_code = """
import requests
import sys

try:
 response = requests.get('http://www.google.com', timeout=5)
 print(f'Richiesta di rete riuscita! Stato: {response.status_code}')
except requests.exceptions.RequestException as e:
 print(f'La richiesta di rete è fallita come previsto (o a causa del timeout): {e}')
except Exception as e:
 print(f'Si è verificato un errore inaspettato durante la richiesta di rete: {e}')
"""
# Nota: Questo potrebbe ancora avere successo se agent_sandbox_user ha accesso alla rete. 
# Per un vero isolamento di rete, vedere l'esempio di Docker.
# run_sandboxed_code(network_request_code)

Limitazioni del Sandboxing a Livello di Processo:

  • Isolamento Incompleto: Condivide ancora il kernel con l’host. Un exploit sofisticato potrebbe potenzialmente evadere.
  • Gestione Manuale delle Risorse: Limitare CPU/memoria/rete è complesso e richiede spesso strumenti aggiuntivi (ad es. cgroups, regole del firewall).
  • Dipendenza dalla Piattaforma: La gestione degli utenti e la separazione dei privilegi variano significativamente tra i vari sistemi operativi.

Esempio Pratico 2: Sandboxing Basato su Container con Docker

Per un sandboxing più solido e portatile, i container come Docker sono lo standard del settore. Docker fornisce virtualizzazione a livello di OS, isolando processi, file system e reti in unità discrete. Questo è ideale per agenti di AI che potrebbero avere dipendenze complesse o richiedere un isolamento più forte.

Scenario: Un Agente AI che Esegue Elaborazione di Immagini

Considera un agente che riceve un’immagine come input, la elabora (ad es. applica filtri, riconosce oggetti) e restituisce un’immagine modificata o dei dati. Questo agente potrebbe aver bisogno di accesso a librerie di immagini (OpenCV, Pillow), ma non dovrebbe accedere al file system dell’host o a risorse di rete arbitrari.

Passi di Implementazione:

  1. Creare un Dockerfile: Definire l’ambiente per il tuo agente.
  2. Costruire l’Immagine Docker: Creare un’immagine riutilizzabile.
  3. Eseguire il Container con Restrizioni: Avviare l’agente con limiti di risorse specifici e isolamento della rete.

Dockerfile (Dockerfile):


# Usa un'immagine di base minimale per sicurezza e dimensioni
FROM python:3.9-slim-buster

# Imposta la directory di lavoro all'interno del container
WORKDIR /app

# Copia il file dei requisiti e installa le dipendenze
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copia il codice del tuo agente
COPY agent.py .

# Crea un utente non root per sicurezza
RUN useradd --create-home --shell /bin/bash agent_user
USER agent_user

# Definisci il comando per eseguire il tuo agente
CMD ["python", "agent.py"]

Codice dell’Agente (agent.py):


import sys
import os
# import requests # Decommenta per testare l'accesso alla rete
from PIL import Image # Esempio di libreria di elaborazione immagini

def process_image(input_image_path, output_image_path):
 try:
 with Image.open(input_image_path) as img:
 # Esempio: Converti in scala di grigi
 grayscale_img = img.convert('L')
 grayscale_img.save(output_image_path)
 print(f"Immagine elaborata con successo: {input_image_path} -> {output_image_path}")
 except FileNotFoundError:
 print(f"Errore: Immagine di input '{input_image_path}' non trovata.")
 except Exception as e:
 print(f"Errore durante l'elaborazione dell'immagine: {e}")

# Logica di esecuzione principale per l'agente
if __name__ == "__main__":
 print("Agente avviato nel container Docker.")
 print(f"Utente corrente: {os.geteuid()}")
 print(f"Directory di lavoro corrente: {os.getcwd()}")
 
 # Tentativo di leggere un file del sistema host (dovrebbe fallire)
 try:
 with open('/etc/shadow', 'r') as f:
 print(f"Accesso a /etc/shadow: {f.read()[:50]}...")
 except PermissionError:
 print("Accesso a /etc/shadow bloccato con successo.")
 except FileNotFoundError:
 print("File /etc/shadow non trovato (atteso in contenitore isolato).")
 
 # Esempio: Elaborare un'immagine se fornita
 if len(sys.argv) > 2:
 input_path = sys.argv[1]
 output_path = sys.argv[2]
 process_image(input_path, output_path)
 else:
 print("Uso: python agent.py  ")
 
 # Esempio di tentativo di accesso alla rete (se requests è installato)
 # try:
 # response = requests.get('http://www.example.com', timeout=5)
 # print(f'Richiesta di rete riuscita! Stato: {response.status_code}')
 # except requests.exceptions.RequestException as e:
 # print(f'Richiesta di rete fallita come previsto (o a causa di timeout): {e}')
 # except Exception as e:
 # print(f'Si è verificato un errore inaspettato durante la richiesta di rete: {e}')

Requisiti (requirements.txt):


Pillow
# requests # Decommenta se testando l'accesso alla rete

Comandi di Build e Esecuzione:

  1. Costruisci l’immagine Docker:
    docker build -t image-processing-agent .
  2. Esegui il Container con Restrizioni:
    Creiamo prima un’immagine dummy per il test: convert -size 100x100 xc:blue test_input.png (richiede ImageMagick).

    docker run --rm \
    -v $(pwd)/test_input.png:/app/input/test_input.png:ro \
    -v $(pwd)/output:/app/output \
    --memory="100m" \
    --cpus="0.5" \
    --network="none" \
    image-processing-agent \
    /app/input/test_input.png /app/output/processed_image.png

    Spiegazione delle opzioni:

    • --rm: Rimuove automaticamente il container al termine.
    • -v $(pwd)/test_input.png:/app/input/test_input.png:ro: Monta il test_input.png locale nella directory /app/input/ del container come sola lettura. Questo è il modo in cui l’agente riceve il suo input.
    • -v $(pwd)/output:/app/output: Monta una directory output locale nel container, permettendo all’agente di scrivere i suoi risultati.
    • --memory="100m": Limita l’uso della memoria del container a 100 MB.
    • --cpus="0.5": Limita il container al 50% di un singolo core CPU.
    • --network="none": Disabilita completamente l’accesso alla rete per il container. Questa è una misura di isolamento forte. Per gli agenti che richiedono accesso controllato alla rete, potresti usare una rete bridge dedicata e regole di firewall.
    • image-processing-agent: Il nome della nostra immagine Docker costruita.
    • /app/input/test_input.png /app/output/processed_image.png: Argomenti passati allo script agent.py all’interno del container.

Benefici del Contenimento in Docker:

  • Forti Isolamenti: Fornisce un alto grado di isolamento per processi, sistemi di file e reti.
  • Riproducibilità: Garantisce che l’agente funzioni in un ambiente coerente ogni volta.
  • Controllo delle Risorse: Facile impostare limiti su CPU, memoria e I/O.
  • Portabilità: I contenitori possono essere facilmente spostati e eseguiti su diversi host.
  • Segmentazione della Rete: Controllo dettagliato sull’accesso alla rete (ad es. porte specifiche, reti interne).
  • Utente Non Root: Pratica migliore eseguire i contenitori come utente non root.

Tecniche di Contenimento Avanzate

Seccomp (Modalità di Calcolo Sicuro)

Seccomp ti consente di filtrare le chiamate di sistema che un agente può fare al kernel Linux. Questo è un meccanismo di sicurezza molto potente. Docker supporta profili Seccomp personalizzati, che possono essere definiti in JSON. Ad esempio, potresti vietare le chiamate execve (esecuzione di nuovi programmi) o open a determinati percorsi.


{
 "defaultAction": "SCMP_ACT_ERRNO",
 "syscalls": [
 {
 "name": "read",
 "action": "SCMP_ACT_ALLOW"
 },
 {
 "name": "write",
 "action": "SCMP_ACT_ALLOW"
 },
 {
 "name": "exit",
 "action": "SCMP_ACT_ALLOW"
 },
 {
 "name": "openat",
 "action": "SCMP_ACT_ALLOW",
 "args": [
 {
 "index": 1,
 "op": "SCMP_CMP_NE",
 "val": 2 // O_WRONLY - vieta operazioni di apertura in sola scrittura
 }
 ]
 }
 // ... più syscalls
 ]
}

Per usarlo con Docker: docker run --security-opt seccomp=/path/to/my_seccomp_profile.json ...

Macchine Virtuali (VM)

Per il massimo livello di isolamento, soprattutto per agenti che gestiscono dati estremamente sensibili o eseguendo codice altamente non attendibile, una macchina virtuale completa (ad es. utilizzando KVM, VMware, VirtualBox) è l’opzione più forte. Le VM forniscono isolamento a livello hardware, il che significa che il sistema operativo guest (dove viene eseguito l’agente) è completamente separato dal sistema operativo host. Questo aggiunge un sovraccarico ma offre una sicurezza senza pari.

Enclavi Hardware (ad es., Intel SGX)

Per operazioni crittografiche o elaborazioni di dati estremamente sensibili dove anche il sistema operativo non è completamente fidato, le enclavi hardware come Intel SGX offrono un ambiente di esecuzione fidato. Questo consente a porzioni del codice e dei dati di un agente di essere eseguiti in una regione di memoria protetta, anche da software privilegiato sull’host. Questa è una forma altamente specializzata e complessa di contenimento, tipicamente utilizzata in applicazioni ad alta sicurezza.

Best Practices per il Contenimento degli Agenti

  • Principio del Minimo Privilegio: Concedi agli agenti solo le autorizzazioni e le risorse minime necessarie.
  • Audit Regolari: Rivedi periodicamente le configurazioni del contenitore e il comportamento degli agenti per potenziali vulnerabilità.
  • Minimizzare la Superficie di Attacco: Usa immagini di base minime per i contenitori, rimuovi pacchetti non necessari e disabilita servizi non utilizzati.
  • Esecuzione Non Root: Esegui sempre gli agenti come utente non root all’interno del contenimento.
  • Comunicazione Sicura: Se gli agenti devono comunicare con servizi esterni, utilizza canali sicuri, autenticati e crittografati (ad es. HTTPS, TLS mutuo).
  • Limiti delle Risorse: Applica sempre limiti a CPU, memoria e I/O per prevenire attacchi di esaurimento delle risorse o bug.
  • Segmentazione della Rete: Implementa politiche di rete rigorose. Di default, nega tutto il traffico di rete e consenti esplicitamente solo ciò che è necessario.
  • Infrastruttura Immutabile: Tratta gli ambienti di contenimento come immutabili. Se sono necessarie modifiche, costruisci una nuova immagine o un contenitore anziché modificare uno in esecuzione.
  • Logging e Monitoraggio: Implementa un logging solido all’interno e intorno al contenitore per rilevare comportamenti anomali.
  • Testing Automatizzato: Includi test di sicurezza nella tua pipeline CI/CD per garantire l’integrità del contenitore.

Conclusione

Il contenimento degli agenti è una pratica fondamentale per sviluppare sistemi AI sicuri e affidabili. Dall’isolamento dei processi base a tecniche avanzate di containerizzazione e macchine virtuali, è disponibile uno spettro di strumenti e tecniche per creare ambienti di esecuzione isolati. Progettando e implementando attentamente i contenitori, gli sviluppatori possono ridurre i rischi associati ad azioni malevole, bug software e abusi di risorse, assicurando che gli agenti AI operino in modo sicuro e prevedibile all’interno dei loro confini designati. Con l’AI sempre più integrata nelle infrastrutture critiche, padroneggiare queste tecniche di contenimento sarà indispensabile per ogni sviluppatore e architetto AI.

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: AI Security | compliance | guardrails | safety | security

Related Sites

AgntlogAgntkitAgntapiAgntup
Scroll to Top