Hide details for health indicators in Spring Boot Actuator - spring-boot

I'm using Spring Boot health indicator from an actuator. So far example response looks like:
{
"status":"DOWN",
"details": {
"diskSpace": {
"status":"UP",
"details": {
"total":499963170816,
"free":250067189760,
"threshold":10485760
}
}
}
}
Because I need to make /actuator/health endpoint public, I need to hide details for health indicators, so I expect to get something like this:
{
"status":"DOWN",
"details": {
"diskSpace": {
"status":"UP"
}
}
}
For disk space it's not a big problem but e.g. for database I don't want to share exception message and details in case of it's outage. Also (as I mentioned at the beginning) it must be public so I don't want to make this endpoint 'when-authorized'. And at the end - it would be great if it's possible to do that without writing my own custom endpoint.
Is it possible at all?

This isn't possible at the time of writing (in Spring Boot 2.1 and earlier) without writing your own custom endpoint. I've opened an issue to consider it as an enhancement for a future version of Spring Boot.

There is a way to achieve this in Spring Boot 2.X
management:
health:
db:
enabled: false
diskspace:
enabled: false
mongo:
enabled: false
refresh:
enabled: false
More information can be found here https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#_auto_configured_healthindicators

Related

How to configure rest client in quarkus microprofile case

When using Quarkus microprofile as a rest client, how can I configure underlying HttpClient?
Like number of retries, connection pool size per host and so on?
Also is it possible to force client restart somehow (so connections pool will be restarted)?
https://download.eclipse.org/microprofile/microprofile-rest-client-2.0-RC2/microprofile-rest-client-2.0-RC2.html#_configuration_keys outlines the full set of configuration keys that can be used.
The ones you're looking for are:
{packageName}.{interfaceName}/mp-rest/connectTimeout
{packageName}.{interfaceName}/mp-rest/readTimeout
The RestClientBuilder also has methods for setting those properties if you're using the programmatic API instead of the CDI approach.
I'm not aware of any means of restarting the underlying HTTP client connection pool. What would be the use case for such a situation that doesn't require the whole application to be restarted?
So... After a lot of digging, here is a solution I've found so far. It is not obvious apparently:
To make it work in pure Java (no native)
Under resources/META-INF/services directory add file named org.eclipse.microprofile.rest.client.spi.RestClientBuilderListener containing class name of your implementation of RestClientBuilderListener interface. For example my.test.MyBuilderListener. This will allow ServiceLocator to execute your listener
Refer a property you want to modify from ResteasyClientBuilder, for example to set your custom value to connectionTTL code will looks like this:
public void onNewBuilder(RestClientBuilder builder) {
log.info("Changing TTL for connections");
builder.property("resteasy.connectionTTL", List.of(2L, TimeUnit.SECONDS));
}
Ie. add a resteasy. prefix to a property name
Profit
Now native support:
After steps above:
Set both MyBuildListener and ResteasyClientBuilder available for reflection by creating a file reflection-config.json:
[
{
"name": "org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}, {
"name": "my.test.MyBuilderListener",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}
]
Add service registration file to resources. Create a file named resources-config.json with content
{
"resources": [
{
"pattern": "META-INF/services/org\\.eclipse\\.microprofile\\.rest\\.client\\.spi\\.RestClientBuilderListener$"
}
]
}
register both files in application.yaml:
quarkus:
native:
additional-build-args: -H:ResourceConfigurationFiles=resources-config.json, -H:ReflectionConfigurationFiles=reflection-config.json
Native profit
Have fun

How do I disable spring security in a Grails 4 integration test?

I had a grails 3 app including spring security, which I recently upgraded to grails 4.
My application.yml includes the following:
environments:
test:
grails:
plugin:
springsecurity:
active: false
security:
ignored: '/**'
basic:
enabled: false
spring:
security:
enabled: false
Why doesn't this work in Grails 4? What's a good alternative solution?
Grails 4 seems to be ignoring this configuration. When I run integration tests, I am getting a 403 error with a message:
Could not verify the provided CSRF token because your session was not found.
It seems like spring security enabled, and it's using SecurityFilterAutoConfiguration, which is normally excluded for my app.
Update
I am using the following dependencies:
compile('org.grails.plugins:spring-security-core:3.2.3') {
exclude group: 'org.springframework.security'
}
compile ('org.springframework.security:spring-security-core:4.2.13.RELEASE') {
force = true
}
compile 'org.springframework.security:spring-security-web:4.2.13.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.13.RELEASE'
Update 2:
In my debugger, I found that the spring security core plugin actually is being disabled. The following code from the plugin class is executed:
SpringSecurityUtils.resetSecurityConfig()
def conf = SpringSecurityUtils.securityConfig
boolean printStatusMessages = (conf.printStatusMessages instanceof Boolean) ? conf.printStatusMessages : true
if (!conf || !conf.active) {
if (printStatusMessages) {
// <-- the code in this block is executed; active flag is false
String message = '\n\nSpring Security is disabled, not loading\n\n'
log.info message
println message
}
return
}
...however, I am still getting the CSRF filter error, so Spring Security must be configuring itself somehow regardless.
Update 3:
The CSRF filter is being set up by ManagementWebSecurityConfigurerAdapter, using the default configuration.
I tried adding the following to resources.groovy:
if (grailsApplication.config.disableSecurity == true && !Environment.isWarDeployed()) {
webSecurityConfigurerAdapter(new WebSecurityConfigurerAdapter(true) {})
}
This did not fix the issue. Although my anonymous WSCA bean is being constructed, the MWSCA default bean is still being used by spring.
Try this in
grails-app/conf/application.groovy
environments {
development {
}
test {
grails.plugin.springsecurity.active = false
}
production {
}
}

Health Endpoint Metrics not being exported after Spring Boot 2 migration

My Team migrated our Microservices from Spring Boot 1 to Version 2 and since the Actuator changed, our Health Endpoint Metrics exported via prometheus jmx exporter do not work anymore.
The usual /actuator/health is working as expected, but the prometheus-jmx-exporter won't pick it up although several things tried:
I changed the Metainformation in the exporter-config.yaml to reflect the name change in Spring Boot 2
I added the io.micrometer:micrometer-registry-prometheus to our build.gradle to see if this is the issue
I exposed web and jmx endpoints acording to the Spring Boot 2 Documentation
So now I run out of ideas and would appreciate any hints oyu might be able to give me
old prometheus-jmx-exporter exporter-config.yaml:
---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
whitelistObjectNames: ["org.springframework.boot:type=Endpoint,name=healthEndpoint"]
rules:
- pattern: 'org.springframework.boot<type=Endpoint, name=healthEndpoint><(.*, )?(.*)>(.*):'
name: health_endpoint_$1$3
attrNameSnakeCase: true
new prometheus-jmx-exporter exporter-config.yaml:
---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
whitelistObjectNames: ["org.springframework.boot:type=Endpoint,name=Health"]
rules:
- pattern: 'org.springframework.boot<type=Endpoint, name=Health>'
name: health_endpoint_$1$3
attrNameSnakeCase: true
current application properties about actuator endpoints:
management.endpoints.web.exposure.include=info, health, refresh, metrics, prometheus
management.endpoints.jmx.exposure.include=health, metrics, prometheus
in Spring Boot 1 with the old exporter-config.yaml I get results like this:
# HELP health_endpoint_hystrix_status Invoke the underlying endpoint (org.springframework.boot<type=Endpoint, name=healthEndpoint><hystrix, status>status)
# TYPE health_endpoint_hystrix_status untyped
health_endpoint_hystrix_status 1.0
# HELP health_endpoint_status Invoke the underlying endpoint (org.springframework.boot<type=Endpoint, name=healthEndpoint><status>status)
# TYPE health_endpoint_status untyped
health_endpoint_status 1.0
But with all the changes and in Spring Boot 2 I get nothing out of this.
You can cofigure your own health value and add it to the Prometheus Metrics endpoint:
#Configuration
public class HealthMetricsConfiguration {
#Bean
public MeterRegistryCustomizer prometheusHealthCheck(HealthEndpoint healthEndpoint) {
return registry -> registry.gauge("health", healthEndpoint, HealthMetricsConfiguration::healthToCode);
}
public static int healthToCode(HealthEndpoint ep) {
Status status = ep.health().getStatus();
return status.equals(Status.UP) ? 1 : 0;
}
}

How to configure "health" Actuator endpoint to work with token authentication?

We are using token-based authentication (with Spring Security) in our Spring Boot 2 application. Now I'm introducing Spring Boot Actuator to it. I would like to configure the /health endpoint to be visible without any permissions but to show health checks details only when authorized.
I found the property management.endpoint.health.show-details=when_authorized which should be helpful but now I'm fighting with the Spring Security configuration to allow everybody to see:
{
"status": "UP"
}
under /actuator/health while users authorized with token should see:
{
"status": "UP",
"details": { ... }
}
Did you face a similar problem? How did you handle it?
OK, now I understand, if you turn off security in your application and keep management.endpoint.health.show-details=when_authorized you are getting just status field? If I'm right it's not an issue, take a look in spring class HealthWebEndpointResponseMapper into map method. As I found out this method overwrites (remove details field from the response) if condition in if is true:
public WebEndpointResponse<Health> map(Health health, SecurityContext securityContext,
ShowDetails showDetails) {
if (showDetails == ShowDetails.NEVER
|| (showDetails == ShowDetails.WHEN_AUTHORIZED
&& (securityContext.getPrincipal() == null
|| !isUserInRole(securityContext)))) {
health = Health.status(health.getStatus()).build();
}
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
return new WebEndpointResponse<>(health, status);
}
In your case, I guess you have set an above-mentioned property to when_authorized also you have turned off authentication, so the principal is null. Not sure if I'm right, but I hope I gave you a clue. :)

Spring Boot - Change the location of the /health endpoint to /ping/me

I set the endpoints.health.path property to /ping/me. But I cannot access the endpoint using http://localhost:9000/ping/me
It only works with http://localhost:9000/health. What am I missing ?
Here is the code in app properties file.
#Configuration for Health endpoint
endpoints.health.id=health
endpoints.health.path=/ping/me
endpoints.health.enabled=true
endpoints.health.sensitive=false
#Manage endpoints
management.port=9000
management.health.diskspace.enabled=false
The response I get is :
{
"timestamp" : 1455736069839,
"status" : 404,
"error" : "Not Found",
"message" : "Not Found",
"path" : "/ping/me"
}
The Actuator became technology-agnostic in Spring Boot 2.0.0, so it's not tied to MVC now. Thus if you use Spring Boot 2.0.x, you can just add the following config properties:
# custom actuator base path: use root mapping `/` instead of default `/actuator/`
management.endpoints.web.base-path=
# override endpoint name for health check: `/health` => `/ping/me`
management.endpoints.web.path-mapping.health=/ping/me
If you don't override the management.endpoints.web.base-path, your health-check will be available at /actuator/ping/me.
The properties like endpoints.* became deprecated in Spring Boot 2.0.0.
See below for Spring Boot 2.*
https://stackoverflow.com/a/50364513/2193477
MvcEndpoints is responsible for reading endpoints.{name}.path configurations and somehow in its afterPropertiesSet method:
for (Endpoint<?> endpoint : delegates) {
if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {
EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);
String path = this.applicationContext.getEnvironment()
.getProperty("endpoints." + endpoint.getId() + ".path");
if (path != null) {
adapter.setPath(path);
}
this.endpoints.add(adapter);
}
}
It refusing from setting the endpoints.health.path, since isGenericEndpoint(...) is returning false for HealthEndpoint. Maybe it's a bug or something.
Update: Apparently this was a bug and got fixed in 1.3.3.RELEASE version. So, you can use the /ping/me as your health monitoring path in this version.

Resources