Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion api/v1alpha1/ext_proc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const (
StreamedExtProcBodyProcessingMode ExtProcBodyProcessingMode = "Streamed"
// BufferedExtProcBodyProcessingMode will buffer the message body in memory and send the entire body at once. If the body exceeds the configured buffer limit, then the downstream system will receive an error.
BufferedExtProcBodyProcessingMode ExtProcBodyProcessingMode = "Buffered"
// FullDuplexStreamedExtBodyProcessingMode will send the body in pieces, to be read in a stream. Full details here: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/processing_mode.proto.html#enum-extensions-filters-http-ext-proc-v3-processingmode-bodysendmode
// FullDuplexStreamedExtBodyProcessingMode will send the body in pieces, to be read in a stream. When enabled, trailers are also sent, and failOpen must be false.
// Full details here: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/processing_mode.proto.html#enum-extensions-filters-http-ext-proc-v3-processingmode-bodysendmode
FullDuplexStreamedExtBodyProcessingMode ExtProcBodyProcessingMode = "FullDuplexStreamed"
// BufferedPartialExtBodyHeaderProcessingMode will buffer the message body in memory and send the entire body in one chunk. If the body exceeds the configured buffer limit, then the body contents up to the buffer limit will be sent.
BufferedPartialExtBodyHeaderProcessingMode ExtProcBodyProcessingMode = "BufferedPartial"
Expand Down Expand Up @@ -67,6 +68,7 @@ type ExtProcProcessingMode struct {
// +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
// +kubebuilder:validation:XValidation:message="If FullDuplexStreamed body processing mode is used, FailOpen must be false.",rule="!(has(self.failOpen) && self.failOpen == true && ((has(self.processingMode.request.body) && self.processingMode.request.body == 'FullDuplexStreamed') || (has(self.processingMode.response.body) && self.processingMode.response.body == 'FullDuplexStreamed')))"
type ExtProc struct {
BackendCluster `json:",inline"`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,12 @@ spec:
group.
rule: 'has(self.backendRefs) ? (self.backendRefs.all(f, f.group
== "" || f.group == ''gateway.envoyproxy.io'')) : true'
- message: If FullDuplexStreamed body processing mode is used, FailOpen
must be false.
rule: '!(has(self.failOpen) && self.failOpen == true && ((has(self.processingMode.request.body)
&& self.processingMode.request.body == ''FullDuplexStreamed'')
|| (has(self.processingMode.response.body) && self.processingMode.response.body
== ''FullDuplexStreamed'')))'
maxItems: 16
type: array
lua:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,12 @@ spec:
group.
rule: 'has(self.backendRefs) ? (self.backendRefs.all(f, f.group
== "" || f.group == ''gateway.envoyproxy.io'')) : true'
- message: If FullDuplexStreamed body processing mode is used, FailOpen
must be false.
rule: '!(has(self.failOpen) && self.failOpen == true && ((has(self.processingMode.request.body)
&& self.processingMode.request.body == ''FullDuplexStreamed'')
|| (has(self.processingMode.response.body) && self.processingMode.response.body
== ''FullDuplexStreamed'')))'
maxItems: 16
type: array
lua:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ require (
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobuffalo/flect v1.0.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
Expand Down
46 changes: 24 additions & 22 deletions internal/gatewayapi/backendtlspolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
return tlsBundle, nil
}

caCert, err := getCaCertsFromCARefs(backend.Spec.TLS.CACertificateRefs, resources)
caCert, err := getCaCertsFromCARefs(backend.Namespace, backend.Spec.TLS.CACertificateRefs, resources)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -234,7 +234,7 @@
return tlsBundle, nil
}

caCert, err := getCaCertsFromCARefs(backendTLSPolicy.Spec.Validation.CACertificateRefs, resources)
caCert, err := getCaCertsFromCARefs(backendTLSPolicy.Namespace, backendTLSPolicy.Spec.Validation.CACertificateRefs, resources)
if err != nil {
return nil, err
}
Expand All @@ -245,43 +245,45 @@
return tlsBundle, nil
}

func getCaCertsFromCARefs(caCertificates []gwapiv1.LocalObjectReference, resources *resource.Resources) ([]byte, error) {
func getCaCertsFromCARefs(namespace string, caCertificates []gwapiv1.LocalObjectReference, resources *resource.Resources) ([]byte, error) {
ca := ""
for _, caRef := range caCertificates {
kind := string(caRef.Kind)

switch kind {
case resource.KindConfigMap:
for _, cmap := range resources.ConfigMaps {
if cmap.Name == string(caRef.Name) {
if crt, dataOk := cmap.Data["ca.crt"]; dataOk {
if ca != "" {
ca += "\n"
}
ca += crt
} else {
return nil, fmt.Errorf("no ca found in configmap %s", cmap.Name)
cm := resources.GetConfigMap(namespace, string(caRef.Name))
if cm != nil {
if crt, dataOk := cm.Data[caCertKey]; dataOk {
if ca != "" {
ca += "\n"

Check warning on line 259 in internal/gatewayapi/backendtlspolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtlspolicy.go#L259

Added line #L259 was not covered by tests
}
ca += crt
} else {
return nil, fmt.Errorf("no ca found in configmap %s", cm.Name)
}
} else {
return nil, fmt.Errorf("configmap %s not found in namespace %s", caRef.Name, namespace)
}
case resource.KindSecret:
for _, secret := range resources.Secrets {
if secret.Name == string(caRef.Name) {
if crt, dataOk := secret.Data["ca.crt"]; dataOk {
if ca != "" {
ca += "\n"
}
ca += string(crt)
} else {
return nil, fmt.Errorf("no ca found in secret %s", secret.Name)
secret := resources.GetSecret(namespace, string(caRef.Name))
if secret != nil {
if crt, dataOk := secret.Data[caCertKey]; dataOk {
if ca != "" {
ca += "\n"

Check warning on line 273 in internal/gatewayapi/backendtlspolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtlspolicy.go#L273

Added line #L273 was not covered by tests
}
ca += string(crt)
} else {
return nil, fmt.Errorf("no ca found in secret %s", secret.Name)

Check warning on line 277 in internal/gatewayapi/backendtlspolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtlspolicy.go#L276-L277

Added lines #L276 - L277 were not covered by tests
}
} else {
return nil, fmt.Errorf("secret %s not found in namespace %s", caRef.Name, namespace)

Check warning on line 280 in internal/gatewayapi/backendtlspolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtlspolicy.go#L279-L280

Added lines #L279 - L280 were not covered by tests
}
}
}

if ca == "" {
return nil, fmt.Errorf("no ca found in referred configmaps")
return nil, fmt.Errorf("no ca found in referred ConfigMap or Secret")

Check warning on line 286 in internal/gatewayapi/backendtlspolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtlspolicy.go#L286

Added line #L286 was not covered by tests
}
return []byte(ca), nil
}
Expand Down
23 changes: 7 additions & 16 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,13 @@ func resolveCTPolicyTargetRef(
}

// If sectionName is set, make sure its valid
sectionName := targetRef.SectionName
if sectionName != nil {
found := false
for _, l := range gateway.listeners {
if l.Name == *sectionName {
found = true
break
}
}
if !found {
message := fmt.Sprintf("No section name %s found for %s", *sectionName, key.String())

return gateway.GatewayContext, &status.PolicyResolveError{
Reason: gwapiv1a2.PolicyReasonInvalid,
Message: message,
}
if targetRef.SectionName != nil {
if err := validateGatewayListenerSectionName(
*targetRef.SectionName,
key,
gateway.listeners,
); err != nil {
return gateway.GatewayContext, err
}
}

Expand Down
44 changes: 27 additions & 17 deletions internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"errors"
"fmt"
"math"
"net"
"strings"

"github.com/google/cel-go/cel"
Expand All @@ -24,7 +25,7 @@
"github.com/envoyproxy/gateway/internal/ir"
"github.com/envoyproxy/gateway/internal/utils"
"github.com/envoyproxy/gateway/internal/utils/naming"
"github.com/envoyproxy/gateway/internal/utils/net"
netutils "github.com/envoyproxy/gateway/internal/utils/net"
"github.com/envoyproxy/gateway/internal/xds/bootstrap"
)

Expand Down Expand Up @@ -105,10 +106,10 @@
continue
}

address := net.IPv4ListenerAddress
address := netutils.IPv4ListenerAddress
ipFamily := getEnvoyIPFamily(gateway.envoyProxy)
if ipFamily != nil && (*ipFamily == egv1a1.IPv6 || *ipFamily == egv1a1.DualStack) {
address = net.IPv6ListenerAddress
address = netutils.IPv6ListenerAddress

Check warning on line 112 in internal/gatewayapi/listener.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/listener.go#L112

Added line #L112 was not covered by tests
}

// Add the listener to the Xds IR
Expand Down Expand Up @@ -408,10 +409,17 @@
if hostname1 == nil || hostname2 == nil {
return true
}
domain1 := strings.Replace(string(*hostname1), "*.", "", 1)
domain2 := strings.Replace(string(*hostname2), "*.", "", 1)
return isSubdomain(domain1, domain2) || isSubdomain(domain2, domain1)
}

h1 := strings.Replace(string(*hostname1), "*.", "", 1)
h2 := strings.Replace(string(*hostname2), "*.", "", 1)
return strings.HasSuffix(h1, h2) || strings.HasSuffix(h2, h1)
// isSubdomain checks if subDomain is a sub-domain of domain
func isSubdomain(subDomain, domain string) bool {
if subDomain == domain {
return true
}
return strings.HasSuffix(subDomain, fmt.Sprintf(".%s", domain))
}

func buildListenerMetadata(listener *ListenerContext, gateway *GatewayContext) *ir.ResourceMetadata {
Expand All @@ -427,14 +435,14 @@
func (t *Translator) processProxyReadyListener(xdsIR *ir.Xds, envoyProxy *egv1a1.EnvoyProxy) {
var (
ipFamily = egv1a1.IPv4
address = net.IPv4ListenerAddress
address = netutils.IPv4ListenerAddress
)

if envoyProxy != nil && envoyProxy.Spec.IPFamily != nil {
ipFamily = *envoyProxy.Spec.IPFamily
}
if ipFamily == egv1a1.IPv6 || ipFamily == egv1a1.DualStack {
address = net.IPv6ListenerAddress
address = netutils.IPv6ListenerAddress

Check warning on line 445 in internal/gatewayapi/listener.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/listener.go#L445

Added line #L445 was not covered by tests
}

xdsIR.ReadyListener = &ir.ReadyListener{
Expand Down Expand Up @@ -583,11 +591,6 @@
}
irAccessLog.Text = append(irAccessLog.Text, al)
case egv1a1.ProxyAccessLogFormatTypeJSON:
if len(format.JSON) == 0 {
// TODO: use a default JSON format if not specified?
continue
}

al := &ir.JSONAccessLog{
JSON: format.JSON,
Path: sink.File.Path,
Expand Down Expand Up @@ -830,12 +833,19 @@
}

func destinationSettingFromHostAndPort(name, host string, port uint32) []*ir.DestinationSetting {
// check if host is an IP address or a hostname
addressType := ir.FQDN
if net.ParseIP(host) != nil {
addressType = ir.IP
}

Check warning on line 840 in internal/gatewayapi/listener.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/listener.go#L839-L840

Added lines #L839 - L840 were not covered by tests

return []*ir.DestinationSetting{
{
Name: name,
Weight: ptr.To[uint32](1),
Protocol: ir.GRPC,
Endpoints: []*ir.DestinationEndpoint{ir.NewDestEndpoint(host, port, false, nil)},
Name: name,
Weight: ptr.To[uint32](1),
Protocol: ir.GRPC,
AddressType: ptr.To(addressType),
Endpoints: []*ir.DestinationEndpoint{ir.NewDestEndpoint(host, port, false, nil)},
},
}
}
Expand Down
6 changes: 6 additions & 0 deletions internal/gatewayapi/listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ func TestIsOverlappingHostname(t *testing.T) {
hostname2: ptr.To(gwapiv1.Hostname("*.test.com")),
want: false,
},
{
name: "different sub domains of same domain",
hostname1: ptr.To(gwapiv1.Hostname("api.foo.dev")),
hostname2: ptr.To(gwapiv1.Hostname("testing-api.foo.dev")),
want: false,
},
}

for _, tt := range tests {
Expand Down
7 changes: 4 additions & 3 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,10 @@ func processRouteTimeout(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
irRoute.Timeout = ptr.To(metav1.Duration{Duration: d})
}

// Also set the IR Route Timeout to the backend request timeout
// until we introduce retries, then set it to per try timeout
if rule.Timeouts.BackendRequest != nil {
// Only set the IR Route Timeout to the backend request timeout
// when retries are not configured. When retries are configured,
// the backend request timeout should set for per-retry timeout.
if rule.Timeouts.BackendRequest != nil && rule.Retry == nil {
d, err := time.ParseDuration(string(*rule.Timeouts.BackendRequest))
if err != nil {
d, _ = time.ParseDuration(HTTPRequestTimeout)
Expand Down
2 changes: 1 addition & 1 deletion internal/gatewayapi/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
result, err := t.Translate(resources)
if err != nil {
// Currently all errors that Translate returns should just be logged
r.Logger.Error(err, "errors detected during translation")
r.Logger.Error(err, "errors detected during translation", "gateway-class", resources.GatewayClass.Name)

Check warning on line 180 in internal/gatewayapi/runner/runner.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/runner/runner.go#L180

Added line #L180 was not covered by tests
}

// Publish the IRs.
Expand Down
11 changes: 11 additions & 0 deletions internal/gatewayapi/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,17 @@ func resolveSecurityPolicyGatewayTargetRef(
return nil, nil
}

// If sectionName is set, make sure its valid
if target.SectionName != nil {
if err := validateGatewayListenerSectionName(
*target.SectionName,
key,
gateway.listeners,
); err != nil {
return gateway.GatewayContext, err
}
}

// Check if another policy targeting the same Gateway exists
if gateway.attached {
message := fmt.Sprintf("Unable to target Gateway %s, another SecurityPolicy has already attached to it",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ secrets:
kind: Secret
metadata:
name: ca-secret
namespace: policies
namespace: backends
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
backendTLSPolicies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ clientTrafficPolicies:
sectionName: foo-bar
conditions:
- lastTransitionTime: null
message: No section name foo-bar found for envoy-gateway/gateway-3
reason: Invalid
message: No section name foo-bar found for Gateway envoy-gateway/gateway-3
reason: TargetNotFound
status: "False"
type: Accepted
controllerName: gateway.envoyproxy.io/gatewayclass-controller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ configMaps:
kind: ConfigMap
metadata:
name: ca-cmap
namespace: default
namespace: envoy-gateway
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
Expand Down
Loading