Skip to content

Support SNI multi-domain certificate for Proxy TLS #10296

@qianye1001

Description

@qianye1001

Problem Statement

Currently RocketMQ Proxy supports only a single certificate model:

  • ProxyConfig has only tlsCertPath / tlsKeyPath for a single cert/key pair
  • gRPC and Remoting servers each build a single SslContext
  • TlsCertificateManager only watches one cert/key pair for hot-reload
  • No SNI (Server Name Indication) support at all

This makes it impossible to serve multiple top-level domains (e.g. *.mq.com and *.rocketmq.com) with different certificates on the same Proxy port.

Proposed Solution

Introduce SNI (Server Name Indication) support using Netty's SniHandler. The Proxy will inspect the TLS ClientHello's SNI hostname and dynamically select the corresponding certificate.

Key Changes

  1. New TlsDomainConfig POJO — per-domain cert/key path configuration
  2. Extended ProxyConfig — new tlsDomainConfigs map (domain pattern → config)
  3. New TlsSniManager — manages multiple SslContext instances with wildcard matching
  4. Extended TlsCertificateManager — watches multiple cert/key pairs independently
  5. gRPC ProxyAndTlsProtocolNegotiator — uses SniHandler for SNI-aware TLS
  6. Remoting NettyRemotingServerTlsModeHandler uses SniHandler via TlsContextProvider

Configuration Example

tlsCertPath: /path/to/default.crt
tlsKeyPath: /path/to/default.key
tlsDomainConfigs:
  "*.alibaba-inc.com":
    certPath: /path/to/alibaba.crt
    keyPath: /path/to/alibaba.key
  "*.rocketmq.com":
    certPath: /path/to/rocketmq.crt
    keyPath: /path/to/rocketmq.key

Wildcard Matching

  • Exact match first
  • Wildcard: foo.rocketmq.com matches *.rocketmq.com
  • Bare domain: rocketmq.com matches *.rocketmq.com
  • Multi-level (a.b.rocketmq.com) does NOT match *.rocketmq.com
  • No match → fallback to default certificate

Verification

Manual verification with openssl s_client:

# .com domain → should return *.rocketmq.com cert
openssl s_client -connect 127.0.0.1:<proxyPort> -servername test.rocketmq.com </dev/null 2>/dev/null | openssl x509 -noout -subject

# .alibaba domain → should return *.alibaba-inc.com cert
openssl s_client -connect 127.0.0.1:<proxyPort> -servername test.alibaba-inc.com </dev/null 2>/dev/null | openssl x509 -noout -subject

# No SNI → should return default (localhost) cert
openssl s_client -connect 127.0.0.1:<proxyPort> </dev/null 2>/dev/null | openssl x509 -noout -subject

Backward Compatibility

When tlsDomainConfigs is not configured, the behavior is identical to the current single-certificate model.

Risks

  1. Netty SniHandler async nature — needs verification that gRPC's ProxyAndTlsProtocolNegotiator pipeline is compatible
  2. Pipeline orderTlsModeHandler (PERMISSIVE mode detection) must run before SniHandler
  3. Old clients without SNI — will fallback to default certificate
  4. TlsSystemConfig compatibility — Remoting's static config system needs backward compatibility

Related PR

#10295

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions