API de administración
El plano de administración es opcional y vive en su propio socket y su propia tarea: el dataplane sigue sirviendo aunque esté caído o no se haya configurado. Esta página recoge los endpoints que la fuente documenta, sus roles, la matriz de autorización y los códigos de error.
Todo lo que hay aquí sale de la sección 9 de SPEC.md y de la matriz de autorización publicada con la evidencia de v0.8; lo que no aparece listado responde 404.
Endpoints
| Método y ruta | Rol | Qué devuelve |
|---|---|---|
GET /api/v1/status | lectura | Versión, uptime, topología validada, estado por servidor (ready, drain, maintenance), salud, intercambios en vuelo, contadores, revision, ETag y tls_fingerprint por listener |
GET /metrics | lectura | Texto Prometheus: familia fija sin etiquetas, detalle opt-in y las cuatro series del presupuesto |
GET /api/v1/cache | lectura | Entradas de la caché de respuestas |
PUT /api/v1/backends/{backend}/servers/{target}/state | escritura | Cambia el estado de un servidor: ready, drain o maintenance |
PUT /api/v1/backends/{name} | escritura | Sustituye la tabla [backend.*] del documento en caliente |
PUT /api/v1/listeners/{name} | escritura | Sustituye la tabla [listener.*] del documento en caliente |
POST /api/v1/certificates/reload | escritura | Relee los certificados y devuelve listener, listen, fingerprint, changed y quic por cada listener TLS |
GET /panel | lectura o escritura | Panel web renderizado en servidor, si panel = true |
La autenticación es siempre una cabecera Authorization: Bearer $TOKEN. Sin token, la respuesta es 401 con WWW-Authenticate: Bearer y no revela nada de la topología.
Roles y códigos
Hay dos secretos y dos niveles: el token de lectura abre las rutas GET; el de escritura abre además las escrituras. Si no hay token de escritura configurado, el plano entero es de solo lectura y toda escritura responde 403 write_disabled.
| Petición | Anónimo | Token de lectura | Token de escritura |
|---|---|---|---|
GET /api/v1/status | 401 | 200 | 200 |
GET /metrics | 401 | 200 | 200 |
GET /ruta-desconocida | 401 | 404 | 404 |
PUT …/servers/{target}/state | 401 | 403 | 200 |
PUT /api/v1/backends/{name} | 401 | 403 | 200 (503 sin aplicador) |
PUT /api/v1/listeners/{name} | 401 | 403 | 200 (503 sin aplicador) |
POST /api/v1/certificates/reload | 401 | 403 | 200 (503 sin aplicador) |
DELETE /api/v1/status | 401 | 405 | 405 |
El 503 del arnés es deliberado: allí no hay aplicador conectado, y esa respuesta prueba que el token de escritura pasó el control de rol y la petición llegó al aplicador. Un 200 en esa casilla sería una promesa que la prueba no puede respaldar.
Otros códigos que hay que saber leer: 400 cuando el cuerpo no parsea o no valida, 409 cuando el candidato es válido pero el dataplane lo rechaza (conflicto de bind, TLS congelado en un listener QUIC), 412 con la revisión actual cuando el If-Match está obsoleto y 428 cuando falta. El 405 trae Allow: GET, PUT, POST, que describe los métodos que sirve el plano, no los que puede usar quien llama. Y ningún rechazo cambia el estado: la generación viva sigue igual.
Escrituras en caliente
Las dos PUT de tabla llevan como cuerpo la tabla TOML (Content-Type: application/toml), desnuda o copiada tal cual del fichero, con un máximo declarado de 64 KiB y sin cabecera Origin. Reemplazan la tabla y crean el nombre si no existía.
TOKEN=$(cat /etc/eqproxy/admin.token)
WRITE=$(cat /etc/eqproxy/admin-write.token)
# Revisión vigente (la que hay que devolver en If-Match)
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:9001/api/v1/status
# Sustituir la tabla del backend "api"
curl -s -X PUT \
-H "Authorization: Bearer $WRITE" \
-H "Content-Type: application/toml" \
-H 'If-Match: "v1"' \
--data-binary @backend-api.toml \
http://127.0.0.1:9001/api/v1/backends/api
La respuesta es 200 solo después de que el dataplane haya hecho el cambio. Un listener que se conserva por nombre y dirección mantiene su socket, y las conexiones ya establecidas drenan en la generación con la que se aceptaron. Los cambios son solo de runtime: el fichero sigue siendo la base y el siguiente SIGHUP los reemplaza.
# Drenar un servidor (cuerpo JSON de 1 KiB como máximo)
curl -s -X PUT \
-H "Authorization: Bearer $WRITE" \
-H "Content-Type: application/json" \
-d '{"state":"drain"}' \
http://127.0.0.1:9001/api/v1/backends/api/servers/10.0.0.11:9000/state
# Renovar certificados: sin cuerpo y sin Origin
curl -s -X POST \
-H "Authorization: Bearer $WRITE" \
http://127.0.0.1:9001/api/v1/certificates/reload
Un servidor drenado no acepta peticiones nuevas, termina las que tiene en vuelo y sobrevive a un SIGHUP. maintenance es lo mismo más cerrar el material ocioso del slot —el pool keep-alive y la sesión HTTP/2 hacia el backend—, para no dejar nada del proxy aparcado en una máquina que se va a parchear.
Auditoría y límites
Cada intento escribe una línea AUDIT con el rol, el par, el método, la ruta, el estado y la transición; nunca el token. No hay sumidero duradero de auditoría ni identidades por usuario: solo los dos roles.
| Límite | Valor |
|---|---|
| Cuerpo de una escritura de topología | 64 KiB |
| Cuerpo de un cambio de estado | 1 KiB, application/json |
| Cabecera y duración de un intercambio | 8 KiB de cabecera, 5 s |
| Sesión del panel | 30 min de inactividad; como mucho 16 sesiones |
El plano no tiene TLS en esta versión:
allow_remote = truemanda el token en claro. Para uso remoto, prefiere el socket Unix con modo0600o0660y allowlist de uids.