Reintroduce dropped v2 dynamic config
Co-authored-by: Baptiste Mayelle <baptiste.mayelle@traefik.io>
This commit is contained in:
parent
18203f57d2
commit
40de310927
53 changed files with 880 additions and 392 deletions
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/ip"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -55,9 +54,13 @@ type GrpcWeb struct {
|
|||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ContentType holds the content-type middleware configuration.
|
||||
// This middleware sets the `Content-Type` header value to the media type detected from the response content,
|
||||
// when it is not set by the backend.
|
||||
type ContentType struct{}
|
||||
// This middleware exists to enable the correct behavior until at least the default one can be changed in a future version.
|
||||
type ContentType struct {
|
||||
// AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
||||
// be automatically set to a value derived from the contents of the response.
|
||||
// Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
||||
AutoDetect *bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
|
@ -218,7 +221,7 @@ type ForwardAuth struct {
|
|||
// Address defines the authentication server address.
|
||||
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
|
||||
// TLS defines the configuration used to secure the connection to the authentication server.
|
||||
TLS *types.ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
// TrustForwardHeader defines whether to trust (ie: forward) all X-Forwarded-* headers.
|
||||
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
|
||||
// AuthResponseHeaders defines the list of headers to copy from the authentication server response and set on forwarded request, replacing any existing conflicting headers.
|
||||
|
@ -235,6 +238,20 @@ type ForwardAuth struct {
|
|||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ClientTLS holds TLS specific configurations as client
|
||||
// CA, Cert and Key can be either path or file contents.
|
||||
// TODO: remove this struct when CAOptional option will be removed.
|
||||
type ClientTLS struct {
|
||||
CA string `description:"TLS CA" json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
|
||||
Cert string `description:"TLS cert" json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
|
||||
Key string `description:"TLS key" json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
|
||||
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||
// Deprecated: TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634).
|
||||
CAOptional *bool `description:"TLS CA.Optional" json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Headers holds the headers middleware configuration.
|
||||
// This middleware manages the requests and responses headers.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/headers/#customrequestheaders
|
||||
|
@ -303,6 +320,17 @@ type Headers struct {
|
|||
// If you would like your development environment to mimic production with complete Host blocking, SSL redirects,
|
||||
// and STS headers, leave this as false.
|
||||
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty" export:"true"`
|
||||
|
||||
// Deprecated: FeaturePolicy option is deprecated, please use PermissionsPolicy instead.
|
||||
FeaturePolicy *string `json:"featurePolicy,omitempty" toml:"featurePolicy,omitempty" yaml:"featurePolicy,omitempty" export:"true"`
|
||||
// Deprecated: SSLRedirect option is deprecated, please use EntryPoint redirection or RedirectScheme instead.
|
||||
SSLRedirect *bool `json:"sslRedirect,omitempty" toml:"sslRedirect,omitempty" yaml:"sslRedirect,omitempty" export:"true"`
|
||||
// Deprecated: SSLTemporaryRedirect option is deprecated, please use EntryPoint redirection or RedirectScheme instead.
|
||||
SSLTemporaryRedirect *bool `json:"sslTemporaryRedirect,omitempty" toml:"sslTemporaryRedirect,omitempty" yaml:"sslTemporaryRedirect,omitempty" export:"true"`
|
||||
// Deprecated: SSLHost option is deprecated, please use RedirectRegex instead.
|
||||
SSLHost *string `json:"sslHost,omitempty" toml:"sslHost,omitempty" yaml:"sslHost,omitempty"`
|
||||
// Deprecated: SSLForceHost option is deprecated, please use RedirectRegex instead.
|
||||
SSLForceHost *bool `json:"sslForceHost,omitempty" toml:"sslForceHost,omitempty" yaml:"sslForceHost,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set.
|
||||
|
@ -327,6 +355,10 @@ func (h *Headers) HasCorsHeadersDefined() bool {
|
|||
func (h *Headers) HasSecureHeadersDefined() bool {
|
||||
return h != nil && (len(h.AllowedHosts) != 0 ||
|
||||
len(h.HostsProxyHeaders) != 0 ||
|
||||
(h.SSLRedirect != nil && *h.SSLRedirect) ||
|
||||
(h.SSLTemporaryRedirect != nil && *h.SSLTemporaryRedirect) ||
|
||||
(h.SSLForceHost != nil && *h.SSLForceHost) ||
|
||||
(h.SSLHost != nil && *h.SSLHost != "") ||
|
||||
len(h.SSLProxyHeaders) != 0 ||
|
||||
h.STSSeconds != 0 ||
|
||||
h.STSIncludeSubdomains ||
|
||||
|
@ -340,6 +372,7 @@ func (h *Headers) HasSecureHeadersDefined() bool {
|
|||
h.ContentSecurityPolicy != "" ||
|
||||
h.PublicKey != "" ||
|
||||
h.ReferrerPolicy != "" ||
|
||||
(h.FeaturePolicy != nil && *h.FeaturePolicy != "") ||
|
||||
h.PermissionsPolicy != "" ||
|
||||
h.IsDevelopment)
|
||||
}
|
||||
|
@ -557,6 +590,11 @@ type Retry struct {
|
|||
type StripPrefix struct {
|
||||
// Prefixes defines the prefixes to strip from the request URL.
|
||||
Prefixes []string `json:"prefixes,omitempty" toml:"prefixes,omitempty" yaml:"prefixes,omitempty" export:"true"`
|
||||
|
||||
// Deprecated: ForceSlash option is deprecated, please remove any usage of this option.
|
||||
// ForceSlash ensures that the resulting stripped path is not the empty string, by replacing it with / when necessary.
|
||||
// Default: true.
|
||||
ForceSlash *bool `json:"forceSlash,omitempty" toml:"forceSlash,omitempty" yaml:"forceSlash,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -86,6 +86,14 @@ type TCPServersLoadBalancer struct {
|
|||
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
||||
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty" export:"true"`
|
||||
|
||||
// TerminationDelay, corresponds to the deadline that the proxy sets, after one
|
||||
// of its connected peers indicates it has closed the writing capability of its
|
||||
// connection, to close the reading capability as well, hence fully terminating the
|
||||
// connection. It is a duration in milliseconds, defaulting to 100. A negative value
|
||||
// means an infinite deadline (i.e. the reading capability is never closed).
|
||||
// Deprecated: use ServersTransport to configure the TerminationDelay instead.
|
||||
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// Mergeable tells if the given service is mergeable.
|
||||
|
|
|
@ -124,6 +124,27 @@ func (in *CircuitBreaker) DeepCopy() *CircuitBreaker {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientTLS) DeepCopyInto(out *ClientTLS) {
|
||||
*out = *in
|
||||
if in.CAOptional != nil {
|
||||
in, out := &in.CAOptional, &out.CAOptional
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientTLS.
|
||||
func (in *ClientTLS) DeepCopy() *ClientTLS {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientTLS)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Compress) DeepCopyInto(out *Compress) {
|
||||
*out = *in
|
||||
|
@ -219,6 +240,11 @@ func (in Configurations) DeepCopy() Configurations {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ContentType) DeepCopyInto(out *ContentType) {
|
||||
*out = *in
|
||||
if in.AutoDetect != nil {
|
||||
in, out := &in.AutoDetect, &out.AutoDetect
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -316,8 +342,8 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
|||
*out = *in
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(types.ClientTLS)
|
||||
**out = **in
|
||||
*out = new(ClientTLS)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AuthResponseHeaders != nil {
|
||||
in, out := &in.AuthResponseHeaders, &out.AuthResponseHeaders
|
||||
|
@ -534,6 +560,31 @@ func (in *Headers) DeepCopyInto(out *Headers) {
|
|||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.FeaturePolicy != nil {
|
||||
in, out := &in.FeaturePolicy, &out.FeaturePolicy
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.SSLRedirect != nil {
|
||||
in, out := &in.SSLRedirect, &out.SSLRedirect
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.SSLTemporaryRedirect != nil {
|
||||
in, out := &in.SSLTemporaryRedirect, &out.SSLTemporaryRedirect
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.SSLHost != nil {
|
||||
in, out := &in.SSLHost, &out.SSLHost
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.SSLForceHost != nil {
|
||||
in, out := &in.SSLForceHost, &out.SSLForceHost
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -794,7 +845,7 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
|
|||
if in.ContentType != nil {
|
||||
in, out := &in.ContentType, &out.ContentType
|
||||
*out = new(ContentType)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.GrpcWeb != nil {
|
||||
in, out := &in.GrpcWeb, &out.GrpcWeb
|
||||
|
@ -1360,6 +1411,11 @@ func (in *StripPrefix) DeepCopyInto(out *StripPrefix) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ForceSlash != nil {
|
||||
in, out := &in.ForceSlash, &out.ForceSlash
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1650,6 +1706,11 @@ func (in *TCPServersLoadBalancer) DeepCopyInto(out *TCPServersLoadBalancer) {
|
|||
*out = make([]TCPServer, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TerminationDelay != nil {
|
||||
in, out := &in.TerminationDelay, &out.TerminationDelay
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,11 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
func String(v string) *string { return &v }
|
||||
|
||||
func TestDecodeConfiguration(t *testing.T) {
|
||||
labels := map[string]string{
|
||||
"traefik.http.middlewares.Middleware0.addprefix.prefix": "foobar",
|
||||
|
@ -43,6 +45,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.http.middlewares.Middleware7.forwardauth.authresponseheaders": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.authrequestheaders": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.ca": "foobar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.caoptional": "true",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.cert": "foobar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.insecureskipverify": "true",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.key": "foobar",
|
||||
|
@ -71,9 +74,14 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.http.middlewares.Middleware8.headers.isdevelopment": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.publickey": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.referrerpolicy": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.featurepolicy": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.permissionspolicy": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.sslforcehost": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.sslhost": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.sslproxyheaders.name0": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.sslproxyheaders.name1": "foobar",
|
||||
"traefik.http.middlewares.Middleware8.headers.sslredirect": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.ssltemporaryredirect": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.stsincludesubdomains": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.stspreload": "true",
|
||||
"traefik.http.middlewares.Middleware8.headers.stsseconds": "42",
|
||||
|
@ -124,6 +132,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.http.middlewares.Middleware16.retry.attempts": "42",
|
||||
"traefik.http.middlewares.Middleware16.retry.initialinterval": "1s",
|
||||
"traefik.http.middlewares.Middleware17.stripprefix.prefixes": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware17.stripprefix.forceslash": "true",
|
||||
"traefik.http.middlewares.Middleware18.stripprefixregex.regex": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware19.compress.minresponsebodybytes": "42",
|
||||
"traefik.http.middlewares.Middleware20.plugin.tomato.aaa": "foo1",
|
||||
|
@ -194,9 +203,11 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.tcp.routers.Router1.tls.options": "foo",
|
||||
"traefik.tcp.routers.Router1.tls.passthrough": "false",
|
||||
"traefik.tcp.services.Service0.loadbalancer.server.Port": "42",
|
||||
"traefik.tcp.services.Service0.loadbalancer.TerminationDelay": "42",
|
||||
"traefik.tcp.services.Service0.loadbalancer.proxyProtocol.version": "42",
|
||||
"traefik.tcp.services.Service0.loadbalancer.serversTransport": "foo",
|
||||
"traefik.tcp.services.Service1.loadbalancer.server.Port": "42",
|
||||
"traefik.tcp.services.Service1.loadbalancer.TerminationDelay": "42",
|
||||
"traefik.tcp.services.Service1.loadbalancer.proxyProtocol": "true",
|
||||
"traefik.tcp.services.Service1.loadbalancer.serversTransport": "foo",
|
||||
|
||||
|
@ -261,6 +272,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
Port: "42",
|
||||
},
|
||||
},
|
||||
TerminationDelay: func(i int) *int { return &i }(42),
|
||||
ProxyProtocol: &dynamic.ProxyProtocol{Version: 42},
|
||||
ServersTransport: "foo",
|
||||
},
|
||||
|
@ -272,6 +284,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
Port: "42",
|
||||
},
|
||||
},
|
||||
TerminationDelay: func(i int) *int { return &i }(42),
|
||||
ProxyProtocol: &dynamic.ProxyProtocol{Version: 2},
|
||||
ServersTransport: "foo",
|
||||
},
|
||||
|
@ -459,6 +472,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
ForceSlash: Bool(true),
|
||||
},
|
||||
},
|
||||
"Middleware18": {
|
||||
|
@ -525,11 +539,12 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"Middleware7": {
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "foobar",
|
||||
TLS: &types.ClientTLS{
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "foobar",
|
||||
Cert: "foobar",
|
||||
Key: "foobar",
|
||||
InsecureSkipVerify: true,
|
||||
CAOptional: Bool(true),
|
||||
},
|
||||
TrustForwardHeader: true,
|
||||
AuthResponseHeaders: []string{
|
||||
|
@ -583,10 +598,14 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
SSLRedirect: Bool(true),
|
||||
SSLTemporaryRedirect: Bool(true),
|
||||
SSLHost: String("foobar"),
|
||||
SSLProxyHeaders: map[string]string{
|
||||
"name0": "foobar",
|
||||
"name1": "foobar",
|
||||
},
|
||||
SSLForceHost: Bool(true),
|
||||
STSSeconds: 42,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
|
@ -599,6 +618,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
ContentSecurityPolicy: "foobar",
|
||||
PublicKey: "foobar",
|
||||
ReferrerPolicy: "foobar",
|
||||
FeaturePolicy: String("foobar"),
|
||||
PermissionsPolicy: "foobar",
|
||||
IsDevelopment: true,
|
||||
},
|
||||
|
@ -758,6 +778,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
ServersTransport: "foo",
|
||||
TerminationDelay: func(i int) *int { return &i }(42),
|
||||
},
|
||||
},
|
||||
"Service1": {
|
||||
|
@ -768,6 +789,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
ServersTransport: "foo",
|
||||
TerminationDelay: func(i int) *int { return &i }(42),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -952,6 +974,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
ForceSlash: Bool(true),
|
||||
},
|
||||
},
|
||||
"Middleware18": {
|
||||
|
@ -1026,11 +1049,12 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"Middleware7": {
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "foobar",
|
||||
TLS: &types.ClientTLS{
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "foobar",
|
||||
Cert: "foobar",
|
||||
Key: "foobar",
|
||||
InsecureSkipVerify: true,
|
||||
CAOptional: Bool(true),
|
||||
},
|
||||
TrustForwardHeader: true,
|
||||
AuthResponseHeaders: []string{
|
||||
|
@ -1084,10 +1108,14 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
SSLRedirect: Bool(true),
|
||||
SSLTemporaryRedirect: Bool(true),
|
||||
SSLHost: String("foobar"),
|
||||
SSLProxyHeaders: map[string]string{
|
||||
"name0": "foobar",
|
||||
"name1": "foobar",
|
||||
},
|
||||
SSLForceHost: Bool(true),
|
||||
STSSeconds: 42,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
|
@ -1100,6 +1128,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
ContentSecurityPolicy: "foobar",
|
||||
PublicKey: "foobar",
|
||||
ReferrerPolicy: "foobar",
|
||||
FeaturePolicy: String("foobar"),
|
||||
PermissionsPolicy: "foobar",
|
||||
IsDevelopment: true,
|
||||
},
|
||||
|
@ -1222,6 +1251,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.AuthResponseHeaders": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.AuthRequestHeaders": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.CA": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.CAOptional": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.Cert": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.InsecureSkipVerify": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.Key": "foobar",
|
||||
|
@ -1250,9 +1280,14 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.HTTP.Middlewares.Middleware8.Headers.IsDevelopment": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.PublicKey": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.ReferrerPolicy": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.FeaturePolicy": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.PermissionsPolicy": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLForceHost": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLHost": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLProxyHeaders.name0": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLProxyHeaders.name1": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLRedirect": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.SSLTemporaryRedirect": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.STSIncludeSubdomains": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.STSPreload": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware8.Headers.STSSeconds": "42",
|
||||
|
@ -1304,6 +1339,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.HTTP.Middlewares.Middleware16.Retry.Attempts": "42",
|
||||
"traefik.HTTP.Middlewares.Middleware16.Retry.InitialInterval": "1000000000",
|
||||
"traefik.HTTP.Middlewares.Middleware17.StripPrefix.Prefixes": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware17.StripPrefix.ForceSlash": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware18.StripPrefixRegex.Regex": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware19.Compress.MinResponseBodyBytes": "42",
|
||||
"traefik.HTTP.Middlewares.Middleware20.Plugin.tomato.aaa": "foo1",
|
||||
|
@ -1373,9 +1409,11 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.TCP.Services.Service0.LoadBalancer.server.Port": "42",
|
||||
"traefik.TCP.Services.Service0.LoadBalancer.server.TLS": "false",
|
||||
"traefik.TCP.Services.Service0.LoadBalancer.ServersTransport": "foo",
|
||||
"traefik.TCP.Services.Service0.LoadBalancer.TerminationDelay": "42",
|
||||
"traefik.TCP.Services.Service1.LoadBalancer.server.Port": "42",
|
||||
"traefik.TCP.Services.Service1.LoadBalancer.server.TLS": "false",
|
||||
"traefik.TCP.Services.Service1.LoadBalancer.ServersTransport": "foo",
|
||||
"traefik.TCP.Services.Service1.LoadBalancer.TerminationDelay": "42",
|
||||
|
||||
"traefik.UDP.Routers.Router0.EntryPoints": "foobar, fiibar",
|
||||
"traefik.UDP.Routers.Router0.Service": "foobar",
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/connectionheader"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"github.com/vulcand/oxy/v2/forward"
|
||||
"github.com/vulcand/oxy/v2/utils"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
@ -53,7 +54,8 @@ type forwardAuth struct {
|
|||
|
||||
// NewForward creates a forward auth middleware.
|
||||
func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) {
|
||||
middlewares.GetLogger(ctx, name, typeNameForward).Debug().Msg("Creating middleware")
|
||||
logger := middlewares.GetLogger(ctx, name, typeNameForward)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
addAuthCookiesToResponse := make(map[string]struct{})
|
||||
for _, cookieName := range config.AddAuthCookiesToResponse {
|
||||
|
@ -79,7 +81,18 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
|
|||
}
|
||||
|
||||
if config.TLS != nil {
|
||||
tlsConfig, err := config.TLS.CreateTLSConfig(ctx)
|
||||
if config.TLS.CAOptional != nil {
|
||||
logger.Warn().Msg("CAOptional option is deprecated, TLS client authentication is a server side option, please remove any usage of this option.")
|
||||
}
|
||||
|
||||
clientTLS := &types.ClientTLS{
|
||||
CA: config.TLS.CA,
|
||||
Cert: config.TLS.Cert,
|
||||
Key: config.TLS.Key,
|
||||
InsecureSkipVerify: config.TLS.InsecureSkipVerify,
|
||||
}
|
||||
|
||||
tlsConfig, err := clientTLS.CreateTLSConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create client TLS configuration: %w", err)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
)
|
||||
|
||||
|
@ -18,8 +19,19 @@ type contentType struct {
|
|||
}
|
||||
|
||||
// New creates a new handler.
|
||||
func New(ctx context.Context, next http.Handler, name string) (http.Handler, error) {
|
||||
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
||||
func New(ctx context.Context, next http.Handler, config dynamic.ContentType, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
if config.AutoDetect != nil {
|
||||
logger.Warn().Msg("AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.")
|
||||
|
||||
// Disable content-type detection (idempotent).
|
||||
if !*config.AutoDetect {
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &contentType{next: next, name: name}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
||||
)
|
||||
|
||||
|
@ -60,7 +61,7 @@ func TestAutoDetection(t *testing.T) {
|
|||
|
||||
if test.autoDetect {
|
||||
var err error
|
||||
next, err = New(context.Background(), next, "foo-content-type")
|
||||
next, err = New(context.Background(), next, dynamic.ContentType{}, "foo-content-type")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,15 +21,27 @@ type stripPrefix struct {
|
|||
next http.Handler
|
||||
prefixes []string
|
||||
name string
|
||||
|
||||
// Deprecated: Must be removed (breaking), the default behavior must be forceSlash=false
|
||||
forceSlash bool
|
||||
}
|
||||
|
||||
// New creates a new strip prefix middleware.
|
||||
func New(ctx context.Context, next http.Handler, config dynamic.StripPrefix, name string) (http.Handler, error) {
|
||||
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
if config.ForceSlash != nil {
|
||||
logger.Warn().Msgf("`ForceSlash` option is deprecated, please remove any usage of this option.")
|
||||
}
|
||||
// Handle default value (here because of deprecation and the removal of setDefault).
|
||||
forceSlash := config.ForceSlash != nil && *config.ForceSlash
|
||||
|
||||
return &stripPrefix{
|
||||
prefixes: config.Prefixes,
|
||||
next: next,
|
||||
name: name,
|
||||
prefixes: config.Prefixes,
|
||||
next: next,
|
||||
name: name,
|
||||
forceSlash: forceSlash,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -58,6 +70,13 @@ func (s *stripPrefix) serveRequest(rw http.ResponseWriter, req *http.Request, pr
|
|||
}
|
||||
|
||||
func (s *stripPrefix) getPrefixStripped(urlPath, prefix string) string {
|
||||
if s.forceSlash {
|
||||
// Only for compatibility reason with the previous behavior,
|
||||
// but the previous behavior is wrong.
|
||||
// This needs to be removed in the next breaking version.
|
||||
return "/" + strings.TrimPrefix(strings.TrimPrefix(urlPath, prefix), "/")
|
||||
}
|
||||
|
||||
return ensureLeadingSlash(strings.TrimPrefix(urlPath, prefix))
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,9 @@ func TestStripPrefix(t *testing.T) {
|
|||
requestURI = r.RequestURI
|
||||
})
|
||||
|
||||
pointer := func(v bool) *bool { return &v }
|
||||
test.config.ForceSlash = pointer(false)
|
||||
|
||||
handler, err := New(context.Background(), next, test.config, "foo-strip-prefix")
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var _ Client = (*clientMock)(nil)
|
||||
|
||||
func init() {
|
||||
// required by k8s.MustParseYaml
|
||||
err := traefikv1alpha1.AddToScheme(kscheme.Scheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type clientMock struct {
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
|
||||
ingressRoutes []*traefikv1alpha1.IngressRoute
|
||||
ingressRouteTCPs []*traefikv1alpha1.IngressRouteTCP
|
||||
ingressRouteUDPs []*traefikv1alpha1.IngressRouteUDP
|
||||
middlewares []*traefikv1alpha1.Middleware
|
||||
middlewareTCPs []*traefikv1alpha1.MiddlewareTCP
|
||||
tlsOptions []*traefikv1alpha1.TLSOption
|
||||
tlsStores []*traefikv1alpha1.TLSStore
|
||||
traefikServices []*traefikv1alpha1.TraefikService
|
||||
serversTransports []*traefikv1alpha1.ServersTransport
|
||||
serversTransportTCPs []*traefikv1alpha1.ServersTransportTCP
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
||||
func newClientMock(paths ...string) clientMock {
|
||||
var c clientMock
|
||||
|
||||
for _, path := range paths {
|
||||
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sObjects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service:
|
||||
c.services = append(c.services, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *traefikv1alpha1.IngressRoute:
|
||||
c.ingressRoutes = append(c.ingressRoutes, o)
|
||||
case *traefikv1alpha1.IngressRouteTCP:
|
||||
c.ingressRouteTCPs = append(c.ingressRouteTCPs, o)
|
||||
case *traefikv1alpha1.IngressRouteUDP:
|
||||
c.ingressRouteUDPs = append(c.ingressRouteUDPs, o)
|
||||
case *traefikv1alpha1.Middleware:
|
||||
c.middlewares = append(c.middlewares, o)
|
||||
case *traefikv1alpha1.MiddlewareTCP:
|
||||
c.middlewareTCPs = append(c.middlewareTCPs, o)
|
||||
case *traefikv1alpha1.TraefikService:
|
||||
c.traefikServices = append(c.traefikServices, o)
|
||||
case *traefikv1alpha1.TLSOption:
|
||||
c.tlsOptions = append(c.tlsOptions, o)
|
||||
case *traefikv1alpha1.ServersTransport:
|
||||
c.serversTransports = append(c.serversTransports, o)
|
||||
case *traefikv1alpha1.ServersTransportTCP:
|
||||
c.serversTransportTCPs = append(c.serversTransportTCPs, o)
|
||||
case *traefikv1alpha1.TLSStore:
|
||||
c.tlsStores = append(c.tlsStores, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngressRoutes() []*traefikv1alpha1.IngressRoute {
|
||||
return c.ingressRoutes
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP {
|
||||
return c.ingressRouteTCPs
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP {
|
||||
return c.ingressRouteUDPs
|
||||
}
|
||||
|
||||
func (c clientMock) GetMiddlewares() []*traefikv1alpha1.Middleware {
|
||||
return c.middlewares
|
||||
}
|
||||
|
||||
func (c clientMock) GetMiddlewareTCPs() []*traefikv1alpha1.MiddlewareTCP {
|
||||
return c.middlewareTCPs
|
||||
}
|
||||
|
||||
func (c clientMock) GetTraefikService(namespace, name string) (*traefikv1alpha1.TraefikService, bool, error) {
|
||||
for _, svc := range c.traefikServices {
|
||||
if svc.Namespace == namespace && svc.Name == name {
|
||||
return svc, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetTraefikServices() []*traefikv1alpha1.TraefikService {
|
||||
return c.traefikServices
|
||||
}
|
||||
|
||||
func (c clientMock) GetTLSOptions() []*traefikv1alpha1.TLSOption {
|
||||
return c.tlsOptions
|
||||
}
|
||||
|
||||
func (c clientMock) GetTLSStores() []*traefikv1alpha1.TLSStore {
|
||||
return c.tlsStores
|
||||
}
|
||||
|
||||
func (c clientMock) GetServersTransports() []*traefikv1alpha1.ServersTransport {
|
||||
return c.serversTransports
|
||||
}
|
||||
|
||||
func (c clientMock) GetServersTransportTCPs() []*traefikv1alpha1.ServersTransportTCP {
|
||||
return c.serversTransportTCPs
|
||||
}
|
||||
|
||||
func (c clientMock) GetTLSOption(namespace, name string) (*traefikv1alpha1.TLSOption, bool, error) {
|
||||
for _, option := range c.tlsOptions {
|
||||
if option.Namespace == namespace && option.Name == name {
|
||||
return option, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if c.apiServiceError != nil {
|
||||
return nil, false, c.apiServiceError
|
||||
}
|
||||
|
||||
for _, service := range c.services {
|
||||
if service.Namespace == namespace && service.Name == name {
|
||||
return service, true, nil
|
||||
}
|
||||
}
|
||||
return nil, false, c.apiServiceError
|
||||
}
|
||||
|
||||
func (c clientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if c.apiEndpointsError != nil {
|
||||
return nil, false, c.apiEndpointsError
|
||||
}
|
||||
|
||||
for _, endpoints := range c.endpoints {
|
||||
if endpoints.Namespace == namespace && endpoints.Name == name {
|
||||
return endpoints, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &corev1.Endpoints{}, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if c.apiSecretError != nil {
|
||||
return nil, false, c.apiSecretError
|
||||
}
|
||||
|
||||
for _, secret := range c.secrets {
|
||||
if secret.Namespace == namespace && secret.Name == name {
|
||||
return secret, true, nil
|
||||
}
|
||||
}
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
return c.watchChan, nil
|
||||
}
|
|
@ -166,7 +166,7 @@ subsets:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
name: external-svc-tcp
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
|
@ -176,7 +176,7 @@ spec:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external.service.with.port
|
||||
name: external.service.with.port.tcp
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
|
@ -186,19 +186,6 @@ spec:
|
|||
protocol: TCP
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external.service.without.port
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
@ -266,7 +253,7 @@ metadata:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: native-svc
|
||||
name: native-svc-tcp
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
|
|
@ -11,5 +11,5 @@ spec:
|
|||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: external-svc
|
||||
- name: external-svc-tcp
|
||||
port: 8000
|
||||
|
|
|
@ -11,5 +11,5 @@ spec:
|
|||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: external.service.with.port
|
||||
- name: external.service.with.port.tcp
|
||||
port: 80
|
||||
|
|
|
@ -11,4 +11,4 @@ spec:
|
|||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: external-svc
|
||||
- name: external-svc-tcp
|
||||
|
|
|
@ -11,6 +11,6 @@ spec:
|
|||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: native-svc
|
||||
- name: native-svc-tcp
|
||||
port: 8000
|
||||
nativeLB: true
|
||||
|
|
|
@ -150,7 +150,7 @@ spec:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
name: external-svc-udp
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
|
@ -160,7 +160,7 @@ spec:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external.service.with.port
|
||||
name: external.service.with.port.udp
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
|
@ -170,19 +170,6 @@ spec:
|
|||
protocol: TCP
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external.service.without.port
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
|
@ -225,7 +212,7 @@ metadata:
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: native-svc
|
||||
name: native-svc-udp
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
|
|
@ -10,5 +10,5 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: external-svc
|
||||
- name: external-svc-udp
|
||||
port: 8000
|
||||
|
|
|
@ -10,5 +10,5 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: external.service.with.port
|
||||
- name: external.service.with.port.udp
|
||||
port: 80
|
||||
|
|
|
@ -10,5 +10,5 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: external.service.with.port
|
||||
- name: external.service.with.port.udp
|
||||
port: 80
|
||||
|
|
|
@ -10,4 +10,4 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: external-svc
|
||||
- name: external-svc-udp
|
||||
|
|
|
@ -10,6 +10,6 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: native-svc
|
||||
- name: native-svc-udp
|
||||
port: 8000
|
||||
nativeLB: true
|
||||
|
|
|
@ -40,7 +40,7 @@ spec:
|
|||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
name: test.route.default
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
|
|
@ -23,7 +23,7 @@ data:
|
|||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
name: test.route.default
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
|
|
@ -735,7 +735,7 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traef
|
|||
return forwardAuth, nil
|
||||
}
|
||||
|
||||
forwardAuth.TLS = &types.ClientTLS{
|
||||
forwardAuth.TLS = &dynamic.ClientTLS{
|
||||
InsecureSkipVerify: auth.TLS.InsecureSkipVerify,
|
||||
}
|
||||
|
||||
|
@ -756,6 +756,8 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traef
|
|||
forwardAuth.TLS.Key = authSecretKey
|
||||
}
|
||||
|
||||
forwardAuth.TLS.CAOptional = auth.TLS.CAOptional
|
||||
|
||||
return forwardAuth, nil
|
||||
}
|
||||
|
||||
|
@ -1008,8 +1010,9 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
|||
CAFiles: clientCAs,
|
||||
ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType,
|
||||
},
|
||||
SniStrict: tlsOption.Spec.SniStrict,
|
||||
ALPNProtocols: alpnProtocols,
|
||||
SniStrict: tlsOption.Spec.SniStrict,
|
||||
ALPNProtocols: alpnProtocols,
|
||||
PreferServerCipherSuites: tlsOption.Spec.PreferServerCipherSuites,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,10 @@ func (p *Provider) createLoadBalancerServerTCP(client Client, parentNamespace st
|
|||
}
|
||||
}
|
||||
|
||||
if service.ServersTransport == "" && service.TerminationDelay != nil {
|
||||
tcpService.LoadBalancer.TerminationDelay = service.TerminationDelay
|
||||
}
|
||||
|
||||
if service.ServersTransport != "" {
|
||||
tcpService.LoadBalancer.ServersTransport, err = p.makeTCPServersTransportKey(parentNamespace, service.ServersTransport)
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
@ -30,6 +31,14 @@ var _ provider.Provider = (*Provider)(nil)
|
|||
func Int(v int) *int { return &v }
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func init() {
|
||||
// required by k8s.MustParseYaml
|
||||
err := traefikv1alpha1.AddToScheme(kscheme.Scheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -1035,6 +1044,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
Services: map[string]*dynamic.TCPService{
|
||||
"default-test.route-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
TerminationDelay: Int(500),
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
|
@ -1568,6 +1578,23 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
||||
client := newClientImpl(kubeClient, crdClient)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
eventCh, err := client.WatchAll(nil, stopCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
if k8sObjects != nil || crdObjects != nil {
|
||||
// just wait for the first event
|
||||
<-eventCh
|
||||
}
|
||||
|
||||
p := Provider{
|
||||
IngressClass: test.ingressClass,
|
||||
AllowCrossNamespace: true,
|
||||
|
@ -1575,8 +1602,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
clientMock := newClientMock(test.paths...)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
@ -3063,6 +3089,15 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Options: "default-foo",
|
||||
},
|
||||
},
|
||||
"default-test-route-default-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-test-route-default-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "default-foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
|
@ -3082,6 +3117,22 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"default-test-route-default-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
|
@ -3602,7 +3653,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
"default-forwardauth": {
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "test.com",
|
||||
TLS: &types.ClientTLS{
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
||||
Cert: "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
|
||||
Key: "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----",
|
||||
|
@ -4017,6 +4068,13 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Priority: 12,
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
"default-test-route-default-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-test-route-default-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
|
@ -4036,6 +4094,22 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"default-test-route-default-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
|
@ -4521,6 +4595,23 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
||||
client := newClientImpl(kubeClient, crdClient)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
eventCh, err := client.WatchAll(nil, stopCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
if k8sObjects != nil || crdObjects != nil {
|
||||
// just wait for the first event
|
||||
<-eventCh
|
||||
}
|
||||
|
||||
p := Provider{
|
||||
IngressClass: test.ingressClass,
|
||||
AllowCrossNamespace: test.allowCrossNamespace,
|
||||
|
@ -4528,8 +4619,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
clientMock := newClientMock(test.paths...)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
@ -5016,6 +5106,23 @@ func TestLoadIngressRouteUDPs(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
||||
client := newClientImpl(kubeClient, crdClient)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
eventCh, err := client.WatchAll(nil, stopCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
if k8sObjects != nil || crdObjects != nil {
|
||||
// just wait for the first event
|
||||
<-eventCh
|
||||
}
|
||||
|
||||
p := Provider{
|
||||
IngressClass: test.ingressClass,
|
||||
AllowCrossNamespace: true,
|
||||
|
@ -5023,8 +5130,7 @@ func TestLoadIngressRouteUDPs(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
clientMock := newClientMock(test.paths...)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
@ -6435,43 +6541,7 @@ func TestCrossNamespace(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var k8sObjects []runtime.Object
|
||||
var crdObjects []runtime.Object
|
||||
for _, path := range test.paths {
|
||||
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
objects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range objects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service, *corev1.Endpoints, *corev1.Secret:
|
||||
k8sObjects = append(k8sObjects, o)
|
||||
case *traefikv1alpha1.IngressRoute:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteTCP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteUDP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.Middleware:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.MiddlewareTCP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TraefikService:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSOption:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSStore:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.ServersTransport:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.ServersTransportTCP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
@ -6742,37 +6812,7 @@ func TestExternalNameService(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var k8sObjects []runtime.Object
|
||||
var crdObjects []runtime.Object
|
||||
for _, path := range test.paths {
|
||||
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
objects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range objects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service, *corev1.Endpoints, *corev1.Secret:
|
||||
k8sObjects = append(k8sObjects, o)
|
||||
case *traefikv1alpha1.IngressRoute:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteTCP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteUDP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.Middleware:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TraefikService:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSOption:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSStore:
|
||||
crdObjects = append(crdObjects, o)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
@ -6955,37 +6995,7 @@ func TestNativeLB(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var k8sObjects []runtime.Object
|
||||
var crdObjects []runtime.Object
|
||||
for _, path := range test.paths {
|
||||
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
objects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range objects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service, *corev1.Endpoints, *corev1.Secret:
|
||||
k8sObjects = append(k8sObjects, o)
|
||||
case *traefikv1alpha1.IngressRoute:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteTCP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.IngressRouteUDP:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.Middleware:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TraefikService:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSOption:
|
||||
crdObjects = append(crdObjects, o)
|
||||
case *traefikv1alpha1.TLSStore:
|
||||
crdObjects = append(crdObjects, o)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
k8sObjects, crdObjects := readResources(t, test.paths)
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
@ -7071,3 +7081,28 @@ func TestCreateBasicAuthCredentials(t *testing.T) {
|
|||
assert.Equal(t, "$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", hashedPassword)
|
||||
assert.True(t, auth.CheckSecret("test2", hashedPassword))
|
||||
}
|
||||
|
||||
func readResources(t *testing.T, paths []string) ([]runtime.Object, []runtime.Object) {
|
||||
t.Helper()
|
||||
|
||||
var k8sObjects []runtime.Object
|
||||
var crdObjects []runtime.Object
|
||||
for _, path := range paths {
|
||||
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
objects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range objects {
|
||||
switch obj.GetObjectKind().GroupVersionKind().Group {
|
||||
case "traefik.io":
|
||||
crdObjects = append(crdObjects, obj)
|
||||
default:
|
||||
k8sObjects = append(k8sObjects, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return k8sObjects, crdObjects
|
||||
}
|
||||
|
|
|
@ -72,6 +72,13 @@ type ServiceTCP struct {
|
|||
Port intstr.IntOrString `json:"port"`
|
||||
// Weight defines the weight used when balancing requests between multiple Kubernetes Service.
|
||||
Weight *int `json:"weight,omitempty"`
|
||||
// TerminationDelay defines the deadline that the proxy sets, after one of its connected peers indicates
|
||||
// it has closed the writing capability of its connection, to close the reading capability as well,
|
||||
// hence fully terminating the connection.
|
||||
// It is a duration in milliseconds, defaulting to 100.
|
||||
// A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||
// Deprecated: TerminationDelay is not supported APIVersion traefik.io/v1, please use ServersTransport to configure the TerminationDelay instead.
|
||||
TerminationDelay *int `json:"terminationDelay,omitempty"`
|
||||
// ProxyProtocol defines the PROXY protocol configuration.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/routing/services/#proxy-protocol
|
||||
ProxyProtocol *dynamic.ProxyProtocol `json:"proxyProtocol,omitempty"`
|
||||
|
|
|
@ -171,6 +171,9 @@ type ClientTLS struct {
|
|||
CertSecret string `json:"certSecret,omitempty"`
|
||||
// InsecureSkipVerify defines whether the server certificates should be validated.
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
|
||||
|
||||
// Deprecated: TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634).
|
||||
CAOptional *bool `json:"caOptional,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -26,9 +26,13 @@ type MiddlewareTCPSpec struct {
|
|||
// InFlightConn defines the InFlightConn middleware configuration.
|
||||
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
|
||||
// IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
// This middleware accepts/refuses connections based on the client IP.
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/tcp/ipwhitelist/
|
||||
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
|
||||
// IPAllowList defines the IPAllowList middleware configuration.
|
||||
// This middleware accepts/refuses connections based on the client IP.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/tcp/ipallowlist/
|
||||
IPAllowList *dynamic.TCPIPAllowList `json:"ipAllowList,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,11 @@ type TLSOptionSpec struct {
|
|||
// ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/https/tls/#alpn-protocols
|
||||
ALPNProtocols []string `json:"alpnProtocols,omitempty"`
|
||||
|
||||
// PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
// It is enabled automatically when minVersion or maxVersion is set.
|
||||
// Deprecated: https://github.com/golang/go/issues/45430
|
||||
PreferServerCipherSuites *bool `json:"preferServerCipherSuites,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -146,6 +146,11 @@ func (in *ClientAuth) DeepCopy() *ClientAuth {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientTLS) DeepCopyInto(out *ClientTLS) {
|
||||
*out = *in
|
||||
if in.CAOptional != nil {
|
||||
in, out := &in.CAOptional, &out.CAOptional
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -213,7 +218,7 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
|||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(ClientTLS)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AddAuthCookiesToResponse != nil {
|
||||
in, out := &in.AddAuthCookiesToResponse, &out.AddAuthCookiesToResponse
|
||||
|
@ -777,7 +782,7 @@ func (in *MiddlewareSpec) DeepCopyInto(out *MiddlewareSpec) {
|
|||
if in.ContentType != nil {
|
||||
in, out := &in.ContentType, &out.ContentType
|
||||
*out = new(dynamic.ContentType)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.GrpcWeb != nil {
|
||||
in, out := &in.GrpcWeb, &out.GrpcWeb
|
||||
|
@ -1318,6 +1323,11 @@ func (in *ServiceTCP) DeepCopyInto(out *ServiceTCP) {
|
|||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
if in.TerminationDelay != nil {
|
||||
in, out := &in.TerminationDelay, &out.TerminationDelay
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
if in.ProxyProtocol != nil {
|
||||
in, out := &in.ProxyProtocol, &out.ProxyProtocol
|
||||
*out = new(dynamic.ProxyProtocol)
|
||||
|
@ -1517,6 +1527,11 @@ func (in *TLSOptionSpec) DeepCopyInto(out *TLSOptionSpec) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PreferServerCipherSuites != nil {
|
||||
in, out := &in.PreferServerCipherSuites, &out.PreferServerCipherSuites
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
func String(v string) *string { return &v }
|
||||
|
||||
func Test_buildConfiguration(t *testing.T) {
|
||||
provider := newProviderMock(mapToPairs(map[string]string{
|
||||
"traefik/http/routers/Router0/entryPoints/0": "foobar",
|
||||
|
@ -79,6 +82,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/key": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/insecureSkipVerify": "true",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/ca": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/caOptional": "true",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/cert": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/address": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/trustForwardHeader": "true",
|
||||
|
@ -105,8 +109,12 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/http/middlewares/Middleware09/headers/accessControlAllowOriginListRegex/1": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/contentTypeNosniff": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/accessControlAllowCredentials": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/featurePolicy": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/permissionsPolicy": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/forceSTSHeader": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslRedirect": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslHost": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslForceHost": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslProxyHeaders/name1": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslProxyHeaders/name0": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/allowedHosts/0": "foobar",
|
||||
|
@ -125,6 +133,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/http/middlewares/Middleware09/headers/addVaryHeader": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/hostsProxyHeaders/0": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/hostsProxyHeaders/1": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/sslTemporaryRedirect": "true",
|
||||
"traefik/http/middlewares/Middleware09/headers/customBrowserXSSValue": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/referrerPolicy": "foobar",
|
||||
"traefik/http/middlewares/Middleware09/headers/accessControlExposeHeaders/0": "foobar",
|
||||
|
@ -201,6 +210,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/http/middlewares/Middleware18/retry/attempts": "42",
|
||||
"traefik/http/middlewares/Middleware19/stripPrefix/prefixes/0": "foobar",
|
||||
"traefik/http/middlewares/Middleware19/stripPrefix/prefixes/1": "foobar",
|
||||
"traefik/http/middlewares/Middleware19/stripPrefix/forceSlash": "true",
|
||||
"traefik/tcp/routers/TCPRouter0/entryPoints/0": "foobar",
|
||||
"traefik/tcp/routers/TCPRouter0/entryPoints/1": "foobar",
|
||||
"traefik/tcp/routers/TCPRouter0/service": "foobar",
|
||||
|
@ -227,6 +237,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/tcp/routers/TCPRouter1/tls/passthrough": "true",
|
||||
"traefik/tcp/routers/TCPRouter1/tls/options": "foobar",
|
||||
"traefik/tcp/routers/TCPRouter1/tls/certResolver": "foobar",
|
||||
"traefik/tcp/services/TCPService01/loadBalancer/terminationDelay": "42",
|
||||
"traefik/tcp/services/TCPService01/loadBalancer/servers/0/address": "foobar",
|
||||
"traefik/tcp/services/TCPService01/loadBalancer/servers/1/address": "foobar",
|
||||
"traefik/tcp/services/TCPService02/weighted/services/0/name": "foobar",
|
||||
|
@ -371,6 +382,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"foobar",
|
||||
},
|
||||
ForceSlash: Bool(true),
|
||||
},
|
||||
},
|
||||
"Middleware00": {
|
||||
|
@ -404,11 +416,12 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"Middleware08": {
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "foobar",
|
||||
TLS: &types.ClientTLS{
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "foobar",
|
||||
Cert: "foobar",
|
||||
Key: "foobar",
|
||||
InsecureSkipVerify: true,
|
||||
CAOptional: Bool(true),
|
||||
},
|
||||
TrustForwardHeader: true,
|
||||
AuthResponseHeaders: []string{
|
||||
|
@ -581,10 +594,14 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"foobar",
|
||||
},
|
||||
SSLRedirect: Bool(true),
|
||||
SSLTemporaryRedirect: Bool(true),
|
||||
SSLHost: String("foobar"),
|
||||
SSLProxyHeaders: map[string]string{
|
||||
"name1": "foobar",
|
||||
"name0": "foobar",
|
||||
},
|
||||
SSLForceHost: Bool(true),
|
||||
STSSeconds: 42,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
|
@ -597,6 +614,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
ContentSecurityPolicy: "foobar",
|
||||
PublicKey: "foobar",
|
||||
ReferrerPolicy: "foobar",
|
||||
FeaturePolicy: String("foobar"),
|
||||
PermissionsPolicy: "foobar",
|
||||
IsDevelopment: true,
|
||||
},
|
||||
|
@ -757,6 +775,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Services: map[string]*dynamic.TCPService{
|
||||
"TCPService01": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
TerminationDelay: func(v int) *int { return &v }(42),
|
||||
Servers: []dynamic.TCPServer{
|
||||
{Address: "foobar"},
|
||||
{Address: "foobar"},
|
||||
|
|
|
@ -263,7 +263,7 @@ func init() {
|
|||
},
|
||||
ForwardAuth: &dynamic.ForwardAuth{
|
||||
Address: "127.0.0.1",
|
||||
TLS: &types.ClientTLS{
|
||||
TLS: &dynamic.ClientTLS{
|
||||
CA: "ca.pem",
|
||||
Cert: "cert.pem",
|
||||
Key: "cert.pem",
|
||||
|
|
|
@ -184,7 +184,7 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
|
|||
return nil, badConf
|
||||
}
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return contenttype.New(ctx, next, middlewareName)
|
||||
return contenttype.New(ctx, next, *config.ContentType, middlewareName)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,8 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
|
|||
|
||||
// IPWhiteList
|
||||
if config.IPWhiteList != nil {
|
||||
log.Warn().Msg("IPWhiteList is deprecated, please use IPAllowList instead.")
|
||||
qualifiedName := provider.GetQualifiedName(ctx, middlewareName)
|
||||
log.Warn().Msgf("Middleware %q of type IPWhiteList is deprecated, please use IPAllowList instead.", qualifiedName)
|
||||
|
||||
if middleware != nil {
|
||||
return nil, badConf
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/logs"
|
||||
"github.com/traefik/traefik/v3/pkg/server/provider"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
// Manager is the TCPHandlers factory.
|
||||
|
@ -53,6 +54,10 @@ func (m *Manager) BuildTCP(rootCtx context.Context, serviceName string) (tcp.Han
|
|||
case conf.LoadBalancer != nil:
|
||||
loadBalancer := tcp.NewWRRLoadBalancer()
|
||||
|
||||
if conf.LoadBalancer.TerminationDelay != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("Service %q load balancer uses `TerminationDelay`, but this option is deprecated, please use ServersTransport configuration instead.", serviceName)
|
||||
}
|
||||
|
||||
if len(conf.LoadBalancer.ServersTransport) > 0 {
|
||||
conf.LoadBalancer.ServersTransport = provider.GetQualifiedName(ctx, conf.LoadBalancer.ServersTransport)
|
||||
}
|
||||
|
@ -72,6 +77,14 @@ func (m *Manager) BuildTCP(rootCtx context.Context, serviceName string) (tcp.Han
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Handle TerminationDelay deprecated option.
|
||||
if conf.LoadBalancer.ServersTransport == "" && conf.LoadBalancer.TerminationDelay != nil {
|
||||
dialer = &dialerWrapper{
|
||||
Dialer: dialer,
|
||||
terminationDelay: time.Duration(*conf.LoadBalancer.TerminationDelay),
|
||||
}
|
||||
}
|
||||
|
||||
handler, err := tcp.NewProxy(server.Address, conf.LoadBalancer.ProxyProtocol, dialer)
|
||||
if err != nil {
|
||||
srvLogger.Error().Err(err).Msg("Failed to create server")
|
||||
|
@ -113,3 +126,13 @@ func shuffle[T any](values []T, r *rand.Rand) []T {
|
|||
|
||||
return shuffled
|
||||
}
|
||||
|
||||
// dialerWrapper is only used to handle TerminationDelay deprecated option on TCPServersLoadBalancer.
|
||||
type dialerWrapper struct {
|
||||
proxy.Dialer
|
||||
terminationDelay time.Duration
|
||||
}
|
||||
|
||||
func (d dialerWrapper) TerminationDelay() time.Duration {
|
||||
return d.terminationDelay
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ type Options struct {
|
|||
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
|
||||
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
|
||||
ALPNProtocols []string `json:"alpnProtocols,omitempty" toml:"alpnProtocols,omitempty" yaml:"alpnProtocols,omitempty" export:"true"`
|
||||
|
||||
// Deprecated: https://github.com/golang/go/issues/45430
|
||||
PreferServerCipherSuites *bool `json:"preferServerCipherSuites,omitempty" toml:"preferServerCipherSuites,omitempty" yaml:"preferServerCipherSuites,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values for an Options struct.
|
||||
|
|
|
@ -68,6 +68,13 @@ func (m *Manager) UpdateConfigs(ctx context.Context, stores map[string]Store, co
|
|||
defer m.lock.Unlock()
|
||||
|
||||
m.configs = configs
|
||||
for optionName, option := range m.configs {
|
||||
// Handle `PreferServerCipherSuites` depreciation
|
||||
if option.PreferServerCipherSuites != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("TLSOption %q uses `PreferServerCipherSuites` option, but this option is deprecated and ineffective, please remove this option.", optionName)
|
||||
}
|
||||
}
|
||||
|
||||
m.storesConfig = stores
|
||||
m.certs = certs
|
||||
|
||||
|
|
|
@ -116,6 +116,11 @@ func (in *Options) DeepCopyInto(out *Options) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PreferServerCipherSuites != nil {
|
||||
in, out := &in.PreferServerCipherSuites, &out.PreferServerCipherSuites
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue