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

feat: support backend tls settings with envoyproxy #3218

Merged
merged 19 commits into from
Apr 25, 2024
Merged
2 changes: 1 addition & 1 deletion api/v1alpha1/clienttrafficpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ type ClientTrafficPolicySpec struct {
// TLS settings configure TLS termination settings with the downstream client.
//
// +optional
TLS *TLSSettings `json:"tls,omitempty"`
TLS *ClientTLSSettings `json:"tls,omitempty"`
// Path enables managing how the incoming path set by clients can be normalized.
//
// +optional
Expand Down
15 changes: 15 additions & 0 deletions api/v1alpha1/envoyproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
)

const (
Expand Down Expand Up @@ -116,6 +117,20 @@ type EnvoyProxySpec struct {
// +optional
// +notImplementedHide
FilterOrder []FilterPosition `json:"filterOrder,omitempty"`
// BackendTLS is the TLS configuration for the Envoy proxy to use when connecting to backends.
// These settings are applied on backends for which TLS policies are specified.
// +optional
BackendTLS *BackendTLSConfig `json:"backendTLS,omitempty"`
}

// BackendTLSConfig describes the BackendTLS configuration for Envoy Proxy.
type BackendTLSConfig struct {
// ClientCertificateRef defines the reference to a Kubernetes Secret that contains
// the client certificate and private key for Envoy to use when connecting to
// backend services and external services, such as ExtAuth, ALS, OpenTelemetry, etc.
// +optional
ClientCertificateRef *gwapiv1.SecretObjectReference `json:"clientCertificateRef,omitempty"`
TLSSettings `json:",inline"`
guydc marked this conversation as resolved.
Show resolved Hide resolved
}

// FilterPosition defines the position of an Envoy HTTP filter in the filter chain.
Expand Down
14 changes: 8 additions & 6 deletions api/v1alpha1/tls_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ import (
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
)

type ClientTLSSettings struct {
// ClientValidation specifies the configuration to validate the client
// initiating the TLS connection to the Gateway listener.
// +optional
ClientValidation *ClientValidationContext `json:"clientValidation,omitempty"`
TLSSettings `json:",inline"`
}

// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && self.minVersion == '1.3' ? !has(self.ciphers) : true", message="setting ciphers has no effect if the minimum possible TLS version is 1.3"
// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && has(self.maxVersion) ? {\"Auto\":0,\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4}[self.minVersion] <= {\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4,\"Auto\":5}[self.maxVersion] : !has(self.minVersion) && has(self.maxVersion) ? 3 <= {\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4,\"Auto\":5}[self.maxVersion] : true", message="minVersion must be smaller or equal to maxVersion"
type TLSSettings struct {

// Min specifies the minimal TLS protocol version to allow.
// The default is TLS 1.2 if this is not specified.
//
Expand Down Expand Up @@ -66,11 +73,6 @@ type TLSSettings struct {
//
// +optional
ALPNProtocols []ALPNProtocol `json:"alpnProtocols,omitempty"`

// ClientValidation specifies the configuration to validate the client
// initiating the TLS connection to the Gateway listener.
// +optional
ClientValidation *ClientValidationContext `json:"clientValidation,omitempty"`
}

// ALPNProtocol specifies the protocol to be negotiated using ALPN
Expand Down
54 changes: 48 additions & 6 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,142 @@ spec:
spec:
description: EnvoyProxySpec defines the desired state of EnvoyProxy.
properties:
backendTLS:
description: |-
BackendTLS is the TLS configuration for the Envoy proxy to use when connecting to backends.
These settings are applied on backends for which TLS policies are specified.
properties:
alpnProtocols:
description: |-
ALPNProtocols supplies the list of ALPN protocols that should be
exposed by the listener. By default h2 and http/1.1 are enabled.
Supported values are:
- http/1.0
- http/1.1
- h2
items:
description: ALPNProtocol specifies the protocol to be negotiated
using ALPN
enum:
- http/1.0
- http/1.1
- h2
type: string
type: array
ciphers:
description: |-
Ciphers specifies the set of cipher suites supported when
negotiating TLS 1.0 - 1.2. This setting has no effect for TLS 1.3.
In non-FIPS Envoy Proxy builds the default cipher list is:
- [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]
- [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
In builds using BoringSSL FIPS the default cipher list is:
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
items:
type: string
type: array
clientCertificateRef:
description: |-
ClientCertificateRef defines the reference to a Kubernetes Secret that contains
the client certificate and private key for Envoy to use when connecting to
backend services and external services, such as ExtAuth, ALS, OpenTelemetry, etc.
properties:
group:
default: ""
description: |-
Group is the group of the referent. For example, "gateway.networking.k8s.io".
When unspecified or empty string, core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
default: Secret
description: Kind is kind of the referent. For example "Secret".
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: |-
Namespace is the namespace of the referenced object. When unspecified, the local
namespace is inferred.


Note that when a namespace different than the local namespace is specified,
a ReferenceGrant object is required in the referent namespace to allow that
namespace's owner to accept the reference. See the ReferenceGrant
documentation for details.


Support: Core
maxLength: 63
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
required:
- name
type: object
ecdhCurves:
description: |-
ECDHCurves specifies the set of supported ECDH curves.
In non-FIPS Envoy Proxy builds the default curves are:
- X25519
- P-256
In builds using BoringSSL FIPS the default curve is:
- P-256
items:
type: string
type: array
maxVersion:
description: |-
Max specifies the maximal TLS protocol version to allow
The default is TLS 1.3 if this is not specified.
enum:
- Auto
- "1.0"
- "1.1"
- "1.2"
- "1.3"
type: string
minVersion:
description: |-
Min specifies the minimal TLS protocol version to allow.
The default is TLS 1.2 if this is not specified.
enum:
- Auto
- "1.0"
- "1.1"
- "1.2"
- "1.3"
type: string
signatureAlgorithms:
description: |-
SignatureAlgorithms specifies which signature algorithms the listener should
support.
items:
type: string
type: array
type: object
x-kubernetes-validations:
- message: setting ciphers has no effect if the minimum possible TLS
version is 1.3
rule: 'has(self.minVersion) && self.minVersion == ''1.3'' ? !has(self.ciphers)
: true'
- message: minVersion must be smaller or equal to maxVersion
rule: 'has(self.minVersion) && has(self.maxVersion) ? {"Auto":0,"1.0":1,"1.1":2,"1.2":3,"1.3":4}[self.minVersion]
<= {"1.0":1,"1.1":2,"1.2":3,"1.3":4,"Auto":5}[self.maxVersion]
: !has(self.minVersion) && has(self.maxVersion) ? 3 <= {"1.0":1,"1.1":2,"1.2":3,"1.3":4,"Auto":5}[self.maxVersion]
: true'
bootstrap:
description: |-
Bootstrap defines the Envoy Bootstrap as a YAML string.
Expand Down
27 changes: 26 additions & 1 deletion internal/gatewayapi/backendtlspolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,32 @@ func (t *Translator) processBackendTLSPolicy(
}

status.SetAcceptedForPolicyAncestors(&policy.Status, ancestorRefs, t.GatewayControllerName)

// apply defaults as per envoyproxy
if resources.EnvoyProxy != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we apply this logic outside of backendtlspolicy translation, since it's not directly originating from that policy? It's probably most efficient and user-friendly to do it here. But, in the future TLS settings may originate from other resources, as described in kubernetes-sigs/gateway-api#2910

Copy link
Contributor Author

@alexwo alexwo Apr 19, 2024

Choose a reason for hiding this comment

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

Right, it can make sense but maybe we can do it after support for additional resources is implemented in upstream. I guess we can move / extend this logic to other areas as well at any time.

Do you see an advantage in making this change now? Maybe If we want to support a use case of applying this on a gateway level already.

wdyt?

if resources.EnvoyProxy.Spec.BackendTLS != nil {
if len(resources.EnvoyProxy.Spec.BackendTLS.Ciphers) > 0 {
tlsBundle.Ciphers = resources.EnvoyProxy.Spec.BackendTLS.Ciphers
}
if len(resources.EnvoyProxy.Spec.BackendTLS.ECDHCurves) > 0 {
tlsBundle.ECDHCurves = resources.EnvoyProxy.Spec.BackendTLS.ECDHCurves
}
if len(resources.EnvoyProxy.Spec.BackendTLS.SignatureAlgorithms) > 0 {
tlsBundle.SignatureAlgorithms = resources.EnvoyProxy.Spec.BackendTLS.SignatureAlgorithms
}
if resources.EnvoyProxy.Spec.BackendTLS.MinVersion != nil {
tlsBundle.MinVersion = ptr.To(ir.TLSVersion(*resources.EnvoyProxy.Spec.BackendTLS.MinVersion))
}
if resources.EnvoyProxy.Spec.BackendTLS.MinVersion != nil {
tlsBundle.MaxVersion = ptr.To(ir.TLSVersion(*resources.EnvoyProxy.Spec.BackendTLS.MaxVersion))
}
if len(resources.EnvoyProxy.Spec.BackendTLS.ALPNProtocols) > 0 {
tlsBundle.ALPNProtocols = make([]string, len(resources.EnvoyProxy.Spec.BackendTLS.ALPNProtocols))
for i := range resources.EnvoyProxy.Spec.BackendTLS.ALPNProtocols {
tlsBundle.ALPNProtocols[i] = string(resources.EnvoyProxy.Spec.BackendTLS.ALPNProtocols[i])
}
}
}
}
return tlsBundle
}

Expand Down
Loading
Loading