orquestador/specs/SECURITY.md

6.7 KiB

Seguridad T07

Para la POC sin Keycloak, el perfil explícito demo-token permite un secreto fijo según POC_AUTH.md y ADR-023. La validación JWT de esta guía describe el modo normal, activo cuando no se selecciona ese perfil.

El servicio valida tokens RS256 mediante JWKS, emisor exacto, audiencia configurada, expiración obligatoria y sujeto no vacío. También valida nbf cuando está presente; el validador temporal de Spring admite 60 segundos de desfase. Las pruebas usan tokens RSA realmente firmados y un servidor JWKS local. No acreditan todavía una emisión real de Keycloak controlms: faltan un token de prueba y su configuración de audiencia/claims, sin necesidad de entregar contraseñas al repositorio.

JWT_AUDIENCE identifica la audiencia y el cliente cuyos roles se aceptan desde resource_access. También se aceptan realm_access.roles. Roles de otros clientes y el claim OAuth scope no conceden permisos técnicos. JWT_BUSINESS_SCOPE_CLAIM selecciona el claim de negocio (por defecto business_scope); debe ser un string no vacío. Identidad, roles y ámbito proceden exclusivamente del JWT verificado.

Administración

FLOW_ADMIN_ENABLED=false mantiene deshabilitados los controladores administrativos. Para habilitarlos se necesita un usuario DB de ejecución restringido, credenciales de migración separadas, catálogo confiable y ADMIN_BUSINESS_SCOPES con ámbitos permitidos separados por comas. Una lista vacía deniega todas las operaciones. Los flujos y tipos son un catálogo global: pertenecer a uno de esos ámbitos autoriza administrarlo según el rol; no implica aislamiento de flujos por tenant.

Operación implementada Rol requerido
POST /api/v1/admin/flows; PUT /api/v1/admin/flows/{id} FLOW_EDITOR
POST /api/v1/admin/flows/{id}/validate FLOW_EDITOR o FLOW_PUBLISHER
POST /api/v1/admin/flows/{id}/publish FLOW_PUBLISHER
POST /api/v1/admin/flows/{id}/retire FLOW_ADMIN
PUT /api/v1/admin/request-types/{key}/active-flow FLOW_ADMIN

Edición, publicación, retiro y activación requieren un ETag fuerte If-Match. Ausente: 428; sintaxis inválida: 400; revisión obsoleta: 412. Editar un flujo publicado retorna 409. JSON inválido/duplicado: 400; definición fuera de schema: 422; cuerpo superior a 1 MiB: 413. Respuestas de error no exponen SQL ni tokens y llevan un correlationId generado por el servidor. Sesiones y caché de peticiones deshabilitadas.

config/publication-catalog.json es configuración de despliegue de solo lectura en Docker. No puede reemplazarse desde HTTP. El ejemplo registra ANALISTA y ningún handler, integración ni documento; no simula proveedores ni permite publicar acciones no registradas. Reiniciar aplica una nueva configuración. Simulación y resolución siguen pendientes de sus tareas funcionales; la matriz de roles no constituye una implementación de esas rutas.

Recursos de negocio

ResourceAccess exige propietario (sub) y ámbito coincidentes para solicitud, ejecución, documento y auditoría. El adapter resuelve los tres últimos contra su solicitud padre en PostgreSQL. Recurso inexistente o ajeno retorna el mismo 404; FLOW_ADMIN no permite eludir esta política. La conciliación tiene una autorización separada: EXECUTION_OPERATOR y mismo ámbito, aunque el propietario sea otro.

T08 integra esta puerta en la consulta de solicitudes y filtra también propietario/ámbito en el SELECT que devuelve los datos. PersistenceAccessConfiguration comparte codec, FlowStore, ResourceAccess y la verificación DB cuando administración o solicitudes estén habilitadas; REQUEST_API_ENABLED es independiente del interruptor administrativo. T09/T12/T13/T15 deben reutilizar la puerta antes de devolver datos o ejecutar comandos. Las pruebas T07 de ejecución/documento/auditoría usan un controlador exclusivo de test, fuera del paquete escaneado y ausente del JAR; sus endpoints funcionales siguen pendientes. T08 prueba POST/GET reales de solicitudes (REQUESTS.md). No se acepta identidad en cuerpos.

PostgreSQL externo

Configurar DB_USERNAME/DB_PASSWORD para un rol LOGIN sin privilegios elevados, sin propiedad ni CREATE en el schema orchestrator, sin pertenencia a roles elevados. Configurar DB_MIGRATION_USERNAME/DB_MIGRATION_PASSWORD para el propietario que aplica Flyway. El DBA provisiona ambos; la aplicación no crea roles automáticamente. Después de las migraciones, el propietario concede los permisos de V2 mediante:

SELECT orchestrator.grant_runtime_access('orchestrator_app'::name);

El nombre es ilustrativo: el rol debe existir previamente. RuntimeRoleVerifier rechaza al iniciar administración un runtime elevado, propietario, con DDL en el schema, capaz de modificar historiales append-only o acceder a flyway_schema_history. Esta comprobación no configura permisos de otras bases/schemas: el DBA controla también los permisos heredados de PUBLIC, particularmente en PostgreSQL 9.6. No cambiar permisos globales del servidor para ejecutar las pruebas.

Prueba reproducible: mvnw.cmd clean verify -Pmigration-tests-external, con MIGRATION_TEST_DB_URL/USER/PASSWORD en entorno de proceso. Solo admite la base orquestador_test. T07 crea schema t07_ y rol LOGIN t07_runtime_, contraseña aleatoria y concesiones limitadas; los elimina en AfterAll. Las pruebas se conectan con ese rol real, no con SET ROLE ni una simulación de permisos. Sin perfil externo, verify requiere Docker y usa PostgreSQL de Testcontainers.

T09 integra ResourceAccess en aceptación de eventos y vuelve a filtrar propietario/ ámbito bajo SELECT FOR UPDATE. allowedRoles del flujo se comprueba para eventos nuevos. El replay requiere acceso actual y sujeto original, pero no vuelve a evaluar roles/guardias: solo consulta una aceptación anterior. actor_snapshot guarda atributos mínimos verificados; nunca JWT. Ver EVENTS.md.

T10: GET de ejecución usa ResourceAccess y repite owner/scope en la consulta SQL; no devuelve inputs, identidad snapshot, leases ni respuestas crudas. WORKER_ENABLED habilita infraestructura común y RuntimeRoleVerifier incluso con ambas APIs apagadas. El worker usa identidad mínima persistida al aceptar, no reutiliza JWT vencidos.

T15: historial y métricas

El historial de solicitudes exige propietario y businessScope iguales al JWT; FLOW_ADMIN/EXECUTION_OPERATOR no obtienen acceso a historial ajeno. La proyección no entrega evidencia de conciliación ni resultados completos de proveedores. /actuator/metrics y descendientes requieren EXECUTION_OPERATOR y ámbito autorizado en ADMIN_BUSINESS_SCOPES, incluso con FLOW_ADMIN_ENABLED=false. Las tres rutas health/liveness/readiness permanecen públicas sin detalles. Resto de /actuator/** se deniega. Ver OBSERVABILITY.md para etiquetas permitidas, cursor y logs.