Skip to content

[ISSUE #8920] Refactor SSL context loading process to support multiple protocols dynamic loading #9483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from

Conversation

EnableAsync
Copy link

@EnableAsync EnableAsync commented Jun 17, 2025

Which Issue(s) This PR Fixes

Fixes #8920

Brief Description

This PR adds functionality to dynamically reload TLS certificates without requiring a server restart. The implementation monitors certificate and key files for changes and automatically updates the TLS configuration when both files are modified.

Key changes:

  • Added file monitoring for TLS certificate and private key files
  • Implemented logic to detect simultaneous changes to both files
  • Added certificate reload mechanism that updates TLS configuration in-place
  • Eliminated the need for service restarts when renewing certificates

This feature improves system availability by allowing certificate updates with zero downtime, which is particularly valuable for production environments with automatic certificate renewal processes.

How Did You Test This Change?

I've implemented comprehensive tests to validate the dynamic TLS certificate update feature. The tests cover several key aspects:

  1. TlsCertificateManager Tests
  • Verified the certificate monitoring logic correctly detects changes in certificate files
  • Confirmed reload is triggered when both certificate and key files are modified
  • Validated that changes to trust certificates trigger immediate reload
  • Ensured the listener notification system works properly when certificate files change
  1. gRPC Server TLS Context Tests
  • Tested successful SSL context reloading for gRPC servers
  • Verified proper error handling for certificate exceptions during reload
  • Confirmed error handling for IO exceptions during reload
  • Validated that reload handlers are properly registered and unregistered
  • Verified the SSL context is correctly replaced after a reload event
  1. Remoting Server TLS Context Tests
  • Confirmed the Netty remoting server properly updates its SSL context when triggered
  • Validated that the TlsCertificateManager correctly notifies all registered listeners
  • Verified that the SSL context is actually replaced with a new instance
  • Tested integration between the certificate manager and the remoting server components

These tests ensure the system can update TLS certificates without requiring a service restart, improving system availability during certificate renewals.

- 在 GrpcServer 和 RemotingProtocolServer 中添加文件监视服务,用于监控 TLS 证书和密钥的变化
- 实现证书和密钥变更时重新加载 SSL 上下文的逻辑
- 优化 ProxyAndTlsProtocolNegotiator 中的 SSL 上下文加载过程
- 添加日志记录,方便调试和监控 TLS 相关操作
- 重构 GrpcServer 中的证书监控逻辑,提取到独立的 GrpcCertKeyFileWatchListener 类中
- 优化证书变更处理流程,提高代码可读性和维护性
- 新增 GrpcServerTest 类,为 gRPC服务器和证书监控添加单元测试- 测试覆盖了各种证书变更场景,包括单独变更和组合变更
- 验证了证书变更时 SSLContext 的重新加载和错误处理

Signed-off-by: Async <raisinata@foxmail.com>
- 重构 GrpcServer 中的证书监控逻辑,提取到独立的 GrpcCertKeyFileWatchListener 类中
- 优化证书变更处理流程,提高代码可读性和维护性
- 新增 GrpcServerTest 类,为 gRPC服务器和证书监控添加单元测试- 测试覆盖了各种证书变更场景,包括单独变更和组合变更
- 验证了证书变更时 SSLContext 的重新加载和错误处理

Signed-off-by: Async <raisinata@foxmail.com>
Signed-off-by: Async <raisinata@foxmail.com>
Signed-off-by: Async <raisinata@foxmail.com>
Signed-off-by: Async <raisinata@foxmail.com>
- 移除 FileWatchService,改用 TlsCertificateManager 统一管理 TLS证书
- 实现 TlsContextReloadListener 接口,响应 TLS 证书更新
- 优化 GrpcServer 和 RemotingProtocolServer 中的 TLS 证书更新逻辑
- 新增单元测试验证 TLS 证书更新功能

Signed-off-by: Async <raisinata@foxmail.com>
- 重构了多个测试类中的重复代码- 提高了测试的可读性和维护性
- 确保在测试中正确关闭资源

Signed-off-by: Async <raisinata@foxmail.com>
- 移除了不必要的导入项
- 显式导入了所有活动类,提高了代码的可读性和维护性

Signed-off-by: Async <raisinata@foxmail.com>
}
}

static class GrpcTlsReloadHandler implements TlsCertificateManager.TlsContextReloadListener {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no static

Signed-off-by: Async <raisinata@foxmail.com>
Signed-off-by: Async <raisinata@foxmail.com>
}
}

public static TlsCertificateManager getInstance() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid using a singleton? use Dependency Injection instead

sslContext = loadSslContext();
try {
loadSslContext();
log.info("SSLContext created for proxy server");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSLContext / SslContext 需要保持一致,保持日志的严谨性

try {
loadSslContext();
log.info("SSLContext created for proxy server");
} catch (IOException | CertificateException e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest catch throwable

Copy link
Author

@EnableAsync EnableAsync Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I want to crash directly if an exception is thrown during SSLContext initialization

@@ -231,7 +245,7 @@ protected void handleHAProxyTLV(HAProxyTLV tlv, Attributes.Builder builder) {
return;
}
Attributes.Key<String> key = AttributeKeys.valueOf(
HAProxyConstants.PROXY_PROTOCOL_TLV_PREFIX + String.format("%02x", tlv.typeByteValue()));
HAProxyConstants.PROXY_PROTOCOL_TLV_PREFIX + String.format("%02x", tlv.typeByteValue()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format

@codecov-commenter
Copy link

Codecov Report

Attention: Patch coverage is 13.46154% with 90 lines in your changes missing coverage. Please review.

Project coverage is 47.99%. Comparing base (cfddd12) to head (b5acb36).
Report is 3 commits behind head on develop.

Files with missing lines Patch % Lines
...etmq/proxy/service/cert/TlsCertificateManager.java 0.00% 49 Missing ⚠️
...etmq/proxy/grpc/ProxyAndTlsProtocolNegotiator.java 50.00% 12 Missing and 2 partials ⚠️
...ava/org/apache/rocketmq/proxy/grpc/GrpcServer.java 0.00% 13 Missing ⚠️
...ocketmq/proxy/remoting/RemotingProtocolServer.java 0.00% 9 Missing ⚠️
...n/java/org/apache/rocketmq/proxy/ProxyStartup.java 0.00% 4 Missing ⚠️
...mq/proxy/remoting/MultiProtocolRemotingServer.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #9483      +/-   ##
=============================================
- Coverage      48.15%   47.99%   -0.16%     
+ Complexity     12017    11995      -22     
=============================================
  Files           1308     1309       +1     
  Lines          92174    92331     +157     
  Branches       11790    11815      +25     
=============================================
- Hits           44382    44315      -67     
- Misses         42302    42514     +212     
- Partials        5490     5502      +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- 新增 CertChangeEvent、CertChangeSource 和 FileCertChangeSource 类
- 实现证书文件变更监听和事件处理机制
- 修改 GrpcServer 以支持证书变更热重载
- 更新相关测试用例

Signed-off-by: Async <raisinata@foxmail.com>
- 在 GrpcServer 类中添加异常堆栈打印,以便更好地调试问题
- 在 ProxyAndTlsProtocolNegotiator 类中修正 SSLContext 初始化错误日志

Signed-off-by: Async <raisinata@foxmail.com>
- 将 FileCertChangeSource 的具体实现细节封装起来
- 使用 CertChangeSource接口替代具体的 FileCertChangeSource 类
- 提高了代码的可维护性和可扩展性

Signed-off-by: Async <raisinata@foxmail.com>
- 添加对证书路径为空的检查
- 优化证书更新事件处理逻辑
- 修复证书更新时的路径检查问题

Signed-off-by: Async <raisinata@foxmail.com>
//import static org.mockito.Mockito.when;
//
//@ExtendWith(MockitoExtension.class)
//public class GrpcServerTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为社么注释掉这些了

- 新增 FileCertChangeSource 类,用于监听证书文件变化
- 添加 GrpcServer 和 MultiProtocolRemotingServer 的 TLS 证书重载处理
- 修改 ProxyAndTlsProtocolNegotiator 类,支持从输入流加载 SSL 上下文
- 删除冗余测试类,优化测试用例

Signed-off-by: Async <raisinata@foxmail.com>
- 修复了一些潜在的代码风格问题

Signed-off-by: Async <raisinata@foxmail.com>
- 在 FileCertChangeSourceTest、GrpcServerTest、GrpcSslContextTest、
  MultiProtocolTlsHelperTest 和 TlsCertificateManagerTest 五个测试类中
  添加了 Apache License 2.0 开源许可证的版权信息
- 删除了 GrpcSslContextTest 中的重复代码

Signed-off-by: Async <raisinata@foxmail.com>
- 修改 CertChangeEvent 类,将 values 字段改为单个 value 字段
- 更新 CertChangeSource 接口,使用事件列表替代单个事件
-调整 FileCertChangeSource 实现,适应新的事件处理方式- 修改 TlsCertificateManager 类,支持处理多个证书变更事件
- 更新相关测试用例,以适应新的事件处理逻辑

Signed-off-by: Async <raisinata@foxmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Enhancement] Refactor SSL context loading process to support multiple protocols dynamic loading.
4 participants