Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/v1.2] cherry pick for v1.2.5 #5029

Open
wants to merge 10 commits into
base: release/v1.2
Choose a base branch
from
4 changes: 2 additions & 2 deletions api/v1alpha1/backend_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ type FQDNEndpoint struct {
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))*$`
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
Hostname string `json:"hostname"`

// Port defines the port of the backend endpoint.
Expand All @@ -116,7 +116,7 @@ type BackendSpec struct {
// Endpoints defines the endpoints to be used when connecting to the backend.
//
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=4
// +kubebuilder:validation:MaxItems=64
// +kubebuilder:validation:XValidation:rule="self.all(f, has(f.fqdn)) || !self.exists(f, has(f.fqdn))",message="fqdn addresses cannot be mixed with other address types"
Endpoints []BackendEndpoint `json:"endpoints,omitempty"`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ spec:
endpoint.
maxLength: 253
minLength: 1
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))*$
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
port:
description: Port defines the port of the backend endpoint.
Expand Down Expand Up @@ -132,7 +132,7 @@ spec:
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
maxItems: 4
maxItems: 64
minItems: 1
type: array
x-kubernetes-validations:
Expand Down
19 changes: 0 additions & 19 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,25 +249,6 @@ func OwnerLabels(gateway *gwapiv1.Gateway, mergeGateways bool) map[string]string
return GatewayOwnerLabels(gateway.Namespace, gateway.Name)
}

// servicePortToContainerPort translates a service port into an ephemeral
// container port.
func servicePortToContainerPort(servicePort int32, envoyProxy *egv1a1.EnvoyProxy) int32 {
if envoyProxy != nil {
if !envoyProxy.NeedToSwitchPorts() {
return servicePort
}
}

// If the service port is a privileged port (1-1023)
// add a constant to the value converting it into an ephemeral port.
// This allows the container to bind to the port without needing a
// CAP_NET_BIND_SERVICE capability.
if servicePort < minEphemeralPort {
return servicePort + wellKnownPortShift
}
return servicePort
}

// computeHosts returns a list of intersecting listener hostnames and route hostnames
// that don't intersect with other listener hostnames.
func computeHosts(routeHostnames []string, listenerContext *ListenerContext) []string {
Expand Down
26 changes: 25 additions & 1 deletion internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource

// Add the listener to the Xds IR
servicePort := &protocolPort{protocol: listener.Protocol, port: int32(listener.Port)}
containerPort := servicePortToContainerPort(int32(listener.Port), gateway.envoyProxy)
containerPort := t.servicePortToContainerPort(int32(listener.Port), gateway.envoyProxy)
switch listener.Protocol {
case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType:
irListener := &ir.HTTPListener{
Expand Down Expand Up @@ -554,3 +554,27 @@ func validCELExpression(expr string) bool {
_, issue := celEnv.Parse(expr)
return issue.Err() == nil
}

// servicePortToContainerPort translates a service port into an ephemeral
// container port.
func (t *Translator) servicePortToContainerPort(servicePort int32, envoyProxy *egv1a1.EnvoyProxy) int32 {
if t.ListenerPortShiftDisabled {
return servicePort
}

if envoyProxy != nil {
if !envoyProxy.NeedToSwitchPorts() {
return servicePort
}
}

// If the service port is a privileged port (1-1023)
// add a constant to the value converting it into an ephemeral port.
// This allows the container to bind to the port without needing a
// CAP_NET_BIND_SERVICE capability.
if servicePort < minEphemeralPort {
return servicePort + wellKnownPortShift
}

return servicePort
}
17 changes: 9 additions & 8 deletions internal/gatewayapi/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,15 @@
for _, resources := range *val {
// Translate and publish IRs.
t := &gatewayapi.Translator{
GatewayControllerName: r.Server.EnvoyGateway.Gateway.ControllerName,
GatewayClassName: gwapiv1.ObjectName(resources.GatewayClass.Name),
GlobalRateLimitEnabled: r.EnvoyGateway.RateLimit != nil,
EnvoyPatchPolicyEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableEnvoyPatchPolicy,
BackendEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableBackend,
Namespace: r.Namespace,
MergeGateways: gatewayapi.IsMergeGatewaysEnabled(resources),
WasmCache: r.wasmCache,
GatewayControllerName: r.Server.EnvoyGateway.Gateway.ControllerName,
GatewayClassName: gwapiv1.ObjectName(resources.GatewayClass.Name),
GlobalRateLimitEnabled: r.EnvoyGateway.RateLimit != nil,
EnvoyPatchPolicyEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableEnvoyPatchPolicy,
BackendEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableBackend,
Namespace: r.Namespace,
MergeGateways: gatewayapi.IsMergeGatewaysEnabled(resources),
WasmCache: r.wasmCache,
ListenerPortShiftDisabled: r.EnvoyGateway.Provider != nil && r.EnvoyGateway.Provider.IsRunningOnHost(),

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

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/runner/runner.go#L147-L155

Added lines #L147 - L155 were not covered by tests
}

// If an extension is loaded, pass its supported groups/kinds to the translator
Expand Down
98 changes: 72 additions & 26 deletions internal/gatewayapi/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package gatewayapi

import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
Expand All @@ -16,7 +17,9 @@
"sort"
"strconv"
"strings"
"time"

"github.com/cenkalti/backoff/v4"
perr "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -672,26 +675,17 @@
protocol ir.AppProtocol
rd *ir.RouteDestination
traffic *ir.TrafficFeatures
providerTLS *ir.TLSUpstreamConfig
err error
)

// Discover the token and authorization endpoints from the issuer's
// well-known url if not explicitly specified
if provider.TokenEndpoint == nil || provider.AuthorizationEndpoint == nil {
tokenEndpoint, authorizationEndpoint, err = fetchEndpointsFromIssuer(provider.Issuer)
if err != nil {
return nil, fmt.Errorf("error fetching endpoints from issuer: %w", err)
}
var u *url.URL
if provider.TokenEndpoint != nil {
u, err = url.Parse(*provider.TokenEndpoint)
} else {
tokenEndpoint = *provider.TokenEndpoint
authorizationEndpoint = *provider.AuthorizationEndpoint
u, err = url.Parse(provider.Issuer)
}

if err = validateTokenEndpoint(tokenEndpoint); err != nil {
return nil, err
}

u, err := url.Parse(tokenEndpoint)
if err != nil {
return nil, err
}
Expand All @@ -708,6 +702,32 @@
}
}

if rd != nil {
for _, st := range rd.Settings {
if st.TLS != nil {
providerTLS = st.TLS
break
}
}
}

// Discover the token and authorization endpoints from the issuer's well-known url if not explicitly specified.
// EG assumes that the issuer url uses the same protocol and CA as the token endpoint.
// If we need to support different protocols or CAs, we need to add more fields to the OIDCProvider CRD.
if provider.TokenEndpoint == nil || provider.AuthorizationEndpoint == nil {
tokenEndpoint, authorizationEndpoint, err = fetchEndpointsFromIssuer(provider.Issuer, providerTLS)
if err != nil {
return nil, fmt.Errorf("error fetching endpoints from issuer: %w", err)
}
} else {
tokenEndpoint = *provider.TokenEndpoint
authorizationEndpoint = *provider.AuthorizationEndpoint
}

if err = validateTokenEndpoint(tokenEndpoint); err != nil {
return nil, err
}

Check warning on line 729 in internal/gatewayapi/securitypolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/securitypolicy.go#L728-L729

Added lines #L728 - L729 were not covered by tests

if traffic, err = translateTrafficFeatures(provider.BackendSettings); err != nil {
return nil, err
}
Expand Down Expand Up @@ -764,18 +784,38 @@
AuthorizationEndpoint string `json:"authorization_endpoint"`
}

func fetchEndpointsFromIssuer(issuerURL string) (string, string, error) {
// Fetch the OpenID configuration from the issuer URL
resp, err := http.Get(fmt.Sprintf("%s/.well-known/openid-configuration", issuerURL))
if err != nil {
return "", "", err
func fetchEndpointsFromIssuer(issuerURL string, providerTLS *ir.TLSUpstreamConfig) (string, string, error) {
var (
tlsConfig *tls.Config
err error
)

if providerTLS != nil {
if tlsConfig, err = providerTLS.ToTLSConfig(); err != nil {
return "", "", err
}

Check warning on line 796 in internal/gatewayapi/securitypolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/securitypolicy.go#L794-L796

Added lines #L794 - L796 were not covered by tests
}

client := &http.Client{}
if tlsConfig != nil {
client.Transport = &http.Transport{
TLSClientConfig: tlsConfig,
}

Check warning on line 803 in internal/gatewayapi/securitypolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/securitypolicy.go#L801-L803

Added lines #L801 - L803 were not covered by tests
}
defer resp.Body.Close()

// Parse the OpenID configuration response
var config OpenIDConfig
err = json.NewDecoder(resp.Body).Decode(&config)
if err != nil {
if err = backoff.Retry(func() error {
resp, err := client.Get(fmt.Sprintf("%s/.well-known/openid-configuration", issuerURL))
if err != nil {
return err
}

Check warning on line 812 in internal/gatewayapi/securitypolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/securitypolicy.go#L811-L812

Added lines #L811 - L812 were not covered by tests
defer resp.Body.Close()
if err = json.NewDecoder(resp.Body).Decode(&config); err != nil {
return err
}
return nil
}, backoff.NewExponentialBackOff(backoff.WithMaxElapsedTime(5*time.Second))); err != nil {
return "", "", err
}

Expand Down Expand Up @@ -955,10 +995,16 @@
}
}

return net.JoinHostPort(
fmt.Sprintf("%s.%s", backendRef.Name, backendNamespace),
strconv.Itoa(int(*backendRef.Port)),
)
// Port is mandatory for Kubernetes services
if backendKind == resource.KindService {
return net.JoinHostPort(
fmt.Sprintf("%s.%s", backendRef.Name, backendNamespace),
strconv.Itoa(int(*backendRef.Port)),
)
}

// Fallback to the backendRef name, normally it's a unix domain socket in this case
return fmt.Sprintf("%s.%s", backendRef.Name, backendNamespace)
}

func (t *Translator) buildAuthorization(policy *egv1a1.SecurityPolicy) (*ir.Authorization, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ backends:
- fqdn:
hostname: 'primary.foo.com'
port: 3000
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: backend-uds
namespace: default
spec:
endpoints:
- unix:
path: '/var/run/uds.sock'
referenceGrants:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: ReferenceGrant
Expand Down Expand Up @@ -179,7 +188,6 @@ securityPolicies:
extAuth:
http:
backendRef:
name: backend-fqdn
name: backend-uds
kind: Backend
group: gateway.envoyproxy.io
port: 3000
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ backends:
reason: Accepted
status: "True"
type: Accepted
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
creationTimestamp: null
name: backend-uds
namespace: default
spec:
endpoints:
- unix:
path: /var/run/uds.sock
status:
conditions:
- lastTransitionTime: null
message: The Backend was accepted
reason: Accepted
status: "True"
type: Accepted
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
Expand Down Expand Up @@ -322,8 +339,7 @@ securityPolicies:
backendRef:
group: gateway.envoyproxy.io
kind: Backend
name: backend-fqdn
port: 3000
name: backend-uds
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
Expand Down Expand Up @@ -530,14 +546,15 @@ xdsIR:
security:
extAuth:
http:
authority: primary.foo.com:3000
authority: backend-uds.default
destination:
name: securitypolicy/default/policy-for-http-route-3-http-backendref/extauth/0
settings:
- addressType: FQDN
- addressType: IP
endpoints:
- host: primary.foo.com
port: 3000
- host: ""
path: /var/run/uds.sock
port: 0
protocol: HTTP
weight: 1
path: ""
Expand Down
Loading
Loading