Eureka registration based on host - spring-boot

I'm working with a simple example of a Spring Boot Eureka service registration. I am using spring-boot-starter 1.5.4.RELEASE, spring-cloud-starter-eureka 1.3.1.RELEASE. The eureka server should register the client instance only if the registration request are coming from white-listed servers.
Is there any out of box feature available in Spring Boot Eureka to achieve this requirement.

The username and password for login is more preferred.
Add maven dependency:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
Add username and password and other configurations to your configuration file application.yaml, note that the client.service-url.defaultZone should contain username and password:
security:
basic:
enabled: true
user:
name: user
password: 123456
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://user:123456#${eureka.instance.hostname}:${server.port}/eureka/

Related

The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]

I'm trying to connect to a sql server but I get the error:
The server selected TLS10 protocol version is not supported by client preferences [TLS13, TLS1]
I've already tried some solutions like "encrypt=false" and also editing the "java.security" file and removing TLSv1.1 and/or TLSv1 and trying to connect with jtds, but all result in the same error. How can I solve this?
Application.yml
server:
port: 8081
spring:
datasource:
#url: jdbc:jtds:sqlserver://123.345.7.890:1433;databaseName=mydatabase
url: jdbc:sqlserver://123.345.7.890:1433;databaseName=mydatabase
username: sa
password: mypassword
#driver-class-name: net.sourceforge.jtds.jdbc.Driver
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.SQLServerDialect
My drivers in pom.xml:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
</dependency>

Spring Cloud Config - config loaded twice and without profile

I have problem with properly configuring spring cloud config. I have dependencies
<spring.cloud.version>2021.0.3</spring.cloud.version>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
Boostrap.yml
spring:
application.name: myapp
profiles:
active: dev
config:
import: optional:configserver:http://ip:8888
cloud:
config:
enabled: true
username: admin
password: secret
Now when my application starts it loads config twice. The first load is by class ConfigServicePropertySourceLocator and is without expected profile. The second is by ConfigServerConfigDataLoader and this time it is with proper profile. It seems that the configs loaded during first load takes precedence and my application does not start.
12:32:54 [ConfigServicePropertySourceLocator:241] - Fetching config from server at : http://ip:8888
12:32:54 [ConfigServicePropertySourceLocator:165] - Located environment: name=myapp, profiles=[default], label=null, version=7d2bc5d68acd8fcca65f34f2074b1860f36e19c6, state=null
12:32:54 [MyApplication:646] - The following 1 profile is active: "dev"
12:32:54 [ConfigServerConfigDataLoader:255] - Fetching config from server at : http://ip:8888
12:32:54 [ConfigServerConfigDataLoader:255] - Located environment: name=myapp, profiles=[dev], label=null, version=7d2bc5d68acd8fcca65f34f2074b1860f36e19c6, state=null
Providing profile using param -Dspring.profiles.active=dev does not help. How to configure profile that can be read by boostrap?
Add file resources -> bootstrap.properties
spring.application.name=myapp
spring.profiles.active=dev
# ip and port of the config server
spring.cloud.config.uri=http://localhost:8888

Spring boot application - failed to start

I have recently upgraded spring boot from 1.x to 2.2.1. I am able to deploy most of the modules. For one of the modules I am getting below error while deploying in openshift.
***************************_APPLICATION FAILED TO START_***************************__Description:__Failed to bind properties under 'spring.jackson.serialization' to java.util.Map<com.fasterxml.jackson.databind.SerializationFeature, java.lang.Boolean>:__ Reason: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<com.fasterxml.jackson.databind.SerializationFeature, java.lang.Boolean>]__Action:__Update your application's configuration_
I have added jackson-databind and jackson-core dependencies but no luck.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.1</version>
</dependency>
In local environment the deployment works fine.
application.yml:
application:
name: #project.name#
server:
port: 8085
context: /*
sessionAPIUrl: localhost:8087
sessionAPIUri: /AppMS/user/session
account:
host: http://localhost:8080
remote:
dev: http://localhost:8080
test: http://10.8.99.8:8080
staging: https://stg2-tic.myapp.com
prod: https://ss1.myapp.com
uri:
data: AppMS/service/test
javax.persistence.query.timeout: 120000
#mongodb
spring.data.mongodb.authentication-database:
spring.data.mongodb.host:
spring.data.mongodb.port: 22017
spring.data.mongodb.database: ticnf
spring.data.mongodb.username: ******
spring.data.mongodb.password: ******
#JMX setting
endpoints.jmx.unique-names: true
#logging setup
logging.level.org.springframework.web: WARN
logging.level.com.myapp: INFO
# Logging pattern for the console
logging.pattern.console: "%d{dd-MMM-yyyy HH:mm:ss:SSS zzz}, TYPE= %-5p, SESSIONID=%X{sessionID}, CLIENT_IP=%X{UserIPAddress}, REQID=%X{requestID}, SSOUID=%X{ssoUserId}, ticUID=%X{ticUserID}, APP=%X{APP}, REQUESTURI=%X{requestURI}, CLASS=%c{1}, METHOD=%M, MSG=%m%n"
# Logging pattern for file
logging.pattern.file: "%d{dd-MMM-yyyy HH:mm:ss:SSS zzz}, TYPE= %-5p, SESSIONID=%X{sessionID}, CLIENT_IP=%X{UserIPAddress}, REQID=%X{requestID}, SSOUID=%X{ssoUserId}, ticUID=%X{ticUserID}, APP=%X{APP}, REQUESTURI=%X{requestURI}, CLASS=%c{1}, METHOD=%M, MSG=%m%n"
logging.file: logs/ticms/ticms.log
#kafka configuration
kafka:
broker:
address: localhost:9099
zookeeper:
connect: localhost:2191
consumerId: tic.account
tic.secret: where to store this is an question? DB/File?
spring:
profiles: dev
jackson:
serialization:
INDENT_OUTPUT: true
datasource:
driver-class-name: com.ibm.db2.jcc.DB2Driver
url: jdbc:db2://192.0.0.1:9000/sdb1:currentSchema=DEV1;
username: *****
password: *****
platform: db2
schema: classpath:schema-db2-stg.sql
jpa:
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.DB2Dialect
default_schema: DEV1
server:
domainURI: https://stg-us-api.myapp.com/oauth2/v1
log4j.logger.org.hibernate.type: trace
org.hibernate.type: trace
org.springframework.transaction: debug```
Thank you everyone.
When I saw the error message saying "_Update your application's configuration" , I was sure something is wrong in my application.yml. But in local it was deploying fine.
In paas it was failing, hence I tried to check all the paas related config files. paas-pom was ok. FInally I found application-paassit.yml file was missing. This file was mentioned in my config map for that application in openshift.
I added the file and it was solved.

Oauth2 security behind load balander

I'm struggling with authorization problem within my local kubernetes cluster when my application are replicated and listen behind load balancer.
architecture-image
I've created some basic application using spring boot and security oauth2 library. I've also launch keycloak (sso) application. They are listening under domains: hello.org (app) and sso.org (keycloak). I thought to add some load balancing before application, but there is the main problem. How to properly complete the login process if the requests are spread evenly over e.g two pods? The authorization process required few redirects, so first request will go to first one, second to another and process will fail cause they don't have shared information about state.
I'm using authorization code flow.
Here is my libraries responsible for security implementation and basic config.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
server:
port: 8080
logging:
level:
org.springframework.security: DEBUG
org.springframework.security.oauth2: DEBUG
org.springframework.security.jwt: DEBUG
keycloak-client:
server-url: http://sso.org/auth
realm: demo
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: hello-app
client-secret: b3ed7f13-88cc-4de1-9dc0-59c80b310dfb
client-name: Hello Application
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
scope:
- hello
- openid
- profile
- email
provider:
keycloak:
token-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/token
authorization-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/auth
user-info-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/userinfo
jwk-set-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/certs
user-name-attribute: preferred_username
filter:
order: 100
I found a way to resolve my problem with sticky session implementation on Load Balancer. It's not the best solution, but for my case is just fine.
Here is my Ingress configuration to enable sticky session.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: hello-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "INGRESS"
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
nginx.ingress.kubernetes.io/session-cookie-path: /
spec:
rules:
- host: hello.org
http:
paths:
- path: /
backend:
serviceName: hello-app
servicePort: 8080
For more information visit: https://kubernetes.github.io/ingress-nginx/examples/affinity/cookie/

Trying to get Spring/Consul/Vault to work together

I'm trying to do something I think is simple. I want to use Consul for configuration, and Vault for secrets.
What I'm looking for is a simple app like this that allows me to get config and services from Consul, and secrets from Vault.
In my example, Consul and Vault are connected, and I can see Vault in the Consul services and key-value store.
In Postman, I can query Vault directly and see my data at {{vault_url}}/v1/secret/interservice-bus/data-categorizer
Right now I cannot see Consul or Vault values in the test app.
My application.yml is simple
spring:
profiles:
active: dev
main:
banner-mode: "CONSOLE"
application:
name: test-consul
logging:
level:
org: INFO
The bootstrap.yml is where I'm doing most of my configuration. Some of it is repeated, because Spring complains if different parts are missing. I'm not sure why.
spring:
profiles:
active: vault, dev
cloud:
consul:
host: 127.0.0.1
port: 8500
config:
enabled: true
discovery:
prefer-ip-address: true
config:
discovery:
enabled: true
service-id: vault
server:
vault:
host: localhost
port: 8200
scheme: http
authentication: TOKEN
token: 00000000-0000-0000-0000-000000000000
vault:
host: localhost
port: 8200
scheme: http
connection-timeout: 5000
read-timeout: 15000
authentication: TOKEN
config:
order: -10
token: 00000000-0000-0000-0000-000000000000
discovery:
enabled: true
service-id: vault
The token is obscured above, but does match the root token for the vault.
Here's my POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.dkist</groupId>
<artifactId>test-consul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test-consul</name>
<description>Small test to see if consul can work with vault</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-dependencies</artifactId>
<version>1.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
And here's the simple app I'm trying to run
package com.example.demo;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
#RefreshScope
#SpringBootApplication
#EnableDiscoveryClient
public class DemoApplication {
#Autowired
org.springframework.cloud.client.discovery.DiscoveryClient discoveryClient;
#Value("${test}")
private String testString;
#Value("${interservice-bus.data-categorizer.username}")
private String user;
#Value("${interservice-bus.data-categorizer.password}")
private String password;
#PostConstruct
public void setRabbitMQLocation() {
if (discoveryClient == null) {
System.out.println("******************************ERROR: Discovery Client is null******************************");
return;
}
System.out.println("****************************** Discovery Client is ACTIVE ******************************");
org.springframework.cloud.client.ServiceInstance serviceInstance =
discoveryClient.getInstances("interservice-bus")
.stream()
.findFirst()
.orElseThrow(() -> new RuntimeException("ERROR: " + "interservice-bus" + " not found"));
System.out.println("****************************** ISB is " + serviceInstance.getHost() + ":" + serviceInstance.getPort() + " ******************************");
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
It's not finding "test". I am trying to pull the username and password from Vault, and test from Consul.
I'm getting
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-06-20 16:30:33.580 ERROR 92722 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.demoApplication': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'test' in value "${test}"
What I'm looking for is a simple app like this that allows me to get config and services from Consul, and secrets from Vault.
From searching on the net and looking at examples, it's not clear to me if I need to pull in the Vault dependencies as well or if I'm getting everything from Consul (and thus don't need the Vault dependencies).
To get configuration from Vault you need to add Spring Cloud Vault to your pom.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
With Spring Cloud Dalston.SR4 (which you used in your pom) you will receive Spring Cloud Vault 1.0.2. So be aware that this version has less stuff than newer one (e.g. you cannot use discovery feature). If you want to use it, consider using at least Edgware.SR4 which comes with Spring Cloud Vault 1.1.1.RELEASE. You can always check version information here: https://github.com/spring-projects/spring-cloud/wiki#release-notes. Anyway, it still will work, but you need to configure it.
Your bootstrap.yml should look like this.
spring:
application:
name: test-consul
profiles:
active: dev
vault:
fail-fast: true
host: localhost
port: 8200
scheme: http
authentication: TOKEN
config:
order: -10 # not sure that you need this, didn't investigate
token: <your_token>
Spring Cloud Vault will search configuration in Vault based on your application name and profile using Vault HTTP API. So you need to store information according to next patterns. (See documentation for Spring Cloud Vault 1.0.2)
/secret/{application}/{profile}
/secret/{application}
/secret/{default-context}/{profile}
/secret/{default-context}
Example:
vault write secret/test-consul/dev username=test_user
In this case during application start Spring Cloud Vault will get properties from secret/test-consul/dev and create Property Source from them. To get value of this test property you should use only key. Example:
#Value("${username}")
private String user; // will be resolved to "test_user"
Getting properties from Consul KV storage is similar. bootstrap.yml file is:
spring:
profiles:
active: dev
application:
name: test-consul
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
Spring Cloud Consul will use next patterns (all of them) for getting key-values from Consul using HTTP API. See documentation for Spring Cloud Consul 1.2.1 (it comes with Dalston.SR4):
config/testApp,dev/
config/testApp/
config/application,dev/
config/application/
So you need to save data accordingly. I did it from Consul GUI by creating folders in KV Storage, using console it should look similarly to this:
consul kv put config/test-consul/test testvalue
By getting data using HTTP API Spring Cloud Consul will create a property source from properties stored there and you will be able to get this using
#Value("${test}")
private String testString; // will be resolved to "testvalue"
You can combine 2 configurations and use Spring Cloud Consul and Vault simultaneously. I did't use application.yml at all for this demo.
Hope this long post will help you :)

Resources