Sanitize Actuator Endpoint with Spring Boot 3

Ronghui Ryan Ye
Level Up Coding
Published in
3 min readApr 1, 2023

--

This page is about implementing sanitize function for actuator endpoint.

What Is an Actuator

In essence, Actuator brings production-ready features to our application. Actuator is mainly used to expose operational information about the running application — health, metrics, info, dump, env, etc. It uses HTTP endpoints or JMX beans to enable us to interact with it.

Getting Started

To enable Spring Boot Actuator, add the following dependency.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Actuator comes with most endpoints disabled, the only two available by default are /health and /info. In the example, we will expose all endpoints.

management:
endpoints:
web:
exposure:
include: '*'

After Springboot 3, all values are masked with “*” under actuator endpoint by default.

Values can be showed by setting management.endpoint.env.show-values to always in application.yml.

management:
endpoints:
web:
exposure:
include: '*'
endpoint:
env:
show-values: always

Sanitize Function

What if we don’t want to show sensitive data like password or secret? Then sanitize function comes into play.

A sanitizingFunction interface needs to be implemented, and apply whatever logic fits your use cases in the apply method. In the following example, all fields other than password and secret will be showed in plain text while password and secret will be masked with “*”, and additional keys can be set by management.endpoint.additionalKeysToSanitize

@Component
public class ActuatorSanitizer implements SanitizingFunction {

private static final String[] REGEX_PARTS = {"*", "$", "^", "+"};
private static final Set<String> DEFAULT_KEYS_TO_SANITIZE = Set.of("password","secret");
private final List<Pattern> keysToSanitize = new ArrayList<>();

public ActuatorSanitizer(@Value("${management.endpoint.additionalKeysToSanitize:}") List<String> additionalKeys) {
addKeysToSanitize(DEFAULT_KEYS_TO_SANITIZE);
addKeysToSanitize(additionalKeys);
}

@Override
public SanitizableData apply(SanitizableData data) {
if (data.getValue() == null) {
return data;
}

for (Pattern pattern : keysToSanitize) {
if (pattern.matcher(data.getKey()).matches()) {
return data.withValue(SanitizableData.SANITIZED_VALUE);
}
}
return data;
}

private void addKeysToSanitize(Collection<String> keysToSanitize) {
for (String key : keysToSanitize) {
this.keysToSanitize.add(getPattern(key));
}
}

private Pattern getPattern(String value) {
if (isRegex(value)) {
return Pattern.compile(value, Pattern.CASE_INSENSITIVE);
}
return Pattern.compile(".*" + value + "$", Pattern.CASE_INSENSITIVE);
}

private boolean isRegex(String value) {
for (String part : REGEX_PARTS) {
if (value.contains(part)) {
return true;
}
}
return false;
}
}

Now if we hit the /actuator/env endpoint, only test.password is masked with “*”

The example code can be found in this link https://github.com/ronghuiye/actuatorSanitizer

Happy Coding!

Reference:

https://www.baeldung.com/spring-boot-actuators

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job

--

--