A workaround is you build your own filter for /actuator/** path with custom headers, something like this:
On application side:
@Configuration
@Order(2)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
public static String name = "actuator-admin";
public static String pw = "actuator-pw";
public static String headerName = "ACTUATOR_HEADER_NAME";
public static String headerPw = "ACTUATOR_HEADER_PW";
protected String getActuatorFilterUrl() {
return "/actuator/" + "**";
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.and()
// we don't need CSRF because our token is invulnerable
.csrf().disable()
// All urls must be authenticated (filter for token always fires (/**)
.antMatcher(getActuatorFilterUrl())
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers(getActuatorFilterUrl()).authenticated()
.and()
.addFilterBefore(new ActuatorSecurityFilter(getActuatorFilterUrl(), name, pw, headerName, headerPw),
UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
public class ActuatorSecurityFilter extends AbstractAuthenticationProcessingFilter {
private String name;
private String pw;
private String headerName;
private String headerPw;
public ActuatorSecurityFilter(String filterUrl, String name, String pw, String headerName, String headerPw) {
super(filterUrl);
this.name = name;
this.pw = pw;
this.headerName = headerName;
this.headerPw = headerPw;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
final String name = request.getHeader(headerName);
final String pw = request.getHeader(headerPw);
if (name.equals(this.name) && pw.equals(this.pw)) {
return new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return new ArrayList<>();
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getDetails() {
return null;
}
@Override
public Object getPrincipal() {
return null;
}
@Override
public boolean isAuthenticated() {
return true;
}
@Override
public void setAuthenticated(boolean b) throws IllegalArgumentException {
}
@Override
public String getName() {
return null;
}
};
}
throw new IllegalStateException("name or pw wrong");
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
// As this authentication is in HTTP header, after success we need to continue the request normally
// and return the response as if the resource was not secured at all
chain.doFilter(request, response);
}
}
On Spring-Admin side:
@Configuration
public class CUstomHeaderConf {
@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return instance -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("ACTUATOR_HEADER_NAME", "actuator-admin");
httpHeaders.add("ACTUATOR_HEADER_PW", "actuator-pw");
return httpHeaders;
};
}
}