- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
背景是我正在开发一个 Kubernetes 项目,我们使用 Geode 集群和 Spring Boot,以及 Spring Boot Data Geode (SBDG)。我们用它开发了一个应用程序,一个ClientCache。此外,我们有一个专有的内部机制来生成集群内部证书,这种机制会根据最佳实践自动更新证书。我们将 App 代码中的 PEM 格式证书转换为 JKS,并使用 @EnableSSL 注释配置 Spring 以获取它们。
所以问题是,在第一个周期中,一切都运行良好,当使用应用程序最初启动的 JKS 文件创建连接时,但是如果证书更新,比如每小时更新一次(在云中这是最佳实践),Geode 失败与一堆异常连接,有时是 SSLException (readHandshakeRecord),很多时候是“无法连接到列表中的任何定位器”(但我调试过,它也是一个 HandshakeException,只是包装在一个连接异常中) .定位器和服务器已启动并正在运行(我检查了 GFSH),只是我认为尝试与旧 SSLContext 连接并在 SSL 握手中失败的应用程序。
到目前为止,我发现的唯一方法是完全重新启动应用程序,但我们需要这个系统是自动的、高度可用的,所以这不应该是解决这个问题的唯一方法。
我认为这个问题正在影响很多 Spring/Java 项目,因为我发现这个问题无处不在(Kafka、PGSQL 等......)。
你们有什么方法可以做到这一点吗?
有没有办法:
@Configuration
@EnableGemfireRepositories(basePackages = "...")
@EnableEntityDefinedRegions(basePackages = "...")
@ClientCacheApplication
@EnableSsl(
truststore = "truststore.jks",
keystore = "keystore.jks",
truststorePassword = "pwd",
keystorePassword = "pwd"
)
public class GeodeTls {}
就是这样!然后我们对@Regions 和@Repositories 使用普通注解,并且我们有我们的@RestControllers,我们在其中调用存储库方法,它们中的大多数只是空的,或者是默认的,因为我们使用OQL annotate 方法来处理Spring。由于 Geode 有一个基于属性的配置,我们从不设置 KeyStores、TrustStores,我只是在调试期间在代码中看到它们。
最佳答案
我昨天遇到了你的问题,正在制作一个原型(prototype)。我认为在你的情况下是可能的。但是,我只是在本地使用 http 客户端和服务器进行了尝试,我能够在运行时更改证书,而无需重新启动这些应用程序或重新创建 SSLContext。
选项 1
从你的问题我可以理解你正在阅读 PEM
从某处获取文件并将其转换为其他内容,最后您使用的是 SSLContext
.在这种情况下,我假设您正在创建一个 KeyManager 和一个 TrustManager。如果是这种情况,您需要做的是创建 KeyManager 和 TrustManager 的自定义实现作为包装类,以将方法调用委托(delegate)给包装类中的实际 KeyManager 和 TrustManager。并且还添加了一个 setter 方法来在证书更新时更改内部 KeyManager 和 TrustManager。
在您的情况下,这将是一个文件观察器,当 PEM 文件被更改时会被触发。在这种情况下,您只需要使用新证书重新生成 KeyManager 和 TrustManager 并通过调用 setter 方法将其提供给包装类。以下是您可以使用的示例代码片段:
HotSwappableX509ExtendedKeyManager
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Objects;
public final class HotSwappableX509ExtendedKeyManager extends X509ExtendedKeyManager {
private X509ExtendedKeyManager keyManager;
public HotSwappableX509ExtendedKeyManager(X509ExtendedKeyManager keyManager) {
this.keyManager = Objects.requireNonNull(keyManager);
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return keyManager.chooseClientAlias(keyType, issuers, socket);
}
@Override
public String chooseEngineClientAlias(String[] keyTypes, Principal[] issuers, SSLEngine sslEngine) {
return keyManager.chooseEngineClientAlias(keyTypes, issuers, sslEngine);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return keyManager.chooseServerAlias(keyType, issuers, socket);
}
@Override
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine sslEngine) {
return keyManager.chooseEngineServerAlias(keyType, issuers, sslEngine);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return keyManager.getPrivateKey(alias);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return keyManager.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return keyManager.getClientAliases(keyType, issuers);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return keyManager.getServerAliases(keyType, issuers);
}
public void setKeyManager(X509ExtendedKeyManager keyManager) {
this.keyManager = Objects.requireNonNull(keyManager);
}
}
HotSwappableX509ExtendedTrustManager
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedTrustManager;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Objects;
public class HotSwappableX509ExtendedTrustManager extends X509ExtendedTrustManager {
private X509ExtendedTrustManager trustManager;
public HotSwappableX509ExtendedTrustManager(X509ExtendedTrustManager trustManager) {
this.trustManager = Objects.requireNonNull(trustManager);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
trustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
trustManager.checkClientTrusted(chain, authType, socket);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException {
trustManager.checkClientTrusted(chain, authType, sslEngine);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
trustManager.checkServerTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
trustManager.checkServerTrusted(chain, authType, socket);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException {
trustManager.checkServerTrusted(chain, authType, sslEngine);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
return Arrays.copyOf(acceptedIssuers, acceptedIssuers.length);
}
public void setTrustManager(X509ExtendedTrustManager trustManager) {
this.trustManager = Objects.requireNonNull(trustManager);
}
}
用法
// Your key and trust manager created from the pem files
X509ExtendedKeyManager aKeyManager = ...
X509ExtendedTrustManager aTrustManager = ...
// Wrapping it into your hot swappable key and trust manager
HotSwappableX509ExtendedKeyManager swappableKeyManager = new HotSwappableX509ExtendedKeyManager(aKeyManager);
HotSwappableX509ExtendedTrustManager swappableTrustManager = new HotSwappableX509ExtendedTrustManager(aTrustManager);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[]{ swappableKeyManager }, new TrustManager[]{ swappableTrustManager })
// Give the sslContext instance to your server or client
// After some time change the KeyManager and TrustManager with the following snippet:
X509ExtendedKeyManager anotherKeyManager = ... // Created from the new pem files
X509ExtendedTrustManager anotherTrustManager = ... // Created from the new pem files
// Set your new key and trust manager into your swappable managers
swappableKeyManager.setKeyManager(anotherKeyManager)
swappableTrustManager.setTrustManager(anotherTrustManager)
因此,即使您的 SSLContext 实例缓存在您的客户端服务器中,您仍然可以换入和换出新的 keymanager 和 trustmanager。
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart</artifactId>
<version>6.6.0</version>
</dependency>
用法
SSLFactory sslFactory = SSLFactory.builder()
.withSwappableIdentityMaterial()
.withIdentityMaterial("identity.jks", "password".toCharArray())
.withSwappableTrustMaterial()
.withTrustMaterial("truststore.jks", "password".toCharArray())
.build();
SSLContext sslContext = sslFactory.getSslContext();
// Give the sslContext instance to your server or client
// After some time change the KeyManager and TrustManager with the following snippet:
// swap identity and trust materials and reuse existing http client
KeyManagerUtils.swapKeyManager(sslFactory.getKeyManager().get(), anotherKeyManager);
TrustManagerUtils.swapTrustManager(sslFactory.getTrustManager().get(), anotherTrustManager);
// Cleanup old ssl sessions by invalidating them all. Forces to use new ssl sessions which will be created by the swapped KeyManager/TrustManager
SSLSessionUtils.invalidateCaches(sslContext);
关于java - 如何在不重新启动的情况下更新 Spring Data Geode 连接中的 keystore (SSLContext)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65868599/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!