Spring Boot Actuator: qué exponer, qué ocultar y qué mirar antes de agregar endpoints
Estaba revisando la configuración de un backend Spring Boot en un escenario de prueba cuando noté que /actuator/env respondía sin autenticación. Nada de producción, nada crítico — pero la configuración era la default de alguien que agregó la dependencia, vio que /actuator/health funcionaba, y siguió. El endpoint env expone variables de entorno activas, incluyendo cualquier cosa que haya en el contexto de Spring. En un ambiente real, eso puede incluir credenciales interpoladas, URLs internas o flags de feature que no deberían ser públicos.
Mi tesis es esta: Actuator no es malo. Es una herramienta operativa seria, documentada y útil. El error es agregarlo sin decidir qué querés exponer, a quién y con qué restricciones. La mayoría de los tutoriales te dicen cómo habilitarlo. Casi ninguno te explica el costo de habilitarlo mal.
Spring Boot Actuator endpoints seguridad: qué dice la documentación oficial
La documentación oficial de Spring Boot Actuator es explícita en algo que mucha gente ignora: los endpoints tienen dos dimensiones independientes — estar habilitados y estar expuestos.
Un endpoint puede estar habilitado (activo en el contexto de la aplicación) pero no expuesto por HTTP. Por defecto, solo health está expuesto vía HTTP. El resto requiere configuración explícita.
Esto es importante porque el comportamiento por defecto es conservador — pero fácil de sobreescribir con una sola línea:
# application.yml
management:
endpoints:
web:
exposure:
include: "*" # Expone TODO — incluyendo lo que no querés exponer
Esa línea aparece en cientos de tutoriales como "para ver todos los endpoints disponibles". Lo cual está bien en localhost. Es un problema si llega a un ambiente compartido o a producción sin revisión.
La doc también distingue entre JMX y HTTP como canales de exposición separados. Por defecto, JMX expone todos los endpoints habilitados, mientras que HTTP es más restrictivo. Si tu aplicación no usa JMX activamente, vale la pena deshabilitar ese canal también.
Los endpoints que merecen atención antes de exponerlos
| Endpoint | Qué expone | Riesgo si está público |
|---|---|---|
/actuator/env |
Variables de entorno del contexto Spring | Alto — puede incluir credenciales |
/actuator/beans |
Todos los beans registrados | Medio — revela arquitectura interna |
/actuator/heapdump |
Dump de memoria JVM | Alto — puede contener datos sensibles en heap |
/actuator/mappings |
Todos los endpoints HTTP de la app | Medio — facilita reconnaissance |
/actuator/loggers |
Configuración de logging activa | Bajo-Medio — permite cambiar niveles en runtime |
/actuator/metrics |
Métricas de la JVM y la app | Bajo — útil internamente, poco valor expuesto |
/actuator/health |
Estado operativo de la app | Bajo si está bien configurado |
Esta tabla no es exhaustiva — la lista completa de endpoints built-in está en la documentación oficial. Pero cubre los más frecuentes y los que generan más discusión.
Dónde se equivoca la gente: la receta fácil y su costo oculto
El patrón más común que veo en proyectos con Actuator mal configurado no es descuido — es acumulación. Alguien agrega spring-boot-starter-actuator para tener /health disponible para el load balancer. Después otro agrega include: "*" para debuggear algo. Después nadie limpia.
El problema con include: "*" no es solo lo que expone hoy — es que expone automáticamente cualquier endpoint que se agregue en el futuro, incluyendo endpoints de librerías de terceros que se integran con Actuator. Spring Security, Micrometer, Spring Cloud y otros frameworks pueden registrar sus propios endpoints bajo /actuator/. Si tenés include: "*", se exponen solos.
# Lo que deberías tener en lugar de "*"
management:
endpoints:
web:
exposure:
# Listado explícito: sabés exactamente qué está expuesto
include: "health,info,metrics"
# Todo lo demás queda bloqueado por defecto
endpoint:
health:
# Mostrá detalles solo a usuarios autenticados
show-details: when_authorized
# Separar el puerto de management del puerto de la app
server:
port: 8081
Ese último punto — management.server.port — es el cambio más práctico que podés hacer. Si Actuator corre en un puerto separado, podés protegerlo a nivel de red (firewall, security group, nginx) sin tocar la lógica de la aplicación. El puerto 8081 nunca llega al load balancer público. El 8080 sí.
Otro error común: confiar en que Spring Security protege Actuator automáticamente. Por defecto, si tenés Spring Security en el classpath, los endpoints de Actuator quedan protegidos con las mismas reglas del resto de la app — pero eso no siempre es suficiente. Vale la pena ser explícito:
// SecurityConfig.java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// Solo /health y /info sin autenticación
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
// El resto de actuator requiere rol ADMIN
.requestMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
return http.build();
}
Esto es más robusto que depender del comportamiento implícito, y además es documentación viva: quien lea la config entiende exactamente qué está protegido y cómo.
Checklist de decisión antes de agregar Actuator a un proyecto
Antes de hacer el primer deploy con Actuator habilitado, estas son las preguntas que vale la pena responder:
Sobre exposición:
- [ ] ¿Listaste explícitamente qué endpoints querés exponer? ¿O usaste
"*"? - [ ] ¿Actuator corre en un puerto separado del puerto de la aplicación?
- [ ] ¿Ese puerto de management está bloqueado para tráfico externo?
Sobre autenticación:
- [ ] ¿Los endpoints sensibles (
env,beans,heapdump) requieren autenticación? - [ ] ¿
healthexpone detalles (show-details) sin restricción? ¿Querés eso? - [ ] ¿Tenés Spring Security configurado explícitamente para
/actuator/**, o dependés del comportamiento por defecto?
Sobre información expuesta:
- [ ] ¿Revisaste qué devuelve
/actuator/enven el ambiente donde va a correr? - [ ] ¿Hay variables de entorno con credenciales que aparecen en ese endpoint?
- [ ] ¿
/actuator/infoexpone versiones, git commit o metadata que no querés pública?
Sobre JMX:
- [ ] Si no usás JMX, ¿lo deshabilitaste?
# Deshabilitar JMX si no lo usás
spring:
jmx:
enabled: false
Este checklist no garantiza seguridad total — eso depende del contexto completo de la aplicación, la red y el ambiente. Pero cubre las decisiones que más frecuentemente quedan sin tomar.
Qué no podés concluir sin datos propios
Hay algo que esta guía no puede hacer por vos: decirte qué endpoints específicamente necesitás en producción.
Eso depende de cómo monitoreas la aplicación. Si usás Prometheus + Grafana, /actuator/prometheus es útil — pero si usás Datadog con el agente instalado, probablemente no necesitás exponerlo en absoluto. Si tenés un load balancer que hace health checks, necesitás /actuator/health — pero si usás Kubernetes con liveness/readiness probes apuntando a un endpoint propio, podés separar eso de Actuator completamente.
También: el comportamiento de show-details: when_authorized depende de cómo Spring Security está configurado en ese contexto. Sin revisar la configuración real de seguridad de la app, ese setting puede comportarse diferente a lo esperado.
Lo que sí podés hacer hoy: arrancar con exposición mínima y agregar endpoints con intención, no con "*". Es más fácil agregar que quitar — especialmente si ya hay ambientes que dependen del estado actual.
Una referencia útil si estás evaluando la integración con observabilidad: en el post sobre Docker healthchecks hay un análisis de qué miden realmente los checks de disponibilidad y qué no deberían prometer — aplica directamente si estás decidiendo si Actuator /health es suficiente para tus probes o necesitás algo más granular.
FAQ: Spring Boot Actuator y seguridad de endpoints
¿Qué endpoints expone Actuator por defecto vía HTTP?
Solo /actuator/health está expuesto por HTTP en la configuración por defecto. El resto requiere declaración explícita en management.endpoints.web.exposure.include. Podés verificarlo en la documentación oficial.
¿include: "*" es siempre un problema?
En localhost para desarrollo, no. En un ambiente compartido, staging con red semipública o producción, sí — porque expone endpoints actuales y futuros sin revisión. El riesgo no es solo lo que exponés hoy, sino lo que se agrega automáticamente cuando actualizás dependencias.
¿Spring Security protege Actuator automáticamente si está en el classpath?
Parcialmente. Spring Security aplica las reglas de seguridad de la aplicación a Actuator, pero el comportamiento concreto depende de cómo esté configurado. La práctica recomendada es ser explícito con un requestMatchers("/actuator/**") en la configuración de seguridad.
¿Vale la pena separar el puerto de Actuator del puerto de la aplicación?
Sí, y es probablemente el cambio de mayor impacto con menor complejidad. Con management.server.port: 8081, podés proteger ese puerto a nivel de red sin tocar el código de la aplicación. El load balancer público solo ve el 8080.
¿/actuator/health puede exponer información sensible?
Sí, si show-details está en always. En ese modo, el endpoint devuelve el estado de cada componente — base de datos, cache, servicios externos — con detalles que pueden revelar URLs internas o estados de dependencias. show-details: when_authorized es el setting más conservador para ambientes expuestos.
¿Cómo sé qué endpoints registraron mis dependencias de terceros?
Podés consultarlo en runtime con una llamada a /actuator (el endpoint raíz, si está expuesto), que devuelve el mapa de todos los endpoints disponibles. También podés habilitarlo solo en desarrollo con profiles de Spring: @Profile("dev") en el bean de configuración o usando spring.profiles.active para cargar un application-dev.yml con include: "*".
Mi postura final: Actuator como herramienta operativa, no como default
Actuator es una de las partes mejor diseñadas del ecosistema Spring Boot. La separación entre habilitado/expuesto, la integración con Micrometer, el soporte nativo para health indicators personalizados — todo eso tiene valor operativo real.
Lo que no tiene valor es agregarlo como "viene en el starter, por las dudas". Esa lógica funciona en desarrollo. En un ambiente con red real, es una superficie que crece sola cada vez que actualizás dependencias.
Mi recomendación práctica: empezá con include: "health,info", separé el puerto de management desde el primer deploy, y agregá endpoints con intención cuando tengas un consumidor concreto — un dashboard de métricas, una herramienta de APM, un script de diagnóstico. Si no sabés quién consume el endpoint, probablemente no necesitás exponerlo todavía.
Si estás construyendo un backend con decisiones de seguridad en capas, puede ser útil revisar también el post sobre arquitectura backend de identidad digital — el criterio de "qué exponer y con qué restricciones" aplica en ambos contextos con lógica similar.
Fuente original:
- Spring Boot Actuator — Endpoints: https://docs.spring.io/spring-boot/reference/actuator/endpoints.html
Este artículo fue publicado originalmente en juanchi.dev
Top comments (0)