1
0
Fork 0

Certificate resolvers.

Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
Co-authored-by: Jean-Baptiste Doumenjou <jb.doumenjou@gmail.com>
This commit is contained in:
Ludovic Fernandez 2019-07-19 11:52:04 +02:00 committed by Traefiker Bot
parent e3627e9cba
commit f75f73f3d2
47 changed files with 1573 additions and 1249 deletions

View file

@ -212,7 +212,6 @@
storage = "foobar"
entryPoint = "foobar"
keyType = "foobar"
onHostRule = true
[acme.dnsChallenge]
provider = "foobar"
delayBeforeCheck = 42

View file

@ -1,6 +1,10 @@
package dynamic
import "reflect"
import (
"reflect"
"github.com/containous/traefik/pkg/types"
)
// +k8s:deepcopy-gen=true
@ -34,7 +38,9 @@ type Router struct {
// RouterTLSConfig holds the TLS configuration for a router
type RouterTLSConfig struct {
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
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"`
}
// +k8s:deepcopy-gen=true

View file

@ -1,6 +1,10 @@
package dynamic
import "reflect"
import (
"reflect"
"github.com/containous/traefik/pkg/types"
)
// +k8s:deepcopy-gen=true
@ -31,8 +35,10 @@ type TCPRouter struct {
// 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"`
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"`
}
// +k8s:deepcopy-gen=true

View file

@ -30,6 +30,7 @@ package dynamic
import (
tls "github.com/containous/traefik/pkg/tls"
types "github.com/containous/traefik/pkg/types"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -876,7 +877,7 @@ func (in *Router) DeepCopyInto(out *Router) {
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(RouterTLSConfig)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}
@ -894,6 +895,13 @@ func (in *Router) DeepCopy() *Router {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RouterTCPTLSConfig) DeepCopyInto(out *RouterTCPTLSConfig) {
*out = *in
if in.Domains != nil {
in, out := &in.Domains, &out.Domains
*out = make([]types.Domain, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
@ -910,6 +918,13 @@ func (in *RouterTCPTLSConfig) DeepCopy() *RouterTCPTLSConfig {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RouterTLSConfig) DeepCopyInto(out *RouterTLSConfig) {
*out = *in
if in.Domains != nil {
in, out := &in.Domains, &out.Domains
*out = make([]types.Domain, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
@ -1096,7 +1111,7 @@ func (in *TCPRouter) DeepCopyInto(out *TCPRouter) {
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(RouterTCPTLSConfig)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -44,7 +44,7 @@ func Test_getRootFieldNames(t *testing.T) {
func Test_decodeFileToNode_compare(t *testing.T) {
nodeToml, err := decodeFileToNode("./fixtures/sample.toml",
"Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "ACME")
"Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "CertificatesResolvers")
if err != nil {
t.Fatal(err)
}
@ -59,7 +59,7 @@ func Test_decodeFileToNode_compare(t *testing.T) {
func Test_decodeFileToNode_Toml(t *testing.T) {
node, err := decodeFileToNode("./fixtures/sample.toml",
"Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "ACME")
"Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "CertificatesResolvers")
if err != nil {
t.Fatal(err)
}
@ -85,42 +85,35 @@ func Test_decodeFileToNode_Toml(t *testing.T) {
{Name: "retryAttempts", Value: "true"},
{Name: "statusCodes", Value: "foobar,foobar"}}},
{Name: "format", Value: "foobar"}}},
{Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
{Name: "dnsChallenge", Children: []*parser.Node{
{Name: "delayBeforeCheck", Value: "42"},
{Name: "disablePropagationCheck", Value: "true"},
{Name: "provider", Value: "foobar"},
{Name: "resolvers", Value: "foobar,foobar"},
}},
{Name: "domains", Children: []*parser.Node{
{Name: "[0]", Children: []*parser.Node{
{Name: "main", Value: "foobar"},
{Name: "sans", Value: "foobar,foobar"},
}},
{Name: "[1]", Children: []*parser.Node{
{Name: "main", Value: "foobar"},
{Name: "sans", Value: "foobar,foobar"},
}},
}},
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "keyType", Value: "foobar"},
{Name: "onHostRule", Value: "true"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
},
},
{Name: "api", Children: []*parser.Node{
{Name: "dashboard", Value: "true"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"},
{Name: "statistics", Children: []*parser.Node{
{Name: "recentErrors", Value: "42"}}}}},
{Name: "certificatesResolvers", Children: []*parser.Node{
{Name: "default", Children: []*parser.Node{
{Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
{Name: "dnsChallenge", Children: []*parser.Node{
{Name: "delayBeforeCheck", Value: "42"},
{Name: "disablePropagationCheck", Value: "true"},
{Name: "provider", Value: "foobar"},
{Name: "resolvers", Value: "foobar,foobar"},
}},
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "keyType", Value: "foobar"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
},
},
}},
}},
{Name: "entryPoints", Children: []*parser.Node{
{Name: "EntryPoint0", Children: []*parser.Node{
{Name: "address", Value: "foobar"},
@ -327,42 +320,35 @@ func Test_decodeFileToNode_Yaml(t *testing.T) {
{Name: "retryAttempts", Value: "true"},
{Name: "statusCodes", Value: "foobar,foobar"}}},
{Name: "format", Value: "foobar"}}},
{Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
{Name: "dnsChallenge", Children: []*parser.Node{
{Name: "delayBeforeCheck", Value: "42"},
{Name: "disablePropagationCheck", Value: "true"},
{Name: "provider", Value: "foobar"},
{Name: "resolvers", Value: "foobar,foobar"},
}},
{Name: "domains", Children: []*parser.Node{
{Name: "[0]", Children: []*parser.Node{
{Name: "main", Value: "foobar"},
{Name: "sans", Value: "foobar,foobar"},
}},
{Name: "[1]", Children: []*parser.Node{
{Name: "main", Value: "foobar"},
{Name: "sans", Value: "foobar,foobar"},
}},
}},
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "keyType", Value: "foobar"},
{Name: "onHostRule", Value: "true"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
},
},
{Name: "api", Children: []*parser.Node{
{Name: "dashboard", Value: "true"},
{Name: "entryPoint", Value: "foobar"},
{Name: "middlewares", Value: "foobar,foobar"},
{Name: "statistics", Children: []*parser.Node{
{Name: "recentErrors", Value: "42"}}}}},
{Name: "certificatesResolvers", Children: []*parser.Node{
{Name: "default", Children: []*parser.Node{
{Name: "acme",
Children: []*parser.Node{
{Name: "acmeLogging", Value: "true"},
{Name: "caServer", Value: "foobar"},
{Name: "dnsChallenge", Children: []*parser.Node{
{Name: "delayBeforeCheck", Value: "42"},
{Name: "disablePropagationCheck", Value: "true"},
{Name: "provider", Value: "foobar"},
{Name: "resolvers", Value: "foobar,foobar"},
}},
{Name: "email", Value: "foobar"},
{Name: "entryPoint", Value: "foobar"},
{Name: "httpChallenge", Children: []*parser.Node{
{Name: "entryPoint", Value: "foobar"}}},
{Name: "keyType", Value: "foobar"},
{Name: "storage", Value: "foobar"},
{Name: "tlsChallenge"},
},
},
}},
}},
{Name: "entryPoints", Children: []*parser.Node{
{Name: "EntryPoint0", Children: []*parser.Node{
{Name: "address", Value: "foobar"},

View file

@ -205,30 +205,21 @@
resolvConfig = "foobar"
resolvDepth = 42
[acme]
[certificatesResolvers.default.acme]
email = "foobar"
acmeLogging = true
caServer = "foobar"
storage = "foobar"
entryPoint = "foobar"
keyType = "foobar"
onHostRule = true
[acme.dnsChallenge]
[certificatesResolvers.default.acme.dnsChallenge]
provider = "foobar"
delayBeforeCheck = 42
resolvers = ["foobar", "foobar"]
disablePropagationCheck = true
[acme.httpChallenge]
[certificatesResolvers.default.acme.httpChallenge]
entryPoint = "foobar"
[acme.tlsChallenge]
[[acme.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[acme.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[certificatesResolvers.default.acme.tlsChallenge]
## Dynamic configuration

View file

@ -214,30 +214,23 @@ hostResolver:
cnameFlattening: true
resolvConfig: foobar
resolvDepth: 42
acme:
email: foobar
acmeLogging: true
caServer: foobar
storage: foobar
entryPoint: foobar
keyType: foobar
onHostRule: true
dnsChallenge:
provider: foobar
delayBeforeCheck: 42
resolvers:
- foobar
- foobar
disablePropagationCheck: true
httpChallenge:
entryPoint: foobar
tlsChallenge: {}
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar
certificatesResolvers:
default:
acme:
email: foobar
acmeLogging: true
caServer: foobar
storage: foobar
entryPoint: foobar
keyType: foobar
dnsChallenge:
provider: foobar
delayBeforeCheck: 42
resolvers:
- foobar
- foobar
disablePropagationCheck: true
httpChallenge:
entryPoint: foobar
tlsChallenge: {}

View file

@ -1,7 +1,8 @@
package static
import (
"errors"
"fmt"
stdlog "log"
"strings"
"time"
@ -23,7 +24,8 @@ import (
"github.com/containous/traefik/pkg/tracing/zipkin"
"github.com/containous/traefik/pkg/types"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/go-acme/lego/challenge/dns01"
legolog "github.com/go-acme/lego/log"
"github.com/sirupsen/logrus"
)
const (
@ -59,6 +61,11 @@ type Configuration struct {
HostResolver *types.HostResolverConfig `description:"Enable CNAME Flattening." json:"hostResolver,omitempty" toml:"hostResolver,omitempty" yaml:"hostResolver,omitempty" label:"allowEmpty" export:"true"`
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
}
// CertificateResolver contains the configuration for the different types of certificates resolver.
type CertificateResolver struct {
ACME *acmeprovider.Configuration `description:"Enable ACME (Let's Encrypt): automatic SSL." json:"acme,omitempty" toml:"acme,omitempty" yaml:"acme,omitempty" export:"true"`
}
@ -194,64 +201,35 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.initACMEProvider()
}
// FIXME handle on new configuration ACME struct
func (c *Configuration) initACMEProvider() {
if c.ACME != nil {
c.ACME.CAServer = getSafeACMECAServer(c.ACME.CAServer)
if c.ACME.DNSChallenge != nil && c.ACME.HTTPChallenge != nil {
log.Warn("Unable to use DNS challenge and HTTP challenge at the same time. Fallback to DNS challenge.")
c.ACME.HTTPChallenge = nil
}
if c.ACME.DNSChallenge != nil && c.ACME.TLSChallenge != nil {
log.Warn("Unable to use DNS challenge and TLS challenge at the same time. Fallback to DNS challenge.")
c.ACME.TLSChallenge = nil
}
if c.ACME.HTTPChallenge != nil && c.ACME.TLSChallenge != nil {
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
c.ACME.HTTPChallenge = nil
for _, resolver := range c.CertificatesResolvers {
if resolver.ACME != nil {
resolver.ACME.CAServer = getSafeACMECAServer(resolver.ACME.CAServer)
}
}
}
// InitACMEProvider create an acme provider from the ACME part of globalConfiguration
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
if c.ACME != nil {
if len(c.ACME.Storage) == 0 {
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
}
return &acmeprovider.Provider{
Configuration: c.ACME,
}, nil
}
return nil, nil
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
}
// ValidateConfiguration validate that configuration is coherent
func (c *Configuration) ValidateConfiguration() {
if c.ACME != nil {
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)
}
}
func (c *Configuration) ValidateConfiguration() error {
var acmeEmail string
for name, resolver := range c.CertificatesResolvers {
if resolver.ACME == nil {
continue
}
if len(resolver.ACME.Storage) == 0 {
return fmt.Errorf("unable to initialize certificates resolver %q with no storage location for the certificates", name)
}
if acmeEmail != "" && resolver.ACME.Email != acmeEmail {
return fmt.Errorf("unable to initialize certificates resolver %q, all the acme resolvers must use the same email", name)
}
acmeEmail = resolver.ACME.Email
}
// 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)
// }
// }
return nil
}
func getSafeACMECAServer(caServerSrc string) string {