I'm having issues with a custom Spring Boot starter. How can a starter cause a profile to be included and pull related configuration from a config server?
Perhaps my use case is unique, because I haven't found any helpful information online. I'm working in an enterprise environment and this starter is for use by my team, so we're able to control some things (like profile names) that perhaps wouldn't make sense in the open source world.
Here is the scenario: We have a Spring Cloud Config Server running to provide configuration. Across our Spring Boot projects, we have standardized on certain profile names such as "prod" and "nonprod" to control configuration in our different environments. I am trying to create a starter to provide reusable functionality. For example purposes, let's say I'm creating a starter that provides an interface to an appliance that performs cryptographic work for us. This starter will need the IP address of the appliance and various other configuration which differs between production and non-production.
Within the config repo, I will have files such as application.yml, application-nonprod.yml, application-nonprodEncryption.yml, etc.
My goal is to have the custom encryption starter automatically include the nonprodEncryption profile when that starter is included in an application. By doing this, apps which don't need encryption do not load the encryption related properties.
Here are my experimental findings so far:
Within an application's bootstrap.yml, I can put a block such as
spring.profiles: nonprod
spring:
profiles:
include:
- nonprodEncryption
and that produces the desired result (i.e. the application-nonprodEncryption.yml file is loaded from the config server and used), but this is an undesirable solution as every app that uses my custom starter would need to include this boilerplate configuration.
When I move the above configuration to the starter's bootstrap.yml, it seems to have no effect.
When I move the above configuration to the starter's application.yml, it seems to be applied (i.e. it shows up in the The following profiles are active: list), but it is too late in the lifecycle to cause the appropriate configuration to be pulled from the config server.
Other things I've considered:
Why not just put all of the configuration into the main profile config file (e.g. application-nonprod.yml)? From a separation of concerns and maintenance standpoint, I'd like to keep configuration for individual starters isolated from each other. Also, some configuration data is more sensitive than other config data, so I don't like the idea of exposing all of the configuration to all apps, since many apps won't need some of the more sensitive configuration. Yes, they could get to it, but why load it into their memory if they don't need it?
Why not just specify the extra profiles when we launch the app? These apps will be running on a cloud platform. The platform will specify either "prod" or "nonprod" as the profile based on which tier the app is running in. I want to manage that at the platform level rather than the app level, so I want the list of profiles provided at app launch to be uniform across all apps (add adding, for example, nonprodEncryption to the list just gets me into the same situation as above - all apps would have all of the configuration, so I might as well just put it all in a single file).
We are currently using Spring Boot 1.5.10.
Any thoughts on how to achieve what I'm trying to do?
I finally found a solution (in case anyone else finds themselves in the same spot).
Step 1: Add a configuration class like this to your starter:
package com.company.bootstrap;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Profile;
#Configuration
#Profile("nonprod")
public class BootstrapNonprod {
public BootstrapNonprod(ConfigurableApplicationContext ctx) {
ctx.getEnvironment().addActiveProfile("nonprodEncryption");
}
}
This will conditionally add a profile. In this example, whenever the "nonprod" profile is active, this class will add the "nonprodEncryption" profile.
Step 2: In your starter's spring.factories file, add a line such as this:
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.company.bootstrap.BootstrapNonprod
It seems like it is just that simple.
Related
I am implementing a Spring Boot application which will be providing a multitenant environment. That is achieved in my case by using a database schema for each customer. Example see this project.
Now I am wondering how to implement tenant-specific configurations. I am using #ConfigurationProperties to bundle my property values, but these are getting instantiated once and not for each tenant.
What if I would like to use Spring Cloud Config with multiple tenant specific git repository as an configuration backend. Would it be possible when using a jdbc backend for Spring Cloud Config?
Is there any way with default Spring mechanisms or do I have to implement a database based configuration framework myself?
Edit: For example I have two tenants called Tenant1 and Tenant2. Both are running over the same application in the same context and are writing in the database schemes tenant_1 and tenant_2.
Identification of tenants is happening over keycloak (see Spring Keycloak multi tenant example). So I identify the tenantId from the jwt token and select the database connection like described here.
But now I would need the same mechanism for #Configuration beans. Since #Configuration beans are as far as I know Singletons, so there is always ONE configuration per application scope, and not ONE configuration per tenant.
So using Spring Cloud Config Tenant1 is using https://git-url/tenant1, Tenant2 is using Hashicorp Vault as backend and perhaps Tenant3 will be using a jdbc based configuration backend. And all of that in ONE (of course scalable) application.
In case your application uses tenant specific files (html templates etc), the following can be applied. As I have used the below approach for handling many tenants and works fine and easy to maintain.
I would suggest that you maintain a consistent configuration source (JDBC) for all of your tenant configurations. This helps you have a single source that is cacheable and scalable for your application. Also, you could have your tenants navigate to a configuration page to manage their settings and alter them to suit their needs at any point of time on the fly. (Example Settings: Records Per Page, Theme, Logo, Filters etc...)
Having the tenant configuration in files in git will be a difficult task when you wanted to auto-provision tenant's when they sign-up as it will involve couple of distributed services. Having them in a TenantSettings table with the tenantId as a column could help you get the data in no time and will be easy.
You can use Spring Cloud Config for your scenario and it is adoptable. It is easily configurable and provides out of the box features. For your specific scenario, you can have any number of microservices running yet all controlled by one Spring Cloud Config Server which is connected to one Git Repository. Your all microservices are asking configuration properties from Spring Cloud Config Server and it is directly fetching properties from Git Repository. That repository can have multiple property files. It can hold common properties for all the microservices or specific service based configuration properties. If you want to keep confidential properties more securely, that is also made possible via HashiCorp vault. I will leave an image below for you to get a better idea about this concept.
In the below image, you can see the Git Repository with common configuration property files and specific configuration property files for different services yet in same repository.
I will add another image for you to get a better idea how does this can be arranged with application profiles as well.
Finally I will add something additional to show the power of Spring Cloud Config and out of the box features it allows us to play with. You can automatically refresh configuration properties in running application as well. You can configure Spring Cloud Config to do that. I will add an architectural diagram to achieve that.
References for this answer is taken from Spring in Action, Fifth Edition
Craig Walls
I have different profiles based on environment wise and needs to load it. How i can achieve and also how to pass program arguments for Quarkus main application to take dev profile(spring.config.location=classpath:/config/dev/application.yml)
Is there a way to load databse configuration while starting #QuarkusMain. I have configured all the database configurations into one class and how this class can be load in main. Please suggest on this.
Quarkus 1.13 (and later), supports profile aware application.properties. Just name your file application-{profile}.properties and activate it with -Dquarkus.profile={profile}
If you want to load specific files, you can also use quarkus.config.locations. This is backed by SmallRye Config. Please check additional documentation here: https://smallrye.io/docs/smallrye-config/main/config/config.html
New to Spring Boot here, long-time Spring Framework user though.
I'm looking for a way to split my externalised configuration into multiple .properties files, for better readability and manageability.
I already saw this SO answer: having the ability to specify a list of configuration file names in spring.config.name (which, by the way, doesn't seem to be mentioned in Boot reference documentation, correct me if I'm wrong) would solve my problem perfectly, however that configuration property can be specified only via system properties or environment variables. If I try to specify it inside my application.properties file, it gets ignored. The same happens for spring.config.additional-location. I understand this happens because, when application.properties is read, it's too late to tell Spring Boot to search for different externalised configuration file names. However this is not a proper solution, because the way I split my configuration should be an "implementation detail" that the consumer of my application shouldn't be aware of, so I don't expect the consumer to specify an external parameter otherwise my application breaks out-of-the-box.
I think that a way to do this should be provided. Perhaps some import mechanism for .properties files or the ability to specify spring.config.name even in application.properties (some known and reasonable limitations would be acceptable).
The best I could find out is to use #PropertySource, but this is not profile aware: unless you use some ugly nested class hack, or you put spring.profiles.active variable in the resource name (which will break if multiple profiles have been activated), you won't get the benefit you have for application.properties profile-specific files.
I was not able to find an "official way" to do this, apart from some statements from Spring Boot devs that say that they're rather promoting the use of a single (possibly giant...) externalised configuration file. It seems like this position is not so popular, judging from the post reactions on GitHub, and IMHO it really seems to be a basic feature missing. I have been working with multiple properties files in Spring Framework (using XML configuration) for years and I never felt that having an only huge file would have been better.
If I understand it right, in Boot 1.x this was in some way possible using the location attribute of #ConfigurationProperties, which is however missing in Boot 2.x.
Any suggestion?
Have you tried with Spring Profile?
What you can do is create application-file1.properties/yml, application-file2.properties/yml and put it in config location and then add spring.profile.active=<your env profiles>,file1,file2.
It will load the files.
This profile entry can be in bootstrap.yml, or JVM args to application, in Manifest-<env>.yml in case of Pivotal Cloud Foundry. Not sure on AWS and other cloud provider.
Hope this will help.
I mean the Eclipse preference under Window|Preferences|Spring|Beans Support
"Disable Auto Config Detection".
When this option is not checked, I notice a delay when saving Java files:
Building Workspace...
Loading ...ServerApplication
or
Loading ...DaoConfig
These messages are for Spring Boot main application classes (ServerApplication) or Spring configuration classes with #ComponentScan (DaoConfig) which are located in the workspace.
This can take a few seconds, which is a bit annoying.
When I check the above preference option, I don't notice the delay for loading these classes (at least for the Spring Boot main classes).
What are the consequences of disabling Auto Config Detection, e.g. what does this option really do, what functionality do I loose? Any pointers to documentation?
Can I speed up the save process without having to disable Auto Config Detection?
In STS3, the IDE creates an internal model of your Spring application, so that it can display a nice overview of your Spring elements in the Spring Explorer view, provide content-assist in Spring XML config files and more. In order to build up this internal Spring beans model, it needs to know where to start from when building that model. You can define those entry points manually in the properties for each project: Spring -> Beans Support. That preference allows you to define Spring XML config files and/or Spring-annotated configuration classes to be used by the IDE internally to build up that model.
In addition to that there is a mechanism to detect those files (Spring XML config files and Spring Boot application configuration annotations) automatically, so that you don't need to configure them manually. But the result is the same. Those files/classes end up being configured to be used by the IDE to built this internal model.
I guess that the delay that you see comes from building this internal beans model - this is at least what the messages indicate that you mentioned.
So far for the background. You can disable that auto-config mechanism and you don't need to configure those files/classes manually. This will result in the Spring Explorer, for example, not showing anything meaningful for those projects.
As an alternative and in case you are working mostly with Spring Boot projects, I would strongly recommend to switch to the all-new Spring Tools 4 (also available as a ready-to-use Eclipse distribution). It provides a slightly different set of features and is implemented in a different way, so that it doesn't need the expensive internal bean model creation. You should give it a try. And if you are missing something that you love in STS3 that is not yet part of Spring Tools 4, let us know.
As said in the title, is there a way to add application users in Thorntail WilFly server, much like you would do with "add-user.sh -a" script in the full server distribution?
I understand you can provide an external configuration file to Thorntail but that seems a bit of overhead just for specifying where users are located.
Thanks
The answer by Thomas Herzog is very good from a conceptual point of view -- I'd especially agree with securing the application using an external Keycloak, potentially with the help of MicroProfile JWT. I'm just gonna provide a few points in case you decide not to.
You can define users directly in project-defaults.yml, like this:
thorntail:
management:
security-realms:
ApplicationRealm:
in-memory-authentication:
users:
bob:
password: tacos!
in-memory-authorization:
users:
bob:
roles:
- admin
The project-defaults.yml file doesn't have to be external to the app, you can build it directly into it. Typically, in your source code, the file will be located in src/main/resources, and after building, it will be embedded inside the -thorntail.jar. It can be external, of course, and if this is something else than a throwaway prototype or test, sensitive data like this should be external.
You can also use the .properties files from WildFly:
thorntail:
management:
security-realms:
ApplicationRealm:
properties-authentication:
path: .../path/to/application-users.properties
properties-authorization:
path: .../path/to/application-roles.properties
It depends on for what you need the users? Thorntail creates standalone Microservices, which are different to hosted applications in a wildfly-server.
Is there are a management console in thorntail?
Yes there is, but I have never used it.
https://docs.thorntail.io/2.2.0.Final/#_management
https://docs.thorntail.io/2.2.0.Final/#_management_console
The users you maybe able to create there shouldn't be persistent, because there is no wildfly-server installation as you are used to with a standalone wildfly-server installation, it is all packaged in the jar. A Microservice shouldn't need to be configured after its deployment anymore, at least not like this.
How to secure my application?
I would recommend to use an external user management via keycloak, which is integrated in thorntail via the keycloak fraction. With the keycloak fraction you can define security constraints to your endpoints similar in a web.xml.
https://docs.thorntail.io/2.2.0.Final/#_keycloak
Another way is to use the security fraction which provides you JAAS support for your microservice.
https://docs.thorntail.io/2.2.0.Final/#_security
The configuration is done via the thorntail specific project-defaults.yml configuration file, where you can configure the fractions via YAML.
What is a thorntail fraction?
A thorntail fraction is similar to a spring boot start dependency with spring, whereby the fraction provides the API for the developement and bundles the implementation and integration into thorntail. The fraction actually is a jboss module which is packaged into the standalone Microservice during re-packaging phase.
Where can I find examples?
See the following links for examples how to use security in thorntail. You should take a look at them.
https://github.com/thorntail/thorntail-examples/tree/master/security
Take a look at the src/main/resources/projects-defaults.yml which contains the configuration for thorntail fractions and the pom.xml which defines the used fractions.