0Pricing
AI Agents · Lección

Políticas de seguridad para la ejecución de código

Restricciones de capacidades, aislamiento de red, límites del sistema de archivos y tiempos de espera.

Políticas de seguridad para la ejecución de código es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.

Por qué las políticas no son suficientes por sí solas

Decirle al LLM «no acceda a la red» no es un control de seguridad, sino una indicación. El LLM podría ignorarla, sufrir un jailbreak o el código generado podría infringir indirectamente la regla.

Las políticas de seguridad reales deben aplicarse en la capa de ejecución, no únicamente en el prompt.

Descripción general de las restricciones de capacidades

Las restricciones de capacidades limitan lo que un proceso aislado puede hacer a nivel del sistema operativo. Las capacidades de Linux dividen los privilegios de root en permisos específicos que pueden eliminarse individualmente.

Eliminar todas las capacidades excepto las mínimas necesarias se denomina principio de mínimo privilegio.

import docker
client = docker.from_env()

# Drop all Linux capabilities
output = client.containers.run(
    'python:3.12-slim',
    'python -c "print(\"safe run\")"',
    cap_drop=['ALL'],
    network_disabled=True,
    mem_limit='256m',
    auto_remove=True
)
print(output.decode())

Bloqueo de escrituras en disco fuera de /tmp

Utilice un sistema de archivos raíz de solo lectura y monte únicamente /tmp como escribible. Esto evita que el código modifique archivos del sistema o conserve datos fuera del área temporal designada.

import tempfile, docker
client = docker.from_env()

with tempfile.TemporaryDirectory() as tmpdir:
    output = client.containers.run(
        'python:3.12-slim',
        'python -c "open(\"/tmp/ok.txt\",\"w\").write(\"ok\"); print(open(\"/tmp/ok.txt\").read())"',
        read_only=True,
        tmpfs={'/tmp': 'size=64m,mode=1777'},
        network_disabled=True,
        mem_limit='128m',
        auto_remove=True
    )
    print(output.decode())  # 'ok' — /tmp write allowed
    # Writing anywhere else raises ReadOnlyFileSystem

Perfiles de seccomp: filtrado de llamadas al sistema

seccomp (secure computing mode) permite especificar una lista de llamadas al sistema permitidas. Cualquier llamada al sistema que no esté en la lista provoca que el proceso finalice con SIGSYS.

Docker incluye un perfil de seccomp predeterminado. Puede proporcionar un perfil JSON personalizado para aplicar restricciones mayores.

import json, docker
client = docker.from_env()

# Minimal seccomp profile: only allow read, write, open, close, exit
seccomp_profile = json.dumps({
    'defaultAction': 'SCMP_ACT_ERRNO',
    'architectures': ['SCMP_ARCH_X86_64'],
    'syscalls': [
        {'names': ['read', 'write', 'open', 'openat', 'close',
                   'fstat', 'mmap', 'mprotect', 'munmap', 'brk',
                   'exit', 'exit_group', 'rt_sigaction',
                   'rt_sigprocmask', 'futex'],
         'action': 'SCMP_ACT_ALLOW'}
    ]
})

output = client.containers.run(
    'python:3.12-slim',
    'python -c "print(1+1)"',
    security_opt=[f'seccomp={seccomp_profile}'],
    auto_remove=True
)
print(output.decode())

Límites de recursos: CPU, memoria y tiempo

Tres límites de recursos que todo sandbox debería aplicar:

  • Memoria: mem_limit; evita ataques de agotamiento de memoria
  • CPU: nano_cpus o cpu_quota; evita el agotamiento de la CPU
  • Tiempo: tiempo de espera de ejecución; evita los bucles infinitos
output = client.containers.run(
    'python:3.12-slim',
    'python -c "import time; time.sleep(100)"',
    mem_limit='128m',
    nano_cpus=500_000_000,   # 0.5 CPU
    network_disabled=True,
    auto_remove=True,
    timeout=10               # kill after 10 seconds
)
# Raises ReadTimeout after 10 seconds

Permitir importaciones de Python mediante una lista de permitidos

Antes de ejecutar el código, analice el AST en busca de instrucciones de importación. Rechace cualquier importación que no esté en la lista de permitidos. Esta es una capa de defensa en profundidad, no un sustituto de los controles a nivel del sistema operativo, pero resulta útil para detectar con antelación infracciones evidentes de las políticas.

import ast

ALLOWED_IMPORTS = {'math', 'statistics', 'json', 'csv', 'datetime', 'collections', 're'}

def check_imports(code: str) -> list[str]:
    tree = ast.parse(code)
    blocked = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                if alias.name.split('.')[0] not in ALLOWED_IMPORTS:
                    blocked.append(alias.name)
        elif isinstance(node, ast.ImportFrom):
            if node.module and node.module.split('.')[0] not in ALLOWED_IMPORTS:
                blocked.append(node.module)
    return blocked

print(check_imports('import socket; print(1)'))   # ['socket']
print(check_imports('import math; print(math.pi)'))  # []

Detección de patrones de código peligrosos

Además de las importaciones, compruebe si existen patrones que eludan las restricciones de importación: __import__, exec(), eval(), compile() y open() con rutas fuera de /tmp.

import ast

DANGEROUS_CALLS = {'exec', 'eval', 'compile', '__import__', 'breakpoint'}

def check_dangerous_calls(code: str) -> list[str]:
    tree = ast.parse(code)
    found = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            if isinstance(node.func, ast.Name):
                if node.func.id in DANGEROUS_CALLS:
                    found.append(node.func.id)
            elif isinstance(node.func, ast.Attribute):
                if node.func.attr in DANGEROUS_CALLS:
                    found.append(node.func.attr)
    return found

print(check_dangerous_calls('exec("import os")'))  # ['exec']

Límites de tamaño de salida

Un bucle descontrolado de impresión puede generar gigabytes de salida. Limite stdout/stderr a un tamaño razonable (por ejemplo, 1 MB) y trunque la salida o detenga el contenedor si se supera ese límite.

MAX_OUTPUT_BYTES = 1 * 1024 * 1024  # 1 MB

def run_with_output_limit(client, code: str) -> dict:
    container = client.containers.run(
        'python:3.12-slim',
        f'python -c "{code}"',
        mem_limit='256m',
        network_disabled=True,
        detach=True
    )
    try:
        container.wait(timeout=30)
        logs = container.logs(stdout=True, stderr=True)
        if len(logs) > MAX_OUTPUT_BYTES:
            return {'success': False, 'error': 'Output too large'}
        return {'success': True, 'output': logs.decode(errors='replace')}
    finally:
        container.remove(force=True)

if __name__ == '__main__':
    class FakeContainer:
        def wait(self, timeout=30): pass
        def logs(self, stdout=True, stderr=True): return b'Analysis complete: 42 rows processed.'
        def remove(self, force=True): pass
    class FakeContainers:
        def run(self, *args, **kwargs): return FakeContainer()
    class FakeClient:
        containers = FakeContainers()

    result = run_with_output_limit(FakeClient(), 'print(42)')
    print('Success:', result['success'])
    print('Output :', result['output'])

Indicador no-new-privileges

La opción de seguridad no-new-privileges impide que el proceso obtenga privilegios adicionales mediante binarios setuid o sudo. Aunque el código acceda a un shell, no podrá escalar privilegios.

output = client.containers.run(
    'python:3.12-slim',
    'python -c "import os; print(os.getuid())"',
    user='nobody',                              # run as non-root
    security_opt=['no-new-privileges:true'],    # no privilege escalation
    cap_drop=['ALL'],                           # no capabilities
    network_disabled=True,
    mem_limit='128m',
    auto_remove=True
)
print(output.decode())  # numeric UID of 'nobody'

Combinación de todas las políticas

Un sandbox preparado para producción combina todas las capas: capacidades del sistema operativo eliminadas, perfil de seccomp, sistema de archivos de solo lectura, no-new-privileges, red desactivada, límites de recursos y tiempo de espera. La defensa en profundidad garantiza que cualquier elusión de una capa sea detenida por otra.

import tempfile, json, docker
client = docker.from_env()

def maximum_security_run(code: str) -> dict:
    with tempfile.TemporaryDirectory() as tmpdir:
        try:
            out = client.containers.run(
                'python:3.12-slim',
                f'python -c "{code}"',
                user='nobody',
                security_opt=['no-new-privileges:true'],
                cap_drop=['ALL'],
                network_disabled=True,
                read_only=True,
                tmpfs={'/tmp': 'size=32m,mode=1777'},
                mem_limit='128m',
                nano_cpus=500_000_000,
                auto_remove=True,
                timeout=15
            )
            return {'success': True, 'output': out.decode()}
        except Exception as e:
            return {'success': False, 'error': str(e)}

Registro de infracciones de políticas

Cuando se detecte una infracción de política (importación bloqueada, llamada peligrosa o tiempo de espera agotado), registre el evento con el ID de sesión del agente, el hash del fragmento de código y el tipo de infracción. Esta información alimenta un panel de seguridad y ayuda a ajustar las políticas con el tiempo.

import hashlib, logging, time

logging.basicConfig(level=logging.INFO)
security_logger = logging.getLogger('sandbox.security')

def policy_check_and_run(code: str, session_id: str) -> dict:
    violations = check_imports(code) + check_dangerous_calls(code)
    code_hash = hashlib.sha256(code.encode()).hexdigest()[:16]

    if violations:
        security_logger.warning(
            'POLICY_VIOLATION session=%s hash=%s violations=%s',
            session_id, code_hash, violations
        )
        return {'success': False, 'error': f'Blocked: {violations}'}

    result = maximum_security_run(code)
    security_logger.info(
        'EXEC session=%s hash=%s success=%s',
        session_id, code_hash, result['success']
    )
    return result

¿Qué hace la configuración 'defaultAction: SCMP_ACT_ERRNO' del perfil de seccomp?

Los perfiles de seccomp controlan qué llamadas al sistema puede realizar un proceso. El campo defaultAction determina qué ocurre con las llamadas al sistema que no aparecen explícitamente en el perfil.

Repaso de las políticas de seguridad

La seguridad eficaz para la ejecución de código requiere múltiples capas: capacidades de Linux eliminadas, filtrado de llamadas al sistema mediante seccomp, sistema de archivos de solo lectura con espacio temporal tmpfs, no-new-privileges, red desactivada, límites de memoria, CPU y tiempo, y comprobación de importaciones a nivel de AST.

Ninguna capa por sí sola es suficiente: la defensa en profundidad significa que cada capa compensa las elusiones de las demás.

Preguntas frecuentes

¿La lección «Políticas de seguridad para la ejecución de código» es gratis?

Sí — el texto completo de «Políticas de seguridad para la ejecución de código» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.

¿Qué aprenderé en «Políticas de seguridad para la ejecución de código»?

Restricciones de capacidades, aislamiento de red, límites del sistema de archivos y tiempos de espera. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar AI Agents?

No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Políticas de seguridad para la ejecución de código»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de AI Agents?

Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Sandboxes de agentes basados en Docker
  2. Aislamiento mediante máquinas virtuales para agentes de código de alta seguridad
  3. E2B y servicios de sandbox en la nube
  4. Políticas de seguridad para la ejecución de código
← Volver a AI Agents