Skip to content

Commit

Permalink
Add support for Kubernetes Gateway API RequestHeaderModifier filter
Browse files Browse the repository at this point in the history
Co-authored-by: Baptiste Mayelle <baptiste.mayelle@traefik.io>
  • Loading branch information
rtribotte and youkoulayley authored Apr 5, 2024
1 parent ac1753a commit f69fd43
Show file tree
Hide file tree
Showing 11 changed files with 499 additions and 32 deletions.
74 changes: 43 additions & 31 deletions docs/content/routing/providers/kubernetes-gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,39 +251,51 @@ Kubernetes cluster before creating `HTTPRoute` objects.
requestRedirect: # [27]
scheme: https # [28]
statusCode: 301 # [29]
- type: RequestHeaderModifier # [30]
requestHeaderModifier: # [31]
set:
- name: X-Foo
value: Bar
add:
- name: X-Bar
value: Foo
remove:
- X-Baz
```

| Ref | Attribute | Description |
|------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
| [2] | `name` | Name of the referent. |
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
| [4] | `sectionName` | Name of a section within the target resource (the Listener name). |
| [5] | `hostnames` | A set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. |
| [6] | `rules` | A list of HTTP matchers, filters and actions. |
| [7] | `matches` | Conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. |
| [8] | `path` | An HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. |
| [9] | `type` | Type of match against the path Value (supported types: `Exact`, `Prefix`). |
| [10] | `value` | The value of the HTTP path to match against. |
| [11] | `headers` | Conditions to select a HTTP route by matching HTTP request headers. |
| [12] | `name` | Name of the HTTP header to be matched. |
| [13] | `value` | Value of HTTP Header to be matched. |
| [14] | `backendRefs` | Defines the backend(s) where matching requests should be sent. |
| [15] | `name` | The name of the referent service. |
| [16] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
| [17] | `port` | The port of the referent service. |
| [18] | `group` | Group is the group of the referent. Only `traefik.io` and `gateway.networking.k8s.io` values are supported. |
| [19] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
| [20] | `filters` | Defines the filters (middlewares) applied to the route. |
| [21] | `type` | Defines the type of filter; ExtensionRef is used for configuring custom HTTP filters. |
| [22] | `extensionRef` | Configuration of the custom HTTP filter. |
| [23] | `group` | Group of the kubernetes object to reference. |
| [24] | `kind` | Kind of the kubernetes object to reference. |
| [25] | `name` | Name of the kubernetes object to reference. |
| [26] | `type` | Defines the type of filter; RequestRedirect redirects a request to another location. |
| [27] | `requestRedirect` | Configuration of redirect filter. |
| [28] | `scheme` | Scheme is the scheme to be used in the value of the Location header in the response. |
| [29] | `statusCode` | StatusCode is the HTTP status code to be used in response. |
| Ref | Attribute | Description |
|------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
| [2] | `name` | Name of the referent. |
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
| [4] | `sectionName` | Name of a section within the target resource (the Listener name). |
| [5] | `hostnames` | A set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. |
| [6] | `rules` | A list of HTTP matchers, filters and actions. |
| [7] | `matches` | Conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. |
| [8] | `path` | An HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. |
| [9] | `type` | Type of match against the path Value (supported types: `Exact`, `Prefix`). |
| [10] | `value` | The value of the HTTP path to match against. |
| [11] | `headers` | Conditions to select a HTTP route by matching HTTP request headers. |
| [12] | `name` | Name of the HTTP header to be matched. |
| [13] | `value` | Value of HTTP Header to be matched. |
| [14] | `backendRefs` | Defines the backend(s) where matching requests should be sent. |
| [15] | `name` | The name of the referent service. |
| [16] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
| [17] | `port` | The port of the referent service. |
| [18] | `group` | Group is the group of the referent. Only `traefik.io` and `gateway.networking.k8s.io` values are supported. |
| [19] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
| [20] | `filters` | Defines the filters (middlewares) applied to the route. |
| [21] | `type` | Defines the type of filter; ExtensionRef is used for configuring custom HTTP filters. |
| [22] | `extensionRef` | Configuration of the custom HTTP filter. |
| [23] | `group` | Group of the kubernetes object to reference. |
| [24] | `kind` | Kind of the kubernetes object to reference. |
| [25] | `name` | Name of the kubernetes object to reference. |
| [26] | `type` | Defines the type of filter; RequestRedirect redirects a request to another location. |
| [27] | `requestRedirect` | Configuration of redirect filter. |
| [28] | `scheme` | Scheme is the scheme to be used in the value of the Location header in the response. |
| [29] | `statusCode` | StatusCode is the HTTP status code to be used in response. |
| [30] | `type` | Defines the type of filter; RequestHeaderModifier modifies request headers. |
| [31] | `requestHeaderModifier` | Configuration of RequestHeaderModifier filter. |

### Kind: `TCPRoute`

Expand Down
8 changes: 7 additions & 1 deletion internal/gendoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,13 @@ func clean(element any) {

var svcFieldNames []string
for i := range valueSvcRoot.NumField() {
svcFieldNames = append(svcFieldNames, valueSvcRoot.Type().Field(i).Name)
field := valueSvcRoot.Type().Field(i)
// do not create empty node for hidden config.
if field.Tag.Get("file") == "-" && field.Tag.Get("kv") == "-" && field.Tag.Get("label") == "-" {
continue
}

svcFieldNames = append(svcFieldNames, field.Name)
}

sort.Strings(svcFieldNames)
Expand Down
12 changes: 12 additions & 0 deletions pkg/config/dynamic/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ type Middleware struct {
GrpcWeb *GrpcWeb `json:"grpcWeb,omitempty" toml:"grpcWeb,omitempty" yaml:"grpcWeb,omitempty" export:"true"`

Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty" export:"true"`

// Gateway API HTTPRoute filters middlewares.
RequestHeaderModifier *RequestHeaderModifier `json:"requestHeaderModifier,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
}

// +k8s:deepcopy-gen=true
Expand Down Expand Up @@ -673,3 +676,12 @@ type TLSClientCertificateSubjectDNInfo struct {

// Users holds a list of users.
type Users []string

// +k8s:deepcopy-gen=true

// RequestHeaderModifier holds the request header modifier configuration.
type RequestHeaderModifier struct {
Set map[string]string `json:"set,omitempty"`
Add map[string]string `json:"add,omitempty"`
Remove []string `json:"remove,omitempty"`
}
40 changes: 40 additions & 0 deletions pkg/config/dynamic/zz_generated.deepcopy.go

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

56 changes: 56 additions & 0 deletions pkg/middlewares/headermodifier/request_header_modifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package headermodifier

import (
"context"
"net/http"

"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
)

const typeName = "RequestHeaderModifier"

// requestHeaderModifier is a middleware used to modify the headers of an HTTP request.
type requestHeaderModifier struct {
next http.Handler
name string

set map[string]string
add map[string]string
remove []string
}

// NewRequestHeaderModifier creates a new request header modifier middleware.
func NewRequestHeaderModifier(ctx context.Context, next http.Handler, config dynamic.RequestHeaderModifier, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeName)
logger.Debug().Msg("Creating middleware")

return &requestHeaderModifier{
next: next,
name: name,
set: config.Set,
add: config.Add,
remove: config.Remove,
}, nil
}

func (r *requestHeaderModifier) GetTracingInformation() (string, string, trace.SpanKind) {
return r.name, typeName, trace.SpanKindUnspecified
}

func (r *requestHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
for headerName, headerValue := range r.set {
req.Header.Set(headerName, headerValue)
}

for headerName, headerValue := range r.add {
req.Header.Add(headerName, headerValue)
}

for _, headerName := range r.remove {
req.Header.Del(headerName)
}

r.next.ServeHTTP(rw, req)
}
Loading

0 comments on commit f69fd43

Please sign in to comment.