Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide a way to dynamically update TLS certificates (#5228)
Motivation: #5033 API design note: - `TlsKeyPair` represents a pair of `PrivateKey` and `X509Certificate` chain. - This API is used as an official key pair type in Armeria. - All APIs for specifying key pairs in `TlsSetters` have been deprecated in favor of `TlsSetters tls(TlsKeyPair)`. ```java TlsKeyPair.of(privateKey, certificate); TlsKeyPair.of(privateKey, keyPassword, certificate); ``` - `TlsProvider` dynamically resolves a `TlsKeyPair` for the given hostname when a connection is established. - DNS wildcard format is supported as a hostname. - `*` is used as a special hostname to get the `TlsKeyPair` for the default virtual host. ```java TlsProvider .builder() // Set the default key pair. .keyPair(TlsKeyPair.of(...)) // Set the key pair for "*.example.com". .keyPair("*.example.com", TlsKeyPair.of(...)) .build(); ``` - To dynamically update/reload `TlsKeyPair`, a custom `TlsProvider` can be implemented. ```java class DynamicTlsProvider implements TlsProvider { @OverRide public TlsKeyPair keyPair(String hostname) { // relodableCache will be updated periodically by a scheduler return relodableCache.get(hostname); } } ``` - The newly returned key pair is used for the TLS handshake of new connections. - `ServerTlsConfig` and `ClientTlsConfig` are added to override the default values and customize `SslContextBuilder`. - Unlike `TlsProvider`, `*TlsConfig` are immutable so all `TlsKeyPair`s returned by a `TlsProvider` build `SslContext` with the same configuration. - Both server and client allow `TlsProvider` and `TlsKeyPair` for TLS configurations. ```java Server .builder() // For dynamic usage .tlsProvider(tlsProvider) // For customizing TLS .tlsProvider(tlsProvider, serverTlsConfig) // For sample usage .tls(tlsKeyPair) .build() ClientFactory .builder() // For dynamic usage .tlsProvider(tlsProvider) // For customizing TLS .tlsProvider(tlsProvider, clientTlsConfig) // For sample usage .tls(tlsKeyPair) .build() ``` - Some internal implementations for TLS handshake have been changed to create `SslContext` dynamically. Modifications: - Server - Add `TlsProviderMapping` that converts `TlsProvider` into SslContext `Mapping` for `SniHandler`. - A dynamic `TlsProvider` can be used to update the certificates without `Server.reconfigure()`. - Add a setter method for `TlsProvider` to `ServerBuilder`. - A builder method for `VirtualHost` isn't added because a `TlsProvider` can contain multiple certificates. - If necessary, I will consider `TlsProvider` at the virtual host level later. - Client - Fix `Bootstraps` to create a `Bootstrap` with a `TlsKeyPair` returned by `TlsProvider` when a new connection is created. - If no `TlsProvider` is set, the original behavior that returns predefined `BootStraap` is used. - Add options for `TlsProvider` to `ClientFactoryBuilder`. - Common - `TlsProvider` provides separate builders for the client and server. - `TlsKeyPair` provides various factory methods to easily create a key pair from different resources. - Cache `SslContext`s and expire them after 1 hour of inactivity. - If you think that the caching strategy will not be effective, I am willing to revert it. - Add `CloseableMeterBinder` to unregister when the associated resource is unused. - Deprecate) The following APIs have been deprecated: - `TlsSetters tls(File keyCertChainFile, File keyFile)` - `TlsSetters tls(File keyCertChainFile, File keyFile, @nullable String keyPassword)` - `TlsSetters tls(InputStream keyCertChainInputStream, InputStream keyInputStream)` - `TlsSetters tls(InputStream keyCertChainInputStream, InputStream keyInputStream, @nullable String keyPassword)` - `TlsSetters tls(PrivateKey key, X509Certificate... keyCertChain)` - `TlsSetters tls(PrivateKey key, Iterable<? extends X509Certificate> keyCertChain)` - `TlsSetters tls(PrivateKey key, @nullable String keyPassword, X509Certificate... keyCertChain)` - `TlsSetters tls(PrivateKey key, @nullable String keyPassword, Iterable<? extends X509Certificate> keyCertChain)` Result: - Closes #5033 - You can now set TLS configurations dynamically using `TlsProvider` --------- Co-authored-by: Ikhun Um <[email protected]> Co-authored-by: jrhee17 <[email protected]>
- Loading branch information