Skip to content

Commit

Permalink
Merge branch 'main' into feat-early-header-mutation
Browse files Browse the repository at this point in the history
  • Loading branch information
guydc authored Aug 12, 2024
2 parents 592ab5b + eeb62c8 commit 846acce
Show file tree
Hide file tree
Showing 91 changed files with 2,504 additions and 277 deletions.
7 changes: 6 additions & 1 deletion api/v1alpha1/envoyproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ type EnvoyProxySpec struct {
//
// - envoy.filters.http.jwt_authn
//
// - envoy.filters.http.stateful_session
//
// - envoy.filters.http.ext_proc
//
// - envoy.filters.http.wasm
Expand Down Expand Up @@ -172,7 +174,7 @@ type FilterPosition struct {
}

// EnvoyFilter defines the type of Envoy HTTP filter.
// +kubebuilder:validation:Enum=envoy.filters.http.health_check;envoy.filters.http.fault;envoy.filters.http.cors;envoy.filters.http.ext_authz;envoy.filters.http.basic_auth;envoy.filters.http.oauth2;envoy.filters.http.jwt_authn;envoy.filters.http.ext_proc;envoy.filters.http.wasm;envoy.filters.http.rbac;envoy.filters.http.local_ratelimit;envoy.filters.http.ratelimit
// +kubebuilder:validation:Enum=envoy.filters.http.health_check;envoy.filters.http.fault;envoy.filters.http.cors;envoy.filters.http.ext_authz;envoy.filters.http.basic_auth;envoy.filters.http.oauth2;envoy.filters.http.jwt_authn;envoy.filters.http.stateful_session;envoy.filters.http.ext_proc;envoy.filters.http.wasm;envoy.filters.http.rbac;envoy.filters.http.local_ratelimit;envoy.filters.http.ratelimit
type EnvoyFilter string

const (
Expand All @@ -197,6 +199,9 @@ const (
// EnvoyFilterJWTAuthn defines the Envoy HTTP JWT authentication filter.
EnvoyFilterJWTAuthn EnvoyFilter = "envoy.filters.http.jwt_authn"

// EnvoyFilterSessionPersistence defines the Envoy HTTP session persistence filter.
EnvoyFilterSessionPersistence EnvoyFilter = "envoy.filters.http.stateful_session"

// EnvoyFilterExtProc defines the Envoy HTTP external process filter.
EnvoyFilterExtProc EnvoyFilter = "envoy.filters.http.ext_proc"

Expand Down
18 changes: 8 additions & 10 deletions api/v1alpha1/ext_auth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ package v1alpha1
//
// +kubebuilder:validation:XValidation:rule="(has(self.grpc) || has(self.http))",message="one of grpc or http must be specified"
// +kubebuilder:validation:XValidation:rule="(has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http))",message="only one of grpc or http can be specified"
// +kubebuilder:validation:XValidation:rule="has(self.grpc) ? (!has(self.grpc.backendRef) || !has(self.grpc.backendRef.group) || self.grpc.backendRef.group == \"\") : true", message="group is invalid, only the core API group (specified by omitting the group field or setting it to an empty string) is supported"
// +kubebuilder:validation:XValidation:rule="has(self.grpc) ? (!has(self.grpc.backendRef) || !has(self.grpc.backendRef.kind) || self.grpc.backendRef.kind == 'Service') : true", message="kind is invalid, only Service (specified by omitting the kind field or setting it to 'Service') is supported"
// +kubebuilder:validation:XValidation:rule="has(self.http) ? (!has(self.http.backendRef) || !has(self.http.backendRef.group) || self.http.backendRef.group == \"\") : true", message="group is invalid, only the core API group (specified by omitting the group field or setting it to an empty string) is supported"
// +kubebuilder:validation:XValidation:rule="has(self.http) ? (!has(self.http.backendRef) || !has(self.http.backendRef.kind) || self.http.backendRef.kind == 'Service') : true", message="kind is invalid, only Service (specified by omitting the kind field or setting it to 'Service') is supported"
type ExtAuth struct {
// GRPC defines the gRPC External Authorization service.
// Either GRPCService or HTTPService must be specified,
Expand Down Expand Up @@ -52,9 +48,10 @@ type ExtAuth struct {
// The authorization request message is defined in
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto
// +kubebuilder:validation:XValidation:message="backendRef or backendRefs needs to be set",rule="has(self.backendRef) || self.backendRefs.size() > 0"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.group == \"\") : true"
// +kubebuilder:validation:XValidation:message="only support Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
// +kubebuilder:validation:XValidation:message="only one backendRef can be specified.",rule="has(self.backendRefs) ? self.backendRefs.size() == 1 : true"
// +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
// +kubebuilder:validation:XValidation:message="Exactly one backendRef can be specified in backendRefs.",rule="has(self.backendRefs) && self.backendRefs.size()==1"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
type GRPCExtAuthService struct {
// Only Service kind is supported for now.
BackendCluster `json:",inline"`
Expand All @@ -63,9 +60,10 @@ type GRPCExtAuthService struct {
// HTTPExtAuthService defines the HTTP External Authorization service
//
// +kubebuilder:validation:XValidation:message="backendRef or backendRefs needs to be set",rule="has(self.backendRef) || self.backendRefs.size() > 0"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.group == \"\") : true"
// +kubebuilder:validation:XValidation:message="only support Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
// +kubebuilder:validation:XValidation:message="only one backendRef can be specified.",rule="has(self.backendRefs) ? self.backendRefs.size() == 1 : true"
// +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
// +kubebuilder:validation:XValidation:message="Exactly one backendRef can be specified in backendRefs.",rule="has(self.backendRefs) && self.backendRefs.size()==1"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
type HTTPExtAuthService struct {
// Only Service kind is supported for now.
BackendCluster `json:",inline"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ spec:
- envoy.filters.http.jwt_authn


- envoy.filters.http.stateful_session


- envoy.filters.http.ext_proc


Expand Down Expand Up @@ -286,6 +289,7 @@ spec:
- envoy.filters.http.basic_auth
- envoy.filters.http.oauth2
- envoy.filters.http.jwt_authn
- envoy.filters.http.stateful_session
- envoy.filters.http.ext_proc
- envoy.filters.http.wasm
- envoy.filters.http.rbac
Expand All @@ -304,6 +308,7 @@ spec:
- envoy.filters.http.basic_auth
- envoy.filters.http.oauth2
- envoy.filters.http.jwt_authn
- envoy.filters.http.stateful_session
- envoy.filters.http.ext_proc
- envoy.filters.http.wasm
- envoy.filters.http.rbac
Expand All @@ -320,6 +325,7 @@ spec:
- envoy.filters.http.basic_auth
- envoy.filters.http.oauth2
- envoy.filters.http.jwt_authn
- envoy.filters.http.stateful_session
- envoy.filters.http.ext_proc
- envoy.filters.http.wasm
- envoy.filters.http.rbac
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1009,15 +1009,17 @@ spec:
x-kubernetes-validations:
- message: backendRef or backendRefs needs to be set
rule: has(self.backendRef) || self.backendRefs.size() > 0
- message: BackendRefs only supports Core group.
rule: 'has(self.backendRefs) ? self.backendRefs.all(f, f.group
== "") : true'
- message: only support Service kind.
- message: BackendRefs must be used, backendRef is not supported.
rule: '!has(self.backendRef)'
- message: Exactly one backendRef can be specified in backendRefs.
rule: has(self.backendRefs) && self.backendRefs.size()==1
- message: BackendRefs only supports Service and Backend kind.
rule: 'has(self.backendRefs) ? self.backendRefs.all(f, f.kind
== ''Service'') : true'
- message: only one backendRef can be specified.
rule: 'has(self.backendRefs) ? self.backendRefs.size() == 1
: true'
== ''Service'' || f.kind == ''Backend'') : true'
- message: BackendRefs only supports Core and gateway.envoyproxy.io
group.
rule: 'has(self.backendRefs) ? (self.backendRefs.all(f, f.group
== "" || f.group == ''gateway.envoyproxy.io'')) : true'
headersToExtAuth:
description: |-
HeadersToExtAuth defines the client request headers that will be included
Expand Down Expand Up @@ -1808,40 +1810,24 @@ spec:
x-kubernetes-validations:
- message: backendRef or backendRefs needs to be set
rule: has(self.backendRef) || self.backendRefs.size() > 0
- message: BackendRefs only supports Core group.
rule: 'has(self.backendRefs) ? self.backendRefs.all(f, f.group
== "") : true'
- message: only support Service kind.
- message: BackendRefs must be used, backendRef is not supported.
rule: '!has(self.backendRef)'
- message: Exactly one backendRef can be specified in backendRefs.
rule: has(self.backendRefs) && self.backendRefs.size()==1
- message: BackendRefs only supports Service and Backend kind.
rule: 'has(self.backendRefs) ? self.backendRefs.all(f, f.kind
== ''Service'') : true'
- message: only one backendRef can be specified.
rule: 'has(self.backendRefs) ? self.backendRefs.size() == 1
: true'
== ''Service'' || f.kind == ''Backend'') : true'
- message: BackendRefs only supports Core and gateway.envoyproxy.io
group.
rule: 'has(self.backendRefs) ? (self.backendRefs.all(f, f.group
== "" || f.group == ''gateway.envoyproxy.io'')) : true'
type: object
x-kubernetes-validations:
- message: one of grpc or http must be specified
rule: (has(self.grpc) || has(self.http))
- message: only one of grpc or http can be specified
rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) &&
has(self.http))
- message: group is invalid, only the core API group (specified by
omitting the group field or setting it to an empty string) is
supported
rule: 'has(self.grpc) ? (!has(self.grpc.backendRef) || !has(self.grpc.backendRef.group)
|| self.grpc.backendRef.group == "") : true'
- message: kind is invalid, only Service (specified by omitting the
kind field or setting it to 'Service') is supported
rule: 'has(self.grpc) ? (!has(self.grpc.backendRef) || !has(self.grpc.backendRef.kind)
|| self.grpc.backendRef.kind == ''Service'') : true'
- message: group is invalid, only the core API group (specified by
omitting the group field or setting it to an empty string) is
supported
rule: 'has(self.http) ? (!has(self.http.backendRef) || !has(self.http.backendRef.group)
|| self.http.backendRef.group == "") : true'
- message: kind is invalid, only Service (specified by omitting the
kind field or setting it to 'Service') is supported
rule: 'has(self.http) ? (!has(self.http.backendRef) || !has(self.http.backendRef.kind)
|| self.http.backendRef.kind == ''Service'') : true'
jwt:
description: JWT defines the configuration for JSON Web Token (JWT)
authentication.
Expand Down
4 changes: 2 additions & 2 deletions examples/extension-server/cmd/extension-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
"os/signal"
"syscall"

pb "github.com/envoyproxy/gateway/proto/extension"
"github.com/exampleorg/envoygateway-extension/internal/extensionserver"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"

"github.com/exampleorg/envoygateway-extension/internal/extensionserver"
pb "github.com/envoyproxy/gateway/proto/extension"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions examples/extension-server/internal/extensionserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import (
"fmt"
"log/slog"

pb "github.com/envoyproxy/gateway/proto/extension"
corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
listenerv3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
bav3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/basic_auth/v3"
hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"
"github.com/exampleorg/envoygateway-extension/api/v1alpha1"
"google.golang.org/protobuf/types/known/anypb"

"github.com/exampleorg/envoygateway-extension/api/v1alpha1"
pb "github.com/envoyproxy/gateway/proto/extension"
)

type Server struct {
Expand Down
51 changes: 50 additions & 1 deletion internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,60 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
ruleRoutes = append(ruleRoutes, irRoute)
}

var sessionPersistence *ir.SessionPersistence
if rule.SessionPersistence != nil {
if rule.SessionPersistence.IdleTimeout != nil {
return nil, fmt.Errorf("idle timeout is not supported in envoy gateway")
}

var sessionName string
if rule.SessionPersistence.SessionName == nil {
// SessionName is optional on the gateway-api, but envoy requires it
// so we generate the one here.

// We generate a unique session name per route.
// `/` isn't allowed in the header key, so we just replace it with `-`.
sessionName = strings.ReplaceAll(irRouteDestinationName(httpRoute, ruleIdx), "/", "-")
} else {
sessionName = *rule.SessionPersistence.SessionName
}

switch {
case rule.SessionPersistence.Type == nil || // Cookie-based session persistence is default.
*rule.SessionPersistence.Type == gwapiv1.CookieBasedSessionPersistence:
sessionPersistence = &ir.SessionPersistence{
Cookie: &ir.CookieBasedSessionPersistence{
Name: sessionName,
},
}
if rule.SessionPersistence.AbsoluteTimeout != nil &&
rule.SessionPersistence.CookieConfig != nil && rule.SessionPersistence.CookieConfig.LifetimeType != nil &&
*rule.SessionPersistence.CookieConfig.LifetimeType == gwapiv1.PermanentCookieLifetimeType {
ttl, err := time.ParseDuration(string(*rule.SessionPersistence.AbsoluteTimeout))
if err != nil {
return nil, err
}
sessionPersistence.Cookie.TTL = &metav1.Duration{Duration: ttl}
}
case *rule.SessionPersistence.Type == gwapiv1.HeaderBasedSessionPersistence:
sessionPersistence = &ir.SessionPersistence{
Header: &ir.HeaderBasedSessionPersistence{
Name: sessionName,
},
}
default:
// Unknown session persistence type is specified.
return nil, fmt.Errorf("unknown session persistence type %s", *rule.SessionPersistence.Type)
}
}

// A rule is matched if any one of its matches
// is satisfied (i.e. a logical "OR"), so generate
// a unique Xds IR HTTPRoute per match.
for matchIdx, match := range rule.Matches {
irRoute := &ir.HTTPRoute{
Name: irRouteName(httpRoute, ruleIdx, matchIdx),
Name: irRouteName(httpRoute, ruleIdx, matchIdx),
SessionPersistence: sessionPersistence,
}
processTimeout(irRoute, rule)

Expand Down Expand Up @@ -699,6 +747,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
Mirrors: routeRoute.Mirrors,
ExtensionRefs: routeRoute.ExtensionRefs,
IsHTTP2: routeRoute.IsHTTP2,
SessionPersistence: routeRoute.SessionPersistence,
}
if routeRoute.Traffic != nil {
hostRoute.Traffic = &ir.TrafficFeatures{
Expand Down
30 changes: 26 additions & 4 deletions internal/gatewayapi/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,11 +848,8 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Reso
if err = t.validateExtServiceBackendReference(backendRef, policy.Namespace, policy.Kind, resources); err != nil {
return nil, err
}
authority = fmt.Sprintf("%s.%s:%d",
backendRef.Name,
NamespaceDerefOr(backendRef.Namespace, policy.Namespace),
*backendRef.Port)

authority = backendRefAuthority(resources, backendRef, policy)
pnn := utils.NamespacedName(policy)
if ds, err = t.processExtServiceDestination(
backendRef,
Expand Down Expand Up @@ -892,6 +889,31 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Reso
return extAuth, nil
}

func backendRefAuthority(resources *Resources, backendRef *gwapiv1.BackendObjectReference, policy *egv1a1.SecurityPolicy) string {
if backendRef == nil {
return ""
}

backendNamespace := NamespaceDerefOr(backendRef.Namespace, policy.Namespace)
backendKind := KindDerefOr(backendRef.Kind, KindService)
if backendKind == egv1a1.KindBackend {
backend := resources.GetBackend(backendNamespace, string(backendRef.Name))
if backend != nil {
// TODO: exists multi FQDN endpoints?
for _, ep := range backend.Spec.Endpoints {
if ep.FQDN != nil {
return fmt.Sprintf("%s:%d", ep.FQDN.Hostname, ep.FQDN.Port)
}
}
}
}

return fmt.Sprintf("%s.%s:%d",
backendRef.Name,
backendNamespace,
*backendRef.Port)
}

func irExtServiceDestinationName(policy *egv1a1.SecurityPolicy, backendRef *gwapiv1.BackendObjectReference) string {
nn := types.NamespacedName{
Name: string(backendRef.Name),
Expand Down
Loading

0 comments on commit 846acce

Please sign in to comment.