8 min de lectura

Agentes de IA en varias cuentas de nube: vincula cada acción

Los agentes de IA que usan varias cuentas de nube necesitan una vinculación explícita del destino. Aprende a asociar cada acción con una cuenta, entorno e identidad verificados, además de un registro de auditoría.

Agentes de IA en varias cuentas de nube: vincula cada acción

Los agentes de IA que trabajan con varias cuentas de nube solo son seguros cuando cada solicitud especifica un único límite de cuenta inmutable y el ejecutor rechaza cualquier discrepancia. Si un agente puede decir «despliega en producción», pero no puede identificar la cuenta de AWS, la suscripción de Azure o el proyecto de Google Cloud que hay detrás de esa palabra, se le ha otorgado una autoridad ambigua.

Los equipos suelen plantearlo como una tarea de limpieza de IAM. En realidad, es un problema de diseño de la ejecución. IAM puede conceder correctamente acceso a dos cuentas mientras el agente, su envoltorio o un perfil de shell sigue eligiendo la equivocada. Cuando ocurre, una credencial perfectamente válida realiza un cambio perfectamente válido en el lugar incorrecto.

La solución es menos llamativa que un modelo ingenioso de permisos. Define de antemano los destinos ejecutables, vincula cada uno con identificadores emitidos por el proveedor y una identidad de ejecución exclusiva, haz que el agente solicite un destino mediante un identificador y verifica al autor de la llamada justo antes de una llamada que cambie el estado. Los nombres de entorno legibles siguen siendo útiles, pero no deben decidir dónde se ejecuta el código.

Los destinos ambiguos crean autoridad real

Una etiqueta de entorno no es un límite de autoridad. «Producción» indica a una persona cómo pretende usar los recursos un equipo. No indica a una API qué cuenta de AWS, suscripción de Azure, proyecto de Google Cloud, tenant, región o rol asumido debe recibir una solicitud.

La diferencia parece quisquillosa hasta que una empresa tiene prod, production, prod-old y production-sandbox repartidos entre organizaciones distintas. He visto alias de cuentas copiados durante migraciones, perfiles de shell obsoletos apuntando a cuentas retiradas y una operación de lectura aparentemente inofensiva terminar en la cuenta que los responsables de responder al incidente intentaban preservar. Los agentes empeoran la situación porque interpretan literalmente las etiquetas en lenguaje natural y pueden actuar mucho más rápido que la persona que detecta la ambigüedad.

Un destino debe responder a todas estas preguntas antes de la ejecución:

  • ¿Qué proveedor es propietario del recurso?
  • ¿Qué límite de cuenta inmutable recibe la llamada?
  • ¿Qué entorno asigna la organización a ese límite?
  • ¿Qué identidad de ejecución puede actuar allí?
  • ¿Qué límites geográficos u organizativos se aplican?

El orden importa. El límite de la cuenta va antes que la etiqueta del entorno. Si una solicitud dice environment: production, pero no incluye un ID de cuenta ni un ID de suscripción, está incompleta. Recházala en lugar de pedir al agente que infiera el dato que falta a partir del nombre de un repositorio, el título de un ticket o su configuración actual del terminal.

Una recomendación frecuente y equivocada afirma que las convenciones para nombrar cuentas resuelven el problema. Ayudan a las personas a revisar una lista y fallan como control. Los nombres son cadenas mutables. Un ID de cuenta, ID de suscripción, ID de tenant, número de proyecto, UID de clúster y ARN de rol son referencias emitidas por el proveedor que identifican con mucha más fuerza el destino.

Una etiqueta de entorno no debe elegir una cuenta

Trata el entorno como metadatos controlados asociados a un registro de destino, no como una entrada que resuelve un destino durante la ejecución. Así, una solicitud como «aplica esta corrección de producción» no busca en un inventario activo y selecciona la cuenta que casualmente coincide con una etiqueta.

La diferencia tiene una consecuencia práctica. Tu catálogo de despliegues puede contener muchos destinos con environment: production: pagos, herramientas internas, servicios regionales y cuentas procedentes de adquisiciones. Cada uno sigue siendo un destino separado. El agente debe seleccionar un identificador aprobado, como aws-prod-payments, en lugar de enviar un selector amplio como environment=production.

Usa los identificadores del proveedor que establecen el límite real:

ProveedorVincular aNo depender de
AWSID de cuenta, partición, ARN de rol y región permitidaAlias de cuenta, nombre de perfil y nombre visible del rol
AzureID de tenant, ID de suscripción y, cuando sea necesario, alcance del grupo de recursosNombre visible de la suscripción y selección del directorio en el portal
Google CloudNúmero e ID de proyecto, y organización o carpeta cuando correspondaNombre visible del proyecto y configuración local activa

El ID de proyecto de Google Cloud suele ser suficientemente estable para usarlo en las solicitudes, mientras que el número de proyecto ofrece una comprobación inmutable adicional. Azure necesita tanto el tenant como la suscripción, porque una suscripción por sí sola no describe el contexto de identidad que emitió un token. En AWS, el número de cuenta por sí solo no indica qué rol usará la acción. Vincula ambos.

No escondas esta información en el texto de una instrucción. Una frase en las instrucciones del agente que diga «nunca toques producción» no puede detener una credencial que ya permite la acción. El ejecutor confiable debe tener el registro del destino y decidir si la identidad y el destino solicitados coinciden.

Un registro de destinos debe contener hechos, no suposiciones

Mantén un registro pequeño y revisado de los destinos de nube ejecutables. No es un segundo sistema IAM ni debe intentar repetir todos los permisos de cada nube. IAM de la nube sigue decidiendo si un rol puede llamar a una API. El registro responde a una pregunta más concreta: ¿a dónde puede llegar esta solicitud cuando usa este identificador de destino?

Este ejemplo usa identificadores ficticios, pero su estructura es intencionada:

targets:
  aws-prod-payments:
    provider: aws
    environment: production
    account_id: "482901736154"
    partition: aws
    role_arn: "arn:aws:iam::482901736154:role/agent-payments-deploy"
    regions:
      - us-east-1
      - us-west-2

  azure-prod-fulfillment:
    provider: azure
    environment: production
    tenant_id: "2f34c630-1ce8-4ed3-a7ce-8a3286e799a1"
    subscription_id: "841742bf-9db5-4cf8-9f6b-f1778d5b7511"
    scopes:
      - "/subscriptions/841742bf-9db5-4cf8-9f6b-f1778d5b7511/resourceGroups/fulfillment-prod"

  gcp-prod-catalog:
    provider: gcp
    environment: production
    project_id: "catalog-prod-417"
    project_number: "548201736915"
    parent: "organizations/193847561029"

El registro debe gestionarse como una configuración de producción. Asigna a cada destino un equipo responsable, un proceso de revisión y una fecha o estado de retirada cuando la cuenta deje de estar en servicio. De lo contrario, los destinos antiguos se convierten silenciosamente en un mapa de lugares a los que el agente todavía puede llegar.

No construyas registros a partir de descubrimientos libres y permitas la ejecución de inmediato. Las API de inventario de la nube sirven para encontrar cuentas que necesitan un responsable. No son decisiones de autorización. Una cuenta descubierta podría ser una copia forense, una suscripción gestionada por un proveedor, un resto de una adquisición o un tenant de pruebas que comparte etiquetas confusas con producción.

El registro también evita un problema sutil de deriva. Una persona puede cambiar el nombre de una suscripción de Azure o de un rol de AWS sin modificar el ID inmutable. La etiqueta visible puede actualizarse para facilitar la lectura mientras la vinculación permanece intacta. Si cambia el ID inmutable, trátalo como un destino nuevo que necesita revisión, aunque el nombre siga siendo el mismo.

El agente debe solicitar un identificador, nunca construir un destino

El agente debe enviar la intención y un identificador de destino. No debe enviar un ARN de rol copiado de un comando, un nombre arbitrario de perfil de nube ni un comando de shell que incluya una suscripción elegida por el usuario. Esos campos dan al agente control sobre la parte más sensible de la solicitud.

Una solicitud puede ser tan sencilla como esta:

{
  "request_id": "chg-8a31f6",
  "target": "aws-prod-payments",
  "operation": "aws.ec2.reboot_instances",
  "region": "us-east-1",
  "arguments": {
    "InstanceIds": ["i-0abc123def4567890"]
  },
  "reason": "Recover the failed checkout worker after approved release"
}

El ejecutor resuelve aws-prod-payments usando el registro que ya tiene. Asume solo el rol indicado, rechaza eu-west-1 porque esa región no figura en el registro y envía la solicitud con la identidad de cuenta seleccionada. El agente nunca recibe una credencial de nube reutilizable durante este intercambio.

El fallo que se evita es fácil de reconocer. Un agente ejecuta un comando con --profile prod, pero el perfil local prod de un desarrollador apunta a la cuenta de servicios compartidos. El comando es sintácticamente correcto, la API lo acepta y el equipo solo descubre el error cuando el trabajador de pagos esperado sigue ejecutándose. Un identificador de destino que se resuelve fuera del agente, seguido de una comprobación de identidad, detiene el comando antes de que la solicitud de reinicio salga del ejecutor.

No aceptes un identificador y un destino proporcionado por quien hace la llamada «por flexibilidad». Eso crea dos fuentes de verdad. Si una solicitud contiene target: aws-prod-payments y un ARN de rol diferente, el ejecutor debe rechazarla. Nunca debe elegir el campo que parezca más específico.

Verifica al autor real de la llamada antes de escribir

Mantén las claves de nube fuera de los agentes
Sallyport guarda las claves de API y SSH en su bóveda cifrada, nunca en el contexto del agente.

Un registro de destino fijo es necesario, pero no demuestra que la credencial activa sea la prevista. Los tokens caducan, las asunciones de roles fallan, los perfiles locales se filtran a los subprocesos y los SDK de nube pueden usar cadenas inesperadas de proveedores de credenciales. Comprueba la identidad activa justo antes de una llamada que cambie el estado.

Para AWS, AWS documenta GetCallerIdentity como una operación que devuelve la cuenta, el ARN y el ID de usuario de la identidad que realiza la llamada. Su documentación también indica que devuelve esos datos incluso cuando una denegación explícita bloquearía la llamada en otras circunstancias. Por eso es una buena herramienta de diagnóstico y comprobación previa. No concede permiso para hacer nada más ni sustituye la comparación con el registro esperado.

Un comando de comprobación previa tiene una salida como esta:

aws sts get-caller-identity --output json
{
  "UserId": "AROAEXAMPLEID:agent-run-8a31f6",
  "Account": "482901736154",
  "Arn": "arn:aws:sts::482901736154:assumed-role/agent-payments-deploy/agent-run-8a31f6"
}

Compara Account con account_id del destino. Analiza el ARN y compara el rol asumido con el rol configurado. No hagas una comprobación parcial como «el ARN contiene payments». Rechaza una partición, cuenta o rol diferentes antes de la llamada de escritura.

Aplica el mismo patrón en otros servicios. En Azure, consulta el tenant y la suscripción activos y compara ambos con el destino seleccionado. En Google Cloud, consulta el proyecto activo y la identidad autenticada y valida el proyecto contra el registro antes de una llamada que modifique datos. Estas comprobaciones deben ejecutarse en el mismo contexto de proceso que envía la acción. Comprobar un terminal y ejecutar en otro solo da una falsa sensación de seguridad.

Las comprobaciones previas tienen un límite: un rol puede ser correcto y aun así tener demasiados permisos. El rol de nube también necesita privilegios mínimos para su destino. La vinculación impide que una solicitud cruce a una cuenta no deseada. IAM limita lo que puede hacer la identidad correcta una vez que llega allí. Necesitas ambos controles.

Los roles amplios entre cuentas esconden el error hasta que causa daños

Un rol de administrador que puede asumir funciones en todas las cuentas es popular porque reduce el trabajo de configuración. También convierte la selección del destino en una decisión irreversible y de alto riesgo. Si el agente o el ejecutor selecciona la cuenta equivocada, esa misma identidad amplia suele tener acceso suficiente para completar el error.

Separa los roles de ejecución por cuenta y por finalidad. Un rol de despliegue de producción para pagos no debería tener también una ruta de confianza hacia las cuentas de analítica, identidad o recuperación ante desastres. Cuando un agente necesite acceso de lectura en muchas cuentas, usa roles de lectura separados y haz visible la vinculación del destino en cada llamada. El acceso de lectura puede exponer datos de clientes, la topología de la infraestructura y credenciales almacenadas en lugares inadecuados. Llamarlo «solo lectura» no hace que los errores de selección sean inofensivos.

Usa las condiciones de confianza nativas de la nube para limitar cómo se puede asumir un rol. Las políticas de confianza de roles de AWS pueden restringir la entidad de confianza y exigir un ID externo cuando ese patrón encaje con el autor de la llamada. Las identidades de carga de trabajo de Azure pueden limitarse mediante afirmaciones de credenciales federadas y asignaciones de roles sobre recursos. La suplantación de cuentas de servicio de Google Cloud puede limitar quién puede acuñar un token de acceso. El mecanismo exacto cambia, pero el diseño es el mismo: una identidad de ejecución debe corresponder a un destino y una finalidad revisados.

No confundas una identidad central de intermediación con una autoridad amplia. Un intermediario puede coordinar solicitudes para muchos destinos, mientras cada solicitud obtiene una identidad específica para su destino. Requiere más configuración que un rol de administrador universal. También hace visible el alcance del daño cuando un proceso, una instrucción o una integración falla.

La aprobación debe mostrar el destino que una persona puede verificar

Aprueba las llamadas sensibles a la nube
Exige una aprobación con un clic o Touch ID cada vez que se usa una credencial seleccionada.

Una persona no puede aprobar una acción segura si la aprobación oculta el límite de la cuenta. «Reinicia el trabajador de pagos en producción» obliga al revisor a confiar en una lógica de resolución invisible. La aprobación debe incluir el identificador del destino, la etiqueta del entorno, el identificador inmutable de la cuenta, el rol o identidad de servicio activa, la operación y el alcance de los recursos que afectará la API.

Para reiniciar una instancia de AWS, una aprobación útil sería así:

Target: aws-prod-payments
Environment: production
Account: 482901736154
Identity: agent-payments-deploy
Action: ec2:RebootInstances
Region: us-east-1
Resource: i-0abc123def4567890
Reason: Recover failed checkout worker after approved release

Ese detalle no es una formalidad. Los revisores suelen conocer el número de cuenta o el identificador de destino de su propio servicio, mientras que la descripción del agente puede parecer razonable y ser incorrecta. Haz que el destino sea lo bastante visible para revisarlo antes de leer la descripción de la acción. Las personas detectan antes un número de cuenta inesperado que una discrepancia sutil escondida en un conjunto de parámetros.

No pidas una aprobación general para «todo el trabajo de esta sesión» cuando la sesión abarque varias cuentas de producción. Una sesión puede tener un límite legítimo, como cambios repetidos en un único destino de despliegue, pero no debe ampliarse silenciosamente. Exige una nueva aprobación cuando cambie el identificador del destino, cuando una operación pase de lectura a escritura o cuando una solicitud afecte a un alcance más sensible que el aprobado por el revisor.

La autorización por sesión de Sallyport identifica el proceso que se conecta, y su configuración de credenciales por llamada puede exigir una aprobación para cada uso. Solo resulta útil cuando la solicitud de acción incluye un destino que el revisor puede reconocer y el ejecutor ya lo ha vinculado a un único lugar.

Los registros deben conectar intención, identidad y pruebas del proveedor

Los registros de auditoría de la nube indican qué identidad llamó a una API, pero rara vez explican la instrucción del agente, la selección del destino o la decisión del revisor. Los registros del agente pueden explicar la intención, pero no demuestran que la nube recibiera la llamada esperada. Conserva ambos registros y relaciónalos mediante un ID de solicitud y los identificadores inmutables del destino.

Para cada acción, registra estos campos antes y después de la ejecución:

  • El proceso o la sesión del agente que realizó la solicitud
  • El identificador de destino seleccionado y sus identificadores inmutables resueltos
  • La identidad de ejecución observada durante la comprobación previa
  • La operación, el alcance del recurso, el resultado y el ID de solicitud
  • La referencia al evento de auditoría del proveedor, cuando este la proporcione

AWS CloudTrail, Azure Activity Log y Google Cloud Audit Logs capturan actividad del lado del proveedor, según los servicios y la configuración de registro utilizados. Conserva esos registros en su propio límite de seguridad. No trates el registro de actividad de un agente como sustituto de las pruebas del proveedor, porque un proceso local comprometido podría mentir sobre una solicitud que nunca completó.

Sallyport registra las ejecuciones de agentes y las llamadas individuales en diarios separados proyectados desde un registro de auditoría cifrado y encadenado mediante hashes. Su comando sp audit verify puede verificar esa cadena sin conexión sobre el texto cifrado, lo que ayuda a comprobar si los registros locales de acciones fueron modificados después de un incidente.

La prueba práctica es un simulacro de investigación. Elige un cambio aprobado y pide a un ingeniero que responda cuatro preguntas sin adivinar: qué proceso de agente lo solicitó, qué destino seleccionó, qué identidad de nube lo ejecutó y qué evento del proveedor lo confirma. Si alguna respuesta requiere correlacionar manualmente marcas de tiempo en tres consolas, tus registros son demasiado débiles.

Un incidente en la cuenta equivocada suele empezar antes de la llamada a la API

Haz que cada acción sea atribuible
El registro de actividad guarda cada llamada individual junto con la sesión que la inició.

El fallo visible suele ser un cambio de producción en la cuenta equivocada. El fallo anterior suele ser una ruta de resolución sin control. Trata el incidente como un defecto de vinculación, no solo como el caso de una persona que «usó el perfil equivocado».

Considera una secuencia plausible. Un repositorio contiene un script que acepta ENV=prod. Su envoltorio lo traduce a un perfil de AWS llamado prod. Durante una migración, un desarrollador cambió ese perfil para que apuntara a una cuenta de servicios compartidos, porque la antigua cuenta de pagos ya no necesitaba acceso directo. Más tarde, un agente recibe una solicitud para reiniciar un trabajador de pagos. Encuentra el script, establece ENV=prod y lo ejecuta. La resolución del perfil del script elige los servicios compartidos. El rol tiene permisos amplios sobre EC2 porque el equipo lo usaba por comodidad operativa. El reinicio se completa en la cuenta equivocada.

La API de la nube no se confundió. El script realizó una solicitud válida con una identidad válida. Una corrección posterior al incidente que solo diga a los agentes «comprueba dos veces la cuenta» volverá a fallar, porque deja intacta la misma ruta de resolución.

Repara este tipo de fallo en este orden concreto:

  1. Desactiva la sesión o la ruta del rol afectada y conserva los registros de auditoría del agente y de la nube.
  2. Identifica el selector exacto que eligió el destino equivocado, como un nombre de perfil, una suscripción predeterminada, una etiqueta de entorno o un ARN de rol proporcionado por quien hizo la llamada.
  3. Sustituye ese selector por un identificador de destino aprobado que el ejecutor resuelva.
  4. Añade una comparación de identidad activa que rechace cualquier discrepancia antes de las escrituras.
  5. Divide el rol amplio si permitía acciones no relacionadas en otras cuentas.

Después, prueba deliberadamente la ruta de rechazo. Apunta un destino de pruebas a una credencial de otra cuenta de prueba y confirma que el ejecutor se detiene antes de la llamada que modifica la API. Los equipos suelen probar los casos de éxito y nunca demuestran que la vinculación de cuentas falle de forma segura.

El despliegue funciona mejor si empiezas por las escrituras más arriesgadas

No esperes a completar el inventario de toda la nube para aplicar una vinculación explícita a las acciones peligrosas. Empieza por las operaciones que pueden cambiar o exponer el estado de producción: despliegues, cambios de identidad, modificaciones de red, exportaciones de datos, rotación de secretos y comandos destructivos de infraestructura. El descubrimiento de solo lectura puede ayudar a construir el registro, pero no debe conceder silenciosamente acceso de ejecución a cuentas recién encontradas.

Primero, enumera las cuentas que pueden recibir esas acciones y asigna a cada una una etiqueta de entorno clara y un responsable. Después, crea un registro de destino para cada par cuenta-finalidad. Luego, haz que una ruta de ejecución resuelva los identificadores, obtenga credenciales específicas del destino, verifique la identidad activa y escriba el registro de la acción. Por último, elimina el acceso directo del agente a perfiles ambientales, suscripciones predeterminadas y archivos de credenciales.

Espera cierta resistencia por parte de los ingenieros acostumbrados a cambiar de cuenta desde un terminal usando una sola variable. Ese hábito es rápido porque deja el contexto en la memoria de una persona. Un agente autónomo no tiene esa memoria, y las personas que revisan sus acciones tampoco. Pon el contexto en la solicitud, el registro de destinos y las pruebas de ejecución.

Si no puedes indicar el número de cuenta, la identidad de ejecución y el alcance de los recursos de una acción antes de que se ejecute, el agente todavía no tiene información suficiente para actuar de forma segura. Haz que recopile los datos que faltan o deja la acción en manos de una persona.

FAQ

¿Basta con el nombre de un entorno para identificar un destino de nube para un agente de IA?

No. Una cuenta, suscripción o proyecto de nube debe identificar el límite de facturación y permisos, mientras que un entorno describe el uso previsto. Tratar una etiqueta como prod como prueba de autoridad permite que un agente seleccione la cuenta equivocada cuando los nombres cambian o se repiten.

¿Qué identificadores debe usar un agente para las cuentas de AWS, Azure y Google Cloud?

Usa identificadores inmutables del proveedor: el ID de cuenta y el ARN del rol de AWS, el ID de tenant y el ID de suscripción de Azure, o el número de proyecto y el ID de proyecto de Google Cloud. Conserva el nombre de cuenta fácil de leer solo como texto visible, porque los nombres pueden cambiar y suelen repetirse.

¿Cómo impido que un agente elija su propia cuenta de nube?

Dale al agente un identificador corto, como aws-prod-payments, y resuelve ese identificador en un ejecutor confiable hacia una cuenta y un rol fijos. No permitas que el agente construya un ARN de rol, una suscripción o un nombre de proyecto al crear la solicitud.

¿Debería dar a un agente de IA un único rol de administrador entre cuentas?

Un único rol de administrador puede llegar a muchas cuentas, pero elimina el límite entre cuentas cuando el agente se equivoca al elegir. Usa roles o credenciales separados para cada destino, con relaciones de confianza limitadas, para que un error de selección no se convierta silenciosamente en un cambio en producción.

¿Cómo puedo verificar qué cuenta de AWS está usando realmente un agente?

Verifica la identidad activa justo antes de cada operación que cambie el estado y compara su identificador inmutable de cuenta o suscripción con el registro del destino aprobado. En AWS, sts:GetCallerIdentity es una comprobación previa útil, pero solo si el ejecutor rechaza las discrepancias en lugar de limitarse a registrarlas.

¿Qué debe contener un registro explícito de destino de nube?

El registro debe incluir el proveedor, el límite inmutable de la cuenta, la etiqueta del entorno, la identidad de ejecución, las regiones permitidas y cualquier límite de tenant u organización que necesite el proveedor. Mantén los permisos en IAM de la nube y usa el registro para vincular la solicitud a un único destino conocido.

¿Qué debe aprobar una persona antes de que un agente cambie la infraestructura de nube?

La aprobación debe mostrar el entorno, el número de cuenta o ID de suscripción, el rol de ejecución, la operación solicitada y el alcance de los recursos afectados. Una aprobación que solo dice deploy production oculta la decisión que concentra la mayor parte del riesgo.

¿Cómo audito las acciones de un agente en varias cuentas de nube?

Usa también las pruebas nativas de cada proveedor: CloudTrail en AWS, Activity Log en Azure y Cloud Audit Logs en Google Cloud. Guarda el ID de solicitud del agente y el identificador del destino junto con la acción para que los investigadores puedan conectar el destino solicitado con el evento del proveedor.

¿Puede un agente de IA descubrir nuevas cuentas de nube automáticamente?

Para ejecutar acciones, un registro de destinos escrito y revisado por personas es más seguro que el descubrimiento automático de cuentas. El descubrimiento puede alimentar un inventario para su revisión, pero no debe crear destinos ejecutables sin que alguien responsable compruebe el límite de la cuenta y el entorno asignado.

¿Qué debo hacer si un agente de IA actúa en la cuenta de nube equivocada?

Revoca la sesión o la credencial de ejecución, conserva los registros de la solicitud del agente y de auditoría del proveedor, e identifica el límite inmutable de la cuenta que recibió la llamada. Después corrige el fallo de vinculación, ya sea un alias sin resolver, una política de confianza demasiado amplia o un ejecutor que aceptó un ARN de rol elegido por quien hizo la solicitud.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov