我试图为spring cloud eureka服务器启用https。 Yaml配置:
server:
port: 8100
ssl:
clientAuth: want
protocol: TLS
key-store: classpath:keystore/keystore.jks
key-store-password: some
key-password: some
eureka:
instance:
prefer-ip-address: true
non-secure-port-enabled: false
secure-port-enabled: true
secure-port: ${server.port}
healthCheckUrl: https://${eureka.hostname}:${secure-port}/health
statusPageUrl: https://${eureka.hostname}:${secure-port}/info
homePageUrl: https://${eureka.hostname}:${secure-port}/
security:
basic:
enabled: true
然后我启动一个客户端注册到服务器。我没有导入自签名证书,因此我得到了解雇 sun.security.provider.certpath.SunCertPathBuilderException:无法找到所请求目标的有效证书路径。我不想导入证书,因为有大量的实例和证书管理成本很高。因此,我将cert放在classpath中并在启动时加载它。我通过添加代码
覆盖客户端默认的ssl上下文和ssl socket facotorySSLContext.setDefault(sslContext);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
当使用假装调用其他eureka客户端时,它工作正常。但是,在注册到eureka服务器时它没有任何努力。 我检查了源代码,发现eureka发现客户端使用jersey,jersey调用http apache客户端。 问题是,它使用 SchemeRegistryFactory.createDefault(),它将最终调用 SSLContexts.createDefault(),他们不会考虑系统属性。换句话说,这个http客户端不会标记我的自定义SSLContexts。 所以我的问题是,有一种方法可以在eureka发现客户端中添加/重新定位/替换默认的http客户端吗?
答案 0 :(得分:6)
最后,我在多次挖掘源代码后找到了解决方案。我正在使用版本Camden.SR5,它将调用eureka-client-1.4.12。
如果您在 DiscoveryClientOptionalArgs 中提供 EurekaJerseyClient ,则Discovery客户端将不会初始化默认客户端。类 DiscoveryClient 。
中的部分代码enum TopBarStyle: Bool {
case darkOnLight
case lightOnDark
}
@IBInspectable var style = TopBarStyle(rawValue: false)!
然后我添加一个类来创建 DiscoveryClientOptionalArgs bean。
private void scheduleServerEndpointTask(EurekaTransport eurekaTransport,
DiscoveryClientOptionalArgs args) {
...
EurekaJerseyClient providedJerseyClient = args == null
? null
: args.eurekaJerseyClient;
eurekaTransport.transportClientFactory = providedJerseyClient == null
? TransportClientFactories.newTransportClientFactory(clientConfig, additionalFilters, applicationInfoManager.getInfo())
: TransportClientFactories.newTransportClientFactory(additionalFilters, providedJerseyClient);
...
}
}
为确保我的自定义 EurekaJerseyClient 运行良好,我从 EurekaJerseyClientImpl 分叉代码并进行了一些修改。
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
import com.qy.insurance.cloud.core.eureka.CustomEurekaJerseyClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class EurekaSslConfig {
@Value("${eureka.client.service-url.defaultZone}")
private String defaultZone;
@Autowired
private EurekaClientConfig config;
@Autowired
private DefaultSslConfig defaultSslConfig;
@Bean
public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs(){
if(!defaultSslConfig.isFinish()){
log.warn("Default SSLContext might not have been updated! Please check!");
}
DiscoveryClient.DiscoveryClientOptionalArgs args = new DiscoveryClient.DiscoveryClientOptionalArgs();
CustomEurekaJerseyClientBuilder clientBuilder = new CustomEurekaJerseyClientBuilder()
.withClientName("DiscoveryClient-HTTPClient-Custom")
.withUserAgent("Java-EurekaClient")
.withConnectionTimeout(config.getEurekaServerConnectTimeoutSeconds() * 1000)
.withReadTimeout(config.getEurekaServerReadTimeoutSeconds() * 1000)
.withMaxConnectionsPerHost(config.getEurekaServerTotalConnectionsPerHost())
.withMaxTotalConnections(config.getEurekaServerTotalConnections())
.withConnectionIdleTimeout(config.getEurekaConnectionIdleTimeoutSeconds() * 1000)
.withEncoderWrapper(CodecWrappers.getEncoder(config.getEncoderName()))
.withDecoderWrapper(CodecWrappers.resolveDecoder(config.getDecoderName(), config.getClientDataAccept()));
if (defaultZone.startsWith("https://")) {
clientBuilder.withSystemSSLConfiguration();
}
EurekaJerseyClient jerseyClient = clientBuilder.build();
args.setEurekaJerseyClient(jerseyClient);//Provide custom EurekaJerseyClient to override default one
return args;
}
希望这可以帮助那些不像我一样在生产JVM中导入证书的人。
答案 1 :(得分:0)
我设法在Finchley.M9 spring cloud中向eureka客户端注入了ssl-context,如下所示:
@Configuration
public class SslConfiguration {
private static final Logger logger = LoggerFactory.getLogger(LoggerConfiguration.class);
@Value("${http.client.ssl.trust-store}")
private File 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 {
logger.info("initialize ssl context bean with keystore {} ", trustStore);
return new SSLContextBuilder()
.loadTrustMaterial(
trustStore,
trustStorePassword.toCharArray()
).build();
}
}