Send anonymized dynamic configuration to Pilot

Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
Harold Ozouf 2020-12-03 15:52:05 +01:00 committed by GitHub
parent a488430f23
commit 64a65cadf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1394 additions and 374 deletions

View file

@ -214,6 +214,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
pilotRegistry = metrics.RegisterPilot()
aviator = pilot.New(staticConfiguration.Pilot.Token, pilotRegistry, routinesPool)
routinesPool.GoCtx(func(ctx context.Context) {
aviator.Tick(ctx)
})
@ -348,7 +349,7 @@ func switchRouter(routerFactory *server.RouterFactory, serverEntryPointsTCP serv
routers, udpRouters := routerFactory.CreateRouters(rtConf)
if aviator != nil {
aviator.SetRuntimeConfiguration(rtConf)
aviator.SetDynamicConfiguration(conf)
}
serverEntryPointsTCP.Switch(routers)

View file

@ -7,6 +7,8 @@ import (
"regexp"
"github.com/mitchellh/copystructure"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/tls"
"mvdan.cc/xurls/v2"
)
@ -43,6 +45,11 @@ func doOnJSON(input string) string {
}
func doOnStruct(field reflect.Value) error {
if field.Type().AssignableTo(reflect.TypeOf(dynamic.PluginConf{})) {
resetPlugin(field)
return nil
}
switch field.Kind() {
case reflect.Ptr:
if !field.IsNil() {
@ -57,19 +64,48 @@ func doOnStruct(field reflect.Value) error {
if !isExported(stField) {
continue
}
if stField.Tag.Get("export") == "true" {
// A struct field cannot be set it must be filled as pointer.
if fld.Kind() == reflect.Struct {
fldPtr := reflect.New(fld.Type())
fldPtr.Elem().Set(fld)
if err := doOnStruct(fldPtr); err != nil {
return err
}
fld.Set(fldPtr.Elem())
continue
}
if err := doOnStruct(fld); err != nil {
return err
}
} else {
if err := reset(fld, stField.Name); err != nil {
return err
}
} else if err := reset(fld, stField.Name); err != nil {
return err
}
}
case reflect.Map:
for _, key := range field.MapKeys() {
if err := doOnStruct(field.MapIndex(key)); err != nil {
val := field.MapIndex(key)
// A struct value cannot be set it must be filled as pointer.
if val.Kind() == reflect.Struct {
valPtr := reflect.New(val.Type())
valPtr.Elem().Set(val)
if err := doOnStruct(valPtr); err != nil {
return err
}
field.SetMapIndex(key, valPtr.Elem())
continue
}
if err := doOnStruct(val); err != nil {
return err
}
}
@ -100,7 +136,11 @@ func reset(field reflect.Value, name string) error {
}
case reflect.String:
if field.String() != "" {
field.Set(reflect.ValueOf(maskShort))
if field.Type().AssignableTo(reflect.TypeOf(tls.FileOrContent(""))) {
field.Set(reflect.ValueOf(tls.FileOrContent(maskShort)))
} else {
field.Set(reflect.ValueOf(maskShort))
}
}
case reflect.Map:
if field.Len() > 0 {
@ -130,6 +170,13 @@ func reset(field reflect.Value, name string) error {
return nil
}
// resetPlugin resets the plugin configuration so it keep the plugin name but not its configuration.
func resetPlugin(field reflect.Value) {
for _, key := range field.MapKeys() {
field.SetMapIndex(key, reflect.ValueOf(struct{}{}))
}
}
// isExported return true is a struct field is exported, else false.
func isExported(f reflect.StructField) bool {
if f.PkgPath != "" && !f.Anonymous {

View file

@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/ping"
"github.com/traefik/traefik/v2/pkg/plugins"
@ -43,7 +44,438 @@ import (
var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
func TestDo_globalConfiguration(t *testing.T) {
func TestDo_dynamicConfiguration(t *testing.T) {
config := &dynamic.Configuration{}
config.HTTP = &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"foo": {
EntryPoints: []string{"foo"},
Middlewares: []string{"foo"},
Service: "foo",
Rule: "foo",
Priority: 42,
TLS: &dynamic.RouterTLSConfig{
Options: "foo",
CertResolver: "foo",
Domains: []types.Domain{
{
Main: "foo",
SANs: []string{"foo"},
},
},
},
},
},
Services: map[string]*dynamic.Service{
"foo": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "foo",
Secure: true,
HTTPOnly: true,
SameSite: "foo",
},
},
HealthCheck: &dynamic.HealthCheck{
Scheme: "foo",
Path: "foo",
Port: 42,
Interval: "foo",
Timeout: "foo",
Hostname: "foo",
FollowRedirects: boolPtr(true),
Headers: map[string]string{
"foo": "bar",
},
},
PassHostHeader: boolPtr(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: "foo",
},
ServersTransport: "foo",
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1:8080",
},
},
},
},
"bar": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "foo",
Weight: intPtr(42),
},
},
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "foo",
Secure: true,
HTTPOnly: true,
SameSite: "foo",
},
},
},
},
"baz": {
Mirroring: &dynamic.Mirroring{
Service: "foo",
MaxBodySize: int64Ptr(42),
Mirrors: []dynamic.MirrorService{
{
Name: "foo",
Percent: 42,
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{
"foo": {
ServerName: "foo",
InsecureSkipVerify: true,
RootCAs: []traefiktls.FileOrContent{"rootca.pem"},
Certificates: []traefiktls.Certificate{
{
CertFile: "cert.pem",
KeyFile: "key.pem",
},
},
MaxIdleConnsPerHost: 42,
ForwardingTimeouts: &dynamic.ForwardingTimeouts{
DialTimeout: 42,
ResponseHeaderTimeout: 42,
IdleConnTimeout: 42,
},
},
},
Models: map[string]*dynamic.Model{
"foo": {
Middlewares: []string{"foo"},
TLS: &dynamic.RouterTLSConfig{
Options: "foo",
CertResolver: "foo",
Domains: []types.Domain{
{
Main: "foo",
SANs: []string{"foo"},
},
},
},
},
},
Middlewares: map[string]*dynamic.Middleware{
"foo": {
AddPrefix: &dynamic.AddPrefix{
Prefix: "foo",
},
StripPrefix: &dynamic.StripPrefix{
Prefixes: []string{"foo"},
ForceSlash: true,
},
StripPrefixRegex: &dynamic.StripPrefixRegex{
Regex: []string{"foo"},
},
ReplacePath: &dynamic.ReplacePath{
Path: "foo",
},
ReplacePathRegex: &dynamic.ReplacePathRegex{
Regex: "foo",
Replacement: "foo",
},
Chain: &dynamic.Chain{
Middlewares: []string{"foo"},
},
IPWhiteList: &dynamic.IPWhiteList{
SourceRange: []string{"foo"},
IPStrategy: &dynamic.IPStrategy{
Depth: 42,
ExcludedIPs: []string{"127.0.0.1"},
},
},
Headers: &dynamic.Headers{
CustomRequestHeaders: map[string]string{"foo": "bar"},
CustomResponseHeaders: map[string]string{"foo": "bar"},
AccessControlAllowCredentials: true,
AccessControlAllowHeaders: []string{"foo"},
AccessControlAllowMethods: []string{"foo"},
AccessControlAllowOrigin: "foo",
AccessControlAllowOriginList: []string{"foo"},
AccessControlAllowOriginListRegex: []string{"foo"},
AccessControlExposeHeaders: []string{"foo"},
AccessControlMaxAge: 42,
AddVaryHeader: true,
AllowedHosts: []string{"foo"},
HostsProxyHeaders: []string{"foo"},
SSLRedirect: true,
SSLTemporaryRedirect: true,
SSLHost: "foo",
SSLProxyHeaders: map[string]string{"foo": "bar"},
SSLForceHost: true,
STSSeconds: 42,
STSIncludeSubdomains: true,
STSPreload: true,
ForceSTSHeader: true,
FrameDeny: true,
CustomFrameOptionsValue: "foo",
ContentTypeNosniff: true,
BrowserXSSFilter: true,
CustomBrowserXSSValue: "foo",
ContentSecurityPolicy: "foo",
PublicKey: "foo",
ReferrerPolicy: "foo",
FeaturePolicy: "foo",
IsDevelopment: true,
},
Errors: &dynamic.ErrorPage{
Status: []string{"foo"},
Service: "foo",
Query: "foo",
},
RateLimit: &dynamic.RateLimit{
Average: 42,
Period: 42,
Burst: 42,
SourceCriterion: &dynamic.SourceCriterion{
IPStrategy: &dynamic.IPStrategy{
Depth: 42,
ExcludedIPs: []string{"foo"},
},
RequestHeaderName: "foo",
RequestHost: true,
},
},
RedirectRegex: &dynamic.RedirectRegex{
Regex: "foo",
Replacement: "foo",
Permanent: true,
},
RedirectScheme: &dynamic.RedirectScheme{
Scheme: "foo",
Port: "foo",
Permanent: true,
},
BasicAuth: &dynamic.BasicAuth{
Users: []string{"foo"},
UsersFile: "foo",
Realm: "foo",
RemoveHeader: true,
HeaderField: "foo",
},
DigestAuth: &dynamic.DigestAuth{
Users: []string{"foo"},
UsersFile: "foo",
RemoveHeader: true,
Realm: "foo",
HeaderField: "foo",
},
ForwardAuth: &dynamic.ForwardAuth{
Address: "127.0.0.1",
TLS: &dynamic.ClientTLS{
CA: "ca.pem",
CAOptional: true,
Cert: "cert.pem",
Key: "cert.pem",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
AuthResponseHeaders: []string{"foo"},
AuthResponseHeadersRegex: "foo",
AuthRequestHeaders: []string{"foo"},
},
InFlightReq: &dynamic.InFlightReq{
Amount: 42,
SourceCriterion: &dynamic.SourceCriterion{
IPStrategy: &dynamic.IPStrategy{
Depth: 42,
ExcludedIPs: []string{"foo"},
},
RequestHeaderName: "foo",
RequestHost: true,
},
},
Buffering: &dynamic.Buffering{
MaxRequestBodyBytes: 42,
MemRequestBodyBytes: 42,
MaxResponseBodyBytes: 42,
MemResponseBodyBytes: 42,
RetryExpression: "foo",
},
CircuitBreaker: &dynamic.CircuitBreaker{
Expression: "foo",
},
Compress: &dynamic.Compress{
ExcludedContentTypes: []string{"foo"},
},
PassTLSClientCert: &dynamic.PassTLSClientCert{
PEM: true,
Info: &dynamic.TLSClientCertificateInfo{
NotAfter: true,
NotBefore: true,
Sans: true,
Subject: &dynamic.TLSCLientCertificateDNInfo{
Country: true,
Province: true,
Locality: true,
Organization: true,
CommonName: true,
SerialNumber: true,
DomainComponent: true,
},
Issuer: &dynamic.TLSCLientCertificateDNInfo{
Country: true,
Province: true,
Locality: true,
Organization: true,
CommonName: true,
SerialNumber: true,
DomainComponent: true,
},
SerialNumber: true,
},
},
Retry: &dynamic.Retry{
Attempts: 42,
InitialInterval: 42,
},
ContentType: &dynamic.ContentType{
AutoDetect: true,
},
Plugin: map[string]dynamic.PluginConf{
"foo": {
"answer": struct{ Answer int }{
Answer: 42,
},
},
},
},
},
}
config.TCP = &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"foo": {
EntryPoints: []string{"foo"},
Service: "foo",
Rule: "foo",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
Options: "foo",
CertResolver: "foo",
Domains: []types.Domain{
{
Main: "foo",
SANs: []string{"foo"},
},
},
},
},
},
Services: map[string]*dynamic.TCPService{
"foo": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
TerminationDelay: intPtr(42),
ProxyProtocol: &dynamic.ProxyProtocol{
Version: 42,
},
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1:8080",
},
},
},
},
"bar": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "foo",
Weight: intPtr(42),
},
},
},
},
},
}
config.UDP = &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"foo": {
EntryPoints: []string{"foo"},
Service: "foo",
},
},
Services: map[string]*dynamic.UDPService{
"foo": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "127.0.0.1:8080",
},
},
},
},
"bar": {
Weighted: &dynamic.UDPWeightedRoundRobin{
Services: []dynamic.UDPWRRService{
{
Name: "foo",
Weight: intPtr(42),
},
},
},
},
},
}
config.TLS = &dynamic.TLSConfiguration{
Options: map[string]traefiktls.Options{
"foo": {
MinVersion: "foo",
MaxVersion: "foo",
CipherSuites: []string{"foo"},
CurvePreferences: []string{"foo"},
ClientAuth: traefiktls.ClientAuth{
CAFiles: []traefiktls.FileOrContent{"ca.pem"},
ClientAuthType: "RequireAndVerifyClientCert",
},
SniStrict: true,
PreferServerCipherSuites: true,
},
},
Certificates: []*traefiktls.CertAndStores{
{
Certificate: traefiktls.Certificate{
CertFile: "cert.pem",
KeyFile: "key.pem",
},
Stores: []string{"foo"},
},
},
Stores: map[string]traefiktls.Store{
"foo": {
DefaultCertificate: &traefiktls.Certificate{
CertFile: "cert.pem",
KeyFile: "key.pem",
},
},
},
}
expectedConfiguration, err := ioutil.ReadFile("./testdata/anonymized-dynamic-config.json")
require.NoError(t, err)
cleanJSON, err := Do(config, true)
require.NoError(t, err)
if *updateExpected {
require.NoError(t, ioutil.WriteFile("testdata/anonymized-dynamic-config.json", []byte(cleanJSON), 0666))
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
}
func TestDo_staticConfiguration(t *testing.T) {
config := &static.Configuration{}
config.Global = &static.Global{
@ -538,3 +970,15 @@ func TestDo_globalConfiguration(t *testing.T) {
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
}
func boolPtr(value bool) *bool {
return &value
}
func intPtr(value int) *int {
return &value
}
func int64Ptr(value int64) *int64 {
return &value
}

View file

@ -5,6 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type Courgette struct {
@ -39,7 +40,6 @@ func Test_doOnStruct(t *testing.T) {
name string
base *Carotte
expected *Carotte
hasError bool
}{
{
name: "primitive",
@ -145,7 +145,7 @@ func Test_doOnStruct(t *testing.T) {
},
},
{
name: "export map string/struct (UNSAFE)",
name: "export map string/struct",
base: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
@ -158,11 +158,10 @@ func Test_doOnStruct(t *testing.T) {
Name: "xxxx",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
Ji: "xxxx",
},
},
},
hasError: true,
},
}
@ -170,12 +169,7 @@ func Test_doOnStruct(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
val := reflect.ValueOf(test.base).Elem()
err := doOnStruct(val)
if !test.hasError && err != nil {
t.Fatal(err)
}
if test.hasError && err == nil {
t.Fatal("Got no error but want an error.")
}
require.NoError(t, err)
assert.EqualValues(t, test.expected, test.base)
})

View file

@ -0,0 +1,476 @@
{
"http": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"middlewares": [
"foo"
],
"service": "foo",
"rule": "xxxx",
"priority": 42,
"tls": {
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "xxxx",
"sans": [
"xxxx"
]
}
]
}
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
],
"sticky": {
"cookie": {
"name": "foo",
"secure": true,
"httpOnly": true,
"sameSite": "foo"
}
}
}
},
"baz": {
"mirroring": {
"service": "foo",
"maxBodySize": 42,
"mirrors": [
{
"name": "foo",
"percent": 42
}
]
}
},
"foo": {
"loadBalancer": {
"sticky": {
"cookie": {
"name": "foo",
"secure": true,
"httpOnly": true,
"sameSite": "foo"
}
},
"servers": [
{
"url": "xxxx"
}
],
"healthCheck": {
"scheme": "foo",
"path": "foo",
"port": 42,
"interval": "foo",
"timeout": "foo",
"hostname": "xxxx",
"followRedirects": true,
"headers": {
"foo": "bar"
}
},
"passHostHeader": true,
"responseForwarding": {
"flushInterval": "foo"
},
"serversTransport": "foo"
}
}
},
"middlewares": {
"foo": {
"addPrefix": {
"prefix": "foo"
},
"stripPrefix": {
"prefixes": [
"foo"
],
"forceSlash": true
},
"stripPrefixRegex": {
"regex": [
"foo"
]
},
"replacePath": {
"path": "foo"
},
"replacePathRegex": {
"regex": "foo",
"replacement": "foo"
},
"chain": {
"middlewares": [
"foo"
]
},
"ipWhiteList": {
"sourceRange": [
"xxxx"
],
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"xxxx"
]
}
},
"headers": {
"customRequestHeaders": {
"foo": "bar"
},
"customResponseHeaders": {
"foo": "bar"
},
"accessControlAllowCredentials": true,
"accessControlAllowHeaders": [
"foo"
],
"accessControlAllowMethods": [
"foo"
],
"accessControlAllowOrigin": "xxxx",
"accessControlAllowOriginList": [
"xxxx"
],
"accessControlAllowOriginListRegex": [
"xxxx"
],
"accessControlExposeHeaders": [
"foo"
],
"accessControlMaxAge": 42,
"addVaryHeader": true,
"allowedHosts": [
"xxxx"
],
"hostsProxyHeaders": [
"foo"
],
"sslRedirect": true,
"sslTemporaryRedirect": true,
"sslHost": "xxxx",
"sslForceHost": true,
"stsSeconds": 42,
"stsIncludeSubdomains": true,
"stsPreload": true,
"forceSTSHeader": true,
"frameDeny": true,
"customFrameOptionsValue": "xxxx",
"contentTypeNosniff": true,
"browserXssFilter": true,
"customBrowserXSSValue": "xxxx",
"contentSecurityPolicy": "xxxx",
"publicKey": "xxxx",
"referrerPolicy": "foo",
"featurePolicy": "foo",
"isDevelopment": true
},
"errors": {
"status": [
"foo"
],
"service": "foo",
"query": "foo"
},
"rateLimit": {
"average": 42,
"period": 42,
"burst": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"xxxx"
]
},
"requestHeaderName": "foo",
"requestHost": true
}
},
"redirectRegex": {
"regex": "xxxx",
"replacement": "xxxx",
"permanent": true
},
"redirectScheme": {
"scheme": "foo",
"port": "foo",
"permanent": true
},
"basicAuth": {
"users": [
"xxxx"
],
"usersFile": "xxxx",
"realm": "xxxx",
"removeHeader": true,
"headerField": "foo"
},
"digestAuth": {
"users": [
"xxxx"
],
"usersFile": "xxxx",
"removeHeader": true,
"realm": "xxxx",
"headerField": "foo"
},
"forwardAuth": {
"address": "xxxx",
"tls": {
"ca": "xxxx",
"caOptional": true,
"cert": "xxxx",
"key": "xxxx",
"insecureSkipVerify": true
},
"trustForwardHeader": true,
"authResponseHeaders": [
"foo"
],
"authResponseHeadersRegex": "foo",
"authRequestHeaders": [
"foo"
]
},
"inFlightReq": {
"amount": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"xxxx"
]
},
"requestHeaderName": "foo",
"requestHost": true
}
},
"buffering": {
"maxRequestBodyBytes": 42,
"memRequestBodyBytes": 42,
"maxResponseBodyBytes": 42,
"memResponseBodyBytes": 42,
"retryExpression": "foo"
},
"circuitBreaker": {
"expression": "foo"
},
"compress": {
"excludedContentTypes": [
"foo"
]
},
"passTLSClientCert": {
"pem": true,
"info": {
"notAfter": true,
"notBefore": true,
"sans": true,
"subject": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
},
"issuer": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
},
"serialNumber": true
}
},
"retry": {
"attempts": 42,
"initialInterval": 42
},
"contentType": {
"autoDetect": true
},
"plugin": {
"foo": {
"answer": {}
}
}
}
},
"models": {
"foo": {
"middlewares": [
"foo"
],
"tls": {
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "xxxx",
"sans": [
"xxxx"
]
}
]
}
}
},
"serversTransports": {
"foo": {
"serverName": "xxxx",
"insecureSkipVerify": true,
"rootCAs": [
"xxxx"
],
"certificates": [
{
"certFile": "xxxx",
"keyFile": "xxxx"
}
],
"maxIdleConnsPerHost": 42,
"forwardingTimeouts": {
"dialTimeout": 42,
"responseHeaderTimeout": 42,
"idleConnTimeout": 42
}
}
}
},
"tcp": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"service": "foo",
"rule": "xxxx",
"tls": {
"passthrough": true,
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "xxxx",
"sans": [
"xxxx"
]
}
]
}
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
]
}
},
"foo": {
"loadBalancer": {
"terminationDelay": 42,
"proxyProtocol": {
"version": 42
},
"servers": [
{
"address": "xxxx"
}
]
}
}
}
},
"udp": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"service": "foo"
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
]
}
},
"foo": {
"loadBalancer": {
"servers": [
{
"address": "xxxx"
}
]
}
}
}
},
"tls": {
"certificates": [
{
"certFile": "xxxx",
"keyFile": "xxxx",
"stores": [
"foo"
]
}
],
"options": {
"foo": {
"minVersion": "foo",
"maxVersion": "foo",
"cipherSuites": [
"foo"
],
"curvePreferences": [
"foo"
],
"clientAuth": {},
"sniStrict": true,
"preferServerCipherSuites": true
}
},
"stores": {
"foo": {
"defaultCertificate": {
"certFile": "xxxx",
"keyFile": "xxxx"
}
}
}
}
}

View file

@ -21,17 +21,17 @@ type Configurations map[string]*Configuration
// Configuration is the root of the dynamic configuration.
type Configuration struct {
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty"`
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty"`
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"`
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty" export:"true"`
UDP *UDPConfiguration `json:"udp,omitempty" toml:"udp,omitempty" yaml:"udp,omitempty" export:"true"`
TLS *TLSConfiguration `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TLSConfiguration contains all the configuration parameters of a TLS connection.
type TLSConfiguration struct {
Certificates []*tls.CertAndStores `json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" label:"-"`
Options map[string]tls.Options `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
Stores map[string]tls.Store `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty"`
Certificates []*tls.CertAndStores `json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" label:"-" export:"true"`
Options map[string]tls.Options `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
Stores map[string]tls.Store `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty" export:"true"`
}

View file

@ -13,58 +13,58 @@ import (
// HTTPConfiguration contains all the HTTP configuration parameters.
type HTTPConfiguration struct {
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
Models map[string]*Model `json:"models,omitempty" toml:"models,omitempty" yaml:"models,omitempty"`
ServersTransports map[string]*ServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-"`
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
Models map[string]*Model `json:"models,omitempty" toml:"models,omitempty" yaml:"models,omitempty" export:"true"`
ServersTransports map[string]*ServersTransport `json:"serversTransports,omitempty" toml:"serversTransports,omitempty" yaml:"serversTransports,omitempty" label:"-" export:"true"`
}
// +k8s:deepcopy-gen=true
// Model is a set of default router's values.
type Model struct {
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Service holds a service configuration (can only be of one type at the same time).
type Service struct {
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-"`
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-" export:"true"`
}
// +k8s:deepcopy-gen=true
// Router holds the router configuration.
type Router struct {
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty"`
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// RouterTLSConfig holds the TLS configuration for a router.
type RouterTLSConfig struct {
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Mirroring holds the Mirroring configuration.
type Mirroring struct {
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty"`
Mirrors []MirrorService `json:"mirrors,omitempty" toml:"mirrors,omitempty" yaml:"mirrors,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty" export:"true"`
Mirrors []MirrorService `json:"mirrors,omitempty" toml:"mirrors,omitempty" yaml:"mirrors,omitempty" export:"true"`
}
// SetDefaults Default values for a WRRService.
@ -77,24 +77,24 @@ func (m *Mirroring) SetDefaults() {
// MirrorService holds the MirrorService configuration.
type MirrorService struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Percent int `json:"percent,omitempty" toml:"percent,omitempty" yaml:"percent,omitempty"`
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
Percent int `json:"percent,omitempty" toml:"percent,omitempty" yaml:"percent,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// WeightedRoundRobin is a weighted round robin load-balancer of services.
type WeightedRoundRobin struct {
Services []WRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty"`
Services []WRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// WRRService is a reference to a service load-balanced with weighted round robin.
type WRRService struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
}
// SetDefaults Default values for a WRRService.
@ -107,29 +107,29 @@ func (w *WRRService) SetDefaults() {
// Sticky holds the sticky configuration.
type Sticky struct {
Cookie *Cookie `json:"cookie,omitempty" toml:"cookie,omitempty" yaml:"cookie,omitempty" label:"allowEmpty" file:"allowEmpty"`
Cookie *Cookie `json:"cookie,omitempty" toml:"cookie,omitempty" yaml:"cookie,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Cookie holds the sticky configuration based on cookie.
type Cookie struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty"`
HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty"`
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty"`
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty" export:"true"`
HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty" export:"true"`
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// ServersLoadBalancer holds the ServersLoadBalancer configuration.
type ServersLoadBalancer struct {
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty" file:"allowEmpty"`
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
PassHostHeader *bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty"`
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty"`
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty" export:"true"`
PassHostHeader *bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader" export:"true"`
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty" export:"true"`
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty" export:"true"`
}
// Mergeable tells if the given service is mergeable.
@ -159,7 +159,7 @@ func (l *ServersLoadBalancer) SetDefaults() {
// ResponseForwarding holds configuration for the forward of the response.
type ResponseForwarding struct {
FlushInterval string `json:"flushInterval,omitempty" toml:"flushInterval,omitempty" yaml:"flushInterval,omitempty"`
FlushInterval string `json:"flushInterval,omitempty" toml:"flushInterval,omitempty" yaml:"flushInterval,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -180,16 +180,16 @@ func (s *Server) SetDefaults() {
// HealthCheck holds the HealthCheck configuration.
type HealthCheck struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty"`
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"`
// FIXME change string to ptypes.Duration
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty"`
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"`
// FIXME change string to ptypes.Duration
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty"`
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty" export:"true"`
Hostname string `json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
FollowRedirects *bool `json:"followRedirects" toml:"followRedirects" yaml:"followRedirects"`
Headers map[string]string `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
FollowRedirects *bool `json:"followRedirects" toml:"followRedirects" yaml:"followRedirects" export:"true"`
Headers map[string]string `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
}
// SetDefaults Default values for a HealthCheck.
@ -202,10 +202,10 @@ func (h *HealthCheck) SetDefaults() {
// ServersTransport options to configure communication between Traefik and the servers.
type ServersTransport struct {
ServerName string `description:"ServerName used to contact the server" json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty" export:"true"`
ServerName string `description:"ServerName used to contact the server" json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
Certificates tls.Certificates `description:"Certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty"`
Certificates tls.Certificates `description:"Certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
}

View file

@ -16,30 +16,30 @@ import (
// Middleware holds the Middleware configuration.
type Middleware struct {
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty"`
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" toml:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty" toml:"chain,omitempty" yaml:"chain,omitempty"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty"`
Headers *Headers `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty" toml:"errors,omitempty" yaml:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty" toml:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty" toml:"redirectRegex,omitempty" yaml:"redirectRegex,omitempty"`
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty" toml:"redirectScheme,omitempty" yaml:"redirectScheme,omitempty"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty" toml:"basicAuth,omitempty" yaml:"basicAuth,omitempty"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty" toml:"digestAuth,omitempty" yaml:"digestAuth,omitempty"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty" toml:"forwardAuth,omitempty" yaml:"forwardAuth,omitempty"`
InFlightReq *InFlightReq `json:"inFlightReq,omitempty" toml:"inFlightReq,omitempty" yaml:"inFlightReq,omitempty"`
Buffering *Buffering `json:"buffering,omitempty" toml:"buffering,omitempty" yaml:"buffering,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty" toml:"circuitBreaker,omitempty" yaml:"circuitBreaker,omitempty"`
Compress *Compress `json:"compress,omitempty" toml:"compress,omitempty" yaml:"compress,omitempty" label:"allowEmpty" file:"allowEmpty"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" toml:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty"`
Retry *Retry `json:"retry,omitempty" toml:"retry,omitempty" yaml:"retry,omitempty"`
ContentType *ContentType `json:"contentType,omitempty" toml:"contentType,omitempty" yaml:"contentType,omitempty"`
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty" export:"true"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty" export:"true"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty" export:"true"`
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty" export:"true"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" toml:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty" export:"true"`
Chain *Chain `json:"chain,omitempty" toml:"chain,omitempty" yaml:"chain,omitempty" export:"true"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty" export:"true"`
Headers *Headers `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
Errors *ErrorPage `json:"errors,omitempty" toml:"errors,omitempty" yaml:"errors,omitempty" export:"true"`
RateLimit *RateLimit `json:"rateLimit,omitempty" toml:"rateLimit,omitempty" yaml:"rateLimit,omitempty" export:"true"`
RedirectRegex *RedirectRegex `json:"redirectRegex,omitempty" toml:"redirectRegex,omitempty" yaml:"redirectRegex,omitempty" export:"true"`
RedirectScheme *RedirectScheme `json:"redirectScheme,omitempty" toml:"redirectScheme,omitempty" yaml:"redirectScheme,omitempty" export:"true"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty" toml:"basicAuth,omitempty" yaml:"basicAuth,omitempty" export:"true"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty" toml:"digestAuth,omitempty" yaml:"digestAuth,omitempty" export:"true"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty" toml:"forwardAuth,omitempty" yaml:"forwardAuth,omitempty" export:"true"`
InFlightReq *InFlightReq `json:"inFlightReq,omitempty" toml:"inFlightReq,omitempty" yaml:"inFlightReq,omitempty" export:"true"`
Buffering *Buffering `json:"buffering,omitempty" toml:"buffering,omitempty" yaml:"buffering,omitempty" export:"true"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty" toml:"circuitBreaker,omitempty" yaml:"circuitBreaker,omitempty" export:"true"`
Compress *Compress `json:"compress,omitempty" toml:"compress,omitempty" yaml:"compress,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty" toml:"passTLSClientCert,omitempty" yaml:"passTLSClientCert,omitempty" export:"true"`
Retry *Retry `json:"retry,omitempty" toml:"retry,omitempty" yaml:"retry,omitempty" export:"true"`
ContentType *ContentType `json:"contentType,omitempty" toml:"contentType,omitempty" yaml:"contentType,omitempty" export:"true"`
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty"`
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -54,23 +54,14 @@ type Middleware struct {
// and it is going to be kept that way in order to support users currently relying on it.
// 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 bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty"`
AutoDetect bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// AddPrefix holds the AddPrefix configuration.
type AddPrefix struct {
Prefix string `json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty"`
}
// +k8s:deepcopy-gen=true
// Auth holds the authentication configuration (BASIC, DIGEST, users).
type Auth struct {
Basic *BasicAuth `json:"basic,omitempty" toml:"basic,omitempty" yaml:"basic,omitempty" export:"true"`
Digest *DigestAuth `json:"digest,omitempty" toml:"digest,omitempty" yaml:"digest,omitempty" export:"true"`
Forward *ForwardAuth `json:"forward,omitempty" toml:"forward,omitempty" yaml:"forward,omitempty" export:"true"`
Prefix string `json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -80,7 +71,7 @@ type BasicAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
}
@ -88,25 +79,25 @@ type BasicAuth struct {
// Buffering holds the request/response buffering configuration.
type Buffering struct {
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty" toml:"maxRequestBodyBytes,omitempty" yaml:"maxRequestBodyBytes,omitempty"`
MemRequestBodyBytes int64 `json:"memRequestBodyBytes,omitempty" toml:"memRequestBodyBytes,omitempty" yaml:"memRequestBodyBytes,omitempty"`
MaxResponseBodyBytes int64 `json:"maxResponseBodyBytes,omitempty" toml:"maxResponseBodyBytes,omitempty" yaml:"maxResponseBodyBytes,omitempty"`
MemResponseBodyBytes int64 `json:"memResponseBodyBytes,omitempty" toml:"memResponseBodyBytes,omitempty" yaml:"memResponseBodyBytes,omitempty"`
RetryExpression string `json:"retryExpression,omitempty" toml:"retryExpression,omitempty" yaml:"retryExpression,omitempty"`
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty" toml:"maxRequestBodyBytes,omitempty" yaml:"maxRequestBodyBytes,omitempty" export:"true"`
MemRequestBodyBytes int64 `json:"memRequestBodyBytes,omitempty" toml:"memRequestBodyBytes,omitempty" yaml:"memRequestBodyBytes,omitempty" export:"true"`
MaxResponseBodyBytes int64 `json:"maxResponseBodyBytes,omitempty" toml:"maxResponseBodyBytes,omitempty" yaml:"maxResponseBodyBytes,omitempty" export:"true"`
MemResponseBodyBytes int64 `json:"memResponseBodyBytes,omitempty" toml:"memResponseBodyBytes,omitempty" yaml:"memResponseBodyBytes,omitempty" export:"true"`
RetryExpression string `json:"retryExpression,omitempty" toml:"retryExpression,omitempty" yaml:"retryExpression,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Chain holds a chain of middlewares.
type Chain struct {
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// CircuitBreaker holds the circuit breaker configuration.
type CircuitBreaker struct {
Expression string `json:"expression,omitempty" toml:"expression,omitempty" yaml:"expression,omitempty"`
Expression string `json:"expression,omitempty" toml:"expression,omitempty" yaml:"expression,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -122,7 +113,7 @@ type Compress struct {
type DigestAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
HeaderField string `json:"headerField,omitempty" toml:"headerField,omitempty" yaml:"headerField,omitempty" export:"true"`
}
@ -131,9 +122,9 @@ type DigestAuth struct {
// ErrorPage holds the custom error page configuration.
type ErrorPage struct {
Status []string `json:"status,omitempty" toml:"status,omitempty" yaml:"status,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
Query string `json:"query,omitempty" toml:"query,omitempty" yaml:"query,omitempty"`
Status []string `json:"status,omitempty" toml:"status,omitempty" yaml:"status,omitempty" export:"true"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
Query string `json:"query,omitempty" toml:"query,omitempty" yaml:"query,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -141,26 +132,26 @@ type ErrorPage struct {
// ForwardAuth holds the http forward authentication configuration.
type ForwardAuth struct {
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty"`
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty"`
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty"`
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty" export:"true"`
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty" export:"true"`
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Headers holds the custom header configuration.
type Headers struct {
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty" toml:"customRequestHeaders,omitempty" yaml:"customRequestHeaders,omitempty"`
CustomResponseHeaders map[string]string `json:"customResponseHeaders,omitempty" toml:"customResponseHeaders,omitempty" yaml:"customResponseHeaders,omitempty"`
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty" toml:"customRequestHeaders,omitempty" yaml:"customRequestHeaders,omitempty" export:"true"`
CustomResponseHeaders map[string]string `json:"customResponseHeaders,omitempty" toml:"customResponseHeaders,omitempty" yaml:"customResponseHeaders,omitempty" export:"true"`
// AccessControlAllowCredentials is only valid if true. false is ignored.
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty" toml:"accessControlAllowCredentials,omitempty" yaml:"accessControlAllowCredentials,omitempty"`
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty" toml:"accessControlAllowCredentials,omitempty" yaml:"accessControlAllowCredentials,omitempty" export:"true"`
// AccessControlAllowHeaders must be used in response to a preflight request with Access-Control-Request-Headers set.
AccessControlAllowHeaders []string `json:"accessControlAllowHeaders,omitempty" toml:"accessControlAllowHeaders,omitempty" yaml:"accessControlAllowHeaders,omitempty"`
AccessControlAllowHeaders []string `json:"accessControlAllowHeaders,omitempty" toml:"accessControlAllowHeaders,omitempty" yaml:"accessControlAllowHeaders,omitempty" export:"true"`
// AccessControlAllowMethods must be used in response to a preflight request with Access-Control-Request-Method set.
AccessControlAllowMethods []string `json:"accessControlAllowMethods,omitempty" toml:"accessControlAllowMethods,omitempty" yaml:"accessControlAllowMethods,omitempty"`
AccessControlAllowMethods []string `json:"accessControlAllowMethods,omitempty" toml:"accessControlAllowMethods,omitempty" yaml:"accessControlAllowMethods,omitempty" export:"true"`
// AccessControlAllowOrigin Can be "origin-list-or-null" or "*". From (https://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
AccessControlAllowOrigin string `json:"accessControlAllowOrigin,omitempty" toml:"accessControlAllowOrigin,omitempty" yaml:"accessControlAllowOrigin,omitempty"` // Deprecated
// AccessControlAllowOriginList is a list of allowable origins. Can also be a wildcard origin "*".
@ -168,33 +159,33 @@ type Headers struct {
// AccessControlAllowOriginListRegex is a list of allowable origins written following the Regular Expression syntax (https://golang.org/pkg/regexp/).
AccessControlAllowOriginListRegex []string `json:"accessControlAllowOriginListRegex,omitempty" toml:"accessControlAllowOriginListRegex,omitempty" yaml:"accessControlAllowOriginListRegex,omitempty"`
// AccessControlExposeHeaders sets valid headers for the response.
AccessControlExposeHeaders []string `json:"accessControlExposeHeaders,omitempty" toml:"accessControlExposeHeaders,omitempty" yaml:"accessControlExposeHeaders,omitempty"`
AccessControlExposeHeaders []string `json:"accessControlExposeHeaders,omitempty" toml:"accessControlExposeHeaders,omitempty" yaml:"accessControlExposeHeaders,omitempty" export:"true"`
// AccessControlMaxAge sets the time that a preflight request may be cached.
AccessControlMaxAge int64 `json:"accessControlMaxAge,omitempty" toml:"accessControlMaxAge,omitempty" yaml:"accessControlMaxAge,omitempty"`
AccessControlMaxAge int64 `json:"accessControlMaxAge,omitempty" toml:"accessControlMaxAge,omitempty" yaml:"accessControlMaxAge,omitempty" export:"true"`
// AddVaryHeader controls if the Vary header is automatically added/updated when the AccessControlAllowOrigin is set.
AddVaryHeader bool `json:"addVaryHeader,omitempty" toml:"addVaryHeader,omitempty" yaml:"addVaryHeader,omitempty"`
AddVaryHeader bool `json:"addVaryHeader,omitempty" toml:"addVaryHeader,omitempty" yaml:"addVaryHeader,omitempty" export:"true"`
AllowedHosts []string `json:"allowedHosts,omitempty" toml:"allowedHosts,omitempty" yaml:"allowedHosts,omitempty"`
HostsProxyHeaders []string `json:"hostsProxyHeaders,omitempty" toml:"hostsProxyHeaders,omitempty" yaml:"hostsProxyHeaders,omitempty"`
SSLRedirect bool `json:"sslRedirect,omitempty" toml:"sslRedirect,omitempty" yaml:"sslRedirect,omitempty"`
SSLTemporaryRedirect bool `json:"sslTemporaryRedirect,omitempty" toml:"sslTemporaryRedirect,omitempty" yaml:"sslTemporaryRedirect,omitempty"`
HostsProxyHeaders []string `json:"hostsProxyHeaders,omitempty" toml:"hostsProxyHeaders,omitempty" yaml:"hostsProxyHeaders,omitempty" export:"true"`
SSLRedirect bool `json:"sslRedirect,omitempty" toml:"sslRedirect,omitempty" yaml:"sslRedirect,omitempty" export:"true"`
SSLTemporaryRedirect bool `json:"sslTemporaryRedirect,omitempty" toml:"sslTemporaryRedirect,omitempty" yaml:"sslTemporaryRedirect,omitempty" export:"true"`
SSLHost string `json:"sslHost,omitempty" toml:"sslHost,omitempty" yaml:"sslHost,omitempty"`
SSLProxyHeaders map[string]string `json:"sslProxyHeaders,omitempty" toml:"sslProxyHeaders,omitempty" yaml:"sslProxyHeaders,omitempty"`
SSLForceHost bool `json:"sslForceHost,omitempty" toml:"sslForceHost,omitempty" yaml:"sslForceHost,omitempty"`
STSSeconds int64 `json:"stsSeconds,omitempty" toml:"stsSeconds,omitempty" yaml:"stsSeconds,omitempty"`
STSIncludeSubdomains bool `json:"stsIncludeSubdomains,omitempty" toml:"stsIncludeSubdomains,omitempty" yaml:"stsIncludeSubdomains,omitempty"`
STSPreload bool `json:"stsPreload,omitempty" toml:"stsPreload,omitempty" yaml:"stsPreload,omitempty"`
ForceSTSHeader bool `json:"forceSTSHeader,omitempty" toml:"forceSTSHeader,omitempty" yaml:"forceSTSHeader,omitempty"`
FrameDeny bool `json:"frameDeny,omitempty" toml:"frameDeny,omitempty" yaml:"frameDeny,omitempty"`
SSLForceHost bool `json:"sslForceHost,omitempty" toml:"sslForceHost,omitempty" yaml:"sslForceHost,omitempty" export:"true"`
STSSeconds int64 `json:"stsSeconds,omitempty" toml:"stsSeconds,omitempty" yaml:"stsSeconds,omitempty" export:"true"`
STSIncludeSubdomains bool `json:"stsIncludeSubdomains,omitempty" toml:"stsIncludeSubdomains,omitempty" yaml:"stsIncludeSubdomains,omitempty" export:"true"`
STSPreload bool `json:"stsPreload,omitempty" toml:"stsPreload,omitempty" yaml:"stsPreload,omitempty" export:"true"`
ForceSTSHeader bool `json:"forceSTSHeader,omitempty" toml:"forceSTSHeader,omitempty" yaml:"forceSTSHeader,omitempty" export:"true"`
FrameDeny bool `json:"frameDeny,omitempty" toml:"frameDeny,omitempty" yaml:"frameDeny,omitempty" export:"true"`
CustomFrameOptionsValue string `json:"customFrameOptionsValue,omitempty" toml:"customFrameOptionsValue,omitempty" yaml:"customFrameOptionsValue,omitempty"`
ContentTypeNosniff bool `json:"contentTypeNosniff,omitempty" toml:"contentTypeNosniff,omitempty" yaml:"contentTypeNosniff,omitempty"`
BrowserXSSFilter bool `json:"browserXssFilter,omitempty" toml:"browserXssFilter,omitempty" yaml:"browserXssFilter,omitempty"`
ContentTypeNosniff bool `json:"contentTypeNosniff,omitempty" toml:"contentTypeNosniff,omitempty" yaml:"contentTypeNosniff,omitempty" export:"true"`
BrowserXSSFilter bool `json:"browserXssFilter,omitempty" toml:"browserXssFilter,omitempty" yaml:"browserXssFilter,omitempty" export:"true"`
CustomBrowserXSSValue string `json:"customBrowserXSSValue,omitempty" toml:"customBrowserXSSValue,omitempty" yaml:"customBrowserXSSValue,omitempty"`
ContentSecurityPolicy string `json:"contentSecurityPolicy,omitempty" toml:"contentSecurityPolicy,omitempty" yaml:"contentSecurityPolicy,omitempty"`
PublicKey string `json:"publicKey,omitempty" toml:"publicKey,omitempty" yaml:"publicKey,omitempty"`
ReferrerPolicy string `json:"referrerPolicy,omitempty" toml:"referrerPolicy,omitempty" yaml:"referrerPolicy,omitempty"`
FeaturePolicy string `json:"featurePolicy,omitempty" toml:"featurePolicy,omitempty" yaml:"featurePolicy,omitempty"`
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty"`
ReferrerPolicy string `json:"referrerPolicy,omitempty" toml:"referrerPolicy,omitempty" yaml:"referrerPolicy,omitempty" export:"true"`
FeaturePolicy string `json:"featurePolicy,omitempty" toml:"featurePolicy,omitempty" yaml:"featurePolicy,omitempty" export:"true"`
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty" export:"true"`
}
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set.
@ -282,23 +273,23 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
// IPWhiteList holds the ip white list configuration.
type IPWhiteList struct {
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// InFlightReq limits the number of requests being processed and served concurrently.
type InFlightReq struct {
Amount int64 `json:"amount,omitempty" toml:"amount,omitempty" yaml:"amount,omitempty"`
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty"`
Amount int64 `json:"amount,omitempty" toml:"amount,omitempty" yaml:"amount,omitempty" export:"true"`
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// PassTLSClientCert holds the TLS client cert headers configuration.
type PassTLSClientCert struct {
PEM bool `json:"pem,omitempty" toml:"pem,omitempty" yaml:"pem,omitempty"`
Info *TLSClientCertificateInfo `json:"info,omitempty" toml:"info,omitempty" yaml:"info,omitempty"`
PEM bool `json:"pem,omitempty" toml:"pem,omitempty" yaml:"pem,omitempty" export:"true"`
Info *TLSClientCertificateInfo `json:"info,omitempty" toml:"info,omitempty" yaml:"info,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -307,9 +298,9 @@ type PassTLSClientCert struct {
// If none are set, the default is to use the request's remote address field.
// All fields are mutually exclusive.
type SourceCriterion struct {
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty"`
RequestHeaderName string `json:"requestHeaderName,omitempty" toml:"requestHeaderName,omitempty" yaml:"requestHeaderName,omitempty"`
RequestHost bool `json:"requestHost,omitempty" toml:"requestHost,omitempty" yaml:"requestHost,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" export:"true"`
RequestHeaderName string `json:"requestHeaderName,omitempty" toml:"requestHeaderName,omitempty" yaml:"requestHeaderName,omitempty" export:"true"`
RequestHost bool `json:"requestHost,omitempty" toml:"requestHost,omitempty" yaml:"requestHost,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -320,17 +311,17 @@ type RateLimit struct {
// It defaults to 0, which means no rate limiting.
// The rate is actually defined by dividing Average by Period. So for a rate below 1req/s,
// one needs to define a Period larger than a second.
Average int64 `json:"average,omitempty" toml:"average,omitempty" yaml:"average,omitempty"`
Average int64 `json:"average,omitempty" toml:"average,omitempty" yaml:"average,omitempty" export:"true"`
// Period, in combination with Average, defines the actual maximum rate, such as:
// r = Average / Period. It defaults to a second.
Period ptypes.Duration `json:"period,omitempty" toml:"period,omitempty" yaml:"period,omitempty"`
Period ptypes.Duration `json:"period,omitempty" toml:"period,omitempty" yaml:"period,omitempty" export:"true"`
// Burst is the maximum number of requests allowed to arrive in the same arbitrarily small period of time.
// It defaults to 1.
Burst int64 `json:"burst,omitempty" toml:"burst,omitempty" yaml:"burst,omitempty"`
Burst int64 `json:"burst,omitempty" toml:"burst,omitempty" yaml:"burst,omitempty" export:"true"`
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty"`
SourceCriterion *SourceCriterion `json:"sourceCriterion,omitempty" toml:"sourceCriterion,omitempty" yaml:"sourceCriterion,omitempty" export:"true"`
}
// SetDefaults sets the default values on a RateLimit.
@ -345,47 +336,47 @@ func (r *RateLimit) SetDefaults() {
type RedirectRegex struct {
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// RedirectScheme holds the scheme redirection configuration.
type RedirectScheme struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty" export:"true"`
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// ReplacePath holds the ReplacePath configuration.
type ReplacePath struct {
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// ReplacePathRegex holds the ReplacePathRegex configuration.
type ReplacePathRegex struct {
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty"`
Regex string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty" export:"true"`
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// Retry holds the retry configuration.
type Retry struct {
Attempts int `json:"attempts,omitempty" toml:"attempts,omitempty" yaml:"attempts,omitempty"`
InitialInterval ptypes.Duration `json:"initialInterval,omitempty" toml:"initialInterval,omitempty" yaml:"initialInterval,omitempty"`
Attempts int `json:"attempts,omitempty" toml:"attempts,omitempty" yaml:"attempts,omitempty" export:"true"`
InitialInterval ptypes.Duration `json:"initialInterval,omitempty" toml:"initialInterval,omitempty" yaml:"initialInterval,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// StripPrefix holds the StripPrefix configuration.
type StripPrefix struct {
Prefixes []string `json:"prefixes,omitempty" toml:"prefixes,omitempty" yaml:"prefixes,omitempty"`
ForceSlash bool `json:"forceSlash,omitempty" toml:"forceSlash,omitempty" yaml:"forceSlash,omitempty"` // Deprecated
Prefixes []string `json:"prefixes,omitempty" toml:"prefixes,omitempty" yaml:"prefixes,omitempty" export:"true"`
ForceSlash bool `json:"forceSlash,omitempty" toml:"forceSlash,omitempty" yaml:"forceSlash,omitempty" export:"true"` // Deprecated
}
// SetDefaults Default values for a StripPrefix.
@ -397,33 +388,33 @@ func (s *StripPrefix) SetDefaults() {
// StripPrefixRegex holds the StripPrefixRegex configuration.
type StripPrefixRegex struct {
Regex []string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty"`
Regex []string `json:"regex,omitempty" toml:"regex,omitempty" yaml:"regex,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TLSClientCertificateInfo holds the client TLS certificate info configuration.
type TLSClientCertificateInfo struct {
NotAfter bool `json:"notAfter,omitempty" toml:"notAfter,omitempty" yaml:"notAfter,omitempty"`
NotBefore bool `json:"notBefore,omitempty" toml:"notBefore,omitempty" yaml:"notBefore,omitempty"`
Sans bool `json:"sans,omitempty" toml:"sans,omitempty" yaml:"sans,omitempty"`
Subject *TLSCLientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty"`
Issuer *TLSCLientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty"`
NotAfter bool `json:"notAfter,omitempty" toml:"notAfter,omitempty" yaml:"notAfter,omitempty" export:"true"`
NotBefore bool `json:"notBefore,omitempty" toml:"notBefore,omitempty" yaml:"notBefore,omitempty" export:"true"`
Sans bool `json:"sans,omitempty" toml:"sans,omitempty" yaml:"sans,omitempty" export:"true"`
Subject *TLSCLientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty" export:"true"`
Issuer *TLSCLientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty" export:"true"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration.
// cf https://tools.ietf.org/html/rfc3739
type TLSCLientCertificateDNInfo struct {
Country bool `json:"country,omitempty" toml:"country,omitempty" yaml:"country,omitempty"`
Province bool `json:"province,omitempty" toml:"province,omitempty" yaml:"province,omitempty"`
Locality bool `json:"locality,omitempty" toml:"locality,omitempty" yaml:"locality,omitempty"`
Organization bool `json:"organization,omitempty" toml:"organization,omitempty" yaml:"organization,omitempty"`
CommonName bool `json:"commonName,omitempty" toml:"commonName,omitempty" yaml:"commonName,omitempty"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty"`
DomainComponent bool `json:"domainComponent,omitempty" toml:"domainComponent,omitempty" yaml:"domainComponent,omitempty"`
Country bool `json:"country,omitempty" toml:"country,omitempty" yaml:"country,omitempty" export:"true"`
Province bool `json:"province,omitempty" toml:"province,omitempty" yaml:"province,omitempty" export:"true"`
Locality bool `json:"locality,omitempty" toml:"locality,omitempty" yaml:"locality,omitempty" export:"true"`
Organization bool `json:"organization,omitempty" toml:"organization,omitempty" yaml:"organization,omitempty" export:"true"`
CommonName bool `json:"commonName,omitempty" toml:"commonName,omitempty" yaml:"commonName,omitempty" export:"true"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty" export:"true"`
DomainComponent bool `json:"domainComponent,omitempty" toml:"domainComponent,omitempty" yaml:"domainComponent,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -437,10 +428,10 @@ type Users []string
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
CAOptional bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty"`
CAOptional bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
Cert string `json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.

View file

@ -10,31 +10,31 @@ import (
// TCPConfiguration contains all the TCP configuration parameters.
type TCPConfiguration struct {
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
Services map[string]*TCPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TCPService holds a tcp service configuration (can only be of one type at the same time).
type TCPService struct {
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
Weighted *TCPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
Weighted *TCPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
}
// +k8s:deepcopy-gen=true
// TCPWeightedRoundRobin is a weighted round robin tcp load-balancer of services.
type TCPWeightedRoundRobin struct {
Services []TCPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Services []TCPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TCPWRRService is a reference to a tcp service load-balanced with weighted round robin.
type TCPWRRService struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
}
// SetDefaults Default values for a TCPWRRService.
@ -47,20 +47,20 @@ func (w *TCPWRRService) SetDefaults() {
// TCPRouter holds the router configuration.
type TCPRouter struct {
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// RouterTCPTLSConfig holds the TLS configuration for a router.
type RouterTCPTLSConfig struct {
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough" export:"true"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -72,9 +72,9 @@ type TCPServersLoadBalancer struct {
// 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).
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty"`
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty"`
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty" export:"true"`
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
}
// SetDefaults Default values for a TCPServersLoadBalancer.
@ -112,7 +112,7 @@ type TCPServer struct {
// ProxyProtocol holds the ProxyProtocol configuration.
type ProxyProtocol struct {
Version int `json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty"`
Version int `json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty" export:"true"`
}
// SetDefaults Default values for a ProxyProtocol.

View file

@ -8,31 +8,31 @@ import (
// UDPConfiguration contains all the UDP configuration parameters.
type UDPConfiguration struct {
Routers map[string]*UDPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
Services map[string]*UDPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Routers map[string]*UDPRouter `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty" export:"true"`
Services map[string]*UDPService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// UDPService defines the configuration for a UDP service. All fields are mutually exclusive.
type UDPService struct {
LoadBalancer *UDPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
Weighted *UDPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
LoadBalancer *UDPServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
Weighted *UDPWeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
}
// +k8s:deepcopy-gen=true
// UDPWeightedRoundRobin is a weighted round robin UDP load-balancer of services.
type UDPWeightedRoundRobin struct {
Services []UDPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
Services []UDPWRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// UDPWRRService is a reference to a UDP service load-balanced with weighted round robin.
type UDPWRRService struct {
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty" export:"true"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
}
// SetDefaults sets the default values for a UDPWRRService.
@ -45,15 +45,15 @@ func (w *UDPWRRService) SetDefaults() {
// UDPRouter defines the configuration for an UDP router.
type UDPRouter struct {
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// UDPServersLoadBalancer defines the configuration for a load-balancer of UDP servers.
type UDPServersLoadBalancer struct {
Servers []UDPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
Servers []UDPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
}
// Mergeable reports whether the given load-balancer can be merged with the receiver.

View file

@ -49,37 +49,6 @@ func (in *AddPrefix) DeepCopy() *AddPrefix {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Auth) DeepCopyInto(out *Auth) {
*out = *in
if in.Basic != nil {
in, out := &in.Basic, &out.Basic
*out = new(BasicAuth)
(*in).DeepCopyInto(*out)
}
if in.Digest != nil {
in, out := &in.Digest, &out.Digest
*out = new(DigestAuth)
(*in).DeepCopyInto(*out)
}
if in.Forward != nil {
in, out := &in.Forward, &out.Forward
*out = new(ForwardAuth)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth.
func (in *Auth) DeepCopy() *Auth {
if in == nil {
return nil
}
out := new(Auth)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BasicAuth) DeepCopyInto(out *BasicAuth) {
*out = *in

View file

@ -5,57 +5,56 @@ import (
"context"
"encoding/json"
"fmt"
"hash/fnv"
"io/ioutil"
"net/http"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/anonymize"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/safe"
"github.com/traefik/traefik/v2/pkg/version"
)
const baseURL = "https://instance-info.pilot.traefik.io/public"
const tokenHeader = "X-Token"
const (
pilotTimer = 5 * time.Minute
maxElapsedTime = 4 * time.Minute
baseInstanceInfoURL = "https://instance-info.pilot.traefik.io/public"
baseGatewayURL = "https://gateway.pilot.traefik.io"
)
// RunTimeRepresentation is the configuration information exposed by the API handler.
type RunTimeRepresentation struct {
Routers map[string]*runtime.RouterInfo `json:"routers,omitempty"`
Middlewares map[string]*runtime.MiddlewareInfo `json:"middlewares,omitempty"`
Services map[string]*serviceInfoRepresentation `json:"services,omitempty"`
TCPRouters map[string]*runtime.TCPRouterInfo `json:"tcpRouters,omitempty"`
TCPServices map[string]*runtime.TCPServiceInfo `json:"tcpServices,omitempty"`
UDPRouters map[string]*runtime.UDPRouterInfo `json:"udpRouters,omitempty"`
UDPServices map[string]*runtime.UDPServiceInfo `json:"udpServices,omitempty"`
}
const (
tokenHeader = "X-Token"
tokenHashHeader = "X-Token-Hash"
)
type serviceInfoRepresentation struct {
*runtime.ServiceInfo
ServerStatus map[string]string `json:"serverStatus,omitempty"`
}
const (
pilotInstanceInfoTimer = 5 * time.Minute
pilotDynConfTimer = 12 * time.Hour
maxElapsedTime = 4 * time.Minute
)
type instanceInfo struct {
ID string `json:"id,omitempty"`
Configuration RunTimeRepresentation `json:"configuration,omitempty"`
Metrics []metrics.PilotMetric `json:"metrics,omitempty"`
ID string `json:"id,omitempty"`
Metrics []metrics.PilotMetric `json:"metrics,omitempty"`
}
// New creates a new Pilot.
func New(token string, metricsRegistry *metrics.PilotRegistry, pool *safe.Pool) *Pilot {
tokenHash := fnv.New64a()
// the `sum64a` implementation of the `Write` method never returns an error.
_, _ = tokenHash.Write([]byte(token))
return &Pilot{
rtConfChan: make(chan *runtime.Configuration),
dynamicConfigCh: make(chan dynamic.Configuration),
client: &client{
token: token,
httpClient: &http.Client{Timeout: 5 * time.Second},
baseURL: baseURL,
token: token,
tokenHash: fmt.Sprintf("%x", tokenHash.Sum64()),
httpClient: &http.Client{Timeout: 5 * time.Second},
baseInstanceInfoURL: baseInstanceInfoURL,
baseGatewayURL: baseGatewayURL,
},
routinesPool: pool,
metricsRegistry: metricsRegistry,
@ -67,44 +66,25 @@ type Pilot struct {
routinesPool *safe.Pool
client *client
rtConf *runtime.Configuration
rtConfChan chan *runtime.Configuration
dynamicConfig dynamic.Configuration
dynamicConfigCh chan dynamic.Configuration
metricsRegistry *metrics.PilotRegistry
}
// SetRuntimeConfiguration stores the runtime configuration.
func (p *Pilot) SetRuntimeConfiguration(rtConf *runtime.Configuration) {
p.rtConfChan <- rtConf
// SetDynamicConfiguration stores the dynamic configuration.
func (p *Pilot) SetDynamicConfiguration(dynamicConfig dynamic.Configuration) {
p.dynamicConfigCh <- dynamicConfig
}
func (p *Pilot) getRepresentation() RunTimeRepresentation {
if p.rtConf == nil {
return RunTimeRepresentation{}
func (p *Pilot) sendAnonDynConf(ctx context.Context, config dynamic.Configuration) {
err := p.client.SendAnonDynConf(ctx, config)
if err != nil {
log.WithoutContext().Error(err)
}
siRepr := make(map[string]*serviceInfoRepresentation, len(p.rtConf.Services))
for k, v := range p.rtConf.Services {
siRepr[k] = &serviceInfoRepresentation{
ServiceInfo: v,
ServerStatus: v.GetAllStatus(),
}
}
result := RunTimeRepresentation{
Routers: p.rtConf.Routers,
Middlewares: p.rtConf.Middlewares,
Services: siRepr,
TCPRouters: p.rtConf.TCPRouters,
TCPServices: p.rtConf.TCPServices,
UDPRouters: p.rtConf.UDPRouters,
UDPServices: p.rtConf.UDPServices,
}
return result
}
func (p *Pilot) sendData(ctx context.Context, conf RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) {
err := p.client.SendData(ctx, conf, pilotMetrics)
func (p *Pilot) sendInstanceInfo(ctx context.Context, pilotMetrics []metrics.PilotMetric) {
err := p.client.SendInstanceInfo(ctx, pilotMetrics)
if err != nil {
log.WithoutContext().Error(err)
}
@ -112,35 +92,33 @@ func (p *Pilot) sendData(ctx context.Context, conf RunTimeRepresentation, pilotM
// Tick sends data periodically.
func (p *Pilot) Tick(ctx context.Context) {
select {
case rtConf := <-p.rtConfChan:
p.rtConf = rtConf
break
case <-ctx.Done():
return
}
conf := p.getRepresentation()
pilotMetrics := p.metricsRegistry.Data()
p.routinesPool.GoCtx(func(ctxRt context.Context) {
p.sendData(ctxRt, conf, pilotMetrics)
p.sendInstanceInfo(ctxRt, pilotMetrics)
})
ticker := time.NewTicker(pilotTimer)
instanceInfoTicker := time.NewTicker(pilotInstanceInfoTimer)
dynConfTicker := time.NewTicker(pilotDynConfTimer)
for {
select {
case tick := <-ticker.C:
log.WithoutContext().Debugf("Send to pilot: %s", tick)
case tick := <-instanceInfoTicker.C:
log.WithoutContext().Debugf("Send instance info to pilot: %s", tick)
conf := p.getRepresentation()
pilotMetrics := p.metricsRegistry.Data()
p.routinesPool.GoCtx(func(ctxRt context.Context) {
p.sendData(ctxRt, conf, pilotMetrics)
p.sendInstanceInfo(ctxRt, pilotMetrics)
})
case rtConf := <-p.rtConfChan:
p.rtConf = rtConf
case tick := <-dynConfTicker.C:
log.WithoutContext().Debugf("Send anonymized dynamic configuration to pilot: %s", tick)
p.routinesPool.GoCtx(func(ctxRt context.Context) {
p.sendAnonDynConf(ctxRt, p.dynamicConfig)
})
case dynamicConfig := <-p.dynamicConfigCh:
p.dynamicConfig = dynamicConfig
case <-ctx.Done():
return
}
@ -148,15 +126,17 @@ func (p *Pilot) Tick(ctx context.Context) {
}
type client struct {
httpClient *http.Client
baseURL string
token string
uuid string
httpClient *http.Client
baseInstanceInfoURL string
baseGatewayURL string
token string
tokenHash string
uuid string
}
func (c *client) createUUID() (string, error) {
data := []byte(`{"version":"` + version.Version + `","codeName":"` + version.Codename + `"}`)
req, err := http.NewRequest(http.MethodPost, c.baseURL+"/", bytes.NewBuffer(data))
req, err := http.NewRequest(http.MethodPost, c.baseInstanceInfoURL+"/", bytes.NewBuffer(data))
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
@ -189,22 +169,23 @@ func (c *client) createUUID() (string, error) {
return created.ID, nil
}
// SendData sends data to Pilot.
func (c *client) SendData(ctx context.Context, rtConf RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) error {
exponentialBackOff := backoff.NewExponentialBackOff()
exponentialBackOff.MaxElapsedTime = maxElapsedTime
// SendAnonDynConf sends anonymized dynamic configuration to Pilot.
func (c *client) SendAnonDynConf(ctx context.Context, config dynamic.Configuration) error {
anonConfig, err := anonymize.Do(&config, false)
if err != nil {
return fmt.Errorf("unable to anonymize dynamic configuration: %w", err)
}
return backoff.RetryNotify(
func() error {
return c.sendData(rtConf, pilotMetrics)
},
backoff.WithContext(exponentialBackOff, ctx),
func(err error, duration time.Duration) {
log.WithoutContext().Errorf("retry in %s due to: %v ", duration, err)
})
req, err := http.NewRequest(http.MethodPost, c.baseGatewayURL+"/collect", bytes.NewReader([]byte(anonConfig)))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
return c.sendDataRetryable(ctx, req)
}
func (c *client) sendData(_ RunTimeRepresentation, pilotMetrics []metrics.PilotMetric) error {
// SendInstanceInfo sends instance information to Pilot.
func (c *client) SendInstanceInfo(ctx context.Context, pilotMetrics []metrics.PilotMetric) error {
if len(c.uuid) == 0 {
var err error
c.uuid, err = c.createUUID()
@ -225,29 +206,45 @@ func (c *client) sendData(_ RunTimeRepresentation, pilotMetrics []metrics.PilotM
return fmt.Errorf("failed to marshall request body: %w", err)
}
request, err := http.NewRequest(http.MethodPost, c.baseURL+"/command", bytes.NewBuffer(b))
req, err := http.NewRequest(http.MethodPost, c.baseInstanceInfoURL+"/command", bytes.NewReader(b))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
return fmt.Errorf("failed to create instance info request: %w", err)
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set(tokenHeader, c.token)
req.Header.Set(tokenHeader, c.token)
resp, err := c.httpClient.Do(request)
if err != nil {
return fmt.Errorf("failed to call Pilot: %w", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("wrong status code while sending configuration: %d: %s", resp.StatusCode, body)
}
return nil
return c.sendDataRetryable(ctx, req)
}
func (c *client) sendDataRetryable(ctx context.Context, req *http.Request) error {
exponentialBackOff := backoff.NewExponentialBackOff()
exponentialBackOff.MaxElapsedTime = maxElapsedTime
req.Header.Set("Content-Type", "application/json")
req.Header.Set(tokenHashHeader, c.tokenHash)
return backoff.RetryNotify(
func() error {
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("failed to call Pilot: %w", err)
}
defer func() { _ = resp.Body.Close() }()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("wrong status code while sending configuration: %d: %s", resp.StatusCode, body)
}
return nil
},
backoff.WithContext(exponentialBackOff, ctx),
func(err error, duration time.Duration) {
log.WithoutContext().Errorf("retry in %s due to: %v ", duration, err)
})
}

View file

@ -4,13 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
"hash/fnv"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/safe"
)
@ -45,15 +48,16 @@ func TestTick(t *testing.T) {
})
pilot := New("token", metrics.RegisterPilot(), safe.NewPool(context.Background()))
pilot.client.baseURL = server.URL
pilot.client.baseInstanceInfoURL = server.URL
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
go pilot.Tick(ctx)
pilot.SetRuntimeConfiguration(&runtime.Configuration{})
pilot.SetRuntimeConfiguration(&runtime.Configuration{})
pilot.SetDynamicConfiguration(dynamic.Configuration{})
pilot.SetDynamicConfiguration(dynamic.Configuration{})
select {
case <-time.Tick(10 * time.Second):
@ -63,9 +67,12 @@ func TestTick(t *testing.T) {
}
}
func TestClient_SendConfiguration(t *testing.T) {
func TestClient_SendInstanceInfo(t *testing.T) {
myToken := "myToken"
myTokenHash, err := hashToken(myToken)
require.NoError(t, err)
mux := http.NewServeMux()
server := httptest.NewServer(mux)
t.Cleanup(server.Close)
@ -79,6 +86,7 @@ func TestClient_SendConfiguration(t *testing.T) {
tk := req.Header.Get(tokenHeader)
if tk != myToken {
http.Error(rw, fmt.Sprintf("invalid token: %s", tk), http.StatusUnauthorized)
return
}
err := json.NewEncoder(rw).Encode(instanceInfo{ID: "123"})
@ -97,9 +105,16 @@ func TestClient_SendConfiguration(t *testing.T) {
tk := req.Header.Get(tokenHeader)
if tk != myToken {
http.Error(rw, fmt.Sprintf("invalid token: %s", tk), http.StatusUnauthorized)
return
}
defer req.Body.Close()
tkh := req.Header.Get(tokenHashHeader)
if tkh != myTokenHash {
http.Error(rw, fmt.Sprintf("invalid token hash: %s", tkh), http.StatusBadRequest)
return
}
defer func() { _ = req.Body.Close() }()
info := &instanceInfo{}
err := json.NewDecoder(req.Body).Decode(info)
@ -114,11 +129,97 @@ func TestClient_SendConfiguration(t *testing.T) {
})
client := client{
baseURL: server.URL,
httpClient: http.DefaultClient,
token: myToken,
baseInstanceInfoURL: server.URL,
httpClient: http.DefaultClient,
token: myToken,
tokenHash: myTokenHash,
}
err := client.SendData(context.Background(), RunTimeRepresentation{}, []metrics.PilotMetric{})
err = client.SendInstanceInfo(context.Background(), []metrics.PilotMetric{})
require.NoError(t, err)
}
func TestClient_SendAnonDynConf(t *testing.T) {
myToken := "myToken"
myTokenHash, err := hashToken(myToken)
require.NoError(t, err)
var count int
mux := http.NewServeMux()
mux.HandleFunc("/collect", func(rw http.ResponseWriter, req *http.Request) {
count++
if count == 1 {
http.Error(rw, "OOPS", http.StatusBadRequest)
return
}
if req.Method != http.MethodPost {
http.Error(rw, "invalid method", http.StatusMethodNotAllowed)
return
}
tkh := req.Header.Get(tokenHashHeader)
if tkh != myTokenHash {
http.Error(rw, fmt.Sprintf("invalid token hash: %s", tkh), http.StatusBadRequest)
return
}
defer func() { _ = req.Body.Close() }()
config := &dynamic.Configuration{}
err := json.NewDecoder(req.Body).Decode(config)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
router, exists := config.HTTP.Routers["foo"]
if !exists {
http.Error(rw, "router configuration is missing", http.StatusBadRequest)
return
}
if !reflect.DeepEqual(router, &dynamic.Router{Service: "foo", Rule: "xxxx"}) {
http.Error(rw, fmt.Sprintf("configuration is not anonymized: %+v", router), http.StatusBadRequest)
return
}
})
server := httptest.NewServer(mux)
t.Cleanup(server.Close)
client := client{
baseGatewayURL: server.URL,
httpClient: http.DefaultClient,
token: myToken,
tokenHash: myTokenHash,
}
config := dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"foo": {
Service: "foo",
Rule: "foo.com",
},
},
},
}
err = client.SendAnonDynConf(context.Background(), config)
require.NoError(t, err)
assert.Equal(t, 2, count)
}
func hashToken(token string) (string, error) {
tokenHash := fnv.New64a()
_, err := tokenHash.Write([]byte(token))
if err != nil {
return "", err
}
return fmt.Sprintf("%x", tokenHash.Sum64()), nil
}

View file

@ -9,7 +9,7 @@ type ClientAuth struct {
CAFiles []FileOrContent `json:"caFiles,omitempty" toml:"caFiles,omitempty" yaml:"caFiles,omitempty"`
// ClientAuthType defines the client authentication type to apply.
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty"`
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -18,8 +18,8 @@ type ClientAuth struct {
type Options struct {
MinVersion string `json:"minVersion,omitempty" toml:"minVersion,omitempty" yaml:"minVersion,omitempty" export:"true"`
MaxVersion string `json:"maxVersion,omitempty" toml:"maxVersion,omitempty" yaml:"maxVersion,omitempty" export:"true"`
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty"`
CurvePreferences []string `json:"curvePreferences,omitempty" toml:"curvePreferences,omitempty" yaml:"curvePreferences,omitempty"`
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty" export:"true"`
CurvePreferences []string `json:"curvePreferences,omitempty" toml:"curvePreferences,omitempty" yaml:"curvePreferences,omitempty" export:"true"`
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty" toml:"preferServerCipherSuites,omitempty" yaml:"preferServerCipherSuites,omitempty" export:"true"`
@ -29,13 +29,13 @@ type Options struct {
// Store holds the options for a given Store.
type Store struct {
DefaultCertificate *Certificate `json:"defaultCertificate,omitempty" toml:"defaultCertificate,omitempty" yaml:"defaultCertificate,omitempty"`
DefaultCertificate *Certificate `json:"defaultCertificate,omitempty" toml:"defaultCertificate,omitempty" yaml:"defaultCertificate,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// CertAndStores allows mapping a TLS certificate to a list of entry points.
type CertAndStores struct {
Certificate `yaml:",inline"`
Stores []string `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty"`
Certificate `yaml:",inline" export:"true"`
Stores []string `json:"stores,omitempty" toml:"stores,omitempty" yaml:"stores,omitempty" export:"true"`
}