Access secured actuators from Spring Boot Admin with Kubernetes Service Discovery - spring-boot

I've got a Spring Boot Admin application which uses a Kubernetes Service Discovery to get the Spring Boot client applications.
spring:
cloud:
kubernetes:
discovery:
all-namespaces: true
service-labels:
springbootadmin: true
reload:
enabled: true
period: 60s
strategy: refresh
Without secured actuator endpoints this works fine.
But as soon as the client actuator endpoints are protected by basic auth this does not work any more. The Spring Boot Admin Documentation describes how to add the authentication data to the Spring Boot Admin Server bit it does not describe how to provide this when the services are discovered via Kubernetes.
I've tried these configurations. But they don't work:
Spring Boot Admin Docs: spring.boot.admin.instance-auth.default-user-name + password
Spring Boot Admin Tutorial spring.boot.admin.client.instance.metadata.user.name + password
I also found an answer which describes how to configure the credentials in the Kubernetes annotations. This works but I would prefer to configure the credentials in the Spring Boot Admin configuration (where I can use Secrets) and not separately for each service in the Kubernetes configuration as an unsecure label.
I think I have to inject the credentials in the Service Discovery metadata. But how?
EDIT
I've examined the service discovery and found no auth configuration options which could be provided:
class KubernetesDiscoveryProperties.Metadata
class de.codecentric.boot.admin.server.cloud.discovery.DefaultServiceInstanceConverter

It might be an option to add a custom header to the requests that are sent by SBA to the clients:
#Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return (instance) -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "Basic bXlTcGVjaWFsVXNlcm5hbWU6bXlTcGVjaWFsUGFzc3dvcmQ=");
return httpHeaders;
};
}

The authentication can be set by these settings:
spring:
boot:
admin:
instance-auth:
default-user-name: user
default-password: pw
These settings are read by the Configuration Class AdminServerInstanceWebClientConfiguration which instantiates a bean basicAuthHttpHeadersProvider.

Related

Why does keycloak.resource not require the ClientId of a registered client

I use Keycloak and I configure it with my application.properties file.
# Keycloak config (instead of keycloak.json)
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.realm=demo
keycloak.resource=DemoApplication
keycloak.principal-attribute=preferred_username
keycloak.bearer-only=true
This works just fine. The problem is that I expected to create a Client in my keycloak admin console for the raealm that is used as keycloak resource.
The docs say
resource
The client-id of the application. Each application has a client-id that is used to identify the application. This is REQUIRED.
But in this example DemoApplication is not registred in keycloak. As I understsand, every Application that includes the keycloak-adapter dependency exchanges the public key with keycloak on startup to be able to verify the signature of an incoming token. But why is this working if the client is not registered in keycloak?

Configuring consumerWindowSize in Spring Boot application

ActiveMQ Artemis configuration file in Spring Boot below:
spring:
artemis:
host: localhost
port: 61616
user: admin
password: admin123
There is no properties for broker-url so that I can set consumerWindowSize like
tcp://localhost:61616?consumerWindowSize=0`
How can i configured consumerWindowSize in a Spring Boot application.
Based on the Spring Boot documentation (which references ArtemisProperties) I don't believe you can set the broker's actual URL or any of the properties associated with it. This is a pretty serious short-coming of the Artemis Spring Boot integration as it really limits the configuration. There is already an issue open to (hopefully) address this.
Added below configuration to solve this issue:
#Bean("connectionFactory")
public ConnectionFactory connectionFactory(AppProperties appProperties) {
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory($brokerUrl);
cf.setUser($user);
cf.setPassword($password);
return cf;
}

Connect secured Client with Spring Boot Admin Security

Can someone guide me how can I connect my secured client with the spring boot admin application?
Scenario: I have a spring boot application (client) with spring security and spring-actuator enabled. The actuator endpoints are secured and for this I have the following (working) configuration in my web security config:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
auth.inMemoryAuthentication().withUser("Test-Actuator").password("Test-Baby").roles("ADMIN", "ACTUATOR");
}
Now I want to integrate the Spring Boot Admin Application in our environment. I set up a simple application with spring-boot-admin-server and spring-boot-admin-server-ui enabled. In the application.properties file I provide the following properties:
spring.boot.admin.username=test
spring.boot.admin.password=test
these are for the server admin, right?
spring.boot.admin.client.metadata.user.name=Test-Actuator
spring.boot.admin.client.metadata.user.password=Test-Baby
these are for the client, right?
Now when I run the applications I get the following error from the client: Failed to register application as Application [...] at spring-boot-admin ([...]) 401 null
I call the spring boot admin page and get a HttpBasic Authentication Pop Up. No credentials from above work for this Pop Up.
Note: If I disable the security in the client application.properties file it works but (like expected) the client doesn't work anymore.

How to create more than one health check endpoints with Spring Boot Actuator

What I want to do
Create two (different) endpoints using Spring Boot Actuator
My environment
Spring Boot 1.4.2
spring-boot-starter-actuator embedded in Spring Boot 1.4.2
Detail
I'm creating a Web app using Spring Boot and will need to create two separated endpoints: one for just checking application health including the app's DB connection and so on (This will be realized by the default behavior of "/health") and the other for just checking if the app is ready for accepting HTTP requests (say "/httpcheck").
To implement health check feature, I guess it's the fastest way to use Spring Boot Actuator (by default, /health is mapped to health check endpoint).
I also understand we can configure this endpoint by extending AbstractHealthIndicator (so that it will include DB health check).
But as far as I could see, I could not find a way to create more than one endpoints to do different health checks.
Do you have any ideas?
Thanks in advance.
Thanks for your answer.
Actually, I dealt with this problem by implementing a new endpoint (/httpcheck) to simply check if its HTTP stack works well or not.
HttpCheckEndpoint.java
#Component
#ConfigurationProperties(prefix = "endpoints.httpcheck") // Specifies the prefix on application.yml
public class HttpCheckEndpoint extends AbstractMvcEndpoint {
public HttpCheckEndpoint() {
super("/httpcheck", false);
}
/**
* Check if simply the app can connect to their own HTTP stack and return 200 OK.
* <ul>
* <li>Method: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS</li>
* <li>Endpoint: "/httpcheck"</li>
* </ul>
*/
#RequestMapping
#ResponseBody
public ResponseEntity<String> checkHttpConnecton() {
if (!isEnabled()) {
return new ResponseEntity<String>("", HttpStatus.NOT_FOUND);
} else {
return new ResponseEntity<String>("{\"status\": \"UP\"}", HttpStatus.OK);
}
}
}
application.yml
endpoints:
enabled: false # Default enabled/disabled on endpoints on Spring Boot Actuator
health: # Health check (already prepared in Spring Boot Actuator)
enabled: true
httpcheck: # Simple HTTP connection check (newly created by myself)
enabled: true
I've confirmed it worked well, although not sure if it's the best solution...
Solution
You can use Jolokia end points in your Spring-boot application and get it registered with o.s.b.a.e.jmx.EndpointMBeanExporter along with your Actuator Plugins.
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
<version>1.2.2</version>
</dependency>
Jolokia Configurations in application.properties
jolokia.config.debug=true
endpoints.jolokia.enabled=true

Use oauth2 scope instead of role to secure spring actuator management endpoints

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().

Resources