266 lines
7.4 KiB
Go
266 lines
7.4 KiB
Go
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
|
|
TLS *tls.TLS `export:"true"`
|
|
Redirect *types.Redirect `export:"true"`
|
|
Auth *types.Auth `export:"true"`
|
|
WhitelistSourceRange []string // Deprecated
|
|
WhiteList *types.WhiteList `export:"true"`
|
|
Compress bool `export:"true"`
|
|
ProxyProtocol *ProxyProtocol `export:"true"`
|
|
ForwardedHeaders *ForwardedHeaders `export:"true"`
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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,
|
|
WhiteList: makeWhiteList(result),
|
|
ProxyProtocol: makeEntryPointProxyProtocol(result),
|
|
ForwardedHeaders: makeEntryPointForwardedHeaders(result),
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|