0
votes

I implement HealthIndicator to spring boot app (actuator 2.5.1) and tried to tweak settings a little bit. Unfortunately, documentation does not "clearly" states default values. And when I dig them ... I experience different behavior. Could you please point me whether it is misunderstanding / misconfiguration / bug? Thank you.

Question:

How to set up actuator to allow anonymous calls to both endpoint: /actuator/health and /actuator/health/custom with simple response (without details nor components). And both endpoint return full details for authenticated(and authorized) requests.

Unfortunately, situation is complicated by spring security configuration... I have two scopes

  • /api/** for SPA aplications with JWT auth
  • /api2/** for other tools with basic auth
  • (nothing else is explicitly handled. So, /actuator/** is accessible for all)

Case 1: default configuration

@Component
public class CustomHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        ...
        return Health
            .status(...)
            .withDetail("detailDto", detailDto)
            .build();
    }
}

default configuration docs management.endpoint.health.show-details=never

Expected response for /actuator/health

{"status":"DOWN"}

BUG?: Real response is WITH details (agains default value: never)

{
  "status": "DOWN",
  "components": {
    "blobStorage": {
      "status": "DOWN",
      "details": ...
    },
    "diskSpace": {
      "status": "UP",
      "details": ...
    },
    "custom": {
      "status": "UP",
      "details": ...
    },
    "ping": {
      "status": "UP"
    }
  }
}

Expected response for /actuator/health/custom, is WITHOUT details, but real response is WITH details. That details are accessible in default config looks to me as a BUG.

Case 2: changed configuration

management.endpoint.health.show-details=when-authorized

Expected behavior is that since I did not add security to /actuator/**. Any request will be handled as unauthorized, so it should return json WITHOUT detail. Real response for /actuator/health is as expected - just status: {"status":"DOWN"}. BUT real response for /actuator/health/custom is HTTP 404 NOT FOUND ?!? Why is whole custom health endpoint disabled? And if any than I would expect HTTP 401 UNAUTHENTICATED. Looks like a BUG. Anyhow, I expected that /actuator/health/custom will functional, but without details: {"status":"DOWN"}

Case 3: changed configuration

management.endpoint.health.show-components=when-authorized
management.endpoint.health.show-details=when-authorized

And add security for /actuator/**

    @Configuration
    @Order(3)
    public static class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           ...
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/actuator/**")
                    .authorizeRequests(authorize -> authorize
                            .anyRequest().permitAll()
                    )
                    .httpBasic();
                    // ?????
        }
    }

Endpoints /actuator/health returns {"status":"DOWN"} for annonymous and full details for authenticated requests as expected. But endpoint /actuator/health/custom still working only for authenticated requests. It returns 404 NOT FOUND for annonymous calls. I do not know how to setup security correctly as is mentioned in docs:

If you have secured your application and wish to use always, your security configuration must permit access to the health endpoint for both authenticated and unauthenticated users.

2

2 Answers

0
votes

Grant access to all in actuator endpoints:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatcher("/actuator/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                ...
    }
0
votes

Return only this and check the status :

builder.build().getStatus()  OR
builder.build().getStatus().getCode()

I generally do this way instead of getting the all the details.

Also keep the properties like this :

management:
  endpoint:
    health:
      sensitive: false
      show-details: never
    dependency-health-check:
      enabled: false
    diskspace:
      enabled: false
    details:
      enabled: false
    application:
      enabled: true