首页 文章

Spring环境中的SpringBoot Eureka CloudConfig

提问于
浏览
2

我想为微服务环境提供以下加密设置 . 支持SSL的Eureka Server具有 Cloud 配置服务和多个微服务,只需连接到Discovery服务,读取配置并运行其内容 . 一切都通过HTTPS和身份验证 .

那么......我做了什么:

包含/ config / *上的 Cloud 配置服务的Eureka Discovery Server服务器正在向Eureka服务器注册,Eureka Dashboard显示该实例 . 此服务在端口9001上运行,启用了SSL并进行了用户身份验证 . 该服务照常运作 .

然后我创建了一个新的SpringBoot服务,它连接到Eureka并注册到它 . 由于自签名证书,我在这篇文章中写了一个小的SSLConfguration类:How to override Spring Cloud Eureka default discovery client default ssl context?将我的个人信任库提供给底层的EurekaClient . 我们所有的服务都配置了application.yml:

spring:
    application:
        name: mark2

server:
    port: 9998
    ssl:
        enabled: true
        key-store: classpath:keystore.p12
        key-store-password: changeit
        key-store-type: PKCS12
        keyAlias: mark2

http:
    client:
      ssl:
          trust-store: classpath:keystore.p12
          trust-store-password: changeit

eureka:
    client:
        serviceUrl:
            defaultZone: https://user:pass@localhost:9001/eureka

客户端完美地连接和注册 .

现在,我希望SpringBoot服务注册到Eureka Server并在引导程序中从Config Server加载配置 . 所以我把spring,http和eureka设置移到了bootstrap.yml

spring:
    application:
        name: mark2
    cloud:
        config:
            username: user
            password: password
            discovery:
                enabled: true
                serviceId: EUREKA-DISCOVERY-SERVICE
            failFast: true
            name: my
            profile: settings
#            label: v1

http:
    client:
      ssl:
          trust-store: classpath:keystore.p12
          trust-store-password: changeit

eureka:
    client:
        serviceUrl:
            defaultZone: https://user:password@localhost:9001/eureka
    instance:
        metadataMap:
            user: user
            password: password
            configPath: /config

如果服务启动,它会尝试在引导期间连接到Eureka服务器 . 这不起作用,因为它不信任来自Eureka服务器的自签名证书 . 我不能使用@Configure或@Bean,因为我在引导程序中(至少我找不到任何工作) . 上面的SSLConfiguration解决方案也不行 .

好的,然后我将JVM args与javax.net.ssl.trustStore等设置到我的个人信任库 .

bootRun {
   jvmArgs = [ 
     "-Djavax.net.ssl.trustStore=/absolute/path/to/keystore.p12", 
     "-Djavax.net.ssl.trustStorePassword=changeit", 
     "-Djavax.net.ssl.trustStoreType=PKCS12", 
   ]
}

服务启动,Eureka客户端开始与Eureka服务器通信,找到Cloud Configuration实例并加载属性文件并创建Spring上下文 . 该属性仅包含一些测试属性 .

但是 - 然后 - 错误:

Field optionalArgs in org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration required a single bean, but 2 were found:
    - getTrustStoredEurekaClient: defined by method 'getTrustStoredEurekaClient' in class path resource [de/mark2/SslConfiguration.class]
    - discoveryClientOptionalArgs: defined by method 'discoveryClientOptionalArgs' in org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration

好的,不好但还可以 . 因为我们给了JVM args,所以我们不应该再使用SSLConfiguration了 . 删除 .

现在 - 一切似乎都没问题,服务应该启动嵌入式Tomcat . 但这不起作用,因为另一个异常说,配置的密钥库为空(“trustAnchors参数必须为非空”表示密钥库存在但不包含任何别名证书) . 我认为,JVM args用于嵌入式Tomcat,它试图将信任库用于某种类型的ClientCertificates . 我不知道 .

如果我禁用 Cloud 配置 - 嵌入式Tomcat仍然具有相同的错误 . 如果我然后删除了JVM args - 服务就会出现 .

所以 - 我没有想法,我需要做什么,在引导期间进行加密通信而不为Eureka客户端定义JVM args或者为嵌入式tomcat提供Truststore(他不需要) .

2 回答

  • 1

    定义META-INF / spring.factories并添加org.springframework.cloud.bootstrap.BootstrapConfiguration = ...行

    这个班可能是这样的:

    @Configuration
    @BootstrapConfiguration
    public class SslConfiguration {
      @Value("${http.client.ssl.trust-store}")
      private URL trustStore;
      @Value("${http.client.ssl.trust-store-password}")
      private String trustStorePassword;
    
      @Bean
      public DiscoveryClient.DiscoveryClientOptionalArgs getTrustStoredEurekaClient(SSLContext sslContext) {
        DiscoveryClient.DiscoveryClientOptionalArgs args = new DiscoveryClient.DiscoveryClientOptionalArgs();
        args.setSSLContext(sslContext);
        return args;
      }
    
      @Bean
      public SSLContext sslContext() throws Exception {
        return new SSLContextBuilder().loadTrustMaterial(trustStore, trustStorePassword.toCharArray()).build();
      }
    }
    

    并且因为DiscoveryClientOptionalArgs现在定义了两次,然后添加另一个类,它在Spring Context up之后加载

    @Configuration
    public class DiscoveryServiceConfiguration {
      @Bean
      public static BeanFactoryPostProcessor registerPostProcessor() {
        return (ConfigurableListableBeanFactory beanFactory) -> {
          BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
          for (String beanDefinitionName : registry.getBeanDefinitionNames()) {
            if (beanDefinitionName.equalsIgnoreCase("discoveryClientOptionalArgs")) {
              BeanDefinition beanDefinition = registry.containsBeanDefinition(beanDefinitionName) ? registry.getBeanDefinition(beanDefinitionName) : null;
              if (beanDefinition != null) {
                if (registry.containsBeanDefinition(beanDefinitionName)) {
                  registry.removeBeanDefinition(beanDefinitionName);
                }
              }
            }
          }
        };
      }
    }
    

    然后它也有效 . 您不再需要定义JVM args .

  • 0

    有趣的事情 - 如果我使用嵌入式Undertow而不是嵌入式Tomcat,它可以工作 - 但这是解决方案吗?

    dependencies {
      compile("org.springframework.boot:spring-boot-starter") {
        exclude module: "tomcat-embed-el"
      }
      compile("org.springframework.boot:spring-boot-starter-web") {
        exclude module: "spring-boot-starter-tomcat"
      }
      compile('org.springframework.boot:spring-boot-starter-undertow')
      ...
    }
    

相关问题