2018-02-08 09:30:06 +01:00
package configuration
import (
"fmt"
"strings"
"github.com/containous/traefik/log"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
)
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
type EntryPoint struct {
Address string
2018-03-23 17:40:04 +01:00
TLS * tls . TLS ` export:"true" `
Redirect * types . Redirect ` export:"true" `
Auth * types . Auth ` export:"true" `
WhitelistSourceRange [ ] string // Deprecated
WhiteList * types . WhiteList ` export:"true" `
2018-02-08 09:30:06 +01:00
Compress bool ` export:"true" `
ProxyProtocol * ProxyProtocol ` export:"true" `
ForwardedHeaders * ForwardedHeaders ` export:"true" `
}
2018-03-23 17:40:04 +01:00
// ProxyProtocol contains Proxy-Protocol configuration
type ProxyProtocol struct {
Insecure bool ` export:"true" `
TrustedIPs [ ] string
}
// ForwardedHeaders Trust client forwarding headers
type ForwardedHeaders struct {
Insecure bool ` export:"true" `
TrustedIPs [ ] string
}
2018-02-08 09:30:06 +01:00
// EntryPoints holds entry points configuration of the reverse proxy (ip, port, TLS...)
type EntryPoints map [ string ] * EntryPoint
// 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 ( ep EntryPoints ) String ( ) string {
return fmt . Sprintf ( "%+v" , map [ string ] * EntryPoint ( ep ) )
}
// Get return the EntryPoints map
func ( ep * EntryPoints ) Get ( ) interface { } {
return * ep
}
// SetValue sets the EntryPoints map with val
func ( ep * EntryPoints ) SetValue ( val interface { } ) {
* ep = val . ( EntryPoints )
}
// Type is type of the struct
func ( ep * EntryPoints ) Type ( ) string {
return "entrypoints"
}
// 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 ( ep * EntryPoints ) Set ( value string ) error {
result := parseEntryPointsConfiguration ( value )
var whiteListSourceRange [ ] string
if len ( result [ "whitelistsourcerange" ] ) > 0 {
whiteListSourceRange = strings . Split ( result [ "whitelistsourcerange" ] , "," )
}
compress := toBool ( result , "compress" )
configTLS , err := makeEntryPointTLS ( result )
if err != nil {
return err
}
( * ep ) [ result [ "name" ] ] = & EntryPoint {
Address : result [ "address" ] ,
TLS : configTLS ,
Auth : makeEntryPointAuth ( result ) ,
Redirect : makeEntryPointRedirect ( result ) ,
Compress : compress ,
WhitelistSourceRange : whiteListSourceRange ,
2018-03-23 17:40:04 +01:00
WhiteList : makeWhiteList ( result ) ,
2018-02-08 09:30:06 +01:00
ProxyProtocol : makeEntryPointProxyProtocol ( result ) ,
ForwardedHeaders : makeEntryPointForwardedHeaders ( result ) ,
}
return nil
}
2018-03-23 17:40:04 +01:00
func makeWhiteList ( result map [ string ] string ) * types . WhiteList {
var wl * types . WhiteList
if rawRange , ok := result [ "whitelist_sourcerange" ] ; ok {
wl = & types . WhiteList {
SourceRange : strings . Split ( rawRange , "," ) ,
UseXForwardedFor : toBool ( result , "whitelist_usexforwardedfor" ) ,
}
}
return wl
}
2018-02-08 09:30:06 +01:00
func makeEntryPointAuth ( result map [ string ] string ) * types . Auth {
var basic * types . Basic
if v , ok := result [ "auth_basic_users" ] ; ok {
basic = & types . Basic {
Users : strings . Split ( v , "," ) ,
}
}
var digest * types . Digest
if v , ok := result [ "auth_digest_users" ] ; ok {
digest = & types . Digest {
Users : strings . Split ( v , "," ) ,
}
}
var forward * types . Forward
if address , ok := result [ "auth_forward_address" ] ; ok {
var clientTLS * types . ClientTLS
cert := result [ "auth_forward_tls_cert" ]
key := result [ "auth_forward_tls_key" ]
insecureSkipVerify := toBool ( result , "auth_forward_tls_insecureskipverify" )
if len ( cert ) > 0 && len ( key ) > 0 || insecureSkipVerify {
clientTLS = & types . ClientTLS {
CA : result [ "auth_forward_tls_ca" ] ,
CAOptional : toBool ( result , "auth_forward_tls_caoptional" ) ,
Cert : cert ,
Key : key ,
InsecureSkipVerify : insecureSkipVerify ,
}
}
forward = & types . Forward {
Address : address ,
TLS : clientTLS ,
TrustForwardHeader : toBool ( result , "auth_forward_trustforwardheader" ) ,
}
}
var auth * types . Auth
if basic != nil || digest != nil || forward != nil {
auth = & types . Auth {
Basic : basic ,
Digest : digest ,
Forward : forward ,
HeaderField : result [ "auth_headerfield" ] ,
}
}
return auth
}
func makeEntryPointProxyProtocol ( result map [ string ] string ) * ProxyProtocol {
var proxyProtocol * ProxyProtocol
ppTrustedIPs := result [ "proxyprotocol_trustedips" ]
if len ( result [ "proxyprotocol_insecure" ] ) > 0 || len ( ppTrustedIPs ) > 0 {
proxyProtocol = & ProxyProtocol {
Insecure : toBool ( result , "proxyprotocol_insecure" ) ,
}
if len ( ppTrustedIPs ) > 0 {
proxyProtocol . TrustedIPs = strings . Split ( ppTrustedIPs , "," )
}
}
if proxyProtocol != nil && proxyProtocol . Insecure {
log . Warn ( "ProxyProtocol.Insecure:true is dangerous. Please use 'ProxyProtocol.TrustedIPs:IPs' and remove 'ProxyProtocol.Insecure:true'" )
}
return proxyProtocol
}
func makeEntryPointForwardedHeaders ( result map [ string ] string ) * ForwardedHeaders {
// TODO must be changed to false by default in the next breaking version.
forwardedHeaders := & ForwardedHeaders { Insecure : true }
if _ , ok := result [ "forwardedheaders_insecure" ] ; ok {
forwardedHeaders . Insecure = toBool ( result , "forwardedheaders_insecure" )
}
fhTrustedIPs := result [ "forwardedheaders_trustedips" ]
if len ( fhTrustedIPs ) > 0 {
// TODO must be removed in the next breaking version.
forwardedHeaders . Insecure = toBool ( result , "forwardedheaders_insecure" )
forwardedHeaders . TrustedIPs = strings . Split ( fhTrustedIPs , "," )
}
return forwardedHeaders
}
func makeEntryPointRedirect ( result map [ string ] string ) * types . Redirect {
var redirect * types . Redirect
if len ( result [ "redirect_entrypoint" ] ) > 0 || len ( result [ "redirect_regex" ] ) > 0 || len ( result [ "redirect_replacement" ] ) > 0 {
redirect = & types . Redirect {
EntryPoint : result [ "redirect_entrypoint" ] ,
Regex : result [ "redirect_regex" ] ,
Replacement : result [ "redirect_replacement" ] ,
Permanent : toBool ( result , "redirect_permanent" ) ,
}
}
return redirect
}
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 {
Certificates : certs ,
}
} else if len ( result [ "tls_acme" ] ) > 0 {
configTLS = & tls . TLS {
Certificates : tls . Certificates { } ,
}
}
if len ( result [ "ca" ] ) > 0 {
files := strings . Split ( result [ "ca" ] , "," )
optional := toBool ( result , "ca_optional" )
configTLS . ClientCA = tls . ClientCA {
Files : files ,
Optional : optional ,
}
}
return configTLS , nil
}
func parseEntryPointsConfiguration ( raw string ) map [ string ] string {
sections := strings . Fields ( raw )
config := make ( map [ string ] string )
for _ , part := range sections {
field := strings . SplitN ( part , ":" , 2 )
name := strings . ToLower ( strings . Replace ( field [ 0 ] , "." , "_" , - 1 ) )
if len ( field ) > 1 {
config [ name ] = field [ 1 ]
} else {
if strings . EqualFold ( name , "TLS" ) {
config [ "tls_acme" ] = "TLS"
} else {
config [ name ] = ""
}
}
}
return config
}
func toBool ( conf map [ string ] string , key string ) bool {
if val , ok := conf [ key ] ; ok {
return strings . EqualFold ( val , "true" ) ||
strings . EqualFold ( val , "enable" ) ||
strings . EqualFold ( val , "on" )
}
return false
}