8 min de lectura

¿Deben esperar las solicitudes pendientes con la bóveda bloqueada?

Las solicitudes pendientes con la bóveda bloqueada necesitan una ruta de fallo explícita, contexto actualizado después del desbloqueo, reglas de reintento limitadas y registros de auditoría que expliquen cada denegación.

¿Deben esperar las solicitudes pendientes con la bóveda bloqueada?

Una solicitud de un agente que llega a una bóveda bloqueada debe fallar en ese momento. No debe convertirse en un comando dormido que vuelva a la vida cuando alguien desbloquee la bóveda una hora más tarde.

La regla parece estricta hasta que piensas en lo que demuestra realmente un desbloqueo. Demuestra que una persona autorizó el acceso a un almacén de secretos en ese momento. No demuestra que un proceso antiguo del agente siga teniendo la misma tarea, que una implementación siga siendo conveniente, que una solicitud de incorporación de cambios no haya cambiado ni que el cuerpo HTTP y el comando SSH antiguos sigan teniendo sentido.

Esta es una de esas decisiones que se disfrazan de función práctica. Alguien ve una ejecución bloqueada y propone una cola: conservar la solicitud, mostrar una notificación y liberar el trabajo después de Touch ID. La cola parece útil porque la solicitud ya está formada. Esa es también la razón por la que resulta peligrosa. Una solicitud formada ya ha cruzado la línea que separa un plan de una acción a la espera de autorización.

La regla más segura es sencilla: mientras la bóveda esté bloqueada, deniega las acciones y descarta su forma lista para enviar. Después del desbloqueo, el agente puede revisar su estado actual y enviar una solicitud nueva. Esa segunda solicitud puede recibir autorización de sesión o aprobación por llamada según el contexto vigente.

Una bóveda bloqueada debe rechazar la acción de inmediato

El bloqueo de una bóveda es un límite de acceso, no una interrupción temporal de red. Tratarlo como una interrupción fomenta los reintentos automáticos, y precisamente eso es lo que no quieres alrededor de una intención antigua de un agente.

Cuando un agente solicita llamar a una API o abrir una conexión SSH, la pasarela tiene información suficiente para decidir si la solicitud puede continuar. Si la bóveda está bloqueada, no necesita inspeccionar un cuerpo, resolver un host, iniciar una conexión ni esperar a una persona. Debe devolver una denegación antes de tocar el exterior.

El resultado debe explicar al agente qué ocurrió sin invitarlo a repetir la acción a ciegas. Una estructura útil sería esta:

{
  "ok": false,
  "error": {
    "code": "VAULT_LOCKED",
    "message": "The credential vault is locked. This action was not queued or sent.",
    "request_id": "req_7d4c1f",
    "retryable": false
  }
}

retryable: false puede parecer contradictorio. El agente puede hacer una solicitud más adelante, pero la solicitud fallida no es segura para repetirla. Esta distinción evita que los autores de clientes creen un bucle genérico de espera que convierta un desbloqueo en una ráfaga no revisada de trabajo antiguo.

No sustituyas este resultado por 503 Service Unavailable, un tiempo de espera agotado o un error de transporte genérico. Esas respuestas indican a un cliente bien intencionado que repita exactamente la misma acción. La pasarela necesita un resultado semántico que diga: «Una condición de seguridad controlada por una persona bloqueó esta llamada, y esta llamada exacta ha terminado».

La regla se aplica igual a las lecturas y a las escrituras. Los equipos suelen reservar la cautela para las escrituras porque una escritura obsoleta puede borrar o implementar algo. Una lectura obsoleta también puede exponer información de clientes, revelar la configuración de producción o hacer que un agente tome una decisión posterior basándose en datos que el usuario ya no pretendía recuperar.

Desbloquear no aprueba una intención anterior

Un evento de desbloqueo y una respuesta de aprobación de acción contestan preguntas distintas. Un desbloqueo pregunta si la bóveda puede usar sus secretos. Una aprobación de acción pregunta si este proceso puede realizar este tipo específico de llamada externa para la tarea actual.

Combinar ambas decisiones crea un fallo de autorización sutil. Imagina que un agente prepara un comando SSH para reiniciar un servicio. El desarrollador cierra el portátil, la bóveda se bloquea y el agente envía la llamada de todos modos. Cuarenta minutos después, el desarrollador vuelve y desbloquea el Mac para revisar otro problema, y el reinicio se ejecuta porque la pasarela conservó el comando antiguo. En ese momento el desarrollador no aprobó un reinicio. Solo aprobó el acceso a la bóveda para sí mismo.

El mismo problema aparece de formas menos visibles:

  • Un agente preparó un comentario para una solicitud de incorporación de cambios, pero el revisor ya resolvió el problema.
  • Un agente preparó una llamada a una API en la nube usando un nombre de rama que ya no apunta al mismo commit.
  • Un agente preparó una consulta en un sistema de soporte, pero la solicitud del cliente que la justificaba ya terminó.
  • Un agente preparó la publicación de un paquete, pero mientras el acceso estaba bloqueado apareció un fallo en las pruebas.

El argumento habitual es que la solicitud ya estaba autorizada antes del bloqueo. A veces es cierto, pero aun así no justifica el envío diferido. La autorización puede mantenerse durante una sesión mientras exista el proceso. La intención no se mantiene solo porque una secuencia de bytes esté en una cola.

Por tanto, una pasarela debe separar claramente estas decisiones:

  1. El bloqueo de la bóveda decide si puede comenzar cualquier acción que dependa de secretos.
  2. La autorización de sesión decide si este proceso del agente está reconocido para su ejecución actual.
  3. La aprobación por llamada decide si puede usarse ahora una credencial marcada para confirmación individual.

Si la primera decisión es negativa, detente. No evalúes las siguientes ni conserves una solicitud lista para enviar cuando la respuesta cambie.

Una notificación no es una cola de solicitudes

Puedes avisar a una persona de que el trabajo está bloqueado sin conservar trabajo que pueda ejecutarse. Son diseños distintos, pero los equipos los confunden porque ambos reciben el nombre de «solicitudes pendientes».

Una notificación es un hecho no accionable. Puede indicar que un proceso intentó usar una referencia de credencial concreta contra una clase de destino en un momento determinado. Ayuda a la persona a decidir si debe desbloquear la bóveda y volver a la tarea. No puede reconstruir encabezados, un cuerpo de solicitud, un comando SSH ni un token de aprobación.

Una cola de solicitudes conserva material suficiente para enviar algo más tarde. Puede incluir un método HTTP, una URL, un cuerpo, argumentos de comando, la selección de credencial, una decisión de autorización o un token de repetición firmado. En cuanto conservas ese material, has creado una ejecución diferida.

La diferencia importa al implementar el sistema. Este aviso de trabajo bloqueado es aceptable:

{
  "event": "action_denied",
  "reason": "vault_locked",
  "session_id": "ses_31b8",
  "channel": "ssh",
  "credential_label": "production-deploy",
  "destination": "deploy host",
  "occurred_at": "2026-07-22T21:14:05Z"
}

No es aceptable si el sistema puede recuperar después el comando completo, la dirección de destino, el cuerpo privado de la solicitud o una autorización para usar la credencial a partir del evento. El registro debe servir para investigar, no para repetir.

Ten cuidado también con los hashes. Un resumen criptográfico suele ser seguro para correlacionar datos, pero solo si la pasarela no puede usarlo para recuperar una carga conservada. Un resumen junto a un bloque oculto sigue siendo una cola. Un resumen que existe únicamente en un registro de auditoría de solo adición es distinto.

Aquí aparece una tentación de producto: una lista de solicitudes pendientes hace que un panel parezca más interactivo. Resístela, a menos que cada entrada obligue al agente a volver a enviar una llamada nueva después de que actúe el usuario. Una pantalla que ofrece «ejecutar todo después del desbloqueo» ha convertido una solicitud de seguridad en un programador de trabajos diferidos.

Dale al agente una máquina de estados que no pueda malinterpretar

Los agentes se comportan mejor cuando la pasarela expone un modelo de estados pequeño y explícito. Los errores ambiguos hacen que los agentes inventen planes de recuperación, y ese plan puede consistir en esperar, reintentar o buscar otra ruta de credenciales.

Usa una máquina de estados en la que una solicitud tenga un único resultado terminal cuando la compuerta de la bóveda la deniegue:

received
  |
  +-- vault locked --\u003e denied_locked (terminal)
  |
  +-- vault unlocked --\u003e session check
                           |
                           +-- not approved --\u003e denied_session (terminal)
                           |
                           +-- approved --\u003e per-call check
                                             |
                                             +-- approval declined --\u003e denied_call (terminal)
                                             |
                                             +-- approved --\u003e dispatched --\u003e completed

Lo importante no es el diagrama. Lo importante es que denied_locked no tenga ninguna flecha hacia dispatched. Una solicitud posterior puede entrar en received, pero la antigua no puede volver a entrar en ningún punto.

Este diseño también facilita razonar sobre la idempotencia. Si una llamada falla porque la bóveda estaba bloqueada, no reserves un token de idempotencia como si el servidor hubiera aceptado la acción. El agente debe crear después otra solicitud, con un ID de solicitud nuevo. Si la API externa admite claves de idempotencia, la solicitud recién enviada puede usar una clave de nivel de aplicación que represente la operación empresarial prevista, pero la denegación de la pasarela no debe crear un registro de acción a medio terminar.

Para las operaciones de escritura, haz que el agente incluya su propia precondición actual siempre que el destino admita una. Puede ser un ID de revisión, una versión de entidad, la cabecera esperada de una rama o un ETag. Cuando se abra la bóveda, el agente debe volver a obtener el contexto actual y crear una llamada que lo refleje. Una solicitud obsoleta no puede superar una buena precondición, y una solicitud nueva aporta pruebas de que el agente volvió a comprobar el estado.

No intentes inferir la actualidad basándote solo en el tiempo transcurrido. Cinco segundos pueden ser demasiado para una implementación que cambia rápidamente, mientras que una hora puede no importar en una consulta estática. La actualidad procede de volver a leer el estado de la tarea y reconstruir la acción, no de un temporizador.

La aprobación debe vincularse a la llamada real

Protege también los comandos SSH
Dirige SSH mediante el ayudante sin estado sp-ssh incluido, en lugar de exponer claves privadas.

Una solicitud nueva después del desbloqueo todavía necesita un modelo de aprobación limitado. De lo contrario, eliminas la repetición diferida solo para sustituirla por un permiso vago que permite al agente cambiar de idea después de que el usuario haga clic.

Una tarjeta de aprobación debe vincularse al material que cambia el significado de seguridad de la acción. Para HTTP, normalmente incluye el método, el destino normalizado, la referencia de la credencial y un resumen del cuerpo de la solicitud. Para SSH, incluye la identidad del host, la cuenta, el comando o su resumen y la referencia de la credencial. También debe vincularse al proceso del agente y caducar pronto.

Evita una tarjeta que diga únicamente «Permitir el acceso del agente a producción». Esa frase hace que una persona apruebe una categoría mientras el agente controla los detalles. La persona puede estar dispuesta a permitir que un proceso lea un endpoint, pero no a invocar un endpoint administrativo bajo el mismo nombre de host.

Un registro de aprobación práctico podría tener este aspecto:

{
  "approval_id": "apr_8c62",
  "session_id": "ses_31b8",
  "process_identity": "signed-authority-and-process-instance",
  "channel": "http",
  "credential_label": "billing-api",
  "method": "POST",
  "destination": "api.example.internal/v1/invoices",
  "payload_digest": "sha256:...",
  "expires_at": "2026-07-22T21:16:00Z",
  "used": false
}

La pasarela no necesita mostrar cada byte de una carga grande para ser honesta sobre lo que aprueba. Sí necesita vincular la aprobación a los bytes que enviará. Un resumen humano conciso puede aparecer junto al resumen criptográfico, pero este último protege la solicitud exacta frente a sustituciones.

Usa registros de aprobación de un solo uso para las credenciales que requieren aprobación por llamada. Marca la aprobación como utilizada antes de iniciar el envío, no después de recibir una respuesta. Si la conexión se interrumpe después del envío, el agente puede tener que inspeccionar el destino para determinar si la acción surtió efecto. Reutilizar la aprobación facilitaría las escrituras duplicadas.

El caso de fallo que debes probar es desbloquear en el momento equivocado

La prueba más reveladora no es «¿falla la llamada mientras la bóveda está bloqueada?». Es «¿qué ocurre cuando el mundo cambia antes de que el usuario desbloquee?».

Prepara un servicio de prueba inofensivo con un endpoint que registre un destino de implementación y otro que cambie el destino permitido en ese momento. Después ejecuta esta secuencia:

  1. Inicia una tarea de agente que planee enviar POST /deploy con {\"revision\":\"a1b2c3\"}.
  2. Bloquea la bóveda antes de que el agente envíe la llamada.
  3. Confirma que la pasarela devuelve VAULT_LOCKED y que el servicio de prueba no recibe nada.
  4. Cambia la revisión permitida a d4e5f6 mientras la bóveda sigue bloqueada.
  5. Desbloquea la bóveda por un motivo no relacionado.
  6. Espera sin tocar el agente.

El resultado correcto es aburrido: el servicio de prueba sigue sin recibir nada. Si recibe una implementación para a1b2c3, tu pasarela tiene una ruta de ejecución diferida.

Después informa al agente de que la llamada fue denegada, deja que vuelva a leer la revisión permitida y haz que envíe una solicitud nueva. La solicitud esperada ahora es d4e5f6, y la pasarela puede solicitar la autorización de sesión o por llamada que corresponda. Esto demuestra que la recuperación conserva el contexto actual en lugar de tratar el tiempo que la bóveda pasó bloqueada como un botón de pausa invisible.

Ejecuta la misma prueba para SSH. Usa un comando que escriba una marca inofensiva con la revisión prevista. No pruebes solo el establecimiento de la conexión. La implementación insegura suele conservar un comando después de seleccionar una clave y enviarlo cuando la bóveda vuelve a estar disponible. Debes demostrar que el propio texto del comando muere en el límite del bloqueo.

No permitas que los clientes oculten la denegación

Comprueba quién solicita acceso
Sallyport muestra la autoridad de firma del código antes de que apruebes un proceso de agente nuevo.

Una pasarela puede tomar la decisión correcta y aun así producir un mal comportamiento si sus clientes convierten todos los errores en «inténtalo de nuevo más tarde». El protocolo debe tener suficiente estructura para que los marcos de agentes y los scripts envolventes gestionen deliberadamente una bóveda bloqueada.

Los agentes deben recibir tres instrucciones en el contrato de respuesta. Primero, la acción no salió de la pasarela. Segundo, la pasarela descartó la solicitud. Tercero, el agente no debe repetir automáticamente la misma solicitud.

El bucle de recuperación del propio agente debería parecerse más a esto:

if result.error.code == \"VAULT_LOCKED\":
    record_blocked_task()
    ask the user to unlock when appropriate
    stop this action

if user later resumes the task:
    reread relevant state
    decide whether the action is still needed
    create a new request

La línea decide whether the action is still needed es importante. No debe sustituirse por retry request. Un agente que recibió nuevas instrucciones del usuario, editó archivos, cambió de rama o descubrió que una prueba falló puede necesitar ahora una acción diferente o ninguna acción.

En ejecuciones sin supervisión, devuelve la denegación al orquestador y deja que la ejecución termine en estado bloqueado. No hagas que la pasarela espere a que alguien desbloquee la bóveda. Un proceso de agente en espera conserva memoria, mantiene un contexto que puede volverse sensible y crea presión para tratar un desbloqueo posterior como permiso para continuar. Una detención limpia da a la persona la oportunidad de revisar la tarea antes de reanudarla.

Si tu interfaz muestra una notificación, redacta el mensaje con precisión: «Una acción del agente fue denegada porque la bóveda estaba bloqueada». Evita botones llamados «continuar» o «aprobar pendientes». Un botón puede abrir la bóveda o mostrar los detalles de la sesión, pero no debe hacer que se ejecute una acción antigua.

Los registros deben demostrar que no se envió nada

Una denegación merece un registro de auditoría porque responde a una pregunta que los operadores acabarán haciendo: ¿el agente solo intentó realizar la acción o llegó a contactar con el sistema externo?

Registra el canal intentado, la identidad de la ejecución del agente, la referencia de la credencial, un destino normalizado, el resultado y las marcas de tiempo. Indica claramente el estado del envío. Los operadores deben poder distinguir denied_before_dispatch de dispatch_started, remote_rejected y completed sin interpretar cadenas de excepciones.

No registres secretos, encabezados de autorización sin procesar, material de claves privadas ni cuerpos completos por defecto. Para cuerpos sensibles, registra un resumen y una pequeña descripción aprobada si el sistema puede producirla sin filtrar contenido. El objetivo es establecer qué ocurrió, no crear una segunda copia de los datos que la bóveda debía proteger.

Una consulta de auditoría debería poder responder a un informe de incidente como este:

21:14:05  session ses_31b8 attempted SSH action using production-deploy
21:14:05  vault gate denied action before dispatch
21:15:41  vault unlocked by local user action
21:16:09  no action dispatched from ses_31b8

Esa última línea puede inferirse por la ausencia de registros de envío, pero los estados terminales explícitos aceleran las investigaciones y reducen la ambigüedad. Si usas un diario encadenado mediante hashes, verifica la cadena durante la revisión de incidentes y también durante las comprobaciones habituales. La evidencia de manipulación sirve de poco si nadie la utiliza cuando el registro importa.

La separación de Sallyport entre un diario Sessions para las ejecuciones y un diario Activity para las llamadas individuales encaja bien con este problema, porque una denegación por bóveda bloqueada pertenece tanto al historial de la ejecución como al registro de nivel de acción. Su comprobación sin conexión sp audit verify también permite al equipo probar la integridad de ese historial sin abrir la bóveda.

Las colas prácticas crean un segundo sistema de autorización

Autoriza la ejecución actual
Autoriza un proceso de agente nuevo una vez y deja que la sesión termine cuando el proceso salga.

Cuando una pasarela almacena solicitudes para liberarlas más tarde, empieza a acumular reglas: cuánto tiempo viven las solicitudes, quién puede liberarlas, si el proceso original debe seguir existiendo, si el contenido puede cambiar, qué ocurre después de un reinicio y si un desbloqueo libera una solicitud o todas.

Esas reglas son un motor de políticas disfrazado. Son difíciles de explicar a los usuarios porque cada excepción cambia el significado del desbloqueo. Un tiempo de espera corto para la cola no resuelve el problema del significado. Exigir que el proceso original siga vivo tampoco, porque el proceso puede estar comprometido o simplemente operar con un contexto obsoleto.

Mantén el diseño más pequeño. La compuerta de la bóveda deniega todas las acciones mientras está bloqueada. Una sesión de proceso nueva puede requerir aprobación. Una credencial marcada para aprobación por llamada requiere confirmación explícita cada vez. Cualquier otra comodidad debe vivir del lado del agente como recuperación de tareas, donde el agente tenga que reconstruir su plan y la persona pueda ver qué cambió.

Esto también proporciona a los usuarios un hábito fiable: desbloquear restaura la posibilidad de considerar acciones nuevas. Nunca libera acciones que olvidaron que estaban esperando. Las personas pueden tomar buenas decisiones con ese modelo mental. Les resulta difícil cuando una pantalla de bloqueo funciona también como una cola de trabajo oculta.

Haz que el camino seguro sea menos molesto que el inseguro

Los equipos crean colas porque un fallo rotundo puede resultar molesto durante el desarrollo normal. Corrige la fricción sin conservar solicitudes ejecutables.

Mantén la autorización de sesión limitada a la vida del proceso del agente para que el desarrollador no tenga que aprobar cada llamada normal. Reserva la confirmación por llamada para las credenciales que merecen una fricción deliberada, como la administración de producción o la publicación externa. Devuelve una denegación clara que permita al agente informar del trabajo bloqueado en un lenguaje sencillo. Ofrece a la persona una forma de desbloquear, inspeccionar la sesión del agente y reanudar la tarea conscientemente.

Después, haz explícitas las instrucciones para los agentes. Indícales que las credenciales permanecen fuera de su contexto, que un resultado de bóveda bloqueada termina la acción intentada y que una acción posterior debe reconstruirse después de comprobar el estado actual. Una instrucción para el agente no puede imponer la regla, pero reduce los reintentos inútiles y facilita trabajar con el comportamiento del protocolo.

La prueba de este diseño es sencilla. Si una persona desbloquea la bóveda distraída, cansada o mientras atiende una tarea no relacionada, no debe ejecutarse ninguna acción anterior del agente. Si esto no es cierto, elimina la cola antes de que se convierta en un informe de incidente.

FAQ

¿Debe una solicitud de un agente de IA esperar hasta que se desbloquee la bóveda?

Trata una bóveda bloqueada como un límite de denegación inmediata. La pasarela debe devolver un resultado legible por la máquina que indique que la bóveda está bloqueada y descartar la solicitud accionable, en lugar de guardarla para ejecutarla más tarde. El agente solo puede volver a intentarlo después de obtener contexto actualizado y decidir hacer la llamada de nuevo.

¿Por qué desbloquear una bóveda no debería ejecutar automáticamente las acciones de agentes que estaban en cola?

No. Desbloquear la bóveda demuestra que una persona puede volver a acceder a los secretos, pero no demuestra que siga queriendo una solicitud anterior. Mientras la bóveda estaba cerrada pueden haber cambiado el tiempo transcurrido, el estado del repositorio, la intención del usuario y el plan del agente.

¿Qué error debe devolver una pasarela cuando la bóveda está bloqueada?

Usa un error específico, como VAULT_LOCKED, con retryable: false para la solicitud original. Incluye una explicación breve para el agente y un ID de solicitud para solucionar problemas, pero no conserves para repetirla la acción que contiene credenciales.

¿Puede un agente repetir una solicitud de forma segura después de abrirse la bóveda?

Por lo general, no. Incluso repetir una llamada de solo lectura puede revelar datos después de que el usuario haya pasado a otra tarea, y repetir una escritura puede crear cambios duplicados u obsoletos. Deja que el agente decida si debe emitir una solicitud nueva después de recibir contexto actualizado.

¿Basta con un tiempo de caducidad corto para que las solicitudes en cola sean seguras?

La caducidad limita la acumulación accidental, pero no corrige una intención obsoleta. Una solicitud creada antes de abrirse la bóveda sigue sin demostrar que la tarea actual del agente y la intención actual de la persona coincidan con la acción original. La caducidad sirve para las tarjetas de aprobación, no para una cola de ejecución oculta.

¿A qué debe vincularse una tarjeta de aprobación?

Sí. La aprobación debe vincularse al método exacto, el destino, la referencia de la credencial, el resumen criptográfico de la solicitud, el proceso del agente y un intervalo de tiempo limitado. Una aprobación general que diga «permitir el acceso del agente» da demasiado margen a un atacante y a un agente confundido para cambiar la acción después.

¿Cómo deben aparecer las denegaciones por bóveda bloqueada en los registros de auditoría?

El registro de la sesión debe mostrar que el proceso intentó realizar una acción mientras el acceso estaba bloqueado y que la pasarela la denegó antes del envío. El registro de actividad debe identificar el canal y el destino intentados sin guardar material secreto. Una denegación es un evento de seguridad, no ruido vacío.

¿Puede una pasarela mostrar solicitudes pendientes sin ponerlas en cola?

Puede funcionar si la sala de espera nunca contiene una solicitud que se pueda enviar. Guarda únicamente un aviso no accionable, como «el agente X necesita acceso al servicio Y», y obliga al agente a enviar una solicitud completa y nueva después del desbloqueo. No conserves encabezados, cuerpos, comandos ni el estado de autorización.

¿Qué ocurre cuando un agente autónomo se ejecuta sin que haya nadie presente?

La pasarela debe mantener el límite humano aunque el agente se ejecute sin supervisión. Si nadie puede desbloquear la bóveda y aprobar la acción, la ejecución debe detenerse, informar del trabajo bloqueado y esperar a que una persona la reanude o reinicie más tarde.

¿Cómo evito entregar credenciales a los agentes cuando la bóveda suele estar bloqueada?

Nunca entregues una credencial al agente como solución alternativa. Espera a una sesión controlada por una persona, usa una credencial no humana con un alcance definido en un sistema separado o rediseña la tarea para que produzca un plan revisable sin realizar la llamada externa.

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