We've seen a number of questions related to Spring Boot's Health Actuator endpoint for version 1.5+. Having gone through a number of them, we're still at a loss.
Our goals are:
To utilize Spring Boot/Spring Security's auto configuration of the security filter chaining (i.e. not have to fully implement/configure HttpSecurity)
To enable secured health access (to see a full view into the health information of the application)
To enable unsecured health access (to allow for an endpoint to function as a liveness probe in Kubernetes)
We've tried:
Using a WebSecurityConfigurerAdapter and configuring the WebSecurity object to ignore security for the /health endpoint, and then mapping a separate endpoint to the /health endpoint according to Routing multiple URLs to Spring Boot Actuator's health endpoint to hopefully enable a secured path.
Ensuring that security.oauth2.resource.filter-order=3 as was recommended in https://github.com/spring-projects/spring-boot/issues/5072. This puts the OAuth2AuthenticationProcessingFilter before the Actuator's Mvc endpoints, and allows for requests that contain pre-authenticated Authorization: Bearer ... headers (such as JWT authorizations) to be processed. However, it dictates that all requests contain authorization - otherwise, the FilterSecurityInterceptor triggers Secure object: FilterInvocation: URL: /health; Attributes: [#oauth2.throwOnError(authenticated)] and an AccessDeniedException
Utilizing Basic Authentication for /health and OAuth2 for everything else is a no-go (see Spring boot oauth2 management httpbasic authentication & https://github.com/spring-projects/spring-boot/issues/5072).
The question that we keep coming back to is how do we get:
Anonymous requests to the /health endpoint to function as unsecured
Pre-authenticated requests (i.e. those that contain pre-authenticated Authorization: Bearer ... headers) to the /health endpoint not having the appropriate authorizations or roles to function as unsecured
Pre-authenticated requests (i.e. those that contain pre-authenticated Authorization: Bearer ... headers) to the /health endpoint having the appropriate authorizations or roles to function as secured
We can easily allow any request to access /health by having something like:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers(HttpMethod.GET, "/health", "/info");
}
}
And that works great solely as a readiness/liveness probe. However, when the user is actually authenticated, it doesn't provide the benefit of seeing which backing services may be misbehaving.
Thanks in advance!
I faced something similar and this somewhat works:
Add a hacky access rule for actuators eg: #oauth2.clientHasRole('ROLE_CLIENT') or hasRole('ROLE_ANONYMOUS') that enables the security context to be populated for the actuator endpoints (for both authenticated and non authenticated requests) and tweak the 'sensitive' actuator endpoints configuration.
/health should return basic info for anonymous and full info for authenticated in this case, provided you enable the management security and mark it as non sensitive.
You still need to keep the filter configuration.
Try this, work for me
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/actuator/**","/assets/**")
.permitAll()
........
;
}
Related
I am having multiple downstream services to which I am routing via a spring cloud gateway service which also has okta auth. Currently I am able to route authenticate users at the gateway and return 401 for all requests without a valid bearer token. However when I try to implement role based auth, i.e. GET requests can be sent downstream for everyone group, but POST requests require 'admin' group membership in okta. This does not work as any authenticated user is currently able to make post requests. I have added claims to the access/id tokens and checked them in the Token preview section of my default Authorisation server in okta. Following is my security configuration.
#EnableWebSecurity
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests -> authorizeRequests
.antMatchers(HttpMethod.POST,"/*").hasAuthority("admin")
.anyRequest().authenticated())
.oauth2ResourceServer().jwt();
}
}
Due to only the gateway having okta auth and downstream services being protected by api token, I cannot implement preAuthorize and have to rely on httpsecurity, but I seem to be missing something
In my SpringBoot application, I am trying to implement two different authorizations for two different areas.
Area 1 [API]:
/api/**
Area 2 [Admin]:
/admin/**
The Area 1 [API] is the API part of my application where I have implemented JWT Authentication. Every request that starts with /api will require an Authorization header containing jwt token.
The Area 2 [Admin]: is the admin area. Where I would like to log in with an URL from the browser, For example (/admin/login). I would like to have my username and password saved in the application.properties and for any URL that starts with /admin, I want the user to be authenticated (Session-based). I want to apply in-memory authentication in that case. I am looking for ideas to implement these two different authentications for two different areas.
You can use .authorizeRequests() method to configure endpoints for that security configuration file.
In void configure(HttpSecurity http) method in your WebSecurityConfigurerAdapter or ResourceServerConfigurerAdapter file you can use like
http
.antMatcher("/api/**")
.authorizeRequests()
...
Then spring security will start authorizing requests starting with /api path.
If added it in ResourceServerConfigurerAdapter spring oauth2 will start authorizing from there. To configure web security for an endpoint like /admin, in your WebSecurityConfigurerAdapter
http
.antMatcher("/admin/**")
.authorizeRequests()
...
we are using netflix oss for reverse proxying and security of microservices, we are following the jhipster pattern mentioned here https://www.jhipster.tech/microservices-architecture/, where request from UI application goes to gateway which is Api Gateway and it proxies the request to our backend microservices , we are using jwt for authentication, we wanted a dashboard to monitor our microservices and api gateway which registers with eureka server , we started a separate spring boot admin server so that it registers with eureka server and poll microservices and gateway for metrics endpoint but we are getting exception
Full authentication is required to access this resource
which is thrown by filters which are filtering for jwts at both api gateway and microservices level,
we also tried disabled
management.security.enabled: false
but still no luck ,can some one please help to guide what changes i need to make to enable spring boot admin to successfully poll the microservices and api gateway?
I tried the following approach
firstly i enabled web.ignoring().antMatchers("/actuator/**"), so that actuator endpoints are ignored by spring security but this approach will risk my api's
Second idea:
if i enable 2 filters in spring security , the first filter would be for spring boot admin with basic authentication for actuator endpoints and second filter will be of my jwt authentication for rest all api's and downstream api's not sure will it be feasible?
i enabled the 2 filters one filter for actuator end points and 1 filter for api's but these filters are working perfectly but not able to connect to SBA
public class SpringSecurityAdminFilter extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
String password = passwordEncoder().encode("xxxx");
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("sam").password(password).roles("ADMIN");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/actuator/**").hasRole("ADMIN")
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
}
}
i enabled basic authentication for spring boot admin server added the property in microservices
eureka.instance.metadata-map.user.name:
eureka.instance.metadata-map.user.password:
now actuator endpoints are protected by basic authentication
I have had a similar issue. On my spring boot application we had a cors filter to block Http Head requests. So head requests cannot be accepted from spring boot admin.
Check maybe filter is blocking HEAD Http requests .
Setting management.security.enabled=false in the application.properties also necessary.
I've upgraded to Spring Cloud Dalston recently, that means Spring Boot 1.5.1, and I can not secure the management endpoints by checking an oauth2 scope anymore. It worked before in Spring Cloud Camden.
This is the configuration that worked before :
#Configuration
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
#Value("${management.context-path}")
private String managementContextPath;
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// some paths I don't want to secure at all
.antMatchers("/path1/**", "/path2/**").permitAll()
// access to health endpoint is open to anyone
.antMatchers(HttpMethod.GET, managementContextPath + "/health").permitAll()
// but app.admin scope is necessary for other management endpoints
.antMatchers(managementContextPath + "/**").access("#oauth2.hasScope('my-super-scope')") //
// And we make sure the user is authenticated for all the other cases
.anyRequest().authenticated();
}
}
And this is the important part of the config :
security:
oauth2:
client:
clientId: a-client
clientSecret: the-client-password
resource:
tokenInfoUri: http://my-spring-oauth2-provider/oauth/check_token
management:
context-path: /my-context
security:
enabled: true
endpoints:
health:
sensitive: false
When I try to POST on /my-context/refresh I get a HTTP 401 "Full authentication is needed" even though I give a valid OAuth2 token
Looking through the log I saw that my request was considered anonymous, and checking the FilterChainProxy log saw that the OAuth2AuthenticationProcessingFilter was not called. After a bit of digging I found that I could change the oauth2 resource filter order, so I tried that and now I have an OAuth2 authentication, yeah, finished right ?
Hum, no, now I have an Access is denied. User must have one of the these roles: ACTUATOR error.
I tried a few other things, including disabling management security (but my rules are not applied and access is open to everyone), playing with (ugh) #Order (no change), and even, lo and behold, reading and applying the documentation which says :
To override the application access rules add a #Bean of type
WebSecurityConfigurerAdapter and use
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) if you don’t want to
override the actuator access rules, or
#Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER) if you do
want to override the actuator access rules.
But this did not change the error : User must have one of these roles: ACTUATOR
Does anybody have a workaround/idea ?
Update : I'm also using Zuul, so I finally created a specific zuul route to the endpoint I needed (cloud bus refresh in my case), unprotected on an other backend service that was not exposed otherwise, and protected that zuul route with oauth2.
I'm leaving this question here nevertheless, if anyone finds a workaround, could be useful.
Probably being captain obvious, but see http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html. You can override the role with management.security.roles and simply add whatever role your Oauth2 credentials have.
I confronted with this issue also. The workaround that I used was to expose the actuator action on a new endpoint which I defined, and just call the actuator bean to handle request.
For example to secure /my-context/refresh with Oauth2 , I just expose a new resource at {whatever-api-prefix}/refreshConfig and I exposed a request handler on the rest controller for this URL; in the rest controller I wire the RefreshEndpoint bean and in the request handler I just call the refreshEndpoint.refresh().
I'm modifying the oauth2-vanilla sample from Springs excellent security tutorials. The oauth2-vanilla combines the Zuul Proxy and the UI into a single application. I would like to seperate the Zuul Proxy and the UI. (The Zuul Proxy should act as an API gateway and as a reverse proxy for several UIs).
When accessing the UI via the zuul proxy, it should be able to do SSO based on Oauth2 between the UI and the resource backend.
The oauth2-vanilla looks like this
Where I want to move to something like this :
I've removed the UI part from the gateway, and added a zuul route for the ui
zuul:
routes:
resource:
url: http://localhost:9000
user:
url: http://localhost:9999/uaa/user
ui:
url: http://localhost:8080
I created a new UI webapp containing the UI (Angular stuff) with an #EnableOAuth2Sso annotation.
So I'm accessing the UI via http://localhost:8888 (through the zuul proxy).
After authenticating and doing through the UI flow, I can access the /user endpoint that returns me the user. (During debugging, I see that when I access the /user endpoint that I have an HTTP Session with an OAuth2Authentication.
When I access the /resource endpoint however, the HttpSessionSecurityContextRepository cannot find a session and is unable to build a context with the OAuth2Authentication.
I've created a git repository with the modified sample.
I'm guessing there is something wrong with the gateway configuration.
I've tried changing cookie paths, changing HttpSecurity rules in the proxy but I cannot get it to work.
What I don't understand is why the UI, when accessed through the proxy is able to resolve the /user endpoint fine (with an HTTP session and a OAuth2Authentication), but it is unable to access the /resource endpoint.
Also, as the UI is now running in the /ui context, it seems that I need to have the following code in the gateway for it to load up the angular css / js files.
.antMatchers("/ui/index.html", "/ui/home.html", "ui/css/**", "/ui/js/**").permitAll().anyRequest().authenticated();
It also doesn't seem right that I need to prefix it with the zuul ui route.
Any help would be appreciated.
I was never able to get the #EnableOauthSso to work. Instead, I annotated as an #EnableResourceServer and created a security config for Zuul.
#Configuration
#EnableResourceServer
public class JwtSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/**").hasAuthority("ROLE_API")
.and()
.csrf().disable();
}
}