[JAVA] Spring Boot 2.0 Actuator, 3 changes you need to know to get it working

It's no exaggeration to say that Actuator is the most modified feature of Spring Boot 2.0. If you raise the details, there will be no sharp edges, so for the time being, here are some points to be aware of when migrating from 1.x.

URL prefix is added by default

Probably the most common error in Actuator when upgrading an existing app made with Boot 1.x to 2.0 is "404 Not Found" (at least I did). In fact, since 2.0, all Actuator endpoints have been prefixed with / actuator. In other words, the URL that was previously specified as localhost: 8080 / info must be changed to localhost: 8080 / actuator / info.

This prefix can be changed with the following properties.

application.Examples of properties


#The default value is"/actuator"
management.endpoints.web.base-path=/admin

You can also change the port number for the Actuator endpoint and add a context path. Please note that if you do not specify the port number, the context path will not be attached.

application.Examples of properties


management.server.port=9999
management.server.servlet.context-path=/admin-context

In other words, if you write all the above three settings, the Actuator endpoint will be localhost: 9999 / admin-context / admin / info.

By default only / info and / health are published

This also causes a 404 error. / env, / beans, etc. are not published by default. Set the endpoint you want to publish as follows.

application.Examples of properties


management.endpoints.web.exposure.include=env,beans,loggers

If you specify even one, it will not be published unless you explicitly specify / info and / health.

Specify * if you want to publish all endpoints.

application.Examples of properties


management.endpoints.web.exposure.include=*

Conversely, endpoints that are not exposed are specified in management.endpoints.web.exposure.exclude. For example, if you write as follows, all endpoints except / env and / info will be published.

application.Examples of properties


management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,info

Endpoints that are set to publish but are not individually activated will not be published. For example, if you write as follows, only / beans and / health will be published. Although / auditevents is specified as public, it will not be published because it has been disabled.

application.Examples of properties


management.endpoints.web.exposure.include=auditevents,beans,health
# /auditevents are disabled and will not be published
management.endpoint.auditevents.enabled=false

Each endpoint can be enabled with management.endpoint.xxxxx.enabled (xxxxx is the endpoint name)

No longer protected by default

Starting with Spring Boot 1.5, sensitive Actuator endpoints have been protected (only users with the ʻACTUATOR` role can access them).

With Spring Boot 2.0, the concept of sensitive is gone in the first place, and all publicly available endpoints are no longer protected. To secure the endpoint, you need to explicitly include Spring Security and write the security settings in Java Config.

pom.xml


...
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--Added Spring Security!-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        ...
    </dependencies>
...

JavaConfig example


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //Create general users and users to access Actuator
        //(User name, password, role name are optional)
        auth.inMemoryAuthentication()
                .passwordEncoder(NoOpPasswordEncoder.getInstance()) //NoOpPasswordEncoder is prohibited in production!
                .withUser("actuator").password("password").roles("ACTUATOR").and()
                .withUser("user").password("password").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //Enable BASIC authentication
        http.httpBasic();
        //Actuator endpoints can only be accessed by the ACTUATOR role,
        //Others can be accessed by any role as long as you are logged in
        http.authorizeRequests()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
                .anyRequest().authenticated();

        //Do not disable CSRF in production!
        http.csrf().disable();
    }
}

Note that there are two ʻEndpointRequest classes, one for Servlet and one for Reactive. This time we are assuming a Servlet base, so use the ʻEndpointRequest class in the ʻorg.springframework.boot.actuate.autoconfigure.security.servlet` package.

Access example with curl


$ curl -v -u actuator:password localhost:8080/actuator/health | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
* Server auth using Basic with user 'actuator'
> GET /actuator/health HTTP/1.1
> Host: localhost:8080
> Authorization: Basic YWN0dWF0b3I6cGFzc3dvcmQ=
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=C472F3844F17FC8EBC779A35DEFB085F; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Fri, 09 Mar 2018 07:03:55 GMT
<
{ [20 bytes data]
100    15    0    15    0     0    165      0 --:--:-- --:--:-- --:--:--   166
* Connection #0 to host localhost left intact
{
  "status": "UP"
}

Finally

If you pay attention to the above three points, you should be able to upgrade the app created in 1.x to 2.0 and run it for the time being. However, there are many other changes to Actuator, so be sure to read through the Actuator chapter in the official docs! https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready.html I'd like to write a blog explaining this ... Well, please wait patiently!

Recommended Posts

Spring Boot 2.0 Actuator, 3 changes you need to know to get it working
Changes when migrating from Spring Boot 1.5 to Spring Boot 2.0
Changes when migrating from Spring Boot 2.0 to Spring Boot 2.2
[Spring Boot] If you use Spring Boot, it was convenient to use a lot of util.
If you want to separate Spring Boot + Thymeleaf processing
Until you create a Spring Boot project in Intellij and push it to Github
[IOS] What you need to know before creating a widget
I tried to get started with Swagger using Spring Boot
Try Spring Boot from 0 to 100.
Get started with Spring boot
Introduction to Spring Boot ① ~ DI ~
Introduction to Spring Boot ② ~ AOP ~
Major changes in Spring Boot 1.5
Introduction to Spring Boot Part 1
Spring Boot validation message changes
If you get tired of "Spring Boot", why not try "jooby"?
How to set Spring Boot + PostgreSQL
Spring Boot Actuator logback_events_total metric value
Get validation results with Spring Boot
How to use ModelMapper (Spring boot)
Upgrade spring boot from 1.5 series to 2.0 series
To you who absolutely need backtrace
How to apply thymeleaf changes to the browser immediately with #Spring Boot + maven
[Spring Boot Actuator] How to manually register your own health check process