La observabilidad es uno de los pilares modernos de las aplicaciones. Sin métricas y trazas, detectar un ataque o un cuello de botella en la capa de seguridad es prácticamente imposible.
Spring Security 6.4+ se integra con Micrometer Observation API, lo que permite exponer cada paso de la cadena de seguridad como una observación que se traduce en métricas Prometheus y trazas OpenTelemetry sin código manual.
Activar observaciones en Spring Security
El soporte está desactivado por defecto. Se habilita con un bean.
@Configuration
public class SecurityObservabilityConfig {
@Bean
SecurityObservationSettings observationSettings() {
return SecurityObservationSettings.withDefaults()
.shouldObserveRequests(true)
.shouldObserveAuthentications(true)
.shouldObserveAuthorizations(true)
.build();
}
}
Y necesitamos las dependencias:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
Con esto, cada paso del SecurityFilterChain produce una observación con nombre spring.security.filterchains y atributos como secured.uri, error o outcome.
Métricas relevantes para seguridad
Las métricas que conviene graficar en Grafana:
spring_security_authentications_seconds_count{outcome="success|failure"}: ratio de logins exitosos vs. fallidos. Un repunte de fallos indica fuerza bruta.spring_security_authorizations_seconds_count{authentication.failure.type=...}: denegaciones por tipo. Pico deAccessDeniedExceptionpuede ser enumeración.http_server_requests_seconds_count{status="401|403|429"}: respuestas de error agrupadas. Útil para alertas.spring_security_filterchains_seconds_count{spring.security.reached.filter.section=...}: ayuda a detectar latencia anormal en algún filtro.
management:
endpoints:
web:
exposure:
include: prometheus, health
metrics:
distribution:
percentiles-histogram:
spring.security: true
http.server.requests: true
No incluyas el
usernamecomo tag de métrica. Genera explosión de cardinalidad. Para auditoría individual, usa logs estructurados o trazas.
Trazas distribuidas con OpenTelemetry
Una traza captura el recorrido completo de una petición a través de varios microservicios. Con Spring Security observable, cada paso de seguridad se convierte en un span dentro de la traza.
management:
tracing:
sampling:
probability: 1.0
otlp:
tracing:
endpoint: "http://otel-collector:4318/v1/traces"
En Tempo, Jaeger o Zipkin verás algo como:
GET /api/pedidos
├── spring.security.filterchains [12 ms]
│ ├── spring.security.authentications [3 ms] outcome=success
│ └── spring.security.authorizations [1 ms] outcome=granted
├── controller.PedidoController#list [8 ms]
└── repository.PedidoRepository#findAll [42 ms]
Las trazas son la herramienta para investigar incidentes: ante un 403 inesperado, abres la traza y ves exactamente qué filter, qué expresión y qué autoridades intervinieron.
Tags personalizados con ObservationConvention
Si necesitas añadir tags propios (por ejemplo, el tenantId o el plan del cliente), implementa un ObservationConvention.
@Component
public class TenantObservationConvention implements ObservationConvention<HttpServerRequestObservationContext> {
@Override
public KeyValues getLowCardinalityKeyValues(HttpServerRequestObservationContext context) {
String tenant = TenantContext.get();
return KeyValues.of("tenant", tenant != null ? tenant : "unknown");
}
@Override
public boolean supportsContext(Observation.Context context) {
return context instanceof HttpServerRequestObservationContext;
}
}
Spring Boot detecta el bean y aplica el convention a todas las peticiones HTTP.
Los low cardinality son tags con pocos valores posibles (
tenant,plan,region). Los high cardinality (username,pedidoId) van a metadata de spans, no a métricas.
MDC para correlación en logs
El Mapped Diagnostic Context (MDC) de SLF4J permite que cada línea de log incluya información contextual sin pasarla manualmente.
Spring Security puede poblarlo automáticamente:
@Component
public class SecurityMdcFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws ServletException, IOException {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.isAuthenticated()) {
MDC.put("user", auth.getName());
}
MDC.put("requestId", req.getHeader("X-Request-Id") != null
? req.getHeader("X-Request-Id")
: UUID.randomUUID().toString());
try {
chain.doFilter(req, res);
} finally {
MDC.clear();
}
}
}
Y configura Logback para incluir esos campos:
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>user</includeMdcKeyName>
<includeMdcKeyName>requestId</includeMdcKeyName>
<includeMdcKeyName>traceId</includeMdcKeyName>
</encoder>
</appender>
Cada log queda enriquecido con
user,requestIdytraceId. Buscar todos los logs de una petición concreta es tan simple como filtrar portraceId.
SLOs de seguridad
Define SLOs (Service Level Objectives) específicos para la capa de seguridad y aliméntalos con las métricas.
- SLO de autenticación: 99.9 % de respuestas a
/auth/loginpor debajo de 500 ms. - SLO de denegación: ratio
403 / totalpor debajo del 1 % en horario laboral. - SLO de fallos de login: menos de 5 fallos por minuto por IP origen.
Configurarlos en Grafana o Datadog como reglas de alerta:
sum(rate(spring_security_authentications_seconds_count{outcome="failure"}[5m]))
by (instance)
> 50
Si la tasa de fallos pasa de 50/s, envía PagerDuty.
Métricas custom para eventos de seguridad
Para auditar eventos específicos (cambios de rol, accesos a datos sensibles, exportaciones), define counters con Micrometer.
@Component
public class AuditMetrics {
private final Counter rolesCambiados;
public AuditMetrics(MeterRegistry registry) {
this.rolesCambiados = Counter.builder("auditoria_roles_cambiados_total")
.description("Cambios de rol detectados")
.register(registry);
}
public void incrementarCambioRol(String tipo) {
Counter.builder("auditoria_roles_cambiados_total")
.tag("tipo", tipo)
.register(Metrics.globalRegistry)
.increment();
}
}
Y en el servicio:
@Transactional
public void asignarRol(Long userId, String nuevoRol) {
repo.actualizarRol(userId, nuevoRol);
metrics.incrementarCambioRol(nuevoRol);
}
Detección de anomalías
Las métricas básicas se complementan con detección de anomalías, que compara el patrón actual con el histórico.
- Prometheus + Grafana: alerta cuando una métrica supera N desviaciones estándar respecto a la media de las últimas 24h.
- OpenSearch / Elastic SIEM: análisis ML sobre logs.
- Datadog Watchdog: detección automática de anomalías sin configuración.
Patrones que vale la pena vigilar:
- Picos de fallos de login concentrados en una IP o un usuario.
- Accesos exitosos desde geolocalizaciones inusuales (geoip lookup).
- Cambios de patrón en la distribución de scopes solicitados.
- Latencia anormal en la verificación de JWT (puede ser ataque al JWK Set).
Errores frecuentes
- Cardinalidad explosiva: poner
userIdorequestIdcomo tag rompe Prometheus. Usa labels solo con cardinalidad baja. - Loguear
Authorizationcompleto: filtra el headerAuthorizationantes de loguear cualquier cosa. Lo mismo con cookies de sesión. - No alertar sobre 401/403: muchas organizaciones solo monitorizan 5xx. Los 4xx son la pista número uno de un ataque en curso.
- Confiar en logs sin trazas: un 403 sin contexto cuesta horas debugar. Las trazas dan el "cómo se llegó hasta aquí" gratis.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Spring Security es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Spring Security
Explora más contenido relacionado con Spring Security y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Instrumentar la cadena de filtros de Spring Security con Micrometer Observation, exponer métricas y trazas con tags útiles y enriquecer logs con MDC sin filtrar PII.