mirror of
https://github.com/containous/traefik.git
synced 2025-10-03 01:44:23 +03:00
Compare commits
5 Commits
v1.6.0-rc1
...
v1.6.0-rc2
Author | SHA1 | Date | |
---|---|---|---|
|
118b4eb07a | ||
|
f1a05ab73c | ||
|
4c85a41bfb | ||
|
30e048d4ab | ||
|
aa0ab6d387 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
## [v1.6.0-rc2](https://github.com/containous/traefik/tree/v1.6.0-rc2) (2018-03-27)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc1...v1.6.0-rc2)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Fix panic with wrong ACME configuration ([#3084](https://github.com/containous/traefik/pull/3084) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme]** Fix wildcard match to ACME domains in cluster mode ([#3080](https://github.com/containous/traefik/pull/3080) by [oldmantaiter](https://github.com/oldmantaiter))
|
||||
|
||||
**Documentation:**
|
||||
- **[servicefabric]** Update SF white list documentation section. ([#3082](https://github.com/containous/traefik/pull/3082) by [ldez](https://github.com/ldez))
|
||||
- Fix basic documentation ([#3086](https://github.com/containous/traefik/pull/3086) by [mmatur](https://github.com/mmatur))
|
||||
|
||||
## [v1.6.0-rc1](https://github.com/containous/traefik/tree/v1.6.0-rc1) (2018-03-26)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.6.0-rc1)
|
||||
|
||||
|
@@ -219,6 +219,9 @@ func (dc *DomainsCertificates) getCertificateForDomain(domainToFind string) (*Do
|
||||
|
||||
for _, domainsCertificate := range dc.Certs {
|
||||
for _, domain := range domainsCertificate.Domains.ToStrArray() {
|
||||
if strings.HasPrefix(domain, "*.") && types.MatchDomain(domainToFind, domain) {
|
||||
return domainsCertificate, true
|
||||
}
|
||||
if domain == domainToFind {
|
||||
return domainsCertificate, true
|
||||
}
|
||||
|
22
acme/acme.go
22
acme/acme.go
@@ -11,7 +11,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -27,7 +26,7 @@ import (
|
||||
"github.com/containous/traefik/tls/generate"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/eapache/channels"
|
||||
acme "github.com/xenolf/lego/acmev2"
|
||||
"github.com/xenolf/lego/acmev2"
|
||||
"github.com/xenolf/lego/providers/dns"
|
||||
)
|
||||
|
||||
@@ -555,15 +554,14 @@ func (a *ACME) getProvidedCertificate(domains string) *tls.Certificate {
|
||||
func searchProvidedCertificateForDomains(domain string, certs map[string]*tls.Certificate) *tls.Certificate {
|
||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||
for certDomains := range certs {
|
||||
domainCheck := false
|
||||
domainChecked := false
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.", -1) + "$"
|
||||
domainCheck, _ = regexp.MatchString(selector, domain)
|
||||
if domainCheck {
|
||||
domainChecked = types.MatchDomain(domain, certDomain)
|
||||
if domainChecked {
|
||||
break
|
||||
}
|
||||
}
|
||||
if domainCheck {
|
||||
if domainChecked {
|
||||
log.Debugf("Domain %q checked by provided certificate %q", domain, certDomains)
|
||||
return certs[certDomains]
|
||||
}
|
||||
@@ -684,15 +682,7 @@ func (a *ACME) getValidDomains(domains []string, wildcardAllowed bool) ([]string
|
||||
func isDomainAlreadyChecked(domainToCheck string, existentDomains map[string]*tls.Certificate) bool {
|
||||
for certDomains := range existentDomains {
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
// Use regex to test for provided existentDomains that might have been added into TLSConfig
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.", -1) + "$"
|
||||
domainCheck, err := regexp.MatchString(selector, domainToCheck)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to compare %q and %q : %s", domainToCheck, certDomain, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if domainCheck {
|
||||
if types.MatchDomain(domainToCheck, certDomain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/containous/traefik/tls/generate"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
acme "github.com/xenolf/lego/acmev2"
|
||||
"github.com/xenolf/lego/acmev2"
|
||||
)
|
||||
|
||||
func TestDomainsSet(t *testing.T) {
|
||||
@@ -444,3 +444,93 @@ func TestAcme_getValidDomain(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcme_getCertificateForDomain(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
domain string
|
||||
dc *DomainsCertificates
|
||||
expected *DomainsCertificate
|
||||
expectedFound bool
|
||||
}{
|
||||
{
|
||||
desc: "non-wildcard exact match",
|
||||
domain: "foo.traefik.wtf",
|
||||
dc: &DomainsCertificates{
|
||||
Certs: []*DomainsCertificate{
|
||||
{
|
||||
Domains: types.Domain{
|
||||
Main: "foo.traefik.wtf",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &DomainsCertificate{
|
||||
Domains: types.Domain{
|
||||
Main: "foo.traefik.wtf",
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
},
|
||||
{
|
||||
desc: "non-wildcard no match",
|
||||
domain: "bar.traefik.wtf",
|
||||
dc: &DomainsCertificates{
|
||||
Certs: []*DomainsCertificate{
|
||||
{
|
||||
Domains: types.Domain{
|
||||
Main: "foo.traefik.wtf",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expectedFound: false,
|
||||
},
|
||||
{
|
||||
desc: "wildcard match",
|
||||
domain: "foo.traefik.wtf",
|
||||
dc: &DomainsCertificates{
|
||||
Certs: []*DomainsCertificate{
|
||||
{
|
||||
Domains: types.Domain{
|
||||
Main: "*.traefik.wtf",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &DomainsCertificate{
|
||||
Domains: types.Domain{
|
||||
Main: "*.traefik.wtf",
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
},
|
||||
{
|
||||
desc: "wildcard no match",
|
||||
domain: "foo.traefik.wtf",
|
||||
dc: &DomainsCertificates{
|
||||
Certs: []*DomainsCertificate{
|
||||
{
|
||||
Domains: types.Domain{
|
||||
Main: "*.bar.traefik.wtf",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expectedFound: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got, found := test.dc.getCertificateForDomain(test.domain)
|
||||
assert.Equal(t, test.expectedFound, found)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -331,15 +331,15 @@ func (gc *GlobalConfiguration) ValidateConfiguration() {
|
||||
log.Fatalf("Unknown entrypoint %q for ACME configuration", gc.ACME.EntryPoint)
|
||||
} else {
|
||||
if gc.EntryPoints[gc.ACME.EntryPoint].TLS == nil {
|
||||
log.Fatalf("Entrypoint without TLS %q for ACME configuration", gc.ACME.EntryPoint)
|
||||
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", gc.ACME.EntryPoint)
|
||||
}
|
||||
}
|
||||
} else if acmeprovider.IsEnabled() {
|
||||
if _, ok := gc.EntryPoints[acmeprovider.Get().EntryPoint]; !ok {
|
||||
log.Fatalf("Unknown entrypoint %q for provider ACME configuration", gc.ACME.EntryPoint)
|
||||
log.Fatalf("Unknown entrypoint %q for provider ACME configuration", acmeprovider.Get().EntryPoint)
|
||||
} else {
|
||||
if gc.EntryPoints[acmeprovider.Get().EntryPoint].TLS == nil {
|
||||
log.Fatalf("Entrypoint without TLS %q for provider ACME configuration", gc.ACME.EntryPoint)
|
||||
log.Fatalf("Entrypoint %q has no TLS configuration for provider ACME configuration", acmeprovider.Get().EntryPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,13 +62,12 @@ And here is another example with client certificate authentication:
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
[entryPoints.https.tls]
|
||||
[entryPoints.https.tls.ClientCA]
|
||||
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||
optional = false
|
||||
[[entryPoints.https.tls.certificates]]
|
||||
certFile = "tests/traefik.crt"
|
||||
keyFile = "tests/traefik.key"
|
||||
[entryPoints.https.tls.ClientCA]
|
||||
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||
optional = false
|
||||
[[entryPoints.https.tls.certificates]]
|
||||
certFile = "tests/traefik.crt"
|
||||
keyFile = "tests/traefik.key"
|
||||
```
|
||||
|
||||
- We enable SSL on `https` by giving a certificate and a key.
|
||||
@@ -483,7 +482,7 @@ Each item takes precedence over the item below it:
|
||||
|
||||
It means that arguments override configuration file, and key-value store overrides arguments.
|
||||
|
||||
!!! note
|
||||
!!! note
|
||||
the provider-enabling argument parameters (e.g., `--docker`) set all default values for the specific provider.
|
||||
It must not be used if a configuration source with less precedence wants to set a non-default provider value.
|
||||
|
||||
|
@@ -120,7 +120,8 @@ Labels, set through extensions or the property manager, can be used on services
|
||||
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
||||
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
|
||||
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Defaults to SF address. |
|
||||
| `traefik.frontend.whitelistSourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
||||
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
||||
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
|
||||
|
||||
### Custom Headers
|
||||
|
||||
|
@@ -365,7 +365,7 @@ To enable IP white listing at the entry point level.
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.http]
|
||||
[entryPoints.http.whiteList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
# useXForwardedFor = true
|
||||
```
|
||||
|
@@ -10,7 +10,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -24,7 +23,7 @@ import (
|
||||
traefikTLS "github.com/containous/traefik/tls"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/pkg/errors"
|
||||
acme "github.com/xenolf/lego/acmev2"
|
||||
"github.com/xenolf/lego/acmev2"
|
||||
"github.com/xenolf/lego/providers/dns"
|
||||
)
|
||||
|
||||
@@ -522,7 +521,7 @@ func (p *Provider) getUncheckedDomains(domainsToCheck []string, checkConfigurati
|
||||
}
|
||||
|
||||
func searchUncheckedDomains(domainsToCheck []string, existentDomains []string) []string {
|
||||
uncheckedDomains := []string{}
|
||||
var uncheckedDomains []string
|
||||
for _, domainToCheck := range domainsToCheck {
|
||||
if !isDomainAlreadyChecked(domainToCheck, existentDomains) {
|
||||
uncheckedDomains = append(uncheckedDomains, domainToCheck)
|
||||
@@ -583,14 +582,7 @@ func (p *Provider) getValidDomains(domain types.Domain, wildcardAllowed bool) ([
|
||||
func isDomainAlreadyChecked(domainToCheck string, existentDomains []string) bool {
|
||||
for _, certDomains := range existentDomains {
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
// Use regex to test for provided existentDomains that might have been added into TLSConfig
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.", -1) + "$"
|
||||
domainCheck, err := regexp.MatchString(selector, domainToCheck)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to compare %q and %q in ACME provider : %s", domainToCheck, certDomain, err)
|
||||
continue
|
||||
}
|
||||
if domainCheck {
|
||||
if types.MatchDomain(domainToCheck, certDomain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,6 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -517,15 +516,13 @@ func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, def
|
||||
return newEPCertificates, nil
|
||||
}
|
||||
|
||||
// getCertificate allows to customize tlsConfig.Getcertificate behaviour to get the certificates inserted dynamically
|
||||
// getCertificate allows to customize tlsConfig.GetCertificate behaviour to get the certificates inserted dynamically
|
||||
func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
domainToCheck := types.CanonicalDomain(clientHello.ServerName)
|
||||
if s.certs.Get() != nil {
|
||||
for domains, cert := range s.certs.Get().(map[string]*tls.Certificate) {
|
||||
for _, domain := range strings.Split(domains, ",") {
|
||||
selector := "^" + strings.Replace(domain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
domainCheck, _ := regexp.MatchString(selector, domainToCheck)
|
||||
if domainCheck {
|
||||
for _, certDomain := range strings.Split(domains, ",") {
|
||||
if types.MatchDomain(domainToCheck, certDomain) {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
|
@@ -88,3 +88,95 @@ func TestDomain_Set(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchDomain(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
certDomain string
|
||||
domain string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "exact match",
|
||||
certDomain: "traefik.wtf",
|
||||
domain: "traefik.wtf",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "wildcard and root domain",
|
||||
certDomain: "*.traefik.wtf",
|
||||
domain: "traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "wildcard and sub domain",
|
||||
certDomain: "*.traefik.wtf",
|
||||
domain: "sub.traefik.wtf",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "wildcard and sub sub domain",
|
||||
certDomain: "*.traefik.wtf",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "double wildcard and sub sub domain",
|
||||
certDomain: "*.*.traefik.wtf",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "sub sub domain and invalid wildcard",
|
||||
certDomain: "sub.*.traefik.wtf",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "sub sub domain and valid wildcard",
|
||||
certDomain: "*.sub.traefik.wtf",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "dot replaced by a cahr",
|
||||
certDomain: "sub.sub.traefik.wtf",
|
||||
domain: "sub.sub.traefikiwtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "*",
|
||||
certDomain: "*",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "?",
|
||||
certDomain: "?",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "...................",
|
||||
certDomain: "...................",
|
||||
domain: "sub.sub.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "wildcard and *",
|
||||
certDomain: "*.traefik.wtf",
|
||||
domain: "*.*.traefik.wtf",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
domains := MatchDomain(test.domain, test.certDomain)
|
||||
assert.Equal(t, test.expected, domains)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -65,3 +65,24 @@ func (ds *Domains) String() string { return fmt.Sprintf("%+v", *ds) }
|
||||
func (ds *Domains) SetValue(val interface{}) {
|
||||
*ds = val.([]Domain)
|
||||
}
|
||||
|
||||
// MatchDomain return true if a domain match the cert domain
|
||||
func MatchDomain(domain string, certDomain string) bool {
|
||||
if domain == certDomain {
|
||||
return true
|
||||
}
|
||||
|
||||
for len(certDomain) > 0 && certDomain[len(certDomain)-1] == '.' {
|
||||
certDomain = certDomain[:len(certDomain)-1]
|
||||
}
|
||||
|
||||
labels := strings.Split(domain, ".")
|
||||
for i := range labels {
|
||||
labels[i] = "*"
|
||||
candidate := strings.Join(labels, ".")
|
||||
if certDomain == candidate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Reference in New Issue
Block a user