-
Notifications
You must be signed in to change notification settings - Fork 94
Add a TimedCertificateReloader
#269
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
Changes from 24 commits
554f22e
6b6a5b5
7a755d7
744d803
0dae5b2
617d1ac
222a050
09520a7
b8eb9fb
ca8e42a
65a4600
c9402e9
76a3dc5
452b193
ef88924
ca5962e
e295c15
2fd8dca
ed45e53
9771210
6eb1e0c
47d25bb
9e3d133
eb78ed3
8fbba2d
2f52c35
fa65c5b
516c61c
f3cce7f
33fe740
d8c0f43
87b0335
c34a816
6570045
2852c84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the SwiftNIO open source project | ||
| // | ||
| // Copyright (c) 2025 Apple Inc. and the SwiftNIO project authors | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // See CONTRIBUTORS.txt for the list of SwiftNIO project authors | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import NIOCore | ||
| import NIOSSL | ||
|
|
||
| /// A protocol that defines a certificate reloader. | ||
| /// | ||
| /// A certificate reloader is a service that can provide you with updated versions of a certificate and private key pair, in | ||
| /// the form of a `NIOSSLContextConfigurationOverride`, which will be used when performing a TLS handshake in NIO. | ||
| /// Each implementation can choose how to observe for changes, but they all require an ``sslContextConfigurationOverride`` | ||
| /// to be exposed. | ||
| public protocol CertificateReloader: Sendable { | ||
| /// A `NIOSSLContextConfigurationOverride` that will be used as part of the NIO application's TLS configuration. | ||
| /// Its certificate and private key will be kept up-to-date via whatever mechanism the specific ``CertificateReloader`` | ||
| /// implementation provides. | ||
| var sslContextConfigurationOverride: NIOSSLContextConfigurationOverride { get } | ||
| } | ||
|
|
||
| extension TLSConfiguration { | ||
| /// Errors thrown when creating a ``NIOSSL/TLSConfiguration`` with a ``CertificateReloader``. | ||
| public struct CertificateReloaderError: Error { | ||
gjcairo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| private enum _Backing { | ||
| case missingCertificateChain | ||
| case missingPrivateKey | ||
| } | ||
|
|
||
| private let backing: _Backing | ||
|
|
||
| private init(backing: _Backing) { | ||
| self.backing = backing | ||
| } | ||
|
|
||
| /// The given ``CertificateReloader`` could not provide a certificate chain with which to create this config. | ||
| public static let missingCertificateChain: Self = .init(backing: .missingCertificateChain) | ||
|
|
||
| /// The given ``CertificateReloader`` could not provide a private key with which to create this config. | ||
| public static let missingPrivateKey: Self = .init(backing: .missingPrivateKey) | ||
gjcairo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /// Create a ``NIOSSL/TLSConfiguration`` for use with server-side contexts, with certificate reloading enabled. | ||
| /// - Parameter certificateReloader: A ``CertificateReloader`` to watch for certificate and key pair updates. | ||
| /// - Returns: A ``NIOSSL/TLSConfiguration`` for use with server-side contexts, that reloads the certificate and key | ||
| /// used in its SSL handshake. | ||
| public static func makeServerConfiguration( | ||
czechboy0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| certificateReloader: some CertificateReloader | ||
| ) throws -> Self { | ||
| let override = certificateReloader.sslContextConfigurationOverride | ||
|
|
||
| guard let certificateChain = override.certificateChain else { | ||
| throw CertificateReloaderError.missingCertificateChain | ||
| } | ||
|
|
||
| guard let privateKey = override.privateKey else { | ||
| throw CertificateReloaderError.missingPrivateKey | ||
| } | ||
|
|
||
| var configuration = Self.makeServerConfiguration( | ||
| certificateChain: certificateChain, | ||
| privateKey: privateKey | ||
| ) | ||
| return configuration.setCertificateReloader(certificateReloader) | ||
| } | ||
|
|
||
| /// Configure a ``CertificateReloader`` to observe updates for the certificate and key pair used. | ||
| /// - Parameter reloader: A ``CertificateReloader`` to watch for certificate and key pair updates. | ||
| /// - Returns: A ``NIOSSL/TLSConfiguration`` that reloads the certificate and key used in its SSL handshake. | ||
| @discardableResult | ||
| mutating public func setCertificateReloader(_ reloader: some CertificateReloader) -> Self { | ||
|
||
| self.sslContextCallback = { _, promise in | ||
| promise.succeed(reloader.sslContextConfigurationOverride) | ||
| } | ||
| return self | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.