1
0
Fork 0

Deprecate IPWhiteList middleware in favor of IPAllowList

Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
Landry Benguigui 2024-01-02 17:04:06 +01:00 committed by GitHub
parent 9662cdca64
commit 0e92b02474
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1268 additions and 50 deletions

View file

@ -19,6 +19,7 @@ type Middleware struct {
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty" toml:"replacePathRegex,omitempty" yaml:"replacePathRegex,omitempty" export:"true"`
Chain *Chain `json:"chain,omitempty" toml:"chain,omitempty" yaml:"chain,omitempty" export:"true"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty" export:"true"`
IPAllowList *IPAllowList `json:"ipAllowList,omitempty" toml:"ipAllowList,omitempty" yaml:"ipAllowList,omitempty" export:"true"`
Headers *Headers `json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
Errors *ErrorPage `json:"errors,omitempty" toml:"errors,omitempty" yaml:"errors,omitempty" export:"true"`
RateLimit *RateLimit `json:"rateLimit,omitempty" toml:"rateLimit,omitempty" yaml:"rateLimit,omitempty" export:"true"`
@ -346,7 +347,7 @@ func (h *Headers) HasSecureHeadersDefined() bool {
// +k8s:deepcopy-gen=true
// IPStrategy holds the IP strategy configuration used by Traefik to determine the client IP.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/http/ipwhitelist/#ipstrategy
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/http/ipallowlist/#ipstrategy
type IPStrategy struct {
// Depth tells Traefik to use the X-Forwarded-For header and take the IP located at the depth position (starting from the right).
Depth int `json:"depth,omitempty" toml:"depth,omitempty" yaml:"depth,omitempty" export:"true"`
@ -388,6 +389,7 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
// IPWhiteList holds the IP whitelist middleware configuration.
// This middleware accepts / refuses requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/http/ipwhitelist/
// Deprecated: please use IPAllowList instead.
type IPWhiteList struct {
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
@ -396,6 +398,17 @@ type IPWhiteList struct {
// +k8s:deepcopy-gen=true
// IPAllowList holds the IP allowlist middleware configuration.
// This middleware accepts / refuses requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/http/ipallowlist/
type IPAllowList struct {
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
// InFlightReq holds the in-flight request middleware configuration.
// This middleware limits the number of requests being processed and served concurrently.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/http/inflightreq/

View file

@ -6,6 +6,7 @@ package dynamic
type TCPMiddleware struct {
InFlightConn *TCPInFlightConn `json:"inFlightConn,omitempty" toml:"inFlightConn,omitempty" yaml:"inFlightConn,omitempty" export:"true"`
IPWhiteList *TCPIPWhiteList `json:"ipWhiteList,omitempty" toml:"ipWhiteList,omitempty" yaml:"ipWhiteList,omitempty" export:"true"`
IPAllowList *TCPIPAllowList `json:"ipAllowList,omitempty" toml:"ipAllowList,omitempty" yaml:"ipAllowList,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -23,8 +24,15 @@ type TCPInFlightConn struct {
// +k8s:deepcopy-gen=true
// TCPIPWhiteList holds the TCP IPWhiteList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
type TCPIPWhiteList struct {
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
}
// +k8s:deepcopy-gen=true
// TCPIPAllowList holds the TCP IPAllowList middleware configuration.
type TCPIPAllowList struct {
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
}

View file

@ -532,6 +532,32 @@ func (in *HealthCheck) DeepCopy() *HealthCheck {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IPAllowList) DeepCopyInto(out *IPAllowList) {
*out = *in
if in.SourceRange != nil {
in, out := &in.SourceRange, &out.SourceRange
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.IPStrategy != nil {
in, out := &in.IPStrategy, &out.IPStrategy
*out = new(IPStrategy)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAllowList.
func (in *IPAllowList) DeepCopy() *IPAllowList {
if in == nil {
return nil
}
out := new(IPAllowList)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IPStrategy) DeepCopyInto(out *IPStrategy) {
*out = *in
@ -659,6 +685,11 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
*out = new(IPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(IPAllowList)
(*in).DeepCopyInto(*out)
}
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = new(Headers)
@ -1355,6 +1386,27 @@ func (in *TCPConfiguration) DeepCopy() *TCPConfiguration {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPIPAllowList) DeepCopyInto(out *TCPIPAllowList) {
*out = *in
if in.SourceRange != nil {
in, out := &in.SourceRange, &out.SourceRange
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPIPAllowList.
func (in *TCPIPAllowList) DeepCopy() *TCPIPAllowList {
if in == nil {
return nil
}
out := new(TCPIPAllowList)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TCPIPWhiteList) DeepCopyInto(out *TCPIPWhiteList) {
*out = *in
@ -1405,6 +1457,11 @@ func (in *TCPMiddleware) DeepCopyInto(out *TCPMiddleware) {
*out = new(TCPIPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(TCPIPAllowList)
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -0,0 +1,88 @@
package ipallowlist
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/opentracing/opentracing-go/ext"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/ip"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/tracing"
)
const (
typeName = "IPAllowLister"
)
// ipAllowLister is a middleware that provides Checks of the Requesting IP against a set of Allowlists.
type ipAllowLister struct {
next http.Handler
allowLister *ip.Checker
strategy ip.Strategy
name string
}
// New builds a new IPAllowLister given a list of CIDR-Strings to allow.
func New(ctx context.Context, next http.Handler, config dynamic.IPAllowList, name string) (http.Handler, error) {
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware")
if len(config.SourceRange) == 0 {
return nil, errors.New("sourceRange is empty, IPAllowLister not created")
}
checker, err := ip.NewChecker(config.SourceRange)
if err != nil {
return nil, fmt.Errorf("cannot parse CIDRs %s: %w", config.SourceRange, err)
}
strategy, err := config.IPStrategy.Get()
if err != nil {
return nil, err
}
logger.Debugf("Setting up IPAllowLister with sourceRange: %s", config.SourceRange)
return &ipAllowLister{
strategy: strategy,
allowLister: checker,
next: next,
name: name,
}, nil
}
func (al *ipAllowLister) GetTracingInformation() (string, ext.SpanKindEnum) {
return al.name, tracing.SpanKindNoneEnum
}
func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
ctx := middlewares.GetLoggerCtx(req.Context(), al.name, typeName)
logger := log.FromContext(ctx)
clientIP := al.strategy.GetIP(req)
err := al.allowLister.IsAuthorized(clientIP)
if err != nil {
msg := fmt.Sprintf("Rejecting IP %s: %v", clientIP, err)
logger.Debug(msg)
tracing.SetErrorWithEvent(req, msg)
reject(ctx, rw)
return
}
logger.Debugf("Accepting IP %s", clientIP)
al.next.ServeHTTP(rw, req)
}
func reject(ctx context.Context, rw http.ResponseWriter) {
statusCode := http.StatusForbidden
rw.WriteHeader(statusCode)
_, err := rw.Write([]byte(http.StatusText(statusCode)))
if err != nil {
log.FromContext(ctx).Error(err)
}
}

View file

@ -0,0 +1,100 @@
package ipallowlist
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
)
func TestNewIPAllowLister(t *testing.T) {
testCases := []struct {
desc string
allowList dynamic.IPAllowList
expectedError bool
}{
{
desc: "invalid IP",
allowList: dynamic.IPAllowList{
SourceRange: []string{"foo"},
},
expectedError: true,
},
{
desc: "valid IP",
allowList: dynamic.IPAllowList{
SourceRange: []string{"10.10.10.10"},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
if test.expectedError {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NotNil(t, allowLister)
}
})
}
}
func TestIPAllowLister_ServeHTTP(t *testing.T) {
testCases := []struct {
desc string
allowList dynamic.IPAllowList
remoteAddr string
expected int
}{
{
desc: "authorized with remote address",
allowList: dynamic.IPAllowList{
SourceRange: []string{"20.20.20.20"},
},
remoteAddr: "20.20.20.20:1234",
expected: 200,
},
{
desc: "non authorized with remote address",
allowList: dynamic.IPAllowList{
SourceRange: []string{"20.20.20.20"},
},
remoteAddr: "20.20.20.21:1234",
expected: 403,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
require.NoError(t, err)
recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "http://10.10.10.10", nil)
if len(test.remoteAddr) > 0 {
req.RemoteAddr = test.remoteAddr
}
allowLister.ServeHTTP(recorder, req)
assert.Equal(t, test.expected, recorder.Code)
})
}
}

View file

@ -0,0 +1,65 @@
package ipallowlist
import (
"context"
"errors"
"fmt"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/ip"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/tcp"
)
const (
typeName = "IPAllowListerTCP"
)
// ipAllowLister is a middleware that provides Checks of the Requesting IP against a set of Allowlists.
type ipAllowLister struct {
next tcp.Handler
allowLister *ip.Checker
name string
}
// New builds a new TCP IPAllowLister given a list of CIDR-Strings to allow.
func New(ctx context.Context, next tcp.Handler, config dynamic.TCPIPAllowList, name string) (tcp.Handler, error) {
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware")
if len(config.SourceRange) == 0 {
return nil, errors.New("sourceRange is empty, IPAllowLister not created")
}
checker, err := ip.NewChecker(config.SourceRange)
if err != nil {
return nil, fmt.Errorf("cannot parse CIDRs %s: %w", config.SourceRange, err)
}
logger.Debugf("Setting up IPAllowLister with sourceRange: %s", config.SourceRange)
return &ipAllowLister{
allowLister: checker,
next: next,
name: name,
}, nil
}
func (al *ipAllowLister) ServeTCP(conn tcp.WriteCloser) {
ctx := middlewares.GetLoggerCtx(context.Background(), al.name, typeName)
logger := log.FromContext(ctx)
addr := conn.RemoteAddr().String()
err := al.allowLister.IsAuthorized(addr)
if err != nil {
logger.Errorf("Connection from %s rejected: %v", addr, err)
conn.Close()
return
}
logger.Debugf("Connection from %s accepted", addr)
al.next.ServeTCP(conn)
}

View file

@ -0,0 +1,139 @@
package ipallowlist
import (
"context"
"io"
"net"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/tcp"
)
func TestNewIPAllowLister(t *testing.T) {
testCases := []struct {
desc string
allowList dynamic.TCPIPAllowList
expectedError bool
}{
{
desc: "Empty config",
allowList: dynamic.TCPIPAllowList{},
expectedError: true,
},
{
desc: "invalid IP",
allowList: dynamic.TCPIPAllowList{
SourceRange: []string{"foo"},
},
expectedError: true,
},
{
desc: "valid IP",
allowList: dynamic.TCPIPAllowList{
SourceRange: []string{"10.10.10.10"},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := tcp.HandlerFunc(func(conn tcp.WriteCloser) {})
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
if test.expectedError {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NotNil(t, allowLister)
}
})
}
}
func TestIPAllowLister_ServeHTTP(t *testing.T) {
testCases := []struct {
desc string
allowList dynamic.TCPIPAllowList
remoteAddr string
expected string
}{
{
desc: "authorized with remote address",
allowList: dynamic.TCPIPAllowList{
SourceRange: []string{"20.20.20.20"},
},
remoteAddr: "20.20.20.20:1234",
expected: "OK",
},
{
desc: "non authorized with remote address",
allowList: dynamic.TCPIPAllowList{
SourceRange: []string{"20.20.20.20"},
},
remoteAddr: "20.20.20.21:1234",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := tcp.HandlerFunc(func(conn tcp.WriteCloser) {
write, err := conn.Write([]byte("OK"))
require.NoError(t, err)
assert.Equal(t, 2, write)
err = conn.Close()
require.NoError(t, err)
})
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
require.NoError(t, err)
server, client := net.Pipe()
go func() {
allowLister.ServeTCP(&contextWriteCloser{client, addr{test.remoteAddr}})
}()
read, err := io.ReadAll(server)
require.NoError(t, err)
assert.Equal(t, test.expected, string(read))
})
}
}
type contextWriteCloser struct {
net.Conn
addr
}
type addr struct {
remoteAddr string
}
func (a addr) Network() string {
panic("implement me")
}
func (a addr) String() string {
return a.remoteAddr
}
func (c contextWriteCloser) CloseWrite() error {
panic("implement me")
}
func (c contextWriteCloser) RemoteAddr() net.Addr { return c.addr }
func (c contextWriteCloser) Context() context.Context {
return context.Background()
}

View file

@ -288,6 +288,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
ReplacePathRegex: middleware.Spec.ReplacePathRegex,
Chain: createChainMiddleware(ctxMid, middleware.Namespace, middleware.Spec.Chain),
IPWhiteList: middleware.Spec.IPWhiteList,
IPAllowList: middleware.Spec.IPAllowList,
Headers: middleware.Spec.Headers,
Errors: errorPage,
RateLimit: rateLimit,
@ -313,6 +314,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
conf.TCP.Middlewares[id] = &dynamic.TCPMiddleware{
InFlightConn: middlewareTCP.Spec.InFlightConn,
IPWhiteList: middlewareTCP.Spec.IPWhiteList,
IPAllowList: middlewareTCP.Spec.IPAllowList,
}
}

View file

@ -33,6 +33,7 @@ type MiddlewareSpec struct {
ReplacePathRegex *dynamic.ReplacePathRegex `json:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty"`
IPWhiteList *dynamic.IPWhiteList `json:"ipWhiteList,omitempty"`
IPAllowList *dynamic.IPAllowList `json:"ipAllowList,omitempty"`
Headers *dynamic.Headers `json:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty"`

View file

@ -26,7 +26,14 @@ type MiddlewareTCPSpec struct {
// InFlightConn defines the InFlightConn middleware configuration.
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
// IPWhiteList defines the IPWhiteList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// Deprecated: please use IPAllowList instead.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/tcp/ipwhitelist/
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
// IPAllowList defines the IPAllowList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/tcp/ipallowlist/
IPAllowList *dynamic.TCPIPAllowList `json:"ipAllowList,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View file

@ -694,6 +694,11 @@ func (in *MiddlewareSpec) DeepCopyInto(out *MiddlewareSpec) {
*out = new(dynamic.IPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(dynamic.IPAllowList)
(*in).DeepCopyInto(*out)
}
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = new(dynamic.Headers)
@ -862,6 +867,11 @@ func (in *MiddlewareTCPSpec) DeepCopyInto(out *MiddlewareTCPSpec) {
*out = new(dynamic.TCPIPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(dynamic.TCPIPAllowList)
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -33,6 +33,7 @@ type MiddlewareSpec struct {
ReplacePathRegex *dynamic.ReplacePathRegex `json:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty"`
IPWhiteList *dynamic.IPWhiteList `json:"ipWhiteList,omitempty"`
IPAllowList *dynamic.IPAllowList `json:"ipAllowList,omitempty"`
Headers *dynamic.Headers `json:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty"`

View file

@ -26,7 +26,14 @@ type MiddlewareTCPSpec struct {
// InFlightConn defines the InFlightConn middleware configuration.
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
// IPWhiteList defines the IPWhiteList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// Deprecated: please use IPAllowList instead.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/tcp/ipwhitelist/
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
// IPAllowList defines the IPAllowList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.10/middlewares/tcp/ipallowlist/
IPAllowList *dynamic.TCPIPAllowList `json:"ipAllowList,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View file

@ -694,6 +694,11 @@ func (in *MiddlewareSpec) DeepCopyInto(out *MiddlewareSpec) {
*out = new(dynamic.IPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(dynamic.IPAllowList)
(*in).DeepCopyInto(*out)
}
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = new(dynamic.Headers)
@ -862,6 +867,11 @@ func (in *MiddlewareTCPSpec) DeepCopyInto(out *MiddlewareTCPSpec) {
*out = new(dynamic.TCPIPWhiteList)
(*in).DeepCopyInto(*out)
}
if in.IPAllowList != nil {
in, out := &in.IPAllowList, &out.IPAllowList
*out = new(dynamic.TCPIPAllowList)
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -10,6 +10,7 @@ import (
"github.com/containous/alice"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/addprefix"
"github.com/traefik/traefik/v2/pkg/middlewares/auth"
"github.com/traefik/traefik/v2/pkg/middlewares/buffering"
@ -19,6 +20,7 @@ import (
"github.com/traefik/traefik/v2/pkg/middlewares/customerrors"
"github.com/traefik/traefik/v2/pkg/middlewares/headers"
"github.com/traefik/traefik/v2/pkg/middlewares/inflightreq"
"github.com/traefik/traefik/v2/pkg/middlewares/ipallowlist"
"github.com/traefik/traefik/v2/pkg/middlewares/ipwhitelist"
"github.com/traefik/traefik/v2/pkg/middlewares/passtlsclientcert"
"github.com/traefik/traefik/v2/pkg/middlewares/ratelimiter"
@ -231,6 +233,8 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
// IPWhiteList
if config.IPWhiteList != nil {
log.FromContext(ctx).Warn("IPWhiteList is deprecated, please use IPAllowList instead.")
if middleware != nil {
return nil, badConf
}
@ -239,6 +243,16 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
}
}
// IPAllowList
if config.IPAllowList != nil {
if middleware != nil {
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
return ipallowlist.New(ctx, next, *config.IPAllowList, middlewareName)
}
}
// InFlightReq
if config.InFlightReq != nil {
if middleware != nil {