1
0
Fork 0

Add a new protocol

Co-authored-by: Gérald Croës <gerald@containo.us>
This commit is contained in:
Julien Salleyron 2019-03-14 09:30:04 +01:00 committed by Traefiker Bot
parent 0ca2149408
commit 4a68d29ce2
231 changed files with 6895 additions and 4395 deletions

View file

@ -13,11 +13,28 @@ import (
// Router holds the router configuration.
type Router struct {
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"`
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 {
Passthrough bool `json:"passthrough,omitempty" toml:"passthrough,omitzero"`
}
// LoadBalancerService holds the LoadBalancerService configuration.
@ -30,6 +47,12 @@ type LoadBalancerService struct {
ResponseForwarding *ResponseForwarding `json:"forwardingResponse,omitempty" toml:",omitempty"`
}
// TCPLoadBalancerService holds the LoadBalancerService configuration.
type TCPLoadBalancerService struct {
Servers []TCPServer `json:"servers,omitempty" toml:",omitempty" label-slice-as-struct:"server"`
Method string `json:"method,omitempty" toml:",omitempty"`
}
// Mergeable tells if the given service is mergeable.
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
savedServers := l.Servers
@ -71,6 +94,12 @@ type Server struct {
Weight int `json:"weight"`
}
// TCPServer holds a TCP Server configuration
type TCPServer struct {
Address string `json:"address" label:"-"`
Weight int `json:"weight"`
}
// SetDefaults Default values for a Server.
func (s *Server) SetDefaults() {
s.Weight = 1
@ -175,18 +204,37 @@ type Message struct {
Configuration *Configuration
}
// 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
}
// Configurations is for currentConfigurations Map.
type Configurations map[string]*Configuration
// Configuration FIXME better name?
type Configuration 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"`
TLS []*traefiktls.Configuration `json:"-" label:"-"`
// 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"`
}
// 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"`
}
// 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"`
}

View file

@ -5,14 +5,12 @@ import (
"strings"
"github.com/containous/traefik/log"
"github.com/containous/traefik/tls"
)
// EntryPoint holds the entry point configuration.
type EntryPoint struct {
Address string
Transport *EntryPointsTransport
TLS *tls.TLS
ProxyProtocol *ProxyProtocol
ForwardedHeaders *ForwardedHeaders
}
@ -65,14 +63,8 @@ func (ep *EntryPoints) Type() string {
func (ep *EntryPoints) Set(value string) error {
result := parseEntryPointsConfiguration(value)
configTLS, err := makeEntryPointTLS(result)
if err != nil {
return err
}
(*ep)[result["name"]] = &EntryPoint{
Address: result["address"],
TLS: configTLS,
ProxyProtocol: makeEntryPointProxyProtocol(result),
ForwardedHeaders: makeEntryPointForwardedHeaders(result),
}
@ -100,55 +92,6 @@ func makeEntryPointProxyProtocol(result map[string]string) *ProxyProtocol {
return proxyProtocol
}
func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) {
var configTLS *tls.TLS
if len(result["tls"]) > 0 {
certs := tls.Certificates{}
if err := certs.Set(result["tls"]); err != nil {
return nil, err
}
configTLS = &tls.TLS{}
} else if len(result["tls_acme"]) > 0 {
configTLS = &tls.TLS{}
}
if configTLS != nil {
if len(result["ca"]) > 0 {
files := tls.FilesOrContents{}
if err := files.Set(result["ca"]); err != nil {
return nil, err
}
optional := toBool(result, "ca_optional")
configTLS.ClientCA = tls.ClientCA{
Files: files,
Optional: optional,
}
}
if len(result["tls_minversion"]) > 0 {
configTLS.MinVersion = result["tls_minversion"]
}
if len(result["tls_ciphersuites"]) > 0 {
configTLS.CipherSuites = strings.Split(result["tls_ciphersuites"], ",")
}
if len(result["tls_snistrict"]) > 0 {
configTLS.SniStrict = toBool(result, "tls_snistrict")
}
if len(result["tls_defaultcertificate_cert"]) > 0 && len(result["tls_defaultcertificate_key"]) > 0 {
configTLS.DefaultCertificate = &tls.Certificate{
CertFile: tls.FileOrContent(result["tls_defaultcertificate_cert"]),
KeyFile: tls.FileOrContent(result["tls_defaultcertificate_key"]),
}
}
}
return configTLS, nil
}
func parseEntryPointsConfiguration(raw string) map[string]string {
sections := strings.Fields(raw)

View file

@ -3,7 +3,6 @@ package static
import (
"testing"
"github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -18,10 +17,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
name: "all parameters",
value: "Name:foo " +
"Address::8000 " +
"TLS:goo,gii " +
"TLS " +
"TLS.MinVersion:VersionTLS11 " +
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"CA:car " +
"CA.Optional:true " +
"Redirect.EntryPoint:https " +
@ -76,10 +71,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"redirect_permanent": "true",
"redirect_regex": "http://localhost/(.*)",
"redirect_replacement": "http://mydomain/$1",
"tls": "goo,gii",
"tls_acme": "TLS",
"tls_ciphersuites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"tls_minversion": "VersionTLS11",
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
"whitelist_ipstrategy_depth": "3",
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
@ -95,15 +86,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"compress": "on",
},
},
{
name: "TLS",
value: "Name:foo TLS:goo TLS",
expectedResult: map[string]string{
"name": "foo",
"tls": "goo",
"tls_acme": "TLS",
},
},
}
for _, test := range testCases {
@ -185,23 +167,12 @@ func TestEntryPoints_Set(t *testing.T) {
name: "all parameters camelcase",
expression: "Name:foo " +
"Address::8000 " +
"TLS " +
"TLS.MinVersion:VersionTLS11 " +
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"CA:car " +
"CA.Optional:true " +
"ProxyProtocol.TrustedIPs:192.168.0.1 ",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"},
Optional: true,
},
},
ProxyProtocol: &ProxyProtocol{
Insecure: false,
TrustedIPs: []string{"192.168.0.1"},
@ -223,14 +194,6 @@ func TestEntryPoints_Set(t *testing.T) {
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"},
Optional: true,
},
},
ProxyProtocol: &ProxyProtocol{
Insecure: false,
TrustedIPs: []string{"192.168.0.1"},

View file

@ -6,7 +6,6 @@ import (
"time"
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
@ -70,7 +69,7 @@ type Configuration struct {
HostResolver *types.HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
ACME *acmeprovider.Configuration `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
}
// Global holds the global configuration.
@ -338,10 +337,6 @@ func (c *Configuration) initACMEProvider() {
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
c.ACME.HTTPChallenge = nil
}
if c.ACME.OnDemand {
log.Warn("ACME.OnDemand is deprecated")
}
}
}
@ -349,18 +344,11 @@ func (c *Configuration) initACMEProvider() {
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
if c.ACME != nil {
if len(c.ACME.Storage) == 0 {
// Delete the ACME configuration to avoid starting ACME in cluster mode
c.ACME = nil
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
}
provider := &acmeprovider.Provider{}
provider.Configuration = convertACMEChallenge(c.ACME)
store := acmeprovider.NewLocalStore(provider.Storage)
provider.Store = store
acme.ConvertToNewFormat(provider.Storage)
c.ACME = nil
return provider, nil
return &acmeprovider.Provider{
Configuration: c.ACME,
}, nil
}
return nil, nil
}
@ -368,12 +356,26 @@ func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
// ValidateConfiguration validate that configuration is coherent
func (c *Configuration) ValidateConfiguration() {
if c.ACME != nil {
if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
} else if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
for _, domain := range c.ACME.Domains {
if domain.Main != dns01.UnFqdn(domain.Main) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
}
for _, san := range domain.SANs {
if san != dns01.UnFqdn(san) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
}
}
}
}
// FIXME Validate store config?
// if c.ACME != nil {
// if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
// log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
// }
// else if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
// log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
// }
// }
}
func getSafeACMECAServer(caServerSrc string) string {
@ -395,47 +397,3 @@ func getSafeACMECAServer(caServerSrc string) string {
return caServerSrc
}
// Deprecated
func convertACMEChallenge(oldACMEChallenge *acme.ACME) *acmeprovider.Configuration {
conf := &acmeprovider.Configuration{
KeyType: oldACMEChallenge.KeyType,
OnHostRule: oldACMEChallenge.OnHostRule,
OnDemand: oldACMEChallenge.OnDemand,
Email: oldACMEChallenge.Email,
Storage: oldACMEChallenge.Storage,
ACMELogging: oldACMEChallenge.ACMELogging,
CAServer: oldACMEChallenge.CAServer,
EntryPoint: oldACMEChallenge.EntryPoint,
}
for _, domain := range oldACMEChallenge.Domains {
if domain.Main != dns01.UnFqdn(domain.Main) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
}
for _, san := range domain.SANs {
if san != dns01.UnFqdn(san) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
}
}
conf.Domains = append(conf.Domains, domain)
}
if oldACMEChallenge.HTTPChallenge != nil {
conf.HTTPChallenge = &acmeprovider.HTTPChallenge{
EntryPoint: oldACMEChallenge.HTTPChallenge.EntryPoint,
}
}
if oldACMEChallenge.DNSChallenge != nil {
conf.DNSChallenge = &acmeprovider.DNSChallenge{
Provider: oldACMEChallenge.DNSChallenge.Provider,
DelayBeforeCheck: oldACMEChallenge.DNSChallenge.DelayBeforeCheck,
}
}
if oldACMEChallenge.TLSChallenge != nil {
conf.TLSChallenge = &acmeprovider.TLSChallenge{}
}
return conf
}