Skip to content

Support reloading gRPC server SSL bundles#50248

Open
ukasus wants to merge 1 commit into
spring-projects:mainfrom
ukasus:main
Open

Support reloading gRPC server SSL bundles#50248
ukasus wants to merge 1 commit into
spring-projects:mainfrom
ukasus:main

Conversation

@ukasus
Copy link
Copy Markdown

@ukasus ukasus commented Apr 29, 2026

Add reloadable KeyManagerFactory for dynamic TLS bundle updates-

  • Introduce ReloadableKeyManagerFactory with SPI-backed implementation
    to support hot-reloading of X509ExtendedKeyManager on SslBundle updates
  • Register bundle update handler via SslBundles to refresh key material
    without server restart
  • Add ReloadableX509ExtendedKeyManager delegating wrapper with volatile swap
    for thread-safe runtime updates
  • Extend GrpcServerProperties.Ssl with reloadOnUpdate flag to toggle behavior
  • Wire conditional KeyManagerFactory resolution in ServerCredentials
    (static vs reloadable based on config)
  • Maintain compatibility with existing SSL setup and shaded/standard Netty

Enables zero-downtime TLS certificate/key rotation for gRPC servers.

Signed-off-by: Ujjawal Sharma ujjawal98kaushik@gmail.com

[resolves #49833]

Add a `reloadOnUpdate` property to `GrpcServerProperties.Ssl` and introduce `ReloadableKeyManagerFactory` to support dynamically updating the key manager when the associated `SslBundle` changes.

Signed-off-by: Ujjawal Sharma <ujjawal98kaushik@gmail.com>
@ukasus ukasus changed the title DRASupport reloading gRPC server SSL bundles Support reloading gRPC server SSL bundles Apr 29, 2026
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 29, 2026
@philwebb
Copy link
Copy Markdown
Member

philwebb commented May 4, 2026

Thanks very much for the PR @ukasus. I need some time to consider this approach as I'm still quite concerned that trying to make the KeyManagerFactory and X509ExtendedKeyManager reloadable in themselves might have unintended consequences.

I'd rather we took an approach similar to org.springframework.boot.reactor.netty.SslServerCustomizer, however, that builds on top of reactor-netty which isn't an option for gRPC.

We realistically won't get to this until Spring Boot 4.2 now, so I'll leave the PR open whilst we consider things.

@philwebb philwebb added the status: on-hold We can't start working on this issue yet label May 4, 2026
Copy link
Copy Markdown

@prashantpiyush1111 prashantpiyush1111 left a comment

Choose a reason for hiding this comment

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

Reviewed the changes. A few inline comments added around thread-safety in setSslBundle and setDelegate — mainly suggesting synchronized to guard against concurrent reload events causing silent overwrites.
Also flagged early validation concern in ServerCredentials.java when reloadOnUpdate=true but no X509ExtendedKeyManager is present, and a config metadata suggestion for reloadOnUpdate flag in GrpcServerProperties.
Regarding @philwebb's concern — ReloadableX509ExtendedKeyManager is purely a delegating wrapper and the swap is scoped only to gRPC's TLS handshake path, so blast radius seems limited and shouldn't affect other SSL consumers. Solid foundation for 4.2.


static class ReloadableKeyManagerFactorySpi extends KeyManagerFactorySpi {

private volatile @Nullable ReloadableX509ExtendedKeyManager keyManager;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

volatile ensures visibility but not atomicity. If two setSslBundle calls fire concurrently, both can read null and create separate instances — second will silently overwrite first. Suggest making setSslBundle synchronized.


static class ReloadableX509ExtendedKeyManager extends X509ExtendedKeyManager {

private volatile X509ExtendedKeyManager delegate;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

volatile here is correct for visibility of the reference swap. However setDelegate has no synchronization — concurrent reloads could cause a torn update mid-handshake. Consider synchronized on setDelegate.

return managers.getKeyManagerFactory();
}
return ReloadableKeyManagerFactory.create(bundles, bundleName, bundle);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Clean conditional wiring. One question — if reloadOnUpdate is true but the bundle has no X509ExtendedKeyManager, it throws IllegalStateException at startup. Should this be validated earlier with a clearer error message in GrpcServerProperties?

/**
* Whether to reload the key manager when the SSL bundle is updated.
*/
private boolean reloadOnUpdate;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Default is false which is safe and backward compatible. Should this have a @NestedConfigurationProperty or config metadata entry so IDEs can hint users about this flag?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: on-hold We can't start working on this issue yet status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for gRPC server TLS certificate rotation

4 participants