In this article, we will be discussing adding spring security to the spring boot admin server console and discuss different ways such as basic authentication and JWT authentication to secure our admin console. We will also look into accessing the secured Actuator endpoint exposed by the spring boot admin client.
This is the 3rd article on a series of tutorials to monitor and manage our microservice-based spring boot apps. First, we discussed about spring boot actuator and then spring boot admin in great detail and now we are discussing securing the spring boot admin console.
Quick Intro to Spring Boot Admin
Spring Boot Admin is a web app developed by codecentric which provides an admin console for the managing and monitoring of spring boot applications by utilizing the actuator REST endpoints exposed by spring boot actuator.
From the spring boot admin perspective, there are 2 modules - admin server and admin client. The admin server provides an admin console to visualize all the metrics and status of a client app. The client app here is any spring boot app that has a spring boot actuator integrated.
With this admin console, we can perform multiple admin-level operations on the client app hence securing the admin console is the most important task. Even if the admin console is hosted on a private network it is recommended to have a basic authentication added.
For this article, we assume that you already have the local setup of admin server and admin client that we discussed in our last article. In this article, we will add security on top of that.
Also, we added Netflix discovery server to enable discovery of our client app by the admin server app.
Adding Basic Authentication to Admin Console
Adding a basic authentication to an admin console only requires some entries in our properties file and it is very similar to adding a spring security basic authentication in a spring boot which we have already discussed in detail in my previous article here.
Basic authentication is a standard HTTP header with the user and password encoded in base64 in the format username:password and sent in HTTP header as Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==.
To add it in our admin console, we need to include below maven dependencies in our existing admin server app pom file. The spring-boot-admin-server-ui artifact provides a login page and a logout button.
<dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-server-ui</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
With this much configuration, we have basic authentication enabled in our admin console. Now, let us add our username and password required for login. For that, we can make below entries in the admin server properties file.
spring.security.user.name=devglan spring.security.user.password=password
Now, if we try to access our admin server console you should ideally see a login page like this.
No extra configuration is required to add a basic authentication in our admin server app to enable basic authentication. As we are doing the client app discovery via Netflix Eureka no extra configuration required in our client app too and since our actuator endpoints are not secured yet the admin server can directly access those actuator endpoints and show the metrics in the console.
But in case you do not wish use any discovery server for client app discovery then make below entries in admin client app to register itself to admin server app as our admin server app is now secured with basic authentication.
spring.boot.admin.client.username=devglan spring.boot.admin.client.password=password
This is a very simple setup and good for a poc. Now for a production system a Spring Security configuration of our server could look like this as per the official doc of spring boot admin.
@Configuration(proxyBeanMethods = false) public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { private final AdminServerProperties adminServer; public SecuritySecureConfig(AdminServerProperties adminServer) { this.adminServer = adminServer; } @Override protected void configure(HttpSecurity http) throws Exception { SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(this.adminServer.path("/")); http.authorizeRequests( (authorizeRequests) -> authorizeRequests.antMatchers(this.adminServer.path("/assets/**")).permitAll() .antMatchers(this.adminServer.path("/login")).permitAll().anyRequest().authenticated() ).formLogin( (formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and() ).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults()) .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringRequestMatchers( new AntPathRequestMatcher(this.adminServer.path("/instances"), HttpMethod.POST.toString()), new AntPathRequestMatcher(this.adminServer.path("/instances/*"), HttpMethod.DELETE.toString()), new AntPathRequestMatcher(this.adminServer.path("/actuator/**")) )) .rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600)); } // Required to provide UserDetailsService for "remember functionality" @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER"); } }
Above configuration is enough to enable basic authentication but we can replace this configuration to use other authentication and authorization mechanism such as JWT token based auth or Oauth2 or session based authentication. You can follow my previous article to integrate JWT token based authentication or integrate it with OAuth2.
Securing Spring Boot Admin Client
Spring Boot admin client is a full fledged spring boot app with spring actuator integrated with it. Hence, there are many ways to secure these apps. Also, we can write our custom security configurations to secure our actuator endpoints.
If you specifically want to know about securing actuator endpoints then you can follow my another article where we have discussed about securing actuator endpoints.
For this article, let us use basic authentication to secure our admin client app. For that let us add below maven dependency in our admin client app and add some properties to enable basic authentication.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>application.properties
spring.security.user.name=client spring.security.user.password=client
Once basic auth is enabled in the admin client app, the actuator endpoints become secured and hence require authentication for the access of these endpoints. For example, if you try to access the /beans
endpoint - http://localhost:8080/actuator/beans you need to produce above-configured username and password - client/client.
And the same authentication is required by the admin server app to access the actuator endpoints now. Hence, below entries are required to add in the admin client properties.
This works in a manner that these credentials are submitted by the admin client app in the metadata to server app when registering the application.
spring.boot.admin.client.instance.metadata.user.name=${spring.security.user.name} spring.boot.admin.client.instance.metadata.user.password=${spring.security.user.password}
The BasicAuthHttpHeaderProvider then uses this metadata to add the Authorization header to access admin client application actuator endpoints. We can also provide your own HttpHeadersProvider to alter the behaviour or add extra headers.
This HttpHeadersProvider can be used to inject custom JWT tokens in the headers.
@Bean public HttpHeadersProvider injectHeaders(){ return instance -> { HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Bearer abc"); return headers; }; }
Above configuration works fine when the admin client app directly registers itself to the admin server app but in our case we have discovery server for service discovery. Hence, below configuration in application.yml file is required to access the actuator endpoints by the admin server app. These entries are made in admin client app.
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka register-with-eureka: true registry-fetch-interval-seconds: 5 instance: preferIpAddress: true metadata-map: user.name: client user.password: client
Conclusion
In this article, we added spring security to the spring boot admin server console and discuss different ways such as basic authentication and JWT authentication to secure our admin console.