Ola 5 · Sebas 5.9: llaves de API con alcance (backend) - #16
Open
heysebitas wants to merge 1 commit into
Open
heysebitas wants to merge 1 commit into
heysebitas wants to merge 1 commit into
Conversation
El HIS de un hospital solo podia hablarle a core con la contraseña de turno,
que puede TODO: crear casos, aceptar traslados, declarar capacidad. Darle eso
a una integracion es darle a un sistema ajeno el boton de aceptar pacientes.
- `pulso_sk_` + 32 bytes aleatorios. El prefijo no es cosmetico: lo detectan
los escaneres de secretos si alguien la commitea.
- Se guarda solo el sha256 y los ultimos 4 caracteres. El valor se muestra
UNA vez; si se pierde, se rota. (sha256 y no Argon2id a proposito: una
llave de 32 bytes aleatorios no tiene diccionario que la contenga, y una
KDF lenta solo cobraria 50 ms de CPU por peticion del HIS.)
- Alcance por llave, **minimo por defecto**: sin alcances explicitos no hace
nada. Y una ruta sin `@Alcance()` no la admite ninguna llave, aunque el
actor tenga el rol `servicio`.
- Rotacion con 24 h de gracia: revocar en el acto convierte "rotar llaves"
en algo que nadie quiere hacer, porque el corte lo causa nuestro boton.
- Revocacion inmediata, y los intentos con una llave revocada se registran:
esa es justo la señal de que alguien todavia la tiene.
- Uso por llave (conteo, ultima vez, IP) — lo que permite detectar una
filtrada. Cada llave entra al limite de tasa de 2.11 con su propio cubo,
porque su actor es `llave:<id>`.
- `GET /estado` abierto a `caso:leer` como primera ruta consumible.
⚠️ Falta la vista `/panel/api`: cuelga del shell de /panel (2.7 → 1.4). Se
administra con curl mientras tanto. Y antes de repartir una llave fuera del
equipo hay que cerrar el aislamiento por organizacion de /estado (1.5/1.6).
Verificado end-to-end: crear, listar sin filtrar el secreto, 403 por alcance
insuficiente, 403 en ruta sin @alcance, rotar sin cortar, revocar, y 404 —no
403— para una llave de otra organizacion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tarea 5.9 · va sobre #15 · backend completo, vista pendiente.
El problema
El HIS de un hospital solo podía hablarle a core con la contraseña de turno, que puede todo: crear casos, aceptar traslados, declarar capacidad. Darle eso a una integración es darle a un sistema ajeno el botón de aceptar pacientes.
Qué trae
pulso_sk_+ 32 bytes aleatorios. El prefijo no es cosmético: lo detectan los escáneres de secretos si alguien la commitea. Cuesta cero y evita el peor final.@Alcance()no la admite ninguna llave, aunque el actor tenga el rolservicio— el mínimo por defecto vale también para las rutas.llave:<id>.GET /estadoabierto acaso:leercomo primera ruta consumible.Por qué sha256 aquí y Argon2id en las contraseñas
No es una inconsistencia. Argon2id/scrypt existen para hacer lento el ataque por diccionario contra secretos de baja entropía —los que elige una persona—. Una llave de 32 bytes aleatorios no tiene diccionario que la contenga: hashearla con una KDF lenta solo cobraría 50 ms de CPU por cada petición del HIS. Lo que sí importa aquí es que el valor no se guarda nunca y que la comparación sea en tiempo constante.
Hecho cuando
12 tests nuevos. Verificado end-to-end: crear, listar sin filtrar el secreto ni el hash, 403 por alcance insuficiente, 403 en ruta sin
@Alcance(), rotar sin cortar, revocar, y 404 —no 403— para una llave de otra organización (confirmar que existe le diría a un administrador ajeno que esa llave es de alguien).Dos cosas que no dependen de mí:
GET /estadotodavía no filtra por organización — una llave concaso:leerve todo lo que hay en memoria. Lo cierra el aislamiento de inquilino (1.5 Zaid / 1.6 Neid).Falta la vista
/panel/api: cuelga del shell de/panel(2.7), que a su vez espera 1.4 (Juan). Mientras tanto se administra concurl, que es como lo va a usar el integrador de un HIS de todas formas.🤖 Generated with Claude Code