I set up multiple instances of eureka servers on the same host. They are using host names eureka-primary, secondary and tertiary which are defined as the localhost aliases in the hosts file and everything is working just fine - they are all visible and available to each other as different instances.
The problem starts when I try to secure eureka instances with basic auth
and this. The idea is add spring security dependency, to specify the security user and password on eureka servers, and to put these credentials in the defaultZone
urls (configs are below), but this does not seem to work.
Eureka instances can't even register to each other and when I try to access eureka web portal I am prompted with login form and then redirected to dashboard. All dashboards are working fine and need credentials to be accessed.
I am using spring cloud Finchley.RC1
with spring boot 2.0.1.RELEASE
and the same version of spring-boot-starter-security
and spring-cloud-starter-netflix-eureka-server
.
Eureka server pom.xml
<?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>rs.microservices</groupId>
<artifactId>eurekaServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eurekaServer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.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>Finchley.RC1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
Eureka server application.yml
---
spring:
security:
user:
name: admin
password: admin
profiles: primary
application:
name: eureka-server-clustered
server:
port: 8011
eureka:
instance:
hostname: eureka-primary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-secondary:8012/eureka/,http://admin:admin@eureka-tertiary:8013/eureka/
---
spring:
security:
user:
name: admin
password: admin
profiles: secondary
application:
name: eureka-server-clustered
server:
port: 8012
eureka:
instance:
hostname: eureka-secondary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-primary:8013/eureka/,http://admin:admin@eureka-tertiary:8011/eureka/
---
spring:
security:
user:
name: admin
password: admin
profiles: tertiary
application:
name: eureka-server-clustered
server:
port: 8013
eureka:
instance:
hostname: eureka-tertiary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-primary:8011/eureka/,http://admin:admin@eureka-secondary:8012/eureka/
Microservice bootstrap.yml
spring:
application:
name: someService
server:
port: 0
eureka:
client:
registerWithEureka: true
fetchRegistry: true
service-url:
defaultZone: http://admin:admin@localhost:8011/eureka/,http://admin:admin@localhost:8012/eureka/,http://admin:admin@localhost:8013/eureka/
What am I doing wrong?
*EDIT
I already found multiple solutions like this one Securing Eureka in Spring cloud, but none of them really fixed my problem - as you can see our configurations are identical.
Solved!
TL;DR
The problem was the CSRF
and for some reason spring couldn't authenticate user configured in application.yml
So I had to override configure methods from WebSecurityConfigurerAdapter
to disable csrf and create inMemory user. Also removed spring.security.user attributes from application.yml.
Eureka server application.yml
now looks like:
---
spring:
profiles: primary
application:
name: eureka-server-clustered
server:
port: 8011
eureka:
instance:
hostname: eureka-primary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-secondary:8012/eureka,http://admin:admin@eureka-tertiary:8013/eureka
---
spring:
profiles: secondary
application:
name: eureka-server-clustered
server:
port: 8012
eureka:
instance:
hostname: eureka-secondary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-primary:8013/eureka,http://admin:admin@eureka-tertiary:8011/eureka
---
spring:
profiles: tertiary
application:
name: eureka-server-clustered
server:
port: 8013
eureka:
instance:
hostname: eureka-tertiary
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://admin:admin@eureka-primary:8011/eureka,http://admin:admin@eureka-secondary:8012/eureka
Newly created WebSecurityConfig
class:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin")
.authorities("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}