Skip to content

Commit

Permalink
add config options for min max tls version on upstream connections
Browse files Browse the repository at this point in the history
Signed-off-by: Clay Kauzlaric <[email protected]>
  • Loading branch information
KauzClay committed Oct 12, 2023
1 parent d09bba1 commit b7f3f38
Show file tree
Hide file tree
Showing 18 changed files with 144 additions and 29 deletions.
5 changes: 5 additions & 0 deletions apis/projectcontour/v1alpha1/contourconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,11 @@ type ClusterParameters struct {
// +kubebuilder:validation:Minimum=1
// +optional
PerConnectionBufferLimitBytes *uint32 `json:"per-connection-buffer-limit-bytes,omitempty"`

// UpstreamTLS contains the TLS policy parameters for upstream connections
//
// +optional
UpstreamTLS *EnvoyTLS `json:"upstream-tls,omitempty"`
}

// HTTPProxyConfig defines parameters on HTTPProxy.
Expand Down
3 changes: 3 additions & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ func (s *Server) doServe() error {
globalRateLimitService: contourConfiguration.RateLimitService,
maxRequestsPerConnection: contourConfiguration.Envoy.Cluster.MaxRequestsPerConnection,
perConnectionBufferLimitBytes: contourConfiguration.Envoy.Cluster.PerConnectionBufferLimitBytes,
upstreamTLS: contourConfiguration.Envoy.Cluster.UpstreamTLS,
})

// Build the core Kubernetes event handler.
Expand Down Expand Up @@ -1082,6 +1083,7 @@ type dagBuilderConfig struct {
maxRequestsPerConnection *uint32
perConnectionBufferLimitBytes *uint32
globalRateLimitService *contour_api_v1alpha1.RateLimitServiceConfig
upstreamTLS *contour_api_v1alpha1.EnvoyTLS
}

func (s *Server) getDAGBuilder(dbc dagBuilderConfig) *dag.Builder {
Expand Down Expand Up @@ -1174,6 +1176,7 @@ func (s *Server) getDAGBuilder(dbc dagBuilderConfig) *dag.Builder {
GlobalRateLimitService: dbc.globalRateLimitService,
PerConnectionBufferLimitBytes: dbc.perConnectionBufferLimitBytes,
SetSourceMetadataOnRoutes: true,
UpstreamTLS: dbc.upstreamTLS,
},
}

Expand Down
5 changes: 5 additions & 0 deletions cmd/contour/servecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,11 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha
DNSLookupFamily: dnsLookupFamily,
MaxRequestsPerConnection: ctx.Config.Cluster.MaxRequestsPerConnection,
PerConnectionBufferLimitBytes: ctx.Config.Cluster.PerConnectionBufferLimitBytes,
UpstreamTLS: &contour_api_v1alpha1.EnvoyTLS{
MinimumProtocolVersion: ctx.Config.Cluster.UpstreamTLS.MinimumProtocolVersion,
MaximumProtocolVersion: ctx.Config.Cluster.UpstreamTLS.MaximumProtocolVersion,
CipherSuites: ctx.Config.Cluster.UpstreamTLS.CipherSuites,
},
},
Network: &contour_api_v1alpha1.NetworkParameters{
XffNumTrustedHops: &ctx.Config.Network.XffNumTrustedHops,
Expand Down
13 changes: 13 additions & 0 deletions internal/dag/dag.go
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,9 @@ type Cluster struct {

// PerConnectionBufferLimitBytes defines the soft limit on size of the cluster’s new connection read and write buffers.
PerConnectionBufferLimitBytes *uint32

// UpstreamTLS contains the TLS version and cipher suite configurations for upstream connections
UpstreamTLS *UpstreamTLS
}

// WeightedService represents the load balancing weight of a
Expand Down Expand Up @@ -1229,6 +1232,9 @@ type ExtensionCluster struct {
// ClientCertificate is the optional identifier of the TLS secret containing client certificate and
// private key to be used when establishing TLS connection to upstream cluster.
ClientCertificate *Secret

// UpstreamTLS contains the TLS version and cipher suite configurations for upstream connections
UpstreamTLS *UpstreamTLS
}

const singleDNSLabelWildcardRegex = "^[a-z0-9]([-a-z0-9]*[a-z0-9])?"
Expand Down Expand Up @@ -1260,3 +1266,10 @@ type SlowStartConfig struct {
func (s *SlowStartConfig) String() string {
return fmt.Sprintf("%s%f%d", s.Window.String(), s.Aggression, s.MinWeightPercent)
}

// UpstreamTLS holds the TLS configuration for upstream connections
type UpstreamTLS struct {
MinimumProtocolVersion string
MaximumProtocolVersion string
CipherSuites []string
}
9 changes: 9 additions & 0 deletions internal/dag/httpproxy_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ type HTTPProxyProcessor struct {
// configurable and off by default in order to support the feature
// without requiring all existing test cases to change.
SetSourceMetadataOnRoutes bool

// UpstreamTLS defines the TLS settings like min/max version
// and cipher suites for upstream connections.
UpstreamTLS *contour_api_v1alpha1.EnvoyTLS
}

// Run translates HTTPProxies into DAG objects and
Expand Down Expand Up @@ -1026,6 +1030,11 @@ func (p *HTTPProxyProcessor) computeRoutes(
SlowStartConfig: slowStart,
MaxRequestsPerConnection: p.MaxRequestsPerConnection,
PerConnectionBufferLimitBytes: p.PerConnectionBufferLimitBytes,
UpstreamTLS: &UpstreamTLS{
MinimumProtocolVersion: p.UpstreamTLS.MinimumProtocolVersion,
MaximumProtocolVersion: p.UpstreamTLS.MaximumProtocolVersion,
CipherSuites: p.UpstreamTLS.CipherSuites,
},
}
if service.Mirror && len(r.MirrorPolicies) > 0 {
validCond.AddError(contour_api_v1.ConditionTypeServiceError, "OnlyOneMirror",
Expand Down
13 changes: 12 additions & 1 deletion internal/envoy/v3/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
// UpstreamTLSContext creates an envoy_v3_tls.UpstreamTlsContext. By default
// UpstreamTLSContext returns a HTTP/1.1 TLS enabled context. A list of
// additional ALPN protocols can be provided.
func UpstreamTLSContext(peerValidationContext *dag.PeerValidationContext, sni string, clientSecret *dag.Secret, alpnProtocols ...string) *envoy_v3_tls.UpstreamTlsContext {
func UpstreamTLSContext(peerValidationContext *dag.PeerValidationContext, sni string, clientSecret *dag.Secret, upstreamTLS *dag.UpstreamTLS, alpnProtocols ...string) *envoy_v3_tls.UpstreamTlsContext {
var clientSecretConfigs []*envoy_v3_tls.SdsSecretConfig
if clientSecret != nil {
clientSecretConfigs = []*envoy_v3_tls.SdsSecretConfig{{
Expand All @@ -34,8 +34,19 @@ func UpstreamTLSContext(peerValidationContext *dag.PeerValidationContext, sni st
}}
}

tlsParams := &envoy_v3_tls.TlsParameters{}

if upstreamTLS != nil {
tlsParams = &envoy_v3_tls.TlsParameters{
TlsMinimumProtocolVersion: ParseTLSVersion(upstreamTLS.MinimumProtocolVersion),
TlsMaximumProtocolVersion: ParseTLSVersion(upstreamTLS.MaximumProtocolVersion),
CipherSuites: tlsParams.CipherSuites,
}
}

context := &envoy_v3_tls.UpstreamTlsContext{
CommonTlsContext: &envoy_v3_tls.CommonTlsContext{
TlsParams: tlsParams,
AlpnProtocols: alpnProtocols,
TlsCertificateSdsSecretConfigs: clientSecretConfigs,
},
Expand Down
19 changes: 17 additions & 2 deletions internal/envoy/v3/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ func TestUpstreamTLSContext(t *testing.T) {
validation *dag.PeerValidationContext
alpnProtocols []string
externalName string
upstreamTLS *dag.UpstreamTLS
want *envoy_v3_tls.UpstreamTlsContext
}{
"no alpn, no validation": {
"no alpn, no validation, no upstreamTLS": {
want: &envoy_v3_tls.UpstreamTlsContext{
CommonTlsContext: &envoy_v3_tls.CommonTlsContext{},
},
Expand Down Expand Up @@ -108,11 +109,25 @@ func TestUpstreamTLSContext(t *testing.T) {
Sni: "projectcontour.local",
},
},
"use TLS 1.3": {
upstreamTLS: &dag.UpstreamTLS{
MinimumProtocolVersion: "1.3",
MaximumProtocolVersion: "1.3",
},
want: &envoy_v3_tls.UpstreamTlsContext{
CommonTlsContext: &envoy_v3_tls.CommonTlsContext{
TlsParams: &envoy_v3_tls.TlsParameters{
TlsMinimumProtocolVersion: ParseTLSVersion("1.3"),
TlsMaximumProtocolVersion: ParseTLSVersion("1.3"),
},
},
},
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := UpstreamTLSContext(tc.validation, tc.externalName, nil, tc.alpnProtocols...)
got := UpstreamTLSContext(tc.validation, tc.externalName, nil, tc.upstreamTLS, tc.alpnProtocols...)
protobuf.ExpectEqual(t, tc.want, got)
})
}
Expand Down
5 changes: 4 additions & 1 deletion internal/envoy/v3/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func Cluster(c *dag.Cluster) *envoy_cluster_v3.Cluster {
c.UpstreamValidation,
c.SNI,
c.ClientCertificate,
c.UpstreamTLS,
),
)
case "h2":
Expand All @@ -106,6 +107,7 @@ func Cluster(c *dag.Cluster) *envoy_cluster_v3.Cluster {
c.UpstreamValidation,
c.SNI,
c.ClientCertificate,
c.UpstreamTLS,
"h2",
),
)
Expand Down Expand Up @@ -177,6 +179,7 @@ func ExtensionCluster(ext *dag.ExtensionCluster) *envoy_cluster_v3.Cluster {
ext.UpstreamValidation,
ext.SNI,
ext.ClientCertificate,
nil, // TODO(KauzClay): should TLS protocol version settings be configurable for extensionservices too?
"h2",
),
)
Expand Down Expand Up @@ -207,7 +210,7 @@ func DNSNameCluster(c *dag.DNSNameCluster) *envoy_cluster_v3.Cluster {

var transportSocket *envoy_core_v3.TransportSocket
if c.Scheme == "https" {
transportSocket = UpstreamTLSTransportSocket(UpstreamTLSContext(c.UpstreamValidation, c.Address, nil))
transportSocket = UpstreamTLSTransportSocket(UpstreamTLSContext(c.UpstreamValidation, c.Address, nil, nil))
}

cluster.LoadAssignment = ClusterLoadAssignment(envoy.DNSNameClusterName(c), SocketAddress(c.Address, c.Port))
Expand Down
50 changes: 44 additions & 6 deletions internal/envoy/v3/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func TestCluster(t *testing.T) {
ServiceName: "default/kuard/http",
},
TransportSocket: UpstreamTLSTransportSocket(
UpstreamTLSContext(nil, "", nil, "h2"),
UpstreamTLSContext(nil, "", nil, nil, "h2"),
),
TypedExtensionProtocolOptions: map[string]*anypb.Any{
"envoy.extensions.upstreams.http.v3.HttpProtocolOptions": protobuf.MustMarshalAny(
Expand Down Expand Up @@ -274,7 +274,7 @@ func TestCluster(t *testing.T) {
ServiceName: "default/kuard/http",
},
TransportSocket: UpstreamTLSTransportSocket(
UpstreamTLSContext(nil, "", nil),
UpstreamTLSContext(nil, "", nil, nil),
),
},
},
Expand All @@ -290,7 +290,7 @@ func TestCluster(t *testing.T) {
ClusterDiscoveryType: ClusterDiscoveryType(envoy_cluster_v3.Cluster_STRICT_DNS),
LoadAssignment: ExternalNameClusterLoadAssignment(service(svcExternal, "tls")),
TransportSocket: UpstreamTLSTransportSocket(
UpstreamTLSContext(nil, "projectcontour.local", nil),
UpstreamTLSContext(nil, "projectcontour.local", nil, nil),
),
},
},
Expand Down Expand Up @@ -318,10 +318,48 @@ func TestCluster(t *testing.T) {
SubjectName: "foo.bar.io",
},
"",
nil,
nil),
),
},
},
"UpstreamTLS protocol version set": {
cluster: &dag.Cluster{
Upstream: service(s1, "tls"),
Protocol: "tls",
UpstreamValidation: &dag.PeerValidationContext{
CACertificate: secret,
SubjectName: "foo.bar.io",
},
UpstreamTLS: &dag.UpstreamTLS{
MinimumProtocolVersion: "1.3",
MaximumProtocolVersion: "1.3",
},
},
want: &envoy_cluster_v3.Cluster{
Name: "default/kuard/443/62d1f9ad02",
AltStatName: "default_kuard_443",
ClusterDiscoveryType: ClusterDiscoveryType(envoy_cluster_v3.Cluster_EDS),
EdsClusterConfig: &envoy_cluster_v3.Cluster_EdsClusterConfig{
EdsConfig: ConfigSource("contour"),
ServiceName: "default/kuard/http",
},
TransportSocket: UpstreamTLSTransportSocket(
UpstreamTLSContext(
&dag.PeerValidationContext{
CACertificate: secret,
SubjectName: "foo.bar.io",
},
"",
nil,
&dag.UpstreamTLS{
MinimumProtocolVersion: "1.3",
MaximumProtocolVersion: "1.3",
},
),
),
},
},
"projectcontour.io/max-connections": {
cluster: &dag.Cluster{
Upstream: &dag.Service{
Expand Down Expand Up @@ -526,7 +564,7 @@ func TestCluster(t *testing.T) {
ServiceName: "default/kuard/http",
},
TransportSocket: UpstreamTLSTransportSocket(
UpstreamTLSContext(nil, "", clientSecret),
UpstreamTLSContext(nil, "", clientSecret, nil),
),
},
},
Expand Down Expand Up @@ -854,7 +892,7 @@ func TestDNSNameCluster(t *testing.T) {
},
},
},
TransportSocket: UpstreamTLSTransportSocket(UpstreamTLSContext(nil, "foo.projectcontour.io", nil)),
TransportSocket: UpstreamTLSTransportSocket(UpstreamTLSContext(nil, "foo.projectcontour.io", nil, nil)),
},
},
"HTTPS cluster with upstream validation": {
Expand Down Expand Up @@ -903,7 +941,7 @@ func TestDNSNameCluster(t *testing.T) {
},
},
SubjectName: "foo.projectcontour.io",
}, "foo.projectcontour.io", nil)),
}, "foo.projectcontour.io", nil, nil)),
},
},
}
Expand Down
4 changes: 2 additions & 2 deletions internal/envoy/v3/socket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func TestUpstreamTLSTransportSocket(t *testing.T) {
want *envoy_core_v3.TransportSocket
}{
"h2": {
ctxt: UpstreamTLSContext(nil, "", nil, "h2"),
ctxt: UpstreamTLSContext(nil, "", nil, nil, "h2"),
want: &envoy_core_v3.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &envoy_core_v3.TransportSocket_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(UpstreamTLSContext(nil, "", nil, "h2")),
TypedConfig: protobuf.MustMarshalAny(UpstreamTLSContext(nil, "", nil, nil, "h2")),
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions internal/featuretests/v3/backendcavalidation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) {
// assert that there is a regular, non validation enabled cluster in CDS.
c.Request(clusterType).Equals(&envoy_discovery_v3.DiscoveryResponse{
Resources: resources(t,
tlsCluster(cluster("default/kuard/443/4929fca9d4", "default/kuard/securebackend", "default_kuard_443"), nil, "", "", nil),
tlsCluster(cluster("default/kuard/443/4929fca9d4", "default/kuard/securebackend", "default_kuard_443"), nil, "", "", nil, nil),
),
TypeUrl: clusterType,
})
Expand Down Expand Up @@ -114,7 +114,7 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) {
// assert that the cluster now has a certificate and subject name.
c.Request(clusterType).Equals(&envoy_discovery_v3.DiscoveryResponse{
Resources: resources(t,
tlsCluster(cluster("default/kuard/443/c6ccd34de5", "default/kuard/securebackend", "default_kuard_443"), []byte(featuretests.CERTIFICATE), "subjname", "", nil),
tlsCluster(cluster("default/kuard/443/c6ccd34de5", "default/kuard/securebackend", "default_kuard_443"), []byte(featuretests.CERTIFICATE), "subjname", "", nil, nil),
),
TypeUrl: clusterType,
})
Expand Down Expand Up @@ -161,7 +161,7 @@ func TestClusterServiceTLSBackendCAValidation(t *testing.T) {
// assert that the cluster now has a certificate and subject name.
c.Request(clusterType).Equals(&envoy_discovery_v3.DiscoveryResponse{
Resources: resources(t,
tlsCluster(cluster("default/kuard/443/c6ccd34de5", "default/kuard/securebackend", "default_kuard_443"), []byte(featuretests.CERTIFICATE), "subjname", "", nil),
tlsCluster(cluster("default/kuard/443/c6ccd34de5", "default/kuard/securebackend", "default_kuard_443"), []byte(featuretests.CERTIFICATE), "subjname", "", nil, nil),
),
TypeUrl: clusterType,
})
Expand Down
5 changes: 3 additions & 2 deletions internal/featuretests/v3/backendclientauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestBackendClientAuthenticationWithHTTPProxy(t *testing.T) {

c.Request(clusterType).Equals(&envoy_discovery_v3.DiscoveryResponse{
Resources: resources(t,
tlsCluster(cluster("default/backend/443/950c17581f", "default/backend/http", "default_backend_443"), []byte(featuretests.CERTIFICATE), "subjname", "", sec1),
tlsCluster(cluster("default/backend/443/950c17581f", "default/backend/http", "default_backend_443"), []byte(featuretests.CERTIFICATE), "subjname", "", sec1, nil),
),
TypeUrl: clusterType,
})
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestBackendClientAuthenticationWithIngress(t *testing.T) {

c.Request(clusterType).Equals(&envoy_discovery_v3.DiscoveryResponse{
Resources: resources(t,
tlsClusterWithoutValidation(cluster("default/backend/443/4929fca9d4", "default/backend/http", "default_backend_443"), "", sec1),
tlsClusterWithoutValidation(cluster("default/backend/443/4929fca9d4", "default/backend/http", "default_backend_443"), "", sec1, nil),
),
TypeUrl: clusterType,
})
Expand Down Expand Up @@ -214,6 +214,7 @@ func TestBackendClientAuthenticationWithExtensionService(t *testing.T) {
SubjectName: "subjname"},
"subjname",
&dag.Secret{Object: sec1},
nil,
"h2",
),
)
Expand Down
Loading

0 comments on commit b7f3f38

Please sign in to comment.