Cannot bind environment variable to application.properties - spring-boot

Im working with Spring-boot and PostgreSQL and failed to bind the database password to the application.properties. I have already set the DATABASE_PASSWORD to env but its still failed to bind the properties
spring.datasource.url=jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}?reWriteBatchedInserts=true
spring.datasource.username=${DATABASE_USER}
spring.datasource.password=${DATABASE_PASSWORD}
Description:
Failed to bind properties under 'spring.datasource.password' to
java.lang.String:
Property: spring.datasource.password
Value: ${DATABASE_PASSWORD}
Origin: class path resource [application.properties]:16:28
Reason: Could not resolve placeholder 'DATABASE_PASSWORD' in value "${DATABASE_PASSWORD}"

if you have set your database_password to a system environment as you say, than spring should use that as this says -:
The values in application.properties are filtered through the existing Environment when they are used, so you can refer back to previously defined values (for example, from System properties).
Did you try restarting ?

Related

encrypt key Property binding error in spring boot 2.7.0

I have Spring boot 2.7.0 application which connects config server with following configuration to decrypt secrets. But when I include below configuration in (application.yml or bootstrap.yml) getting binding error. Not sure what is the root cause of this issue as format is correct for the keys but still getting this error. Same config is working fine with Spring boot 2.2.1.
I have used same config in application.yml without bootstrap.yml as it depricated in 2.7.0 but still same issue.
encrypt:
key-store:
location: file:${key.path}
password: anthem$$docker
alias: docker
secret: anthem$$docker
org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'encrypt.key-store.alias' to java.lang.String
at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:384)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:344)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$4(Binder.java:469)
at org.springframework.boot.context.properties.bind.Binder$$Lambda$78/234145890.bindProperty(Unknown Source)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:95)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:83)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$5(Binder.java:473)
Description:
Failed to bind properties under 'encrypt.key-store.alias' to java.lang.String:
Property: encrypt.key-store.alias
Value: docker
Origin: class path resource [bootstrap.yml] - 40:12
Reason: org.springframework.boot.context.config.InactiveConfigDataAccessException: Inactive property source 'Config resource 'class path resource [bootstrap.yml]' via location 'optional:classpath:/' (document #5)' imported from location 'class path resource [bootstrap.yml]' cannot contain property 'encrypt.key-store.alias' [origin: class path resource [bootstrap.yml] - 40:12]
Action:
Update your application's configuration

Docker-compose string interpolation causes type conversion issue in spring boot project

I am running a stack of services/applications and would like to deploy these using a single docker-compose file. I tested this and it works flawlessly. But now, when I try to make the docker-compose file more configurable by having an .env file take control of the configuration the spring boot project that has to be deployed gives me the following error:
api | Failed to bind properties under 'spring.data.mongodb.port' to java.lang.Integer:
api |
api | Property: spring.data.mongodb.port
api | Value: '27017'
api | Origin: System Environment Property "spring.data.mongodb.port"
api | Reason: failed to convert java.lang.String to java.lang.Integer (caused by java.lang.NumberFormatException: For input string: "'27017'")
The env file I am using:
SPRING_DATA_MONGODB_PORT=27017
How the back-end is receiving the configuration request in spring boot's application.properties file:
spring.data.mongodb.port=27017
The problem is clear, but how do I make sure that whenever the environment variable arrives, the '27017' in String format is casted to an Integer?
Thanks!

JHipster Microservice Centralization without using Docker compose or any Docker container, need assistance

Currently the scenario is I am trying to implement
I used Jhipster Registry app directly from git-hub to use it as Eureka registry and Spring-Cloud-Config server(be default feature though).
I need to centralize the configurations of micro-service-apps' configurations files in Jhipster registry.
All these we have to do without using Docker as current project doesn't uses Docker.
To do that I made changes to
bootstrap.yml file as shown below( to run as composite profile though native type with local file system as we don't have access to production git repository. So chose file-system only with dev /composite profile only.
Currently my boostrap.yml looks as below
spring:
application:
name: jhipster-registry
profiles:
active: dev
include: composite
cloud:
config:
server:
bootstrap: true
composite:
- type: native #git
search-locations: file:/C:/Jhipster_Eureka/jhipster-registry-master/central-config/
prefix: /config
fail-fast: true
name: jhipster-registry
profile: composite
I have also created a gateway.yml file under central-config folder( gateway is one of micro-service sample app whose configuration I am trying to centralize, be it eureka client, data-source everything which comes under by default to application-dev.yml in the Jhipster micro-service gateway app I generated.)
by stating all configuration like below
gateway.yml
server:
port: 8888
management:
health:
diskspace:
enabled: false
# ===================================================================
# JHipster Sample Spring Cloud Config.
# ===================================================================
# Property used on app startup to check the config server status
configserver:
name: JHipster Registry config server
status: Connected to the JHipster Registry config server!
# Default JWT secret token (to be changed in production!)
jhipster:
security:
authentication:
jwt:
# It is recommended to encrypt the secret key in Base64, using the `base64-secret` property.
# For compabitibily issues with applications generated with older JHipster releases,
# we use the non Base64-encoded `secret` property here.
# secret: my-secret-key-which-should-be-changed-in-production-and-be-base64-encoded
# The `base64-secret` property is recommended if you use JHipster v5.3.0+
# (you can type `echo 'secret-key'|base64` on your command line)
base64-secret: bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo=
spring:
profiles:
active: dev
include:
- swagger
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://admin:admin#localhost:8761/eureka/
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/conference?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true
username: root
password: root
hikari:
poolName: Hikari
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
jpa:
show-sql: true
liquibase:
# Remove 'faker' if you do not want the sample data to be loaded automatically
contexts: dev
Issue#1
If I run my registry it's coming up properly without any issue. If I try to run "gateway" micro-service app without defining data-source definitions mentioned in it's own configuration file(application-dev.yml) it's failing at runtime.
Exception Stack trace during runtime
2020-08-06 21:45:58.301 WARN 28804 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Unsatisfied dependency expressed through method 'healthEndpoint' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'healthContributorRegistry' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthContributorRegistry]: Factory method 'healthContributorRegistry' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
I am surprised how eureka instance it picked up from that gateway.yml file but not the data source, so what went wrong here?
Issue#2
In the gateway.app yml server.port:8888 is mentioned, but would it be spring-cloud-config-server's port or the micro-service app port e.g., 8083
.
I observed if i try to alter that port from 8888 to 8083 it's giving error at runtime not able to find discovery client, what's the issue or am i still missing something configuration-wise?
Please let me know if the query is detailed enough now to respond.
Docker is absolutely NOT required for JHipster micro services architecture using jhipster-registry, your use case is well supported and the issues you encountered are only due to your configuration errors.
gateway.yml is not indented correctly so property names for datasource do not match and this is why you get this error about being unable to find JDBC driver.
The eureka block in the middle of the spring block completely broke it and anyway eureka config is shared by all apps so it should be placed in application-dev.yml and application-prod.yml.
gateway.yml as any other files that are in environment repository (central-config folder when using native) must be exactly the same format as your local application.yml files.
If you are not comfortable with YAML files you could switch to normal properties.
About file naming in native repository, Spring Cloud Config Server doc says:
If the repository is file-based, the server creates an Environment from application.yml (shared between all clients) and foo.yml (with foo.yml taking precedence). If the YAML files have documents inside them that point to Spring profiles, those are applied with higher precedence (in order of the profiles listed). If there are profile-specific YAML (or properties) files, these are also applied with higher precedence than the defaults.
So basically it means that in your central-config folder you should have these files:
application.yml: all properties common to all apps when no profile is set
application-dev.yml: all properties common to all apps when dev profile is set. This is where you will put the JWT secret for dev, the url for dev Eureka server (often localhost)
application-prod.yml: all properties common to all apps when prod profile is set. This is where you will put the JWT secret for prod, the url for prod Eureka server
gateway.yml: all properties of gateway app when no profile is set
gateway-dev.yml: all properties of gateway app when dev profile is set. This is where you will put dev datasource
gateway-prod.yml: all properties of gateway app when prod profile is set. This is where you will put prod datasource
So when your gateway bootstraps with dev profile, it will gets a combination of application.yml, application-dev.yml, gateway.yml and gateway-dev.yml
This mechanism can work only if you follow the naming convention {app name}-{profile}.yml
So, having named a file application-dev-gateway.yml just meant properties common to all apps with dev-gateway profile which is probably not what you meant.

${VAULT_SCHEME} not working in bootstrap.properties

I have configured spring boot application to take properties from my environment but strangely I am facing an error while starting my application.
I have added the properties in my ~/.bash_profile and also did source ~/.bash_profile after adding them to the profile.
This is how my bootstrap.properties look like:
spring.application.name=gamification
spring.cloud.vault.enabled=${VAULT_ENABLE:true}
spring.cloud.vault.fail-fast=false
spring.cloud.vault.token=${VAULT_TOKEN}
spring.cloud.vault.scheme=${VAULT_SCHEME}
spring.cloud.vault.host=${VAULT_HOST}
spring.cloud.vault.port=${VAULT_PORT:8200}
I am getting this error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.vault.config.VaultReactiveBootstrapConfiguration]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Scheme must be http or https
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:216) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
... 30 common frames omitted
Caused by: java.lang.IllegalArgumentException: Scheme must be http or https
at org.springframework.util.Assert.isTrue(Assert.java:118) ~[spring-core-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.vault.client.VaultEndpoint.setScheme(VaultEndpoint.java:167) ~[spring-vault-core-2.2.0.RELEASE.jar:2.2.0.RELEASE]
at org.springframework.cloud.vault.config.VaultConfigurationUtil.createVaultEndpoint(VaultConfigurationUtil.java:91) ~[spring-cloud-vault-config-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.cloud.vault.config.VaultReactiveBootstrapConfiguration.<init>(VaultReactiveBootstrapConfiguration.java:110) ~[spring-cloud-vault-config-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_231]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_231]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_231]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_231]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:203) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
... 32 common frames omitted
I added a debug point in Vault Endpoint and found this:
Here as you can see, the VAULT_HOST is being taken as VAULT_HOST instead of the value of that environment variable, and same with the VAULT_SCHEME
[EDIT]
Adding bash_profile vault configuration:
export VAULT_ENABLE=true
export VAULT_SCHEME=http
export VAULT_HOST=vault-1.dev.lokal
export VAULT_PORT=8200
export VAULT_TOKEN=5F97X
[EDIT #2]
Tried out the solution suggested by #Gopinath
I am getting environment as null when trying to autowire it
The root cause of the problem can be found form this error message:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting
from type [java.lang.String]
to type [org.springframework.cloud.vault.config.VaultProperties$Config]
The above message indicates that the VaultProperties object could not be initialized using the string parameter supplied.
Here is the link to documentation and instructions on configuring VaultProperties:
https://spring.io/guides/gs/vault-config/
Some more information to help understand vault:
References:
Spring Cloud Vault: https://cloud.spring.io/spring-cloud-vault/
Hashicorp Vault: https://www.vaultproject.io
What is a Vault?
A vault is a secure storage space meant for storing secret information.
Hashicorp Vault is one tool that offers vault functionality for cloud applications.
What is Spring Boot Vault?
Spring Boot applications commonly require secret information for those to work.
Some examples of secret information are:
Database password
Private key
API key
Usually, the input parameters are passed to Spring boot application through the
"application.properties" file or "bootstrap.properties" file.
The use of such properties file poses a security risk, if secret data is directly mentioned in the file.
Spring Boot Vault addresses this risk.
It pulls secret information from vault and supplies to the application at the start-up time.
The .properties file will only tell the application the names of parameters that it can expect from Vault.
The actual values of the parameters will be taken from vault.
How to setup Vault?
Step 1: Install and launch HashiCorp Vault from
https://www.vaultproject.io/downloads.html:
Step 2: After installing Vault, test whether it works, by launching
it in a console window.
> vault server --dev --dev-root-token-id="spring-boot-vault-demo"
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: false, enabled: false
Recovery Mode: false
Storage: inmem
Version: Vault v1.4.1
WARNING! dev mode is enabled!
.....
You may need to set the following environment variable:
PowerShell:
$env:VAULT_ADDR="http://127.0.0.1:8200"
cmd.exe:
set VAULT_ADDR=http://127.0.0.1:8200
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: +Dihvgj/oRN2zo6/97ZqpWt086/CFRZEPkuauDu4uQo=
Root Token: spring-boot-vault-demo
Step 3: Store some secret data in the vault,
by running these commands in a separate command window:
> set VAULT_ADDR=http://127.0.0.1:8200
> set VAULT_TOKEN=spring-boot-vault-demo
> vault kv put secret/spring-boot-vault-demo password=££££$$$$%%%%
Key Value
--- -----
created_time 2020-05-02T09:59:41.2233332Z
deletion_time n/a
destroyed false
version 1
I did this:
I made a shell script called setenv.sh and put this under it:
#!/bin/bash
launchctl setenv VAULT_ENABLE true
launchctl setenv VAULT_SCHEME http
launchctl setenv VAULT_HOST vault-1.dev.lokal
launchctl setenv VAULT_PORT 8200
launchctl setenv VAULT_TOKEN 5F97X
And then, before starting the application I ran the shell script with
sudo sh setenv.sh
And the application seems to work fine without any errors. Strangely if I do it with my previous approach of adding the env variables inside the .bash_profile, it doesn't work.

spring boot Invalid bean definition with name 'WDSDataSource' defined in URL "

while executing the application getting invalid "WDSDataSource" in persistance.xml , could not resolve placeholder "AppEncryptionKey"
Below is snap of persistence.xml of wds configuration.
<bean id="WDSDataSource" class="com.deere.dsfj.utility.datasource.DSFJTomcatDataSource" init-method="initialize"
p:username="${ApplicatinID}"
p:encryptionKey="${AppEncryptionKey}"
p:encryptionPassword="${AppEncryptedPassword}"
p:driverClassName="com.ibm.db2.jcc.DB2Driver"
p:url="${WDSJdbcUrl}"
p:testWhileIdle="false"
p:testOnBorrow="true"
p:testOnReturn="false"
p:validationInterval="300000"
p:timeBetweenEvictionRunsMillis="300000"
p:maxActive="80"
p:initialSize="0"
p:maxWait="300000"
p:removeAbandonedTimeout="300"
p:minEvictableIdleTimeMillis="300000"
p:minIdle="1"
p:maxIdle="10"
p:logAbandoned="true"
p:removeAbandoned="true"/>
Looks like spring is not able to find any value or the Key AppEncryptionKey in your properties file from which you are taking these values.
So ensure that the key AppEncryptionKey is present in the properties file.

Resources