Skip to content
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

Separate out the security config from the rest of the transport config #37

Merged
merged 7 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 80 additions & 4 deletions Sources/GRPCNIOTransportHTTP2Posix/Config+TLS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

extension HTTP2ServerTransport.Posix.Config {
extension HTTP2ServerTransport.Posix {
/// The security configuration for this connection.
public struct TransportSecurity: Sendable {
package enum Wrapped: Sendable {
Expand All @@ -27,12 +27,52 @@ extension HTTP2ServerTransport.Posix.Config {
/// This connection is plaintext: no encryption will take place.
public static let plaintext = Self(wrapped: .plaintext)

/// This connection will use TLS.
/// Secure connections with the given TLS configuration.
public static func tls(_ tls: TLS) -> Self {
Self(wrapped: .tls(tls))
}

/// Secure connections with TLS.
///
/// - Parameters:
/// - certificateChain: The certificates the server will offer during negotiation.
/// - privateKey: The private key associated with the leaf certificate.
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func tls(
certificateChain: [TLSConfig.CertificateSource],
privateKey: TLSConfig.PrivateKeySource,
configure: (_ config: inout TLS) -> Void = { _ in }
) -> Self {
let tlsConfig: TLS = .defaults(
certificateChain: certificateChain,
privateKey: privateKey,
configure: configure
)
return .tls(tlsConfig)
}

/// Secure the connection with mutual TLS.
///
/// - Parameters:
/// - certificateChain: The certificates the client will offer during negotiation.
/// - privateKey: The private key associated with the leaf certificate.
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func mTLS(
certificateChain: [TLSConfig.CertificateSource],
privateKey: TLSConfig.PrivateKeySource,
configure: (_ config: inout TLS) -> Void = { _ in }
) -> Self {
let tlsConfig: TLS = .mTLS(
certificateChain: certificateChain,
privateKey: privateKey,
configure: configure
)
return .tls(tlsConfig)
}
}
}

extension HTTP2ServerTransport.Posix.TransportSecurity {
public struct TLS: Sendable {
/// The certificates the server will offer during negotiation.
public var certificateChain: [TLSConfig.CertificateSource]
Expand Down Expand Up @@ -127,7 +167,7 @@ extension HTTP2ServerTransport.Posix.Config {
}
}

extension HTTP2ClientTransport.Posix.Config {
extension HTTP2ClientTransport.Posix {
/// The security configuration for this connection.
public struct TransportSecurity: Sendable {
package enum Wrapped: Sendable {
Expand All @@ -140,12 +180,48 @@ extension HTTP2ClientTransport.Posix.Config {
/// This connection is plaintext: no encryption will take place.
public static let plaintext = Self(wrapped: .plaintext)

/// This connection will use TLS.
/// Secure the connection with the given TLS configuration.
public static func tls(_ tls: TLS) -> Self {
Self(wrapped: .tls(tls))
}

/// Secure the connection with TLS using the default configuration.
///
/// - Parameters:
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func tls(
configure: (_ config: inout TLS) -> Void = { _ in }
) -> Self {
Self.tls(.defaults(configure: configure))
}

/// Secure the connection with TLS using the default configuration.
public static var tls: Self {
Self.tls(.defaults())
}

/// Secure the connection with mutual TLS.
///
/// - Parameters:
/// - certificateChain: The certificates the client will offer during negotiation.
/// - privateKey: The private key associated with the leaf certificate.
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func mTLS(
certificateChain: [TLSConfig.CertificateSource],
privateKey: TLSConfig.PrivateKeySource,
configure: (_ config: inout TLS) -> Void = { _ in }
) -> Self {
let tlsConfig: TLS = .mTLS(
certificateChain: certificateChain,
privateKey: privateKey,
configure: configure
)
return .tls(tlsConfig)
}
}
}

extension HTTP2ClientTransport.Posix.TransportSecurity {
public struct TLS: Sendable {
/// The certificates the client will offer during negotiation.
public var certificateChain: [TLSConfig.CertificateSource]
Expand Down
45 changes: 27 additions & 18 deletions Sources/GRPCNIOTransportHTTP2Posix/HTTP2ClientTransport+Posix.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extension HTTP2ClientTransport {
/// try await withThrowingDiscardingTaskGroup { group in
/// let transport = try HTTP2ClientTransport.Posix(
/// target: .ipv4(host: "example.com"),
/// config: .defaults(transportSecurity: .plaintext)
/// transportSecurity: .plaintext
/// )
/// let client = GRPCClient(transport: transport)
/// group.addTask {
Expand All @@ -62,6 +62,7 @@ extension HTTP2ClientTransport {
///
/// - Parameters:
/// - target: A target to resolve.
/// - transportSecurity: The configuration for securing network traffic.
/// - config: Configuration for the transport.
/// - resolverRegistry: A registry of resolver factories.
/// - serviceConfig: Service config controlling how the transport should establish and
Expand All @@ -72,7 +73,8 @@ extension HTTP2ClientTransport {
/// - Throws: When no suitable resolver could be found for the `target`.
public init(
target: any ResolvableTarget,
config: Config,
transportSecurity: TransportSecurity,
config: Config = .defaults,
resolverRegistry: NameResolverRegistry = .defaults,
serviceConfig: ServiceConfig = ServiceConfig(),
eventLoopGroup: any EventLoopGroup = .singletonMultiThreadedEventLoopGroup
Expand All @@ -89,7 +91,11 @@ extension HTTP2ClientTransport {

self.channel = GRPCChannel(
resolver: resolver,
connector: try Connector(eventLoopGroup: eventLoopGroup, config: config),
connector: try Connector(
eventLoopGroup: eventLoopGroup,
config: config,
transportSecurity: transportSecurity
),
config: GRPCChannel.Config(posix: config),
defaultServiceConfig: serviceConfig
)
Expand Down Expand Up @@ -129,11 +135,15 @@ extension HTTP2ClientTransport.Posix {
private let sslContext: NIOSSLContext?
private let isPlainText: Bool

init(eventLoopGroup: any EventLoopGroup, config: HTTP2ClientTransport.Posix.Config) throws {
init(
eventLoopGroup: any EventLoopGroup,
config: HTTP2ClientTransport.Posix.Config,
transportSecurity: HTTP2ClientTransport.Posix.TransportSecurity
) throws {
self.eventLoopGroup = eventLoopGroup
self.config = config

switch self.config.transportSecurity.wrapped {
switch transportSecurity.wrapped {
case .plaintext:
self.sslContext = nil
self.isPlainText = true
Expand Down Expand Up @@ -198,48 +208,44 @@ extension HTTP2ClientTransport.Posix {
/// Compression configuration.
public var compression: HTTP2ClientTransport.Config.Compression

/// The transport's security.
public var transportSecurity: TransportSecurity

/// Creates a new connection configuration.
///
/// - Parameters:
/// - http2: HTTP2 configuration.
/// - backoff: Backoff configuration.
/// - connection: Connection configuration.
/// - compression: Compression configuration.
/// - transportSecurity: The transport's security configuration.
///
/// - SeeAlso: ``defaults(transportSecurity:configure:)``
/// - SeeAlso: ``defaults(configure:)`` and ``defaults``.
public init(
http2: HTTP2ClientTransport.Config.HTTP2,
backoff: HTTP2ClientTransport.Config.Backoff,
connection: HTTP2ClientTransport.Config.Connection,
compression: HTTP2ClientTransport.Config.Compression,
transportSecurity: TransportSecurity
compression: HTTP2ClientTransport.Config.Compression
) {
self.http2 = http2
self.connection = connection
self.backoff = backoff
self.compression = compression
self.transportSecurity = transportSecurity
}

/// Default configuration.
public static var defaults: Self {
Self.defaults()
}

/// Default values.
///
/// - Parameters:
/// - transportSecurity: The security settings applied to the transport.
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func defaults(
transportSecurity: TransportSecurity,
configure: (_ config: inout Self) -> Void = { _ in }
) -> Self {
var config = Self(
http2: .defaults,
backoff: .defaults,
connection: .defaults,
compression: .defaults,
transportSecurity: transportSecurity
compression: .defaults
)
configure(&config)
return config
Expand All @@ -263,6 +269,7 @@ extension ClientTransport where Self == HTTP2ClientTransport.Posix {
///
/// - Parameters:
/// - target: A target to resolve.
/// - transportSecurity: The configuration for securing network traffic.
/// - config: Configuration for the transport.
/// - resolverRegistry: A registry of resolver factories.
/// - serviceConfig: Service config controlling how the transport should establish and
Expand All @@ -273,13 +280,15 @@ extension ClientTransport where Self == HTTP2ClientTransport.Posix {
/// - Throws: When no suitable resolver could be found for the `target`.
public static func http2NIOPosix(
target: any ResolvableTarget,
config: HTTP2ClientTransport.Posix.Config,
transportSecurity: HTTP2ClientTransport.Posix.TransportSecurity,
config: HTTP2ClientTransport.Posix.Config = .defaults,
resolverRegistry: NameResolverRegistry = .defaults,
serviceConfig: ServiceConfig = ServiceConfig(),
eventLoopGroup: any EventLoopGroup = .singletonMultiThreadedEventLoopGroup
) throws -> Self {
return try HTTP2ClientTransport.Posix(
target: target,
transportSecurity: transportSecurity,
config: config,
resolverRegistry: resolverRegistry,
serviceConfig: serviceConfig,
Expand Down
38 changes: 20 additions & 18 deletions Sources/GRPCNIOTransportHTTP2Posix/HTTP2ServerTransport+Posix.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension HTTP2ServerTransport {
/// try await withThrowingDiscardingTaskGroup { group in
/// let transport = HTTP2ServerTransport.Posix(
/// address: .ipv4(host: "127.0.0.1", port: 0),
/// config: .defaults(transportSecurity: .plaintext)
/// transportSecurity: .plaintext
/// )
/// let server = GRPCServer(transport: transport, services: someServices)
/// group.addTask {
Expand All @@ -54,6 +54,7 @@ extension HTTP2ServerTransport {
public struct Posix: ServerTransport, ListeningServerTransport {
private struct ListenerFactory: HTTP2ListenerFactory {
let config: Config
let transportSecurity: TransportSecurity

func makeListeningChannel(
eventLoopGroup: any EventLoopGroup,
Expand All @@ -62,7 +63,7 @@ extension HTTP2ServerTransport {
) async throws -> NIOAsyncChannel<AcceptedChannel, Never> {
let sslContext: NIOSSLContext?

switch self.config.transportSecurity.wrapped {
switch self.transportSecurity.wrapped {
case .plaintext:
sslContext = nil
case .tls(let tlsConfig):
Expand Down Expand Up @@ -97,7 +98,7 @@ extension HTTP2ServerTransport {

let requireALPN: Bool
let scheme: Scheme
switch self.config.transportSecurity.wrapped {
switch self.transportSecurity.wrapped {
case .plaintext:
requireALPN = false
scheme = .http
Expand Down Expand Up @@ -141,14 +142,16 @@ extension HTTP2ServerTransport {
///
/// - Parameters:
/// - address: The address to which the server should be bound.
/// - transportSecurity: The configuration for securing network traffic.
/// - config: The transport configuration.
/// - eventLoopGroup: The ELG from which to get ELs to run this transport.
public init(
address: GRPCNIOTransportCore.SocketAddress,
config: Config,
transportSecurity: TransportSecurity,
config: Config = .defaults,
eventLoopGroup: MultiThreadedEventLoopGroup = .singletonMultiThreadedEventLoopGroup
) {
let factory = ListenerFactory(config: config)
let factory = ListenerFactory(config: config, transportSecurity: transportSecurity)
let helper = ServerQuiescingHelper(group: eventLoopGroup)
self.underlyingTransport = CommonHTTP2ServerTransport(
address: address,
Expand Down Expand Up @@ -188,48 +191,44 @@ extension HTTP2ServerTransport.Posix {
/// RPC configuration.
public var rpc: HTTP2ServerTransport.Config.RPC

/// The transport's security.
public var transportSecurity: TransportSecurity

/// Construct a new `Config`.
///
/// - Parameters:
/// - http2: HTTP2 configuration.
/// - rpc: RPC configuration.
/// - connection: Connection configuration.
/// - compression: Compression configuration.
/// - transportSecurity: The transport's security configuration.
///
/// - SeeAlso: ``defaults(transportSecurity:configure:)``
/// - SeeAlso: ``defaults(configure:)`` and ``defaults``.
public init(
http2: HTTP2ServerTransport.Config.HTTP2,
rpc: HTTP2ServerTransport.Config.RPC,
connection: HTTP2ServerTransport.Config.Connection,
compression: HTTP2ServerTransport.Config.Compression,
transportSecurity: TransportSecurity
compression: HTTP2ServerTransport.Config.Compression
) {
self.compression = compression
self.connection = connection
self.http2 = http2
self.rpc = rpc
self.transportSecurity = transportSecurity
}

/// Default configuration.
public static var defaults: Self {
Self.defaults()
}

/// Default values for the different configurations.
///
/// - Parameters:
/// - transportSecurity: The security settings applied to the transport.
/// - configure: A closure which allows you to modify the defaults before returning them.
public static func defaults(
transportSecurity: TransportSecurity,
configure: (_ config: inout Self) -> Void = { _ in }
) -> Self {
var config = Self(
http2: .defaults,
rpc: .defaults,
connection: .defaults,
compression: .defaults,
transportSecurity: transportSecurity
compression: .defaults
)
configure(&config)
return config
Expand Down Expand Up @@ -267,17 +266,20 @@ extension ServerTransport where Self == HTTP2ServerTransport.Posix {
///
/// - Parameters:
/// - address: The address to which the server should be bound.
/// - transportSecurity: The configuration for securing network traffic.
/// - config: The transport configuration.
/// - eventLoopGroup: The underlying NIO `EventLoopGroup` to the server on. This must
/// be a `MultiThreadedEventLoopGroup` or an `EventLoop` from
/// a `MultiThreadedEventLoopGroup`.
public static func http2NIOPosix(
address: GRPCNIOTransportCore.SocketAddress,
config: HTTP2ServerTransport.Posix.Config,
transportSecurity: HTTP2ServerTransport.Posix.TransportSecurity,
config: HTTP2ServerTransport.Posix.Config = .defaults,
eventLoopGroup: MultiThreadedEventLoopGroup = .singletonMultiThreadedEventLoopGroup
) -> Self {
return HTTP2ServerTransport.Posix(
address: address,
transportSecurity: transportSecurity,
config: config,
eventLoopGroup: eventLoopGroup
)
Expand Down
Loading
Loading