feat: re introduce IpWhitelist middleware as deprecated
This commit is contained in:
parent
3bbc560283
commit
ff7966f9cd
38 changed files with 1314 additions and 200 deletions
|
@ -12,12 +12,14 @@ import (
|
|||
|
||||
// Middleware holds the Middleware configuration.
|
||||
type Middleware struct {
|
||||
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty" export:"true"`
|
||||
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty" export:"true"`
|
||||
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty" export:"true"`
|
||||
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty" export:"true"`
|
||||
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"`
|
||||
AddPrefix *AddPrefix `json:"addPrefix,omitempty" toml:"addPrefix,omitempty" yaml:"addPrefix,omitempty" export:"true"`
|
||||
StripPrefix *StripPrefix `json:"stripPrefix,omitempty" toml:"stripPrefix,omitempty" yaml:"stripPrefix,omitempty" export:"true"`
|
||||
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty" toml:"stripPrefixRegex,omitempty" yaml:"stripPrefixRegex,omitempty" export:"true"`
|
||||
ReplacePath *ReplacePath `json:"replacePath,omitempty" toml:"replacePath,omitempty" yaml:"replacePath,omitempty" export:"true"`
|
||||
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"`
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
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"`
|
||||
|
@ -376,6 +378,18 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
|||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// IPWhiteList holds the IP whitelist middleware configuration.
|
||||
// This middleware accepts / refuses requests based on the client IP.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/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"`
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// +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/v3.0/middlewares/http/ipallowlist/
|
||||
|
|
|
@ -5,7 +5,9 @@ package dynamic
|
|||
// TCPMiddleware holds the TCPMiddleware configuration.
|
||||
type TCPMiddleware struct {
|
||||
InFlightConn *TCPInFlightConn `json:"inFlightConn,omitempty" toml:"inFlightConn,omitempty" yaml:"inFlightConn,omitempty" export:"true"`
|
||||
IPAllowList *TCPIPAllowList `json:"ipAllowList,omitempty" toml:"ipAllowList,omitempty" yaml:"ipAllowList,omitempty" export:"true"`
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
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
|
||||
|
@ -22,6 +24,15 @@ type TCPInFlightConn struct {
|
|||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPIPWhiteList holds the TCP IPWhiteList middleware configuration.
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
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).
|
||||
|
|
|
@ -600,6 +600,32 @@ func (in *IPStrategy) DeepCopy() *IPStrategy {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IPWhiteList) DeepCopyInto(out *IPWhiteList) {
|
||||
*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 IPWhiteList.
|
||||
func (in *IPWhiteList) DeepCopy() *IPWhiteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IPWhiteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InFlightReq) DeepCopyInto(out *InFlightReq) {
|
||||
*out = *in
|
||||
|
@ -675,6 +701,11 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
|
|||
*out = new(Chain)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPWhiteList != nil {
|
||||
in, out := &in.IPWhiteList, &out.IPWhiteList
|
||||
*out = new(IPWhiteList)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPAllowList != nil {
|
||||
in, out := &in.IPAllowList, &out.IPAllowList
|
||||
*out = new(IPAllowList)
|
||||
|
@ -1443,6 +1474,27 @@ func (in *TCPIPAllowList) DeepCopy() *TCPIPAllowList {
|
|||
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
|
||||
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 TCPIPWhiteList.
|
||||
func (in *TCPIPWhiteList) DeepCopy() *TCPIPWhiteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TCPIPWhiteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TCPInFlightConn) DeepCopyInto(out *TCPInFlightConn) {
|
||||
*out = *in
|
||||
|
@ -1467,6 +1519,11 @@ func (in *TCPMiddleware) DeepCopyInto(out *TCPMiddleware) {
|
|||
*out = new(TCPInFlightConn)
|
||||
**out = **in
|
||||
}
|
||||
if in.IPWhiteList != nil {
|
||||
in, out := &in.IPWhiteList, &out.IPWhiteList
|
||||
*out = new(TCPIPWhiteList)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPAllowList != nil {
|
||||
in, out := &in.IPAllowList, &out.IPAllowList
|
||||
*out = new(TCPIPAllowList)
|
||||
|
|
88
pkg/middlewares/ipwhitelist/ip_whitelist.go
Normal file
88
pkg/middlewares/ipwhitelist/ip_whitelist.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/ip"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
typeName = "IPWhiteLister"
|
||||
)
|
||||
|
||||
// ipWhiteLister is a middleware that provides Checks of the Requesting IP against a set of Whitelists.
|
||||
type ipWhiteLister struct {
|
||||
next http.Handler
|
||||
whiteLister *ip.Checker
|
||||
strategy ip.Strategy
|
||||
name string
|
||||
}
|
||||
|
||||
// New builds a new IPWhiteLister given a list of CIDR-Strings to whitelist.
|
||||
func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
if len(config.SourceRange) == 0 {
|
||||
return nil, errors.New("sourceRange is empty, IPWhiteLister not created")
|
||||
}
|
||||
|
||||
checker, err := ip.NewChecker(config.SourceRange)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse CIDR whitelist %s: %w", config.SourceRange, err)
|
||||
}
|
||||
|
||||
strategy, err := config.IPStrategy.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Debug().Msgf("Setting up IPWhiteLister with sourceRange: %s", config.SourceRange)
|
||||
|
||||
return &ipWhiteLister{
|
||||
strategy: strategy,
|
||||
whiteLister: checker,
|
||||
next: next,
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (wl *ipWhiteLister) GetTracingInformation() (string, string, trace.SpanKind) {
|
||||
return wl.name, typeName, trace.SpanKindInternal
|
||||
}
|
||||
|
||||
func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
logger := middlewares.GetLogger(req.Context(), wl.name, typeName)
|
||||
ctx := logger.WithContext(req.Context())
|
||||
|
||||
clientIP := wl.strategy.GetIP(req)
|
||||
err := wl.whiteLister.IsAuthorized(clientIP)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Rejecting IP %s: %v", clientIP, err)
|
||||
logger.Debug().Msg(msg)
|
||||
tracing.SetStatusErrorf(req.Context(), msg)
|
||||
reject(ctx, rw)
|
||||
return
|
||||
}
|
||||
logger.Debug().Msgf("Accepting IP %s", clientIP)
|
||||
|
||||
wl.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.Ctx(ctx).Error().Err(err).Send()
|
||||
}
|
||||
}
|
100
pkg/middlewares/ipwhitelist/ip_whitelist_test.go
Normal file
100
pkg/middlewares/ipwhitelist/ip_whitelist_test.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
)
|
||||
|
||||
func TestNewIPWhiteLister(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
whiteList dynamic.IPWhiteList
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "invalid IP",
|
||||
whiteList: dynamic.IPWhiteList{
|
||||
SourceRange: []string{"foo"},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
desc: "valid IP",
|
||||
whiteList: dynamic.IPWhiteList{
|
||||
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) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, whiteLister)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPWhiteLister_ServeHTTP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
whiteList dynamic.IPWhiteList
|
||||
remoteAddr string
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
desc: "authorized with remote address",
|
||||
whiteList: dynamic.IPWhiteList{
|
||||
SourceRange: []string{"20.20.20.20"},
|
||||
},
|
||||
remoteAddr: "20.20.20.20:1234",
|
||||
expected: 200,
|
||||
},
|
||||
{
|
||||
desc: "non authorized with remote address",
|
||||
whiteList: dynamic.IPWhiteList{
|
||||
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) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "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
|
||||
}
|
||||
|
||||
whiteLister.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, test.expected, recorder.Code)
|
||||
})
|
||||
}
|
||||
}
|
63
pkg/middlewares/tcp/ipwhitelist/ip_whitelist.go
Normal file
63
pkg/middlewares/tcp/ipwhitelist/ip_whitelist.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/ip"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
)
|
||||
|
||||
const (
|
||||
typeName = "IPWhiteListerTCP"
|
||||
)
|
||||
|
||||
// ipWhiteLister is a middleware that provides Checks of the Requesting IP against a set of Whitelists.
|
||||
type ipWhiteLister struct {
|
||||
next tcp.Handler
|
||||
whiteLister *ip.Checker
|
||||
name string
|
||||
}
|
||||
|
||||
// New builds a new TCP IPWhiteLister given a list of CIDR-Strings to whitelist.
|
||||
func New(ctx context.Context, next tcp.Handler, config dynamic.TCPIPWhiteList, name string) (tcp.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
if len(config.SourceRange) == 0 {
|
||||
return nil, errors.New("sourceRange is empty, IPWhiteLister not created")
|
||||
}
|
||||
|
||||
checker, err := ip.NewChecker(config.SourceRange)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse CIDR whitelist %s: %w", config.SourceRange, err)
|
||||
}
|
||||
|
||||
logger.Debug().Msgf("Setting up IPWhiteLister with sourceRange: %s", config.SourceRange)
|
||||
|
||||
return &ipWhiteLister{
|
||||
whiteLister: checker,
|
||||
next: next,
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (wl *ipWhiteLister) ServeTCP(conn tcp.WriteCloser) {
|
||||
logger := middlewares.GetLogger(context.Background(), wl.name, typeName)
|
||||
|
||||
addr := conn.RemoteAddr().String()
|
||||
|
||||
err := wl.whiteLister.IsAuthorized(addr)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("Connection from %s rejected", addr)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
logger.Debug().Msgf("Connection from %s accepted", addr)
|
||||
|
||||
wl.next.ServeTCP(conn)
|
||||
}
|
139
pkg/middlewares/tcp/ipwhitelist/ip_whitelist_test.go
Normal file
139
pkg/middlewares/tcp/ipwhitelist/ip_whitelist_test.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
)
|
||||
|
||||
func TestNewIPWhiteLister(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
whiteList dynamic.TCPIPWhiteList
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "Empty config",
|
||||
whiteList: dynamic.TCPIPWhiteList{},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
desc: "invalid IP",
|
||||
whiteList: dynamic.TCPIPWhiteList{
|
||||
SourceRange: []string{"foo"},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
desc: "valid IP",
|
||||
whiteList: dynamic.TCPIPWhiteList{
|
||||
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) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, whiteLister)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPWhiteLister_ServeHTTP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
whiteList dynamic.TCPIPWhiteList
|
||||
remoteAddr string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "authorized with remote address",
|
||||
whiteList: dynamic.TCPIPWhiteList{
|
||||
SourceRange: []string{"20.20.20.20"},
|
||||
},
|
||||
remoteAddr: "20.20.20.20:1234",
|
||||
expected: "OK",
|
||||
},
|
||||
{
|
||||
desc: "non authorized with remote address",
|
||||
whiteList: dynamic.TCPIPWhiteList{
|
||||
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)
|
||||
})
|
||||
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
server, client := net.Pipe()
|
||||
|
||||
go func() {
|
||||
whiteLister.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()
|
||||
}
|
|
@ -288,6 +288,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
|||
ReplacePath: middleware.Spec.ReplacePath,
|
||||
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,
|
||||
|
@ -314,6 +315,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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,14 @@ type Middleware struct {
|
|||
|
||||
// MiddlewareSpec defines the desired state of a Middleware.
|
||||
type MiddlewareSpec struct {
|
||||
AddPrefix *dynamic.AddPrefix `json:"addPrefix,omitempty"`
|
||||
StripPrefix *dynamic.StripPrefix `json:"stripPrefix,omitempty"`
|
||||
StripPrefixRegex *dynamic.StripPrefixRegex `json:"stripPrefixRegex,omitempty"`
|
||||
ReplacePath *dynamic.ReplacePath `json:"replacePath,omitempty"`
|
||||
ReplacePathRegex *dynamic.ReplacePathRegex `json:"replacePathRegex,omitempty"`
|
||||
Chain *Chain `json:"chain,omitempty"`
|
||||
AddPrefix *dynamic.AddPrefix `json:"addPrefix,omitempty"`
|
||||
StripPrefix *dynamic.StripPrefix `json:"stripPrefix,omitempty"`
|
||||
StripPrefixRegex *dynamic.StripPrefixRegex `json:"stripPrefixRegex,omitempty"`
|
||||
ReplacePath *dynamic.ReplacePath `json:"replacePath,omitempty"`
|
||||
ReplacePathRegex *dynamic.ReplacePathRegex `json:"replacePathRegex,omitempty"`
|
||||
Chain *Chain `json:"chain,omitempty"`
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
IPWhiteList *dynamic.IPWhiteList `json:"ipWhiteList,omitempty"`
|
||||
IPAllowList *dynamic.IPAllowList `json:"ipAllowList,omitempty"`
|
||||
Headers *dynamic.Headers `json:"headers,omitempty"`
|
||||
Errors *ErrorPage `json:"errors,omitempty"`
|
||||
|
|
|
@ -25,6 +25,9 @@ type MiddlewareTCP struct {
|
|||
type MiddlewareTCPSpec struct {
|
||||
// InFlightConn defines the InFlightConn middleware configuration.
|
||||
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
|
||||
// IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
|
||||
// IPAllowList defines the IPAllowList middleware configuration.
|
||||
IPAllowList *dynamic.TCPIPAllowList `json:"ipAllowList,omitempty"`
|
||||
}
|
||||
|
|
|
@ -689,6 +689,11 @@ func (in *MiddlewareSpec) DeepCopyInto(out *MiddlewareSpec) {
|
|||
*out = new(Chain)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPWhiteList != nil {
|
||||
in, out := &in.IPWhiteList, &out.IPWhiteList
|
||||
*out = new(dynamic.IPWhiteList)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPAllowList != nil {
|
||||
in, out := &in.IPAllowList, &out.IPAllowList
|
||||
*out = new(dynamic.IPAllowList)
|
||||
|
@ -862,6 +867,11 @@ func (in *MiddlewareTCPSpec) DeepCopyInto(out *MiddlewareTCPSpec) {
|
|||
*out = new(dynamic.TCPInFlightConn)
|
||||
**out = **in
|
||||
}
|
||||
if in.IPWhiteList != nil {
|
||||
in, out := &in.IPWhiteList, &out.IPWhiteList
|
||||
*out = new(dynamic.TCPIPWhiteList)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.IPAllowList != nil {
|
||||
in, out := &in.IPAllowList, &out.IPAllowList
|
||||
*out = new(dynamic.TCPIPAllowList)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/addprefix"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/auth"
|
||||
|
@ -22,6 +23,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/middlewares/headers"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/inflightreq"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/ipallowlist"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/ipwhitelist"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/passtlsclientcert"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/ratelimiter"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/redirect"
|
||||
|
@ -236,6 +238,18 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
|
|||
}
|
||||
}
|
||||
|
||||
// IPWhiteList
|
||||
if config.IPWhiteList != nil {
|
||||
log.Warn().Msg("IPWhiteList is deprecated, please use IPAllowList instead.")
|
||||
|
||||
if middleware != nil {
|
||||
return nil, badConf
|
||||
}
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return ipwhitelist.New(ctx, next, *config.IPWhiteList, middlewareName)
|
||||
}
|
||||
}
|
||||
|
||||
// IPAllowList
|
||||
if config.IPAllowList != nil {
|
||||
if middleware != nil {
|
||||
|
|
|
@ -5,9 +5,11 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/tcp/inflightconn"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/tcp/ipallowlist"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/tcp/ipwhitelist"
|
||||
"github.com/traefik/traefik/v3/pkg/server/provider"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
)
|
||||
|
@ -94,6 +96,15 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
|
|||
}
|
||||
}
|
||||
|
||||
// IPWhiteList
|
||||
if config.IPWhiteList != nil {
|
||||
log.Warn().Msg("IPWhiteList is deprecated, please use IPAllowList instead.")
|
||||
|
||||
middleware = func(next tcp.Handler) (tcp.Handler, error) {
|
||||
return ipwhitelist.New(ctx, next, *config.IPWhiteList, middlewareName)
|
||||
}
|
||||
}
|
||||
|
||||
// IPAllowList
|
||||
if config.IPAllowList != nil {
|
||||
middleware = func(next tcp.Handler) (tcp.Handler, error) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue