Custom actuator (Spring Boot)

1. Introduction


11. Security

For security purposes, only the /health endpoint is exposed over HTTP by default. You can use the management.endpoints.web.exposure.include property to configure the endpoints that are exposed.

Note: Before setting the management.endpoints.web.exposure.include, ensure that the exposed actuators do not contain sensitive information, are secured by placing them behind a firewall, or are secured by something like Spring Security.


11.1. Web Endpoint Security

An operation on a web endpoint or a web-specific endpoint extension can receive the current java.security.Principal or org.springframework.boot.actuate.endpoint.SecurityContext as a method parameter. The former is typically used in conjunction with @Nullable to provide different behavior for authenticated and unauthenticated users. The latter is typically used to perform authorization checks by using its isUserInRole(String) method.


31. Feature flags custom endpoint (example)

Let's create an Actuator endpoint to query, enable, and disable feature flags in our application (aka Feature toggles):

package edu.cou.mayapp.featureflag;


import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;


import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;

import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;

import org.springframework.boot.actuate.endpoint.annotation.Selector;

import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;

import org.springframework.stereotype.Component;


import lombok.Getter;

import lombok.Setter;


/**

* Actuator endpoint to query, enable, and disable feature flags in this application.

*

* Warning: Before setting the management.endpoints.web.exposure.include, ensure that the exposed

* actuators do not contain sensitive information, are secured by placing them behind a firewall, or

* are secured by something like Spring Security.

*

* <pre>

* == myapp endpoints==

*

* /rest/actuator/featureflags

* /rest/actuator/featureflags/{name}

* </pre>

*/

@Component

@Endpoint(id = "featureflags"/* , enableByDefault = false */)

public class FeatureFlagEndpoint {


private Map<String, FeatureFlag> features = new ConcurrentHashMap<>();


/** HTTP GET */

@ReadOperation

public Map<String, FeatureFlag> features() {

return features;

}


/** HTTP GET */

@ReadOperation

public FeatureFlag feature(@Selector String name) {

return features.get(name);

}


/** HTTP POST */

@WriteOperation

public void configureFeature(@Selector String name, FeatureFlag feature) {

features.put(name, feature);

}


/** HTTP DELETE */

@DeleteOperation

public void deleteFeature(@Selector String name) {

features.remove(name);

}


/**

* Class Feature.

*/

@Builder

@Getter

@Setter

public static class FeatureFlag {

private boolean enabled;

} // Class FeatureFlag


}