Why protect metrics?
So, imagine... You proudly set up Actuator in your demo (or real) project and now you can finally see /metrics, /health and other endpoints in action. You feel like a monitoring genius, but suddenly you find out that... anyone can access this data. Surprise!
Actuator exposes pretty sensitive info about your app: health status, CPU load, memory usage, thread counts and a lot more. Now imagine an attacker using that info to craft an attack. Scary!
Potential threats
- Information leakage about the system: metrics can reveal critical info, like an outdated JVM version or dependencies that might have vulnerabilities.
- Reconnaissance before an attack: system state data can be used to pick the best time or method for an attack.
- Overloading the system: an attacker could flood Actuator endpoints with requests, causing extra load.
Bottom line: limiting access to Actuator endpoints is not just a recommendation — it's an absolute must. Let's see how to do it right.
Securing Actuator
By default Spring Boot Actuator exposes endpoints that may be open to everyone (depending on configuration level). Let's lock them down using Spring Security.
1. Add the Spring Security dependency
If your project doesn't have Spring Security yet, add it. For Maven it looks like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
For Gradle:
implementation 'org.springframework.boot:spring-boot-starter-security'
2. Enable basic security
Once Spring Security is added, access to most Actuator endpoints will be blocked by default. Now authentication will be required.
Try opening any Actuator endpoint, for example /actuator/health. You'll see the browser asks for a username and password. Congrats, your first layer of security is up!
Spring Security will automatically create a user with username user and a password that gets generated at app startup. You can find this password in the logs:
Using generated security password: 2a9c2b52-4f3d-4937-b5d0-8b0fe9ed8702
3. Change the credentials
The generated password is only useful temporarily. Let's set more readable credentials in application.properties:
spring.security.user.name=admin
spring.security.user.password=supersecurepassword
Now you can log in with the username and password you set.
4. Granular access control
What if you want certain metrics only available to specific roles? For example, /actuator/health can be public, but /actuator/metrics only for admins.
Access configuration via HttpSecurity
For that you need to configure a SecurityFilterChain:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/actuator/health").permitAll() // Open access to /health
.requestMatchers("/actuator/**").hasRole("ADMIN") // Access to the rest only for ADMIN
.and()
.httpBasic(); // Use basic authentication
return http.build();
}
}
Setting up user roles
When using Spring Security with roles, you need to set up users with their roles. For example:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class MyUserDetailsService {
@Bean
public UserDetailsService userDetailsService() {
var user1 = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
var admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("adminpassword")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user1, admin);
}
}
Now the admin user will have access to Actuator endpoints, while the user will not.
This is an example for testing. For real applications you should use more secure ways to store passwords and credentials.
Configuration via application.properties
If you don't want to write code, Spring Boot lets you simplify security configuration via application.properties:
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.probes.enabled=true
# Protect all endpoints
spring.security.user.name=admin
spring.security.user.password=supersecurepassword
Common mistakes when configuring security
Role mismatch
If you create a user without the proper role (ROLE_ADMIN for Actuator), they won't be able to access endpoints even if the username and password are correct. Make sure roles are set consistently in both code and data.
Completely disabling security
Some developers, for convenience, just turn off authentication and open Actuator to everyone. That's acceptable only for local development, never in production. Always protect metrics in real projects.
When and which endpoints to open?
Sometimes it's useful to leave some metrics public. For example, the /health endpoint can be open to monitoring systems like Kubernetes so they can check the app's status.
But always restrict access to more detailed endpoints like /metrics or /env to admins only.
After this lecture you not only learned how to protect metrics, but also understood why this step is crucial for the security of your applications.
GO TO FULL VERSION