Spring Boot Actuator expone información de monitorización imprescindible: salud, métricas, configuración, hilos, memoria. Esa misma información, en manos equivocadas, es un mapa detallado para atacar la aplicación.
Por defecto, solo /actuator/health y /actuator/info son accesibles vía HTTP. El resto requiere autenticación, pero la configuración por defecto no es suficiente para producción. Esta lección cubre cómo securizar Actuator de forma sólida.
Endpoints sensibles que conviene revisar
| Endpoint | Riesgo si es público |
|---|---|
| /actuator/env | Revela todas las propiedades, incluida URL de BD y secrets |
| /actuator/configprops | Lista de configuration properties con valores |
| /actuator/heapdump | Volcado completo del heap, contiene strings con tokens |
| /actuator/threaddump | Stack traces que pueden filtrar lógica interna |
| /actuator/httpexchanges | Últimas peticiones con cabeceras (incluida Authorization) |
| /actuator/loggers | Permite cambiar el nivel de logs en caliente, útil para inundar disco |
| /actuator/shutdown | Para la aplicación |
| /actuator/beans | Lista beans, util para mapear arquitectura interna |
Heap dump y env son los dos vectores más explotados en CVEs de Actuator. Trátalos como contraseñas: solo accesibles desde la red interna y con autenticación.
Configuración base segura
Empezamos por exponer solo los endpoints necesarios y nunca los administrativos.
management:
endpoints:
web:
exposure:
include: health, info, prometheus, metrics
endpoint:
health:
probes:
enabled: true
show-details: when-authorized
show-components: when-authorized
info:
git:
mode: full
exposure.includeen blanco lista lo que se expone, no lo que se oculta. Es la opción segura.show-details: when-authorizedevita revelar el estado de cada componente (BD, Redis, Kafka) a anónimos.
Para producción, excluye explícitamente lo peligroso aunque pienses que no está:
management:
endpoints:
web:
exposure:
include: "*"
exclude: env, configprops, heapdump, threaddump, beans, mappings, loggers, shutdown
Separar el management port
Una buena práctica en empresa es exponer Actuator en un puerto distinto al de la API pública. Ese puerto solo escucha desde la red de monitorización (Prometheus, Grafana, operadores).
server:
port: 8080
management:
server:
port: 9090
address: 127.0.0.1
Con esto, http://app:9090/actuator/* solo es accesible desde localhost. En Kubernetes, el Service que expone el management port nunca tiene LoadBalancer público; está restringido al namespace de monitoring por NetworkPolicy.
El truco es defensa en profundidad: aunque un Pod malicioso entrara al cluster, no podría llegar al management port si las NetworkPolicy están bien escritas.
SecurityFilterChain dedicado
Spring Security puede aplicar reglas distintas al management port mediante un SecurityFilterChain con securityMatcher específico.
@Configuration
public class ActuatorSecurityConfig {
@Bean
@Order(1)
SecurityFilterChain actuator(HttpSecurity http) throws Exception {
http
.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll()
.requestMatchers(EndpointRequest.to("prometheus")).hasAuthority("ROLE_PROMETHEUS")
.anyRequest().hasAuthority("ROLE_ACTUATOR"))
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable());
return http.build();
}
@Bean
@Order(2)
SecurityFilterChain api(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()));
return http.build();
}
}
EndpointRequest.toAnyEndpoint() matchea solo URLs de Actuator. EndpointRequest.to(...) permite filtrar por nombre o por clase.
El orden importa. La cadena más específica va primero (
@Order(1)). Si la API se evalúa antes, los endpoints de Actuator quedarán bajo la política general y romperá la separación.
Usuarios para Prometheus, operador y CI
Define usuarios diferenciados con autoridades específicas. Cada cliente accede solo a lo que necesita.
@Bean
UserDetailsService actuatorUsers(PasswordEncoder encoder) {
UserDetails prom = User.withUsername("prometheus")
.password(encoder.encode(System.getenv("PROMETHEUS_TOKEN")))
.authorities("ROLE_PROMETHEUS")
.build();
UserDetails ops = User.withUsername("ops")
.password(encoder.encode(System.getenv("OPS_TOKEN")))
.authorities("ROLE_ACTUATOR")
.build();
return new InMemoryUserDetailsManager(prom, ops);
}
- prometheus: scrappeo automatizado, solo
/actuator/prometheus. - ops: operador humano, acceso completo (no a
/heapdumpy/env, según política).
Las credenciales NO van en
application.yaml. Llegan como variables de entorno desde el secret manager.
Health endpoint con detalles selectivos
El endpoint /actuator/health es público por necesidad: lo consultan los probes de Kubernetes y los balanceadores. Pero su salida puede revelar más de lo conveniente.
management:
endpoint:
health:
show-details: never
show-components: never
group:
readiness:
include: db, redis
show-details: never
liveness:
include: ping
Con show-details: never, la respuesta es simplemente:
{ "status": "UP" }
Suficiente para los probes. Los detalles solo se muestran al operador que llega autenticado al endpoint general (no a los grupos readiness y liveness).
Métricas con Micrometer y dimensiones de seguridad
Micrometer es la abstracción de métricas de Spring Boot. Para enriquecer las métricas con información de seguridad sin filtrar PII, conviene definir tags acotados.
@Component
public class SecurityMetricsConfig implements MeterRegistryCustomizer<MeterRegistry> {
@Override
public void customize(MeterRegistry registry) {
registry.config()
.commonTags("application", "pagos-service", "tenant", System.getenv("TENANT"))
.meterFilter(MeterFilter.deny(id ->
id.getName().startsWith("jvm.classes.loaded")));
}
}
Los counters habituales de seguridad son:
spring_security_authentications_total{outcome="success|failure"}spring_security_filterchains_active{name="..."}http_server_requests_seconds{status="401|403|429"}
No incluyas
usernamecomo tag de métrica. Genera alta cardinalidad (un timeseries por usuario) que hunde Prometheus. Para cardinality alta, usa logs estructurados o trazas.
Auditoría de cambios en Actuator
Si permites cambiar loggers o disparar shutdown, registra todas esas operaciones en logs de auditoría. Spring Security publica AuthenticationSuccessEvent y AuthorizationDeniedEvent; suscríbete y persístelos.
@Component
public class ActuatorAuditListener {
private static final Logger log = LoggerFactory.getLogger("AUDIT");
@EventListener
public void onSuccess(AuthenticationSuccessEvent event) {
Authentication auth = event.getAuthentication();
if (auth.getDetails() instanceof WebAuthenticationDetails web
&& web.getRemoteAddress() != null) {
log.info("AUTH OK user={} ip={}", auth.getName(), web.getRemoteAddress());
}
}
}
Y registra qué endpoint se ha invocado con un Filter que loguea método, path y usuario.
CSRF en Actuator
Endpoints como /actuator/loggers/{name} aceptan POST. CSRF está activo por defecto, lo que rompe los scripts de operación.
- Si Actuator usa Basic Auth con cliente automatizado, deshabilita CSRF en su
SecurityFilterChain. Un cliente que envía Authorization Basic no es vulnerable a CSRF (la cookie no se reusa). - Si Actuator se usa solo desde navegador con sesión, mantén CSRF activo y exige el token.
.csrf(csrf -> csrf.disable())
Disable CSRF solo cuando el contexto sea exclusivamente Basic Auth o JWT. Nunca cuando haya cookies de sesión.
Errores frecuentes
- Exponer
*: incluye/heapdumpy/envpor defecto. Usa lista blanca explícita. - Reusar el SecurityFilterChain de la API: las reglas de la API REST (
csrf.disable,STATELESS) suelen no encajar con Actuator. Sepáralos. - Olvidar
management.server.address: si lo dejas en0.0.0.0, Actuator queda accesible desde fuera. - Métricas con username: alta cardinalidad y, en algunos sectores, viola GDPR al exportar datos personales a Prometheus.
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
Configurar Spring Boot Actuator para exponer solo endpoints seguros, separar el management port, restringir acceso con SecurityFilterChain dedicado y controlar quién consulta heap dumps o thread dumps.