15.4 Securing Actuator
The information presented by Actuator is probably not something that you would want prying eyes to see. Moreover, because Actuator provides a few operations that let you change environment properties and logging levels, it’s probably a good idea to secure Actuator so that only clients with proper access will be allowed to consume its endpoints.
Even though it’s important to secure Actuator, security is outside of Actuator’s responsibilities. Instead, you’ll need to use Spring Security to secure Actuator. And because Actuator endpoints are just paths in the application like any other path in the application, there’s nothing unique about securing Actuator versus any other application path. Everything we discussed in chapter 5 applies when securing Actuator endpoints.
Because all Actuator endpoints are gathered under a common base path of /actuator (or possibly some other base path if the management.endpoints.web.base-path property is set), it’s easy to apply authorization rules to all Actuator endpoints across the board. For example, to require that a user have ROLE_ADMIN authority to invoke Actuator endpoints, you might override the configure() method of WebSecurityConfigurerAdapter like this:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/actuator/**").hasRole("ADMIN")
.and()
.httpBasic();
}This requires that all requests be from an authenticated user with ROLE_ADMIN authority. It also configures HTTP basic authentication so that client applications can submit encoded authentication information in their request Authorization headers.
The only real problem with securing Actuator this way is that the path to the endpoints is hardcoded as /actuator/** . If this were to change because of a change to the management.endpoints.web.base-path property, it would no longer work. To help with this, Spring Boot also provides EndpointRequest — a request matcher class that makes this even easier and less dependent on a given String path. Using EndpointRequest, you can apply the same security requirements for Actuator endpoints without hardcoding the /actuator/** path, as shown here:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}The EndpointRequest.toAnyEndpoint() method returns a request matcher that matches any Actuator endpoint. If you’d like to exclude some of the endpoints from the request matcher, you can call excluding(), specifying them by name as follows:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.toAnyEndpoint().excluding("health", "info"))
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}On the other hand, should you wish to apply security to only a handful of Actuator endpoints, you can specify those endpoints by name by calling to() instead of toAnyEndpoint(), like this:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.to("beans", "threaddump", "loggers"))
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}This limits Actuator security to only the /beans, /threaddump, and /loggers endpoints. All other Actuator endpoints are left wide open.
