2018-11-14 09:18:03 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-01-18 14:18:04 +00:00
|
|
|
"reflect"
|
2018-11-14 09:18:03 +00:00
|
|
|
|
2019-03-15 08:42:03 +00:00
|
|
|
traefiktls "github.com/containous/traefik/pkg/tls"
|
2018-11-14 09:18:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Router holds the router configuration.
|
|
|
|
type Router struct {
|
2019-03-14 08:30:04 +00:00
|
|
|
EntryPoints []string `json:"entryPoints"`
|
|
|
|
Middlewares []string `json:"middlewares,omitempty" toml:",omitempty"`
|
|
|
|
Service string `json:"service,omitempty" toml:",omitempty"`
|
|
|
|
Rule string `json:"rule,omitempty" toml:",omitempty"`
|
|
|
|
Priority int `json:"priority,omitempty" toml:"priority,omitzero"`
|
|
|
|
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitzero" label:"allowEmpty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// RouterTLSConfig holds the TLS configuration for a router
|
|
|
|
type RouterTLSConfig struct{}
|
|
|
|
|
|
|
|
// TCPRouter holds the router configuration.
|
|
|
|
type TCPRouter struct {
|
|
|
|
EntryPoints []string `json:"entryPoints"`
|
|
|
|
Service string `json:"service,omitempty" toml:",omitempty"`
|
|
|
|
Rule string `json:"rule,omitempty" toml:",omitempty"`
|
|
|
|
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitzero" label:"allowEmpty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// RouterTCPTLSConfig holds the TLS configuration for a router
|
|
|
|
type RouterTCPTLSConfig struct {
|
2019-03-14 14:56:06 +00:00
|
|
|
Passthrough bool `json:"passthrough" toml:"passthrough,omitzero"`
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadBalancerService holds the LoadBalancerService configuration.
|
|
|
|
type LoadBalancerService struct {
|
2018-12-04 13:24:04 +00:00
|
|
|
Stickiness *Stickiness `json:"stickiness,omitempty" toml:",omitempty" label:"allowEmpty"`
|
|
|
|
Servers []Server `json:"servers,omitempty" toml:",omitempty" label-slice-as-struct:"server"`
|
2018-11-14 09:18:03 +00:00
|
|
|
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:",omitempty"`
|
|
|
|
PassHostHeader bool `json:"passHostHeader" toml:",omitempty"`
|
|
|
|
ResponseForwarding *ResponseForwarding `json:"forwardingResponse,omitempty" toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2019-03-14 08:30:04 +00:00
|
|
|
// TCPLoadBalancerService holds the LoadBalancerService configuration.
|
|
|
|
type TCPLoadBalancerService struct {
|
|
|
|
Servers []TCPServer `json:"servers,omitempty" toml:",omitempty" label-slice-as-struct:"server"`
|
|
|
|
}
|
|
|
|
|
2019-03-21 14:22:06 +00:00
|
|
|
// Mergeable tells if the given service is mergeable.
|
|
|
|
func (l *TCPLoadBalancerService) Mergeable(loadBalancer *TCPLoadBalancerService) bool {
|
|
|
|
savedServers := l.Servers
|
|
|
|
defer func() {
|
|
|
|
l.Servers = savedServers
|
|
|
|
}()
|
|
|
|
l.Servers = nil
|
|
|
|
|
|
|
|
savedServersLB := loadBalancer.Servers
|
|
|
|
defer func() {
|
|
|
|
loadBalancer.Servers = savedServersLB
|
|
|
|
}()
|
|
|
|
loadBalancer.Servers = nil
|
|
|
|
|
|
|
|
return reflect.DeepEqual(l, loadBalancer)
|
|
|
|
}
|
|
|
|
|
2019-01-18 14:18:04 +00:00
|
|
|
// Mergeable tells if the given service is mergeable.
|
|
|
|
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
|
|
|
savedServers := l.Servers
|
|
|
|
defer func() {
|
|
|
|
l.Servers = savedServers
|
|
|
|
}()
|
|
|
|
l.Servers = nil
|
|
|
|
|
|
|
|
savedServersLB := loadBalancer.Servers
|
|
|
|
defer func() {
|
|
|
|
loadBalancer.Servers = savedServersLB
|
|
|
|
}()
|
|
|
|
loadBalancer.Servers = nil
|
|
|
|
|
|
|
|
return reflect.DeepEqual(l, loadBalancer)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDefaults Default values for a LoadBalancerService.
|
|
|
|
func (l *LoadBalancerService) SetDefaults() {
|
|
|
|
l.PassHostHeader = true
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
// ResponseForwarding holds configuration for the forward of the response.
|
|
|
|
type ResponseForwarding struct {
|
|
|
|
FlushInterval string `json:"flushInterval,omitempty" toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stickiness holds the stickiness configuration.
|
|
|
|
type Stickiness struct {
|
2019-06-12 22:42:06 +00:00
|
|
|
CookieName string `json:"cookieName,omitempty" toml:",omitempty"`
|
|
|
|
SecureCookie bool `json:"secureCookie,omitempty" toml:",omitempty"`
|
|
|
|
HTTPOnlyCookie bool `json:"httpOnlyCookie,omitempty" toml:",omitempty"`
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Server holds the server configuration.
|
|
|
|
type Server struct {
|
2019-01-18 14:18:04 +00:00
|
|
|
URL string `json:"url" label:"-"`
|
|
|
|
Scheme string `toml:"-" json:"-"`
|
|
|
|
Port string `toml:"-" json:"-"`
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
|
2019-03-14 08:30:04 +00:00
|
|
|
// TCPServer holds a TCP Server configuration
|
|
|
|
type TCPServer struct {
|
|
|
|
Address string `json:"address" label:"-"`
|
2019-03-21 14:22:06 +00:00
|
|
|
Port string `toml:"-" json:"-"`
|
|
|
|
}
|
|
|
|
|
2019-01-18 14:18:04 +00:00
|
|
|
// SetDefaults Default values for a Server.
|
|
|
|
func (s *Server) SetDefaults() {
|
|
|
|
s.Scheme = "http"
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
// HealthCheck holds the HealthCheck configuration.
|
|
|
|
type HealthCheck struct {
|
|
|
|
Scheme string `json:"scheme,omitempty" toml:",omitempty"`
|
|
|
|
Path string `json:"path,omitempty" toml:",omitempty"`
|
|
|
|
Port int `json:"port,omitempty" toml:",omitempty,omitzero"`
|
|
|
|
// FIXME change string to parse.Duration
|
|
|
|
Interval string `json:"interval,omitempty" toml:",omitempty"`
|
|
|
|
// FIXME change string to parse.Duration
|
|
|
|
Timeout string `json:"timeout,omitempty" toml:",omitempty"`
|
|
|
|
Hostname string `json:"hostname,omitempty" toml:",omitempty"`
|
|
|
|
Headers map[string]string `json:"headers,omitempty" toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateTLSConfig creates a TLS config from ClientTLS structures.
|
|
|
|
func (clientTLS *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
|
|
|
|
if clientTLS == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
caPool := x509.NewCertPool()
|
|
|
|
clientAuth := tls.NoClientCert
|
|
|
|
if clientTLS.CA != "" {
|
|
|
|
var ca []byte
|
|
|
|
if _, errCA := os.Stat(clientTLS.CA); errCA == nil {
|
|
|
|
ca, err = ioutil.ReadFile(clientTLS.CA)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read CA. %s", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ca = []byte(clientTLS.CA)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !caPool.AppendCertsFromPEM(ca) {
|
|
|
|
return nil, fmt.Errorf("failed to parse CA")
|
|
|
|
}
|
|
|
|
|
|
|
|
if clientTLS.CAOptional {
|
|
|
|
clientAuth = tls.VerifyClientCertIfGiven
|
|
|
|
} else {
|
|
|
|
clientAuth = tls.RequireAndVerifyClientCert
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cert := tls.Certificate{}
|
|
|
|
_, errKeyIsFile := os.Stat(clientTLS.Key)
|
|
|
|
|
|
|
|
if !clientTLS.InsecureSkipVerify && (len(clientTLS.Cert) == 0 || len(clientTLS.Key) == 0) {
|
|
|
|
return nil, fmt.Errorf("TLS Certificate or Key file must be set when TLS configuration is created")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(clientTLS.Cert) > 0 && len(clientTLS.Key) > 0 {
|
|
|
|
if _, errCertIsFile := os.Stat(clientTLS.Cert); errCertIsFile == nil {
|
|
|
|
if errKeyIsFile == nil {
|
|
|
|
cert, err = tls.LoadX509KeyPair(clientTLS.Cert, clientTLS.Key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("tls cert is a file, but tls key is not")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if errKeyIsFile != nil {
|
|
|
|
cert, err = tls.X509KeyPair([]byte(clientTLS.Cert), []byte(clientTLS.Key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("TLS key is a file, but tls cert is not")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
RootCAs: caPool,
|
|
|
|
InsecureSkipVerify: clientTLS.InsecureSkipVerify,
|
|
|
|
ClientAuth: clientAuth,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Message holds configuration information exchanged between parts of traefik.
|
|
|
|
type Message struct {
|
|
|
|
ProviderName string
|
|
|
|
Configuration *Configuration
|
|
|
|
}
|
|
|
|
|
2019-03-14 08:30:04 +00:00
|
|
|
// Configuration is the root of the dynamic configuration
|
|
|
|
type Configuration struct {
|
|
|
|
HTTP *HTTPConfiguration
|
|
|
|
TCP *TCPConfiguration
|
|
|
|
TLS []*traefiktls.Configuration `json:"-" label:"-"`
|
|
|
|
TLSOptions map[string]traefiktls.TLS
|
|
|
|
TLSStores map[string]traefiktls.Store
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
// Configurations is for currentConfigurations Map.
|
|
|
|
type Configurations map[string]*Configuration
|
|
|
|
|
2019-03-14 08:30:04 +00:00
|
|
|
// HTTPConfiguration FIXME better name?
|
|
|
|
type HTTPConfiguration struct {
|
|
|
|
Routers map[string]*Router `json:"routers,omitempty" toml:",omitempty"`
|
|
|
|
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:",omitempty"`
|
|
|
|
Services map[string]*Service `json:"services,omitempty" toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// TCPConfiguration FIXME better name?
|
|
|
|
type TCPConfiguration struct {
|
|
|
|
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:",omitempty"`
|
|
|
|
Services map[string]*TCPService `json:"services,omitempty" toml:",omitempty"`
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Service holds a service configuration (can only be of one type at the same time).
|
|
|
|
type Service struct {
|
|
|
|
LoadBalancer *LoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
|
|
|
|
}
|
2019-03-14 08:30:04 +00:00
|
|
|
|
|
|
|
// TCPService holds a tcp service configuration (can only be of one type at the same time).
|
|
|
|
type TCPService struct {
|
|
|
|
LoadBalancer *TCPLoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
|
|
|
|
}
|