Add whitelist configuration option for entrypoints
* Add whitelist configuration option for entrypoints * Add whitelist support to --entrypoint flag
This commit is contained in:
parent
a7ec785994
commit
759a19bc4f
5 changed files with 131 additions and 39 deletions
|
@ -279,6 +279,12 @@ To write JSON format logs, specify `json` as the format:
|
||||||
# address = ":80"
|
# address = ":80"
|
||||||
# compress = true
|
# compress = true
|
||||||
|
|
||||||
|
# To enable IP whitelisting at the entrypoint level:
|
||||||
|
# [entryPoints]
|
||||||
|
# [entryPoints.http]
|
||||||
|
# address = ":80"
|
||||||
|
# whiteListSourceRange = ["127.0.0.1/32"]
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
|
@ -189,7 +189,7 @@ func (ep *EntryPoints) String() string {
|
||||||
// Set's argument is a string to be parsed to set the flag.
|
// Set's argument is a string to be parsed to set the flag.
|
||||||
// It's a comma-separated list, so we split it.
|
// It's a comma-separated list, so we split it.
|
||||||
func (ep *EntryPoints) Set(value string) error {
|
func (ep *EntryPoints) Set(value string) error {
|
||||||
regex := regexp.MustCompile("(?:Name:(?P<Name>\\S*))\\s*(?:Address:(?P<Address>\\S*))?\\s*(?:TLS:(?P<TLS>\\S*))?\\s*((?P<TLSACME>TLS))?\\s*(?:CA:(?P<CA>\\S*))?\\s*(?:Redirect.EntryPoint:(?P<RedirectEntryPoint>\\S*))?\\s*(?:Redirect.Regex:(?P<RedirectRegex>\\S*))?\\s*(?:Redirect.Replacement:(?P<RedirectReplacement>\\S*))?\\s*(?:Compress:(?P<Compress>\\S*))?")
|
regex := regexp.MustCompile("(?:Name:(?P<Name>\\S*))\\s*(?:Address:(?P<Address>\\S*))?\\s*(?:TLS:(?P<TLS>\\S*))?\\s*((?P<TLSACME>TLS))?\\s*(?:CA:(?P<CA>\\S*))?\\s*(?:Redirect.EntryPoint:(?P<RedirectEntryPoint>\\S*))?\\s*(?:Redirect.Regex:(?P<RedirectRegex>\\S*))?\\s*(?:Redirect.Replacement:(?P<RedirectReplacement>\\S*))?\\s*(?:Compress:(?P<Compress>\\S*))?\\s*(?:WhiteListSourceRange:(?P<WhiteListSourceRange>\\S*))?")
|
||||||
match := regex.FindAllStringSubmatch(value, -1)
|
match := regex.FindAllStringSubmatch(value, -1)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
return fmt.Errorf("bad EntryPoints format: %s", value)
|
return fmt.Errorf("bad EntryPoints format: %s", value)
|
||||||
|
@ -233,11 +233,17 @@ func (ep *EntryPoints) Set(value string) error {
|
||||||
compress = strings.EqualFold(result["Compress"], "enable") || strings.EqualFold(result["Compress"], "on")
|
compress = strings.EqualFold(result["Compress"], "enable") || strings.EqualFold(result["Compress"], "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
whiteListSourceRange := []string{}
|
||||||
|
if len(result["WhiteListSourceRange"]) > 0 {
|
||||||
|
whiteListSourceRange = strings.Split(result["WhiteListSourceRange"], ",")
|
||||||
|
}
|
||||||
|
|
||||||
(*ep)[result["Name"]] = &EntryPoint{
|
(*ep)[result["Name"]] = &EntryPoint{
|
||||||
Address: result["Address"],
|
Address: result["Address"],
|
||||||
TLS: tls,
|
TLS: tls,
|
||||||
Redirect: redirect,
|
Redirect: redirect,
|
||||||
Compress: compress,
|
Compress: compress,
|
||||||
|
WhitelistSourceRange: whiteListSourceRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -260,12 +266,13 @@ func (ep *EntryPoints) Type() string {
|
||||||
|
|
||||||
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
|
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
|
||||||
type EntryPoint struct {
|
type EntryPoint struct {
|
||||||
Network string
|
Network string
|
||||||
Address string
|
Address string
|
||||||
TLS *TLS
|
TLS *TLS
|
||||||
Redirect *Redirect
|
Redirect *Redirect
|
||||||
Auth *types.Auth
|
Auth *types.Auth
|
||||||
Compress bool
|
WhitelistSourceRange []string
|
||||||
|
Compress bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect configures a redirection of an entry point to another, or to an URL
|
// Redirect configures a redirection of an entry point to another, or to an URL
|
||||||
|
|
|
@ -188,38 +188,51 @@ func (server *Server) startHTTPServers() {
|
||||||
server.serverEntryPoints = server.buildEntryPoints(server.globalConfiguration)
|
server.serverEntryPoints = server.buildEntryPoints(server.globalConfiguration)
|
||||||
|
|
||||||
for newServerEntryPointName, newServerEntryPoint := range server.serverEntryPoints {
|
for newServerEntryPointName, newServerEntryPoint := range server.serverEntryPoints {
|
||||||
serverMiddlewares := []negroni.Handler{middlewares.NegroniRecoverHandler(), metrics}
|
serverEntryPoint := server.setupServerEntryPoint(newServerEntryPointName, newServerEntryPoint)
|
||||||
if server.accessLoggerMiddleware != nil {
|
|
||||||
serverMiddlewares = append(serverMiddlewares, server.accessLoggerMiddleware)
|
|
||||||
}
|
|
||||||
metrics := newMetrics(server.globalConfiguration, newServerEntryPointName)
|
|
||||||
if metrics != nil {
|
|
||||||
serverMiddlewares = append(serverMiddlewares, middlewares.NewMetricsWrapper(metrics))
|
|
||||||
}
|
|
||||||
if server.globalConfiguration.Web != nil && server.globalConfiguration.Web.Statistics != nil {
|
|
||||||
statsRecorder = middlewares.NewStatsRecorder(server.globalConfiguration.Web.Statistics.RecentErrors)
|
|
||||||
serverMiddlewares = append(serverMiddlewares, statsRecorder)
|
|
||||||
}
|
|
||||||
if server.globalConfiguration.EntryPoints[newServerEntryPointName].Auth != nil {
|
|
||||||
authMiddleware, err := middlewares.NewAuthenticator(server.globalConfiguration.EntryPoints[newServerEntryPointName].Auth)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error starting server: ", err)
|
|
||||||
}
|
|
||||||
serverMiddlewares = append(serverMiddlewares, authMiddleware)
|
|
||||||
}
|
|
||||||
if server.globalConfiguration.EntryPoints[newServerEntryPointName].Compress {
|
|
||||||
serverMiddlewares = append(serverMiddlewares, &middlewares.Compress{})
|
|
||||||
}
|
|
||||||
newsrv, err := server.prepareServer(newServerEntryPointName, newServerEntryPoint.httpRouter, server.globalConfiguration.EntryPoints[newServerEntryPointName], serverMiddlewares...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error preparing server: ", err)
|
|
||||||
}
|
|
||||||
serverEntryPoint := server.serverEntryPoints[newServerEntryPointName]
|
|
||||||
serverEntryPoint.httpServer = newsrv
|
|
||||||
go server.startServer(serverEntryPoint.httpServer, server.globalConfiguration)
|
go server.startServer(serverEntryPoint.httpServer, server.globalConfiguration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (server *Server) setupServerEntryPoint(newServerEntryPointName string, newServerEntryPoint *serverEntryPoint) *serverEntryPoint {
|
||||||
|
serverMiddlewares := []negroni.Handler{middlewares.NegroniRecoverHandler(), metrics}
|
||||||
|
if server.accessLoggerMiddleware != nil {
|
||||||
|
serverMiddlewares = append(serverMiddlewares, server.accessLoggerMiddleware)
|
||||||
|
}
|
||||||
|
metrics := newMetrics(server.globalConfiguration, newServerEntryPointName)
|
||||||
|
if metrics != nil {
|
||||||
|
serverMiddlewares = append(serverMiddlewares, middlewares.NewMetricsWrapper(metrics))
|
||||||
|
}
|
||||||
|
if server.globalConfiguration.Web != nil && server.globalConfiguration.Web.Statistics != nil {
|
||||||
|
statsRecorder = middlewares.NewStatsRecorder(server.globalConfiguration.Web.Statistics.RecentErrors)
|
||||||
|
serverMiddlewares = append(serverMiddlewares, statsRecorder)
|
||||||
|
}
|
||||||
|
if server.globalConfiguration.EntryPoints[newServerEntryPointName].Auth != nil {
|
||||||
|
authMiddleware, err := middlewares.NewAuthenticator(server.globalConfiguration.EntryPoints[newServerEntryPointName].Auth)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error starting server: ", err)
|
||||||
|
}
|
||||||
|
serverMiddlewares = append(serverMiddlewares, authMiddleware)
|
||||||
|
}
|
||||||
|
if server.globalConfiguration.EntryPoints[newServerEntryPointName].Compress {
|
||||||
|
serverMiddlewares = append(serverMiddlewares, &middlewares.Compress{})
|
||||||
|
}
|
||||||
|
if len(server.globalConfiguration.EntryPoints[newServerEntryPointName].WhitelistSourceRange) > 0 {
|
||||||
|
ipWhitelistMiddleware, err := middlewares.NewIPWhitelister(server.globalConfiguration.EntryPoints[newServerEntryPointName].WhitelistSourceRange)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error starting server: ", err)
|
||||||
|
}
|
||||||
|
serverMiddlewares = append(serverMiddlewares, ipWhitelistMiddleware)
|
||||||
|
}
|
||||||
|
newsrv, err := server.prepareServer(newServerEntryPointName, newServerEntryPoint.httpRouter, server.globalConfiguration.EntryPoints[newServerEntryPointName], serverMiddlewares...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error preparing server: ", err)
|
||||||
|
}
|
||||||
|
serverEntryPoint := server.serverEntryPoints[newServerEntryPointName]
|
||||||
|
serverEntryPoint.httpServer = newsrv
|
||||||
|
|
||||||
|
return serverEntryPoint
|
||||||
|
}
|
||||||
|
|
||||||
func (server *Server) listenProviders(stop chan bool) {
|
func (server *Server) listenProviders(stop chan bool) {
|
||||||
lastReceivedConfiguration := safe.New(time.Unix(0, 0))
|
lastReceivedConfiguration := safe.New(time.Unix(0, 0))
|
||||||
lastConfigs := cmap.New()
|
lastConfigs := cmap.New()
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/negroni"
|
||||||
"github.com/containous/flaeg"
|
"github.com/containous/flaeg"
|
||||||
"github.com/containous/mux"
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/healthcheck"
|
"github.com/containous/traefik/healthcheck"
|
||||||
|
@ -516,3 +517,62 @@ type okHTTPHandler struct{}
|
||||||
func (okHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (okHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerEntrypointWhitelistConfig(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
entrypoint *EntryPoint
|
||||||
|
wantMiddleware bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "no whitelist middleware if no config on entrypoint",
|
||||||
|
entrypoint: &EntryPoint{
|
||||||
|
Address: ":8080",
|
||||||
|
},
|
||||||
|
wantMiddleware: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "whitelist middleware should be added if configured on entrypoint",
|
||||||
|
entrypoint: &EntryPoint{
|
||||||
|
Address: ":8080",
|
||||||
|
WhitelistSourceRange: []string{
|
||||||
|
"127.0.0.1/32",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantMiddleware: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
srv := Server{
|
||||||
|
globalConfiguration: GlobalConfiguration{
|
||||||
|
EntryPoints: map[string]*EntryPoint{
|
||||||
|
"test": test.entrypoint,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
srv.serverEntryPoints = srv.buildEntryPoints(srv.globalConfiguration)
|
||||||
|
srvEntryPoint := srv.setupServerEntryPoint("test", srv.serverEntryPoints["test"])
|
||||||
|
handler := srvEntryPoint.httpServer.Handler.(*negroni.Negroni)
|
||||||
|
found := false
|
||||||
|
for _, handler := range handler.Handlers() {
|
||||||
|
if reflect.TypeOf(handler) == reflect.TypeOf((*middlewares.IPWhitelister)(nil)) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found && !test.wantMiddleware {
|
||||||
|
t.Errorf("ip whitelist middleware was installed even though it should not")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found && test.wantMiddleware {
|
||||||
|
t.Errorf("ip whitelist middleware was not installed even though it should have")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -329,6 +329,12 @@
|
||||||
# [entryPoints.http]
|
# [entryPoints.http]
|
||||||
# address = "10.42.13.37:80"
|
# address = "10.42.13.37:80"
|
||||||
|
|
||||||
|
# To enable IP whitelisting at the entrypoint level:
|
||||||
|
# [entryPoints]
|
||||||
|
# [entryPoints.http]
|
||||||
|
# address = ":80"
|
||||||
|
# whiteListSourceRange = ["127.0.0.1/32"]
|
||||||
|
|
||||||
# Enable retry sending request if network error
|
# Enable retry sending request if network error
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
|
|
Loading…
Reference in a new issue