How are custom Actuator endpoints discovered and registered, and what are the exposure/security implications of adding a @WriteOperation endpoint in production?
answer
- EndpointDiscoverer per technology (Web/Jmx)
- WebMvcEndpointHandlerMapping routes /actuator/**
- never exposure.include=*
- secure with Spring Security + EndpointRequest matcher
- separate management.server.port; sanitize env; audit writes
basics
~20 sActuator scans @Endpoint-annotated beans via EndpointDiscoverers and registers them per technology (web/JMX). A @WriteOperation is a POST that mutates state, so you must both restrict web exposure (not *) and secure it — require an ADMIN role for /actuator/**, and treat it like any mutating API.
solid answer
~50 sAt startup Actuator's EndpointDiscoverer implementations (WebEndpointDiscoverer, JmxEndpointDiscoverer) scan the context for beans annotated @Endpoint/@WebEndpoint/@JmxEndpoint plus their extensions, build ExposableEndpoint metadata (id, operations, selectors, media types), and register them with the appropriate infrastructure — web endpoints get mapped by WebMvcEndpointHandlerMapping (or WebFlux/Jersey equivalents) under the actuator base path. Enablement and exposure are filtered here. For a mutating @WriteOperation endpoint in production the risks are real: it changes state over HTTP. Never expose with '*'; include only the ids you need. Secure /actuator/** with Spring Security — a dedicated authorization rule requiring an admin role, ideally on a separate management port/context so it isn't reachable from the public app. Validate and bound all inputs, audit-log the action, consider CSRF (Actuator write ops are POST/DELETE), and prefer read-only endpoints unless a management action is genuinely needed. Also mind that exposing env/configprops can leak secrets.
code
java · 20 linesimport org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class ActuatorSecurity {
@Bean
SecurityFilterChain actuatorChain(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(reg -> reg
.requestMatchers(EndpointRequest.to("health")).permitAll()
.anyRequest().hasRole("ADMIN")) // mutating write ops require admin
.httpBasic(withDefaults());
return http.build();
}
}
// application.yml — expose only what you need, ideally on a private port:
// management.server.port: 9001
// management.endpoints.web.exposure.include: health,featuresgo deeper
Know endpoints are auto-discovered and that write endpoints need to be secured and exposed deliberately.
Explain the enabled/exposed gates and adding a Spring Security rule for /actuator/**.
Describe EndpointDiscoverer/handler-mapping registration and the EndpointRequest-based authorization.
Reason about management-plane design: separate port, least exposure, secret sanitization, auditing, CSRF, and when a mutating endpoint belongs in the management plane at all.
## Discovery and registration pipeline Actuator resolves endpoints at context refresh through **`EndpointDiscoverer`** implementations, one per technology: - `WebEndpointDiscoverer` — finds `@Endpoint` and `@WebEndpoint` beans (and `@EndpointWebExtension`s). - `JmxEndpointDiscoverer` — finds `@Endpoint` and `@JmxEndpoint` beans (and `@EndpointJmxExtension`s). Each discoverer scans the `ApplicationContext` for annotated beans, reads their operation methods (`@ReadOperation`/`@WriteOperation`/`@DeleteOperation`), resolves `@Selector`s, media types, and produces `ExposableWebEndpoint` / `ExposableJmxEndpoint` metadata objects describing id + operations. **Exposure and enablement filters** are applied during discovery so only enabled, exposed endpoints survive. For web, the resulting endpoints are wired into a handler mapping — `WebMvcEndpointHandlerMapping` on MVC (WebFlux/Jersey have equivalents) — which routes requests under `management.endpoints.web.base-path` (default `/actuator`) to the operation methods, adapting HTTP request/response to/from the operation invocation (query/body binding, selectors, media-type negotiation). JMX endpoints are registered as MBeans. ## Enablement vs exposure (recap, precise) - `management.endpoints.enabled-by-default` and `management.endpoint.<id>.enabled` control whether the endpoint is created. - `management.endpoints.web.exposure.include/exclude` and `...jmx.exposure.include/exclude` control reachability per technology. Web default exposes only `health`. ## Why a @WriteOperation demands extra care A `@WriteOperation`/`@DeleteOperation` **mutates state over HTTP**. Adding one turns `/actuator/<id>` into a management action surface. Principal-level concerns: 1. **Least exposure** — never `exposure.include=*`; enumerate ids. `*` will also web-expose sensitive built-ins (`env`, `configprops`, `heapdump`, `threaddump`, `loggers` write, `shutdown` if enabled). 2. **Authorization** — Actuator does not secure itself; you configure Spring Security. Add an authorization rule (e.g. `EndpointRequest.toAnyEndpoint()` matcher) requiring an admin authority. Consider a separate **management port** (`management.server.port`) and address so the actuator surface isn't served on the public application connector. 3. **CSRF / method** — write ops are POST/DELETE; if the management context uses cookie auth, CSRF applies; token/mTLS auth on a separate port is cleaner. 4. **Input validation** — bound and validate selector/body params; a management action toggling behavior is a privileged operation. 5. **Auditing** — log who invoked the mutation (Actuator integrates with the audit events endpoint / `AuditEventRepository`). 6. **Info leakage** — reads can be as dangerous as writes: `env`/`configprops` can expose secrets; sanitize via `management.endpoint.env.show-values`/`keys-to-sanitize` and don't expose them broadly. 7. **Blast radius** — prefer read-only telemetry endpoints; only add mutating ones when an operational action truly belongs in the management plane rather than a normal secured API. ## Testing Spring Boot provides slice/support for endpoint tests; you can unit-test the endpoint bean directly, and use `@WebMvcTest`-style or `WebTestClient`/`MockMvc` against the handler mapping to assert routing, status codes (204/404/406/415), and security. ## Gotchas - Endpoints are discovered from the context, so a `@Bean`-declared endpoint works identically to a `@Component` one; conditional beans mean conditional endpoints. - Changing the base path or moving to a separate management port changes URLs and security matchers. - `shutdown` is the only endpoint disabled by default — enabling and exposing it is a frequent security mistake.
- A team exposes actuator with include=* to 'debug easily'. What do you flag?It web-exposes sensitive endpoints (env, configprops, heapdump, threaddump, loggers writes). Enumerate needed ids instead, secure /actuator/** with an admin role, sanitize env values, and ideally serve actuator on a separate management port.
- Where does the actuator security boundary live relative to the app's own Spring Security config?Actuator ships no security of its own; you add a SecurityFilterChain (often matched via EndpointRequest) — either within the app or on a separate management port/context — so endpoints, especially write ops, require the right authority.
saying these in an interview costs you the question
- Believing Actuator secures endpoints automatically
- Using exposure.include=* in production
- Ignoring that env/configprops reads can leak secrets
- Treating a @WriteOperation as harmless because it's 'just actuator'
- Forgetting shutdown is disabled by default for a reason