diff --git a/internal/gatewayapi/contexts.go b/internal/gatewayapi/contexts.go index 60670eebd1..96956810bb 100644 --- a/internal/gatewayapi/contexts.go +++ b/internal/gatewayapi/contexts.go @@ -145,6 +145,10 @@ type ListenerContext struct { namespaceSelector labels.Selector + // specValid indicates whether per-listener spec validation succeeded. + // Conflict detection should only consider listeners with specValid=true. + specValid bool + tls ListenerTLSConfig httpIR *ir.HTTPListener diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 78d59e5718..a7bbc26957 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -219,9 +219,84 @@ func validClientCertificateRef(ref *gwapiv1.SecretObjectReference) error { return nil } +// allowedRouteKindsForProtocol returns the route kinds supported by the given listener protocol. +func allowedRouteKindsForProtocol(protocol gwapiv1.ProtocolType, tlsMode *gwapiv1.TLSModeType) []gwapiv1.Kind { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: + return []gwapiv1.Kind{resource.KindHTTPRoute, resource.KindGRPCRoute} + case gwapiv1.TLSProtocolType: + if tlsMode != nil && *tlsMode == gwapiv1.TLSModePassthrough { + return []gwapiv1.Kind{resource.KindTLSRoute} + } + // Terminate mode or unspecified defaults to accept both TCP and TLS routes + return []gwapiv1.Kind{resource.KindTCPRoute, resource.KindTLSRoute} + case gwapiv1.TCPProtocolType: + return []gwapiv1.Kind{resource.KindTCPRoute} + case gwapiv1.UDPProtocolType: + return []gwapiv1.Kind{resource.KindUDPRoute} + default: + return nil + } +} + +func (t *Translator) validateListenerSpec(listener *ListenerContext, resources *resource.Resources) bool { + // Validate listener spec directly without relying on conditions. + // Start with valid assumption and invalidate on failures. + // Phase 1: Validate fundamental rules + specValid := t.validateAllowedNamespaces(listener) + + // Phase 2: Validate allowed routes based on protocol + if isSupportedListenerProtocol(listener.Protocol) { + var tlsMode *gwapiv1.TLSModeType + if listener.TLS != nil { + tlsMode = listener.TLS.Mode + } + allowedKinds := allowedRouteKindsForProtocol(listener.Protocol, tlsMode) + if !t.validateAllowedRoutes(listener, allowedKinds...) { + specValid = false + } + } else { + // Unsupported protocol + specValid = false + listener.SetSupportedKinds() + listener.SetCondition( + gwapiv1.ListenerConditionAccepted, + metav1.ConditionFalse, + gwapiv1.ListenerReasonUnsupportedProtocol, + fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, + gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), + ) + } + + // Phase 3: Validate TLS configuration details + if !t.validateTLSConfiguration(listener, resources) { + specValid = false + } + + // Phase 4: Validate Hostname configuration + if !t.validateHostName(listener) { + specValid = false + } + + return specValid +} + func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources) { // Infra IR proxy ports must be unique. foundPorts := make(map[string][]*protocolPort) + + // Phase 1: Validate each listener's spec independently. + // This must happen before conflict resolution so that invalid listeners + // don't block valid ones during conflict detection. + for _, gateway := range gateways { + for _, listener := range gateway.listeners { + listener.specValid = t.validateListenerSpec(listener, resources) + } + } + + // Phase 2: Run conflict detection. + // Only listeners that haven't been marked as invalid will participate in conflict resolution. + t.validateConflictedProtocolsListeners(gateways) t.validateConflictedLayer7Listeners(gateways) t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType) t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType) @@ -229,9 +304,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource t.validateConflictedMergedListeners(gateways) } - // Iterate through all listeners to validate spec - // and compute status for each, and add valid ones - // to the Xds IR. + // Phase 3: Build IR for valid listeners. for _, gateway := range gateways { irKey := t.getIRKey(gateway.Gateway) @@ -242,49 +315,12 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource t.processProxyObservability(gateway, xdsIR[irKey], infraIR[irKey].Proxy, resources) for _, listener := range gateway.listeners { - // Process protocol & supported kinds - switch listener.Protocol { - case gwapiv1.TLSProtocolType: - if listener.TLS != nil { - switch *listener.TLS.Mode { - case gwapiv1.TLSModePassthrough: - t.validateAllowedRoutes(listener, resource.KindTLSRoute) - case gwapiv1.TLSModeTerminate: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - default: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - } else { - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: - t.validateAllowedRoutes(listener, resource.KindHTTPRoute, resource.KindGRPCRoute) - case gwapiv1.TCPProtocolType: - t.validateAllowedRoutes(listener, resource.KindTCPRoute) - case gwapiv1.UDPProtocolType: - t.validateAllowedRoutes(listener, resource.KindUDPRoute) - default: - listener.SetSupportedKinds() - listener.SetCondition( - gwapiv1.ListenerConditionAccepted, - metav1.ConditionFalse, - gwapiv1.ListenerReasonUnsupportedProtocol, - fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, - gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), - ) - } - - // Validate allowed namespaces - t.validateAllowedNamespaces(listener) - - // Process TLS configuration - t.validateTLSConfiguration(listener, resources) - - // Process Hostname configuration - t.validateHostName(listener) - - // Process conditions and check if the listener is ready + // Finalize listener conditions and check readiness. t.validateListenerConditions(listener) + if !listener.IsReady() { + // Skip invalid listeners from IR building + continue + } // Skip listeners with invalid frontend TLS validation as they are not functional. if listener.frontendTLSValidationInvalid() { @@ -427,10 +463,18 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } @@ -509,10 +553,18 @@ func checkOverlappingCertificates(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 4c86bcc38c..da63bf2acf 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -2287,7 +2287,7 @@ func (t *Translator) processAllowedListenersForParentRefs( } parentRefCtx.SetListeners(allowedListeners...) - if !HasReadyListener(selectedListeners) { + if !HasReadyListener(allowedListeners) { routeStatus := GetRouteStatus(routeContext) status.SetRouteStatusCondition(routeStatus, parentRefCtx.routeParentStatusIdx, diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml index af39245f4e..ce7c003177 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml @@ -508,12 +508,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -735,20 +729,6 @@ xdsIR: namespace: envoy-gateway name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* traffic: {} - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml index a29dfb9785..41827b1006 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml @@ -218,12 +218,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-1/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -309,20 +303,6 @@ xdsIR: name: "" prefix: /foo traffic: {} - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-1/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml index 6fa616eead..6d47792238 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml @@ -453,12 +453,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -596,20 +590,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml index 081fd59005..9508ec8d51 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml @@ -508,12 +508,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -727,20 +721,6 @@ xdsIR: name: grpcroute-1 namespace: envoy-gateway name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml index c2ac20067f..f11b451baf 100644 --- a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml @@ -326,13 +326,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route: proxy: - listeners: - - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: unresolved-gateway-with-one-attached-unresolved-route @@ -487,21 +480,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: unresolved-gateway-with-one-attached-unresolved-route - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml new file mode 100644 index 0000000000..1b0dfa84fc --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml @@ -0,0 +1,64 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + # This listener has an invalid certificate reference (secret does not exist) + # It should have ResolvedRefs=False with InvalidCertificateRef + # and should be skipped during conflict resolution + - name: invalid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: non-existent-secret + # This listener has valid configuration and should be accepted + # even though it's on the same port/hostname as the invalid listener + - name: valid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3pkSjZ6QmttT3REamcKWnkxR1I0d1EyTlpQSTE2ZWhvc1prSVVqZnNtRWYxQUhveVlRZlVleW5aenNMY1luRGM5N2dKdnliVU5TUkJPTApwNmdjVkREdHJvNkZNc1gvdnVJS0pCRzNvalZ6T3lab3lEdkpRMlVYS1J4RFVPOGdpUDhMcVJRS2NkT3JwT1NnCkNXVU5TSDFNV0dQMEJRWmJNTGk3VEk5MVQ4OGRDRytCMW1CcllWcWR0MElKOVJoVUhrdkhOSGNJMkhBQzVKQzEKcVdJRTN1aFRoR2hzYUV1NlRCWi9xSDdSRWZhbmZncTdRaUxQVHRadlp5MERrMTJ3dVRZQ3VMblZtdEQ1MjlzeQp5UEdlcFU2a0NOMGZOZXVpeVJBZ2YyQ1ZkMVpDNklOVVpiY0FKTjhaRjZvSmwwbml4Lyt1OU1jOUM4dkh4Z0dYCjg5U3dHWFNMQWdNQkFBRUNnZ0VBSmYrYW53UEV6WS9CdjFwNWpya1ZvbmVYb1hnMno5QmpZYzFsTTZma0djY3YKZGY2SXo5TUhQSDM5UFZGUDlQTUtyUGNGam1hdWE1djRtNGlyb3h2OHBFZGk3RGRkRDVNbW44a1ZhMUhRaVk3TAp5a0lqenJFVGxiemh2Q3RHQnhpYkVLZ0RrMWFZNEc1dzdxWXVuSXB0NVoyTnhKelB4TDFqVUYyY3Z0VmdZS0FPCjN2TWY1dENWbS9kL2JBT2xvWnVVc3ArSnc1ZTYvSFN3c3lEdjV2Y2dDQkRXRjFkTFFiYUxCelZDZGJBY0Fma1AKbFUzeGhZMVYyMGU2NmhBbU0veE53MzArSUhvTUlTUTFiQW9MOXVzN3NsTlYxT2ZNZk5hWC83WVdKWFVab1MzNwpyY1IvVXYwZlRtQkhPR3pwK25oaWpLRUlYU1ZESjNxK040amM4Ni9IeVFLQmdRRFhWbzNKSmlia0cvY1JBZ2pICkVqdWROMHJMSGJvVldPanN5ekZmaXg1MHJKTTYwMDJKZURicGdQeEt4ZUtFdGl4ZkVWQmU0eHdqNG9oK1ZubEIKT0dMU3BWcHRRVFRnRVprWXFvVU1iUDIyNHQ2cUZuSXZsTkkwZFJGWDUyS3I2L1FCS0EwWEk3K0I1bTV3Z2hLcgo4ZEQrMGRWNkZzMmxFT0NMWUJKck1weFNIUUtCZ1FEVlY0REVaUlFvVUo5UGRkb3IyK2IweFV2Y3JHeUJ1NlM2CjJZOFJuMzdWUVlBSThHUnlYRkcxTGxZaHpMOWNwd0tUR21SMVhPRTVkMC9mMStaU3h5TVc1d2FSaXU1b0dFK2cKUlNsMXBBdTNUdlEzM1BVNUJzNFhhcHBLOC9BZVk3cG1pd1JhYnRPSFlQa0FHMXNzL3k1d1NjVGUxQXZiWlpsTAo1TmgwdHZvZ3h3S0JnUUNtRkFJOFhlbG15czZ0Vm1WUXE1WkF0YkZBb0VleFNTWXo0cTdNb200MXpCZXRLZVRHCkhtb3pneUNSeHJiaVplSW8zQ0NoWGdXSkE2RUQxMHVqYW9xRkxiUmxTUUl2d2tMU1RFbGJBUUJZdWZiRE5aYVIKYmZVRk1qalRGQWo4MFhrYUh6cWhXeGZMWnQ1TWRYVlRHYWgzcjN3MnNqbWVranFzSThkdzE5TEtYUUtCZ0NoMQp3T0QrUG5WcTNOdklBUWxpV2dtL3hTUmp1dXhidHVFTTA1cEhBbG5WWXovT3YyNEUzaVliVkpCeWNUUlVKQ1BiCjFJT0JpdUZJSkdqU1hFY0VwejMzc0lJM3RBRWY0eklGQzlqWXRMUWVFQ2pzQ2NHMzdhdjVOcXZTV1k2WjRVY0QKUkY4V041MnNJVzBJd3lEa2dGMGhVR25tRXgyWHhodmptYjJBMmkwUEFvR0FUV1kzbXZRVWtZcmU5R0J0alVqYgpDWUx5Mm1VVElKbjVDcmhjTHMvMlh5MkNoVSt5MnhsT3pIcm1vanRIaHFFcnVCK0xyZkpBd3B3cGVRNmxyWnFQCjFGazVKT2c2bmV2U3lDcWF4SDZaenZRMXJ6VzAycm1IMUJrV1BiY0NwKy9VRTIrS3JselZtNHkvZ0ZoRGVGZlcKRUc5UzIzYndKME1JUmF0WVpFQm0wcWs9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: valid-https + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml new file mode 100644 index 0000000000..663bd2014f --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml @@ -0,0 +1,213 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: invalid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: non-existent-secret + mode: Terminate + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: valid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: 'No valid secrets exist: certificate refs 0: Secret envoy-gateway/non-existent-secret + does not exist.' + reason: InvalidCertificateRef + status: "False" + type: ResolvedRefs + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed + name: invalid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: valid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/valid-https + ports: + - containerPort: 10443 + name: https-443 + protocol: HTTPS + servicePort: 443 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 443 + hostnames: + - '*.example.com' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + name: envoy-gateway/gateway-1/valid-https + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10443 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*.example.com' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/*_example_com + pathMatch: + distinct: false + name: "" + prefix: / + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml index 898c56910c..fb1bca1c0e 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml @@ -78,13 +78,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -120,21 +113,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml index c1be28da35..d6eddedd1d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml index 875e056fd0..ad9f652f5d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml index c9e11f45f4..891bdd8a8b 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml index 0127e45fe8..8a474483bb 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml @@ -38,13 +38,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10080 - name: tls-80 - protocol: TLS - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -116,13 +109,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml index 4e0b318363..82b7f2918d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml @@ -158,12 +158,6 @@ infraIR: name: https-8443 protocol: HTTPS servicePort: 8443 - - name: envoy-gateway/gateway-1/tls-all-invalid-cert - ports: - - containerPort: 8444 - name: https-8444 - protocol: HTTPS - servicePort: 8444 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -302,20 +296,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ2VENDQVVTZ0F3SUJBZ0lVU2l2SkdURHdva1M3aGVZLzJjc1JzejR2SkIwd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFptOXZMbUpoY2k1amIyMHdIaGNOTWpRd01qSTVNRGt6TURFd1doY05NelF3TWpJMgpNRGt6TURFd1dqQVdNUlF3RWdZRFZRUUREQXRtYjI4dVltRnlMbU52YlRCMk1CQUdCeXFHU000OUFnRUdCU3VCCkJBQWlBMklBQkZ2cnZSZWJhYVd1UzZNQUVJZDZ3WmZPS3Z1Q1R5VU1PbFpKcUZDRjlUa3pNWWw4Q2lvZnluT3QKQ3JzMHZ2YTlrZC9QMkpNR0JKcWdZZXZid290clJpMTJxTG5IMDQvam9HSWpqVE9LbzNJb2ZyK0ZrOHdMdkFlMwpPMVpLdFI5c3pxTlRNRkV3SFFZRFZSME9CQllFRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1COEdBMVVkCkl3UVlNQmFBRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0NnWUkKS29aSXpqMEVBd0lEWndBd1pBSXdIMzF0SHlmVVAwNFhIcGJXR2UxWjFJYUJaQndJdGg1NURVNGhqZlB1OG0rSgpXdjdiVzh6VFNnd0xpcW9yZmN1bkFqQTBnaE5KQkExWDJYdElLRG1sM3M3L1Z4OEZKY1MwNHZwQ2hoK2xBYkxTCnZlYWEyOFIzVExFWTNVK1FUWEkvd0lrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== name: envoy-gateway/tls-secret-ecdsa-2 privateKey: '[redacted]' - - address: 0.0.0.0 - externalPort: 8444 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-all-invalid-cert - name: envoy-gateway/gateway-1/tls-all-invalid-cert - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8444 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml index f5eb3615ea..d3b527cf81 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml index f0b8e08392..08b2c9ae80 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml @@ -72,13 +72,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,21 +107,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml index 17179618ef..fdf22c3ae1 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml index 94d6649edd..be22741fa9 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml @@ -76,13 +76,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -118,21 +111,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml index acfc47f023..5ab341a973 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml index eb0643097a..ed93a40205 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml index 1e3bf50365..eee30d760d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml index f3d7139fc7..cdc8155dc4 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/udp - ports: - - containerPort: 10080 - name: udp-80 - protocol: UDP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - udp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp - name: envoy-gateway/gateway-1/udp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml index 4672cbedfb..1765434059 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/unsupported - ports: - - containerPort: 10080 - name: "-80" - protocol: "" - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml index 228b0bf29f..f255acbcf4 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml @@ -70,12 +70,6 @@ infraIR: name: tcp-162 protocol: TCP servicePort: 162 - - name: envoy-gateway/gateway-1/tcp2 - ports: - - containerPort: 10162 - name: tls-162 - protocol: TLS - servicePort: 162 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -182,12 +176,3 @@ xdsIR: name: tcproute-1 namespace: default name: tcproute/default/tcproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp2 - name: envoy-gateway/gateway-1/tcp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml index cac7a60a43..f858c8d772 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml @@ -175,12 +175,3 @@ xdsIR: protocol: UDP weight: 1 name: udproute/default/udproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp2 - name: envoy-gateway/gateway-1/udp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml index 823f9813a5..20c4241d1a 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml @@ -106,13 +106,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -179,33 +172,8 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-1 - name: envoy-gateway/gateway-1/tls-1 - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml index 0df14ad10c..ecb8190327 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml @@ -106,13 +106,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -148,35 +141,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml index 37c0a342f3..4d899da6a8 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml @@ -21,6 +21,20 @@ gateways: allowedRoutes: namespaces: from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A0QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml index 3eab4a3a04..4af2173f3d 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml @@ -21,6 +21,10 @@ gateways: name: http-2 port: 80 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate status: listeners: - attachedRoutes: 1 @@ -54,7 +58,7 @@ gateways: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. + message: Listener is invalid, see other Conditions for details. reason: Invalid status: "False" type: Programmed @@ -106,13 +110,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -148,35 +145,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - bar.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml index 476881b619..1a31d49847 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml @@ -25,15 +25,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "True" - type: Programmed + type: Conflicted - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -45,18 +45,18 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute - - attachedRoutes: 1 + - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "True" - type: Programmed + type: Conflicted - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -87,9 +87,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -103,19 +103,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -143,9 +130,9 @@ tcpRoutes: parents: - conditions: - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -182,89 +169,8 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - routes: - - destination: - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default - name: httproute/default/httproute-1/rule/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8080 - metadata: - kind: Service - name: service-1 - namespace: default - sectionName: "8080" - name: httproute/default/httproute-1/rule/0/backend/0 - protocol: HTTP - weight: 1 - hostname: '*' - isHTTP2: false - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default - name: httproute/default/httproute-1/rule/0/match/0/* - pathMatch: - distinct: false - name: "" - prefix: / readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 - routes: - - destination: - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1/rule/-1 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8163 - metadata: - kind: Service - name: service-1 - namespace: default - sectionName: "8163" - name: tcproute/default/tcproute-1/rule/-1/backend/0 - protocol: TCP - weight: 1 - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1 diff --git a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml index 736ddb24a9..de19b641c4 100644 --- a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml @@ -84,18 +84,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway-xls/composite-gateway/conflict-listener - ports: - - containerPort: 8888 - name: http-8888 - protocol: HTTP - servicePort: 8888 - - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-1 - ports: - - containerPort: 8089 - name: http-8089 - protocol: HTTP - servicePort: 8089 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-two-xlss/good-listener ports: - containerPort: 8090 @@ -409,62 +397,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 8888 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8888 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener-1 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener-2 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-two-xlss/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - address: 0.0.0.0 externalPort: 8090 hostnames: @@ -479,20 +411,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 8090 - - address: 0.0.0.0 - externalPort: 8888 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/listener-conflict-with-gateway/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8888 - address: 0.0.0.0 externalPort: 8091 hostnames: diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml index a302de7ee8..25283fbf2c 100644 --- a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml @@ -92,12 +92,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - ports: - - containerPort: 8443 - name: https-8443 - protocol: HTTPS - servicePort: 8443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway @@ -204,20 +198,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 8443 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway - sectionName: extra-https-same-ns - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml index d456feeb28..449d97e743 100644 --- a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml @@ -200,30 +200,12 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-one - ports: - - containerPort: 8085 - name: "-8085" - protocol: "" - servicePort: 8085 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-two - ports: - - containerPort: 8086 - name: "-8086" - protocol: "" - servicePort: 8086 - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-valid ports: - containerPort: 8087 name: http-8087 protocol: HTTP servicePort: 8087 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-invalid - ports: - - containerPort: 8088 - name: "-8088" - protocol: "" - servicePort: 8088 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 28b1ac3406..f41c3b186d 100644 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -170,20 +170,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-2/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml index c58cf94f48..68afd0fe72 100644 --- a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml @@ -228,12 +228,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -551,20 +545,6 @@ xdsIR: name: "" safeRegex: http://.*\.example\.com maxAge: 16m40s - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml index 70c8273b9f..3ea4f78801 100644 --- a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml @@ -315,13 +315,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/gateway-tlsroute-tcproute-only: proxy: - listeners: - - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - ports: - - containerPort: 10443 - name: tls-443 - protocol: TLS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-tlsroute-tcproute-only @@ -743,16 +736,6 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 443 - metadata: - kind: Gateway - name: gateway-tlsroute-tcproute-only - namespace: envoy-gateway - sectionName: tls-passthrough - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - port: 10443 envoy-gateway/gateway-tlsroute-tls-passthrough-only: accessLog: json: diff --git a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml index f7221094bd..5a7b2c7289 100644 --- a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml @@ -36,13 +36,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,13 +107,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml index eca1a7d9b6..e1f898a957 100644 --- a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml @@ -39,13 +39,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,13 +110,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index d8138446d9..528a0f03da 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -332,12 +332,49 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { "Listener references have been resolved", ) } - // skip computing IR - return } } -func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { +// hasInvalidCondition checks if a listener has been marked as invalid during per-listener validation. +// A listener is considered invalid if it has Programmed=False, Accepted=False, or ResolvedRefs=False +// (except for the special case of PartiallyInvalidCertificateRef which is allowed). +// This is used during conflict resolution to skip invalid listeners so they don't block valid ones. +func hasInvalidCondition(listener *ListenerContext) bool { + conditions := listener.GetConditions() + for _, cond := range conditions { + if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionFalse { + return true + } + if cond.Type == string(gwapiv1.ListenerConditionAccepted) && cond.Status == metav1.ConditionFalse { + return true + } + // ResolvedRefs=False is invalid except for PartiallyInvalidCertificateRef which allows + // the listener to still be programmed with valid certificates + if cond.Type == string(gwapiv1.ListenerConditionResolvedRefs) && + cond.Status == metav1.ConditionFalse && + cond.Reason != string(status.ListenerReasonPartiallyInvalidCertificateRef) { + return true + } + } + return false +} + +// isSpecValidForConflictChecks returns whether a listener should participate in +// conflict detection. In the normal translation flow this is driven by +// listener.specValid. The fallback to hasInvalidCondition exists only for unit +// tests that invoke conflict checks directly without running per-listener spec +// validation (Phase 1) first. Production code paths always run validateListenerSpec +// before conflict detection. +func isSpecValidForConflictChecks(listener *ListenerContext) bool { + if listener.specValid { + return true + } + return !hasInvalidCondition(listener) +} + +// validateAllowedNamespaces validates namespace selector configuration. +// Returns true if the namespace spec is valid, false otherwise. +func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) bool { if listener.AllowedRoutes != nil && listener.AllowedRoutes.Namespaces != nil && listener.AllowedRoutes.Namespaces.From != nil && @@ -349,26 +386,28 @@ func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, "The allowedRoutes.namespaces.selector field must be specified when allowedRoutes.namespaces.from is set to \"Selector\".", ) - } else { - selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) - if err != nil { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), - ) - } - - listener.namespaceSelector = selector + return false } + selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) + if err != nil { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), + ) + return false + } + + listener.namespaceSelector = selector } + return true } func (t *Translator) validateTerminateModeAndGetTLSSecrets( listener *ListenerContext, resources *resource.Resources, -) ([]*corev1.Secret, []*x509.Certificate) { +) ([]*corev1.Secret, []*x509.Certificate, bool) { if len(listener.TLS.CertificateRefs) == 0 { listener.SetCondition( gwapiv1.ListenerConditionProgrammed, @@ -376,7 +415,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( gwapiv1.ListenerReasonInvalid, "Listener must have at least 1 TLS certificate ref", ) - return nil, nil + return nil, nil, false } var errs []status.ListenerError @@ -486,7 +525,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("No valid secrets exist: %v", errors.Join(errList...)), ) - return nil, nil + return nil, nil, false } validSecrets, certs, err := parseCertsFromTLSSecretsData(secrets) @@ -498,7 +537,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( err.Reason(), fmt.Sprintf("No valid secrets exist: %v.", err.Error()), ) - return nil, nil + return nil, nil, false } else { errs = append(errs, err) } @@ -517,13 +556,17 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("Some secrets are invalid: %v", errors.Join(errList...)), ) } - return validSecrets, certs + return validSecrets, certs, true } +// validateTLSConfiguration validates TLS configuration per protocol. +// Returns true if the TLS spec is valid, false otherwise. func (t *Translator) validateTLSConfiguration( listener *ListenerContext, resources *resource.Resources, -) { +) bool { + specValid := true + switch listener.Protocol { case gwapiv1.HTTPProtocolType, gwapiv1.UDPProtocolType, gwapiv1.TCPProtocolType: if listener.TLS != nil { @@ -533,6 +576,7 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have TLS set when protocol is %s.", listener.Protocol), ) + specValid = false } case gwapiv1.HTTPSProtocolType: if listener.TLS == nil { @@ -542,25 +586,29 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - "UnsupportedTLSMode", - fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), - ) - break - } + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + "UnsupportedTLSMode", + fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), + ) + specValid = false + } else { + secrets, certs, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) - secrets, certs := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) + if !ok { + specValid = false + } - listener.tls.certDNSNames = make([]string, 0) - for _, cert := range certs { - listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + listener.tls.certDNSNames = make([]string, 0) + for _, cert := range certs { + listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + } + } } case gwapiv1.TLSProtocolType: if listener.TLS == nil { @@ -570,33 +618,38 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { - if len(listener.TLS.CertificateRefs) > 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must not have TLS certificate refs set for TLS mode Passthrough.", - ) - break + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { + if len(listener.TLS.CertificateRefs) > 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must not have TLS certificate refs set for TLS mode Passthrough.", + ) + specValid = false + } } - } - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { - if len(listener.TLS.CertificateRefs) == 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must have TLS certificate refs set for TLS mode Terminate.", - ) - break + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { + if len(listener.TLS.CertificateRefs) == 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must have TLS certificate refs set for TLS mode Terminate.", + ) + specValid = false + } else { + secrets, _, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) + + if !ok { + specValid = false + } + } } - secrets, _ := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) } } @@ -630,10 +683,15 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonNoValidCACertificate, message, ) + specValid = false } + + return specValid } -func (t *Translator) validateHostName(listener *ListenerContext) { +// validateHostName validates hostname configuration per protocol. +// Returns true if the hostname spec is valid, false otherwise. +func (t *Translator) validateHostName(listener *ListenerContext) bool { if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { if listener.Hostname != nil { listener.SetCondition( @@ -642,20 +700,25 @@ func (t *Translator) validateHostName(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have hostname set when protocol is %s.", listener.Protocol), ) + return false } } + return true } -func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) { +// validateAllowedRoutes validates allowed route kinds configuration. +// Returns true if the allowed routes spec is valid, false otherwise. +func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) bool { canSupportKinds := make([]gwapiv1.RouteGroupKind, len(routeKinds)) for i, routeKind := range routeKinds { canSupportKinds[i] = gwapiv1.RouteGroupKind{Group: GroupPtr(gwapiv1.GroupName), Kind: routeKind} } if listener.AllowedRoutes == nil || len(listener.AllowedRoutes.Kinds) == 0 { listener.SetSupportedKinds(canSupportKinds...) - return + return true } + specValid := true supportedRouteKinds := make([]gwapiv1.Kind, 0) supportedKinds := make([]gwapiv1.RouteGroupKind, 0) unSupportedKinds := make([]gwapiv1.RouteGroupKind, 0) @@ -670,6 +733,7 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("Group is not supported, group must be %s", gwapiv1.GroupName), ) + specValid = false continue } @@ -701,9 +765,11 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("%s is not supported, kind must be one of %v", string(kind.Kind), printRouteKinds), ) + specValid = false } listener.SetSupportedKinds(supportedKinds...) + return specValid } type portListeners struct { @@ -717,6 +783,11 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex listenerSets := sets.Set[string]{} for _, gateway := range gateways { for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } hostname := new(gwapiv1.Hostname) if listener.Hostname != nil { hostname = listener.Hostname @@ -735,6 +806,118 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex } } +// validateConflictedProtocolsListeners checks for listeners that have conflicting protocols on the same port. +// UDP can coexist with any protocol. HTTPS and TLS are treated as compatible via getProtocolForListener. +func (t *Translator) validateConflictedProtocolsListeners(gateways []*GatewayContext) { + validateByPort := func(listeners []*ListenerContext) { + portListenerInfo := map[gwapiv1.PortNumber][]*ListenerContext{} + for _, listener := range listeners { + if !isSpecValidForConflictChecks(listener) || !isSupportedListenerProtocol(listener.Protocol) { + continue + } + portListenerInfo[listener.Port] = append(portListenerInfo[listener.Port], listener) + } + + for _, listenersOnPort := range portListenerInfo { + nonUDPProtocols := sets.New[string]() + nonListenerSetCount := 0 + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + if protocol == string(gwapiv1.UDPProtocolType) { + continue + } + nonUDPProtocols.Insert(protocol) + if !listener.isFromListenerSet() { + nonListenerSetCount++ + } + } + + // No protocol conflict when all non-UDP listeners are compatible. + if len(nonUDPProtocols) <= 1 { + continue + } + + // If there are more than 1 non-UDP protocols and more than 1 listener not from ListenerSet, + // we cannot determine a clear winner and all listeners on this port are in conflict. + if nonListenerSetCount > 1 { + // If any conflicted listener is not from ListenerSet, do not pick a winner. + for _, listener := range listenersOnPort { + if getProtocolForListener(listener) == string(gwapiv1.UDPProtocolType) { + continue + } + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + continue + } + + // When nonListenerSetCount == 1, explicitly pick the Gateway-owned listener as winner. + // When nonListenerSetCount == 0, pick the first ListenerSet listener as winner. + // Note: UDP conflicts are handled by validateConflictedLayer4Listeners, so we skip + // UDP listeners here (this branch is only reached when len(nonUDPProtocols) > 1). + var winnerProtocol string + if nonListenerSetCount == 1 { + // Find and use the non-ListenerSet listener's protocol as the winner + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + if !listener.isFromListenerSet() && protocol != string(gwapiv1.UDPProtocolType) { + winnerProtocol = protocol + break + } + } + } + + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + // Skip UDP listeners as they are handled by validateConflictedLayer4Listeners + if protocol == string(gwapiv1.UDPProtocolType) { + continue + } + + // If we have an explicit winner protocol, use it; otherwise first one wins + if winnerProtocol != "" { + if protocol != winnerProtocol { + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + } else { + // All conflicted listeners are from ListenerSet, first one wins + if winnerProtocol == "" { + winnerProtocol = protocol + } else if protocol != winnerProtocol { + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + } + } + } + } + + for _, gateway := range gateways { + validateByPort(gateway.listeners) + } + + if t.MergeGateways { + allListeners := make([]*ListenerContext, 0) + for _, gateway := range gateways { + allListeners = append(allListeners, gateway.listeners...) + } + validateByPort(allListeners) + } +} + func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContext) { // Iterate through all layer-7 (HTTP, HTTPS, TLS) listeners and collect info about protocols // and hostnames per port. @@ -744,6 +927,11 @@ func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContex if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { continue } + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } if portListenerInfo[listener.Port] == nil { portListenerInfo[listener.Port] = &portListeners{ protocols: sets.Set[string]{}, @@ -806,6 +994,11 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex for _, gateway := range gateways { portListenerInfo := map[gwapiv1.PortNumber]*portListeners{} for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } for _, protocol := range protocols { if listener.Protocol == protocol { if portListenerInfo[listener.Port] == nil { @@ -832,6 +1025,26 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex } } +func getProtocolForListener(listener *ListenerContext) string { + switch listener.Protocol { + // HTTPS and TLS can co-exist on the same port. + case gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType: + return "https/tls" + default: + return string(listener.Protocol) + } +} + +func isSupportedListenerProtocol(protocol gwapiv1.ProtocolType) bool { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType, + gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType: + return true + default: + return false + } +} + // Checks if a hostname is valid according to RFC 1123 and gateway API's requirement that it not be an IP address func (t *Translator) validateHostname(hostname string) error { if errs := validation.IsDNS1123Subdomain(hostname); errs != nil {