2017-11-09 11:16:03 +00:00
package tls
import (
"crypto/tls"
"fmt"
"strings"
2017-12-08 10:02:03 +00:00
"github.com/containous/traefik/log"
2018-01-22 11:16:03 +00:00
"github.com/sirupsen/logrus"
2017-12-08 10:02:03 +00:00
)
const (
certificateHeader = "-----BEGIN CERTIFICATE-----\n"
2017-11-09 11:16:03 +00:00
)
2017-11-10 09:30:04 +00:00
// ClientCA defines traefik CA files for a entryPoint
// and it indicates if they are mandatory or have just to be analyzed if provided
type ClientCA struct {
Files [ ] string
Optional bool
}
2017-11-09 11:16:03 +00:00
// TLS configures TLS for an entry point
type TLS struct {
MinVersion string ` export:"true" `
CipherSuites [ ] string
Certificates Certificates
2017-11-10 09:30:04 +00:00
ClientCAFiles [ ] string // Deprecated
ClientCA ClientCA
2017-11-09 11:16:03 +00:00
}
// RootCAs hold the CA we want to have in root
type RootCAs [ ] FileOrContent
// DomainsCertificates allows mapping TLS certificates to a list of domains
type DomainsCertificates map [ string ] * tls . Certificate
// Configuration allows mapping a TLS certificate to a list of entrypoints
type Configuration struct {
EntryPoints [ ] string
Certificate * Certificate
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func ( dc * DomainsCertificates ) add ( domain string , cert * tls . Certificate ) error {
dc . Get ( ) . ( map [ string ] * tls . Certificate ) [ domain ] = cert
return nil
}
// Get method allow getting the map stored into the DomainsCertificates
func ( dc * DomainsCertificates ) Get ( ) interface { } {
return map [ string ] * tls . Certificate ( * dc )
}
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func ( r * RootCAs ) String ( ) string {
sliceOfString := make ( [ ] string , len ( [ ] FileOrContent ( * r ) ) )
for key , value := range * r {
sliceOfString [ key ] = value . String ( )
}
return strings . Join ( sliceOfString , "," )
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func ( r * RootCAs ) Set ( value string ) error {
rootCAs := strings . Split ( value , "," )
if len ( rootCAs ) == 0 {
return fmt . Errorf ( "bad RootCAs format: %s" , value )
}
for _ , rootCA := range rootCAs {
* r = append ( * r , FileOrContent ( rootCA ) )
}
return nil
}
// Get return the RootCAs list
func ( r * RootCAs ) Get ( ) interface { } {
2017-12-18 08:14:03 +00:00
return * r
2017-11-09 11:16:03 +00:00
}
// SetValue sets the RootCAs with val
func ( r * RootCAs ) SetValue ( val interface { } ) {
2017-12-18 08:14:03 +00:00
* r = val . ( RootCAs )
2017-11-09 11:16:03 +00:00
}
// Type is type of the struct
func ( r * RootCAs ) Type ( ) string {
return "rootcas"
}
// SortTLSConfigurationPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
2017-12-08 10:02:03 +00:00
func SortTLSConfigurationPerEntryPoints ( configurations [ ] * Configuration , epConfiguration map [ string ] * DomainsCertificates , defaultEntryPoints [ ] string ) error {
2017-11-09 11:16:03 +00:00
if epConfiguration == nil {
epConfiguration = make ( map [ string ] * DomainsCertificates )
}
for _ , conf := range configurations {
2017-12-08 10:02:03 +00:00
if conf . EntryPoints == nil || len ( conf . EntryPoints ) == 0 {
if log . GetLevel ( ) >= logrus . DebugLevel {
certName := conf . Certificate . CertFile . String ( )
// Truncate certificate information only if it's a well formed certificate content with more than 50 characters
if ! conf . Certificate . CertFile . IsPath ( ) && strings . HasPrefix ( conf . Certificate . CertFile . String ( ) , certificateHeader ) && len ( conf . Certificate . CertFile . String ( ) ) > len ( certificateHeader ) + 50 {
certName = strings . TrimPrefix ( conf . Certificate . CertFile . String ( ) , certificateHeader ) [ : 50 ]
}
log . Debugf ( "No entryPoint is defined to add the certificate %s, it will be added to the default entryPoints: %s" , certName , strings . Join ( defaultEntryPoints , ", " ) )
}
conf . EntryPoints = append ( conf . EntryPoints , defaultEntryPoints ... )
}
2017-11-09 11:16:03 +00:00
for _ , ep := range conf . EntryPoints {
if err := conf . Certificate . AppendCertificates ( epConfiguration , ep ) ; err != nil {
return err
}
}
}
return nil
}