feat: re introduce IpWhitelist middleware as deprecated

This commit is contained in:
Michael 2024-01-11 10:40:06 +01:00 committed by GitHub
parent 3bbc560283
commit ff7966f9cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1314 additions and 200 deletions

View file

@ -252,6 +252,12 @@ issues:
text: 'SA1019: config.ClientCAs.Subjects has been deprecated since Go 1.18'
- path: pkg/types/tls_test.go
text: 'SA1019: tlsConfig.RootCAs.Subjects has been deprecated since Go 1.18'
- path: pkg/provider/kubernetes/crd/kubernetes.go
text: 'SA1019: middleware.Spec.IPWhiteList is deprecated: please use IPAllowList instead.'
- path: pkg/server/middleware/tcp/middlewares.go
text: 'SA1019: config.IPWhiteList is deprecated: please use IPAllowList instead.'
- path: pkg/server/middleware/middlewares.go
text: 'SA1019: config.IPWhiteList is deprecated: please use IPAllowList instead.'
- path: pkg/provider/kubernetes/(crd|gateway)/client.go
linters:
- interfacebloat

View file

@ -0,0 +1,201 @@
---
title: "Traefik HTTP Middlewares IPWhiteList"
description: "Learn how to use IPWhiteList in HTTP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
---
# IPWhiteList
Limiting Clients to Specific IPs
{: .subtitle }
![IPWhiteList](../../assets/img/middleware/ipwhitelist.png)
IPWhiteList accepts / refuses requests based on the client IP.
!!! warning
This middleware is deprecated, please use the [IPAllowList](./ipallowlist.md) middleware instead.
## Configuration Examples
```yaml tab="Docker"
# Accepts request from defined IP
labels:
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-ipwhitelist
spec:
ipWhiteList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.7
```
```yaml tab="Consul Catalog"
# Accepts request from defined IP
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="File (YAML)"
# Accepts request from defined IP
http:
middlewares:
test-ipwhitelist:
ipWhiteList:
sourceRange:
- "127.0.0.1/32"
- "192.168.1.7"
```
```toml tab="File (TOML)"
# Accepts request from defined IP
[http.middlewares]
[http.middlewares.test-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
```
## Configuration Options
### `sourceRange`
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
### `ipStrategy`
The `ipStrategy` option defines two parameters that set how Traefik determines the client IP: `depth`, and `excludedIPs`.
If no strategy is set, the default behavior is to match `sourceRange` against the Remote address found in the request.
!!! important "As a middleware, whitelisting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through whitelisting. Therefore, during whitelisting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be matched against `sourceRange`."
#### `ipStrategy.depth`
The `depth` option tells Traefik to use the `X-Forwarded-For` header and take the IP located at the `depth` position (starting from the right).
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
- `depth` is ignored if its value is less than or equal to 0.
!!! example "Examples of Depth & X-Forwarded-For"
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used for the whitelisting is `"12.0.0.1"` (`depth=2`).
| `X-Forwarded-For` | `depth` | clientIP |
|-----------------------------------------|---------|--------------|
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `1` | `"13.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
```yaml tab="Docker"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
labels:
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.depth=2"
```
```yaml tab="Kubernetes"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-ipwhitelist
spec:
ipWhiteList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.7
ipStrategy:
depth: 2
```
```yaml tab="Consul Catalog"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.depth=2"
```
```yaml tab="File (YAML)"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
http:
middlewares:
test-ipwhitelist:
ipWhiteList:
sourceRange:
- "127.0.0.1/32"
- "192.168.1.7"
ipStrategy:
depth: 2
```
```toml tab="File (TOML)"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
[http.middlewares]
[http.middlewares.test-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
depth = 2
```
#### `ipStrategy.excludedIPs`
`excludedIPs` configures Traefik to scan the `X-Forwarded-For` header and select the first IP not in the list.
!!! important "If `depth` is specified, `excludedIPs` is ignored."
!!! example "Example of ExcludedIPs & X-Forwarded-For"
| `X-Forwarded-For` | `excludedIPs` | clientIP |
|-----------------------------------------|-----------------------|--------------|
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"12.0.0.1,13.0.0.1"` | `"11.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"10.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
```yaml tab="Docker"
# Exclude from `X-Forwarded-For`
labels:
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="Kubernetes"
# Exclude from `X-Forwarded-For`
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-ipwhitelist
spec:
ipWhiteList:
ipStrategy:
excludedIPs:
- 127.0.0.1/32
- 192.168.1.7
```
```yaml tab="Consul Catalog"
# Exclude from `X-Forwarded-For`
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="File (YAML)"
# Exclude from `X-Forwarded-For`
http:
middlewares:
test-ipwhitelist:
ipWhiteList:
ipStrategy:
excludedIPs:
- "127.0.0.1/32"
- "192.168.1.7"
```
```toml tab="File (TOML)"
# Exclude from `X-Forwarded-For`
[http.middlewares]
[http.middlewares.test-ipwhitelist.ipWhiteList]
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
```

View file

@ -8,7 +8,7 @@ description: "Learn how to use IPAllowList in TCP middleware for limiting client
Limiting Clients to Specific IPs
{: .subtitle }
IPWhitelist accepts / refuses connections based on the client IP.
IPAllowList accepts / refuses connections based on the client IP.
## Configuration Examples

View file

@ -0,0 +1,64 @@
---
title: "Traefik TCP Middlewares IPWhiteList"
description: "Learn how to use IPWhiteList in TCP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
---
# IPWhiteList
Limiting Clients to Specific IPs
{: .subtitle }
IPWhiteList accepts / refuses connections based on the client IP.
!!! warning
This middleware is deprecated, please use the [IPAllowList](./ipallowlist.md) middleware instead.
## Configuration Examples
```yaml tab="Docker"
# Accepts connections from defined IP
labels:
- "traefik.tcp.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: MiddlewareTCP
metadata:
name: test-ipwhitelist
spec:
ipWhiteList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.7
```
```yaml tab="Consul Catalog"
# Accepts request from defined IP
- "traefik.tcp.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```toml tab="File (TOML)"
# Accepts request from defined IP
[tcp.middlewares]
[tcp.middlewares.test-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
```
```yaml tab="File (YAML)"
# Accepts request from defined IP
tcp:
middlewares:
test-ipwhitelist:
ipWhiteList:
sourceRange:
- "127.0.0.1/32"
- "192.168.1.7"
```
## Configuration Options
### `sourceRange`
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).

View file

@ -65,57 +65,60 @@
- "traefik.http.middlewares.middleware10.headers.stsincludesubdomains=true"
- "traefik.http.middlewares.middleware10.headers.stspreload=true"
- "traefik.http.middlewares.middleware10.headers.stsseconds=42"
- "traefik.http.middlewares.middleware11.ipallowlist.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware11.ipallowlist.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware11.ipallowlist.sourcerange=foobar, foobar"
- "traefik.http.middlewares.middleware11.ipallowlist.rejectstatuscode=404"
- "traefik.http.middlewares.middleware12.inflightreq.amount=42"
- "traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.commonname=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.country=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.domaincomponent=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.locality=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.organization=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.province=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.serialnumber=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.notafter=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.notbefore=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.sans=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.serialnumber=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.commonname=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.country=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.domaincomponent=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.locality=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.organization=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.organizationalunit=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.province=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.serialnumber=true"
- "traefik.http.middlewares.middleware13.passtlsclientcert.pem=true"
- "traefik.http.middlewares.middleware14.plugin.foobar.foo=bar"
- "traefik.http.middlewares.middleware15.ratelimit.average=42"
- "traefik.http.middlewares.middleware15.ratelimit.burst=42"
- "traefik.http.middlewares.middleware15.ratelimit.period=42"
- "traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware16.redirectregex.permanent=true"
- "traefik.http.middlewares.middleware16.redirectregex.regex=foobar"
- "traefik.http.middlewares.middleware16.redirectregex.replacement=foobar"
- "traefik.http.middlewares.middleware17.redirectscheme.permanent=true"
- "traefik.http.middlewares.middleware17.redirectscheme.port=foobar"
- "traefik.http.middlewares.middleware17.redirectscheme.scheme=foobar"
- "traefik.http.middlewares.middleware18.replacepath.path=foobar"
- "traefik.http.middlewares.middleware19.replacepathregex.regex=foobar"
- "traefik.http.middlewares.middleware19.replacepathregex.replacement=foobar"
- "traefik.http.middlewares.middleware20.retry.attempts=42"
- "traefik.http.middlewares.middleware20.retry.initialinterval=42"
- "traefik.http.middlewares.middleware21.stripprefix.prefixes=foobar, foobar"
- "traefik.http.middlewares.middleware22.stripprefixregex.regex=foobar, foobar"
- "traefik.http.middlewares.middleware23.grpcweb.alloworigins=foobar, foobar"
- "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware11.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware12.ipwhitelist.sourcerange=foobar, foobar"
- "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware12.ipallowlist.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware12.ipallowlist.sourcerange=foobar, foobar"
- "traefik.http.middlewares.middleware12.ipallowlist.rejectstatuscode=404"
- "traefik.http.middlewares.middleware13.inflightreq.amount=42"
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware13.inflightreq.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.commonname=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.country=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.domaincomponent=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.locality=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.organization=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.province=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.issuer.serialnumber=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.notafter=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.notbefore=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.sans=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.serialnumber=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.commonname=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.country=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.domaincomponent=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.locality=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organization=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.organizationalunit=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.province=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.info.subject.serialnumber=true"
- "traefik.http.middlewares.middleware14.passtlsclientcert.pem=true"
- "traefik.http.middlewares.middleware15.plugin.foobar.foo=bar"
- "traefik.http.middlewares.middleware16.ratelimit.average=42"
- "traefik.http.middlewares.middleware16.ratelimit.burst=42"
- "traefik.http.middlewares.middleware16.ratelimit.period=42"
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.depth=42"
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requestheadername=foobar"
- "traefik.http.middlewares.middleware16.ratelimit.sourcecriterion.requesthost=true"
- "traefik.http.middlewares.middleware17.redirectregex.permanent=true"
- "traefik.http.middlewares.middleware17.redirectregex.regex=foobar"
- "traefik.http.middlewares.middleware17.redirectregex.replacement=foobar"
- "traefik.http.middlewares.middleware18.redirectscheme.permanent=true"
- "traefik.http.middlewares.middleware18.redirectscheme.port=foobar"
- "traefik.http.middlewares.middleware18.redirectscheme.scheme=foobar"
- "traefik.http.middlewares.middleware19.replacepath.path=foobar"
- "traefik.http.middlewares.middleware20.replacepathregex.regex=foobar"
- "traefik.http.middlewares.middleware20.replacepathregex.replacement=foobar"
- "traefik.http.middlewares.middleware21.retry.attempts=42"
- "traefik.http.middlewares.middleware21.retry.initialinterval=42"
- "traefik.http.middlewares.middleware22.stripprefix.prefixes=foobar, foobar"
- "traefik.http.middlewares.middleware23.stripprefixregex.regex=foobar, foobar"
- "traefik.http.middlewares.middleware24.grpcweb.alloworigins=foobar, foobar"
- "traefik.http.routers.router0.entrypoints=foobar, foobar"
- "traefik.http.routers.router0.middlewares=foobar, foobar"
- "traefik.http.routers.router0.priority=42"
@ -162,8 +165,8 @@
- "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service01.loadbalancer.server.port=foobar"
- "traefik.http.services.service01.loadbalancer.server.scheme=foobar"
- "traefik.tcp.middlewares.tcpmiddleware00.ipallowlist.sourcerange=foobar, foobar"
- "traefik.tcp.middlewares.tcpmiddleware01.inflightconn.amount=42"
- "traefik.tcp.middlewares.tcpmiddleware00.inflightconn.amount=42"
- "traefik.tcp.middlewares.tcpmiddleware01.ipwhitelist.sourcerange=foobar, foobar"
- "traefik.tcp.middlewares.tcpmiddleware02.ipallowlist.sourcerange=foobar, foobar"
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
- "traefik.tcp.routers.tcprouter0.middlewares=foobar, foobar"

View file

@ -197,30 +197,36 @@
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware11]
[http.middlewares.Middleware11.ipAllowList]
[http.middlewares.Middleware11.ipWhiteList]
sourceRange = ["foobar", "foobar"]
rejectStatusCode = 404
[http.middlewares.Middleware11.ipAllowList.ipStrategy]
[http.middlewares.Middleware11.ipWhiteList.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware12]
[http.middlewares.Middleware12.inFlightReq]
[http.middlewares.Middleware12.ipAllowList]
sourceRange = ["foobar", "foobar"]
rejectStatusCode = 404
[http.middlewares.Middleware12.ipAllowList.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware13]
[http.middlewares.Middleware13.inFlightReq]
amount = 42
[http.middlewares.Middleware12.inFlightReq.sourceCriterion]
[http.middlewares.Middleware13.inFlightReq.sourceCriterion]
requestHeaderName = "foobar"
requestHost = true
[http.middlewares.Middleware12.inFlightReq.sourceCriterion.ipStrategy]
[http.middlewares.Middleware13.inFlightReq.sourceCriterion.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware13]
[http.middlewares.Middleware13.passTLSClientCert]
[http.middlewares.Middleware14]
[http.middlewares.Middleware14.passTLSClientCert]
pem = true
[http.middlewares.Middleware13.passTLSClientCert.info]
[http.middlewares.Middleware14.passTLSClientCert.info]
notAfter = true
notBefore = true
sans = true
serialNumber = true
[http.middlewares.Middleware13.passTLSClientCert.info.subject]
[http.middlewares.Middleware14.passTLSClientCert.info.subject]
country = true
province = true
locality = true
@ -229,7 +235,7 @@
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware13.passTLSClientCert.info.issuer]
[http.middlewares.Middleware14.passTLSClientCert.info.issuer]
country = true
province = true
locality = true
@ -237,50 +243,50 @@
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware14]
[http.middlewares.Middleware14.plugin]
[http.middlewares.Middleware14.plugin.PluginConf]
foo = "bar"
[http.middlewares.Middleware15]
[http.middlewares.Middleware15.rateLimit]
[http.middlewares.Middleware15.plugin]
[http.middlewares.Middleware15.plugin.PluginConf]
foo = "bar"
[http.middlewares.Middleware16]
[http.middlewares.Middleware16.rateLimit]
average = 42
period = "42s"
burst = 42
[http.middlewares.Middleware15.rateLimit.sourceCriterion]
[http.middlewares.Middleware16.rateLimit.sourceCriterion]
requestHeaderName = "foobar"
requestHost = true
[http.middlewares.Middleware15.rateLimit.sourceCriterion.ipStrategy]
[http.middlewares.Middleware16.rateLimit.sourceCriterion.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
[http.middlewares.Middleware16]
[http.middlewares.Middleware16.redirectRegex]
[http.middlewares.Middleware17]
[http.middlewares.Middleware17.redirectRegex]
regex = "foobar"
replacement = "foobar"
permanent = true
[http.middlewares.Middleware17]
[http.middlewares.Middleware17.redirectScheme]
[http.middlewares.Middleware18]
[http.middlewares.Middleware18.redirectScheme]
scheme = "foobar"
port = "foobar"
permanent = true
[http.middlewares.Middleware18]
[http.middlewares.Middleware18.replacePath]
path = "foobar"
[http.middlewares.Middleware19]
[http.middlewares.Middleware19.replacePathRegex]
[http.middlewares.Middleware19.replacePath]
path = "foobar"
[http.middlewares.Middleware20]
[http.middlewares.Middleware20.replacePathRegex]
regex = "foobar"
replacement = "foobar"
[http.middlewares.Middleware20]
[http.middlewares.Middleware20.retry]
[http.middlewares.Middleware21]
[http.middlewares.Middleware21.retry]
attempts = 42
initialInterval = "42s"
[http.middlewares.Middleware21]
[http.middlewares.Middleware21.stripPrefix]
prefixes = ["foobar", "foobar"]
[http.middlewares.Middleware22]
[http.middlewares.Middleware22.stripPrefixRegex]
regex = ["foobar", "foobar"]
[http.middlewares.Middleware22.stripPrefix]
prefixes = ["foobar", "foobar"]
[http.middlewares.Middleware23]
[http.middlewares.Middleware23.grpcWeb]
[http.middlewares.Middleware23.stripPrefixRegex]
regex = ["foobar", "foobar"]
[http.middlewares.Middleware24]
[http.middlewares.Middleware24.grpcWeb]
allowOrigins = ["foobar", "foobar"]
[http.serversTransports]
[http.serversTransports.ServersTransport0]

View file

@ -224,6 +224,16 @@ http:
permissionsPolicy: foobar
isDevelopment: true
Middleware11:
ipWhiteList:
sourceRange:
- foobar
- foobar
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
Middleware12:
ipAllowList:
rejectStatusCode: 404
sourceRange:
@ -234,7 +244,7 @@ http:
excludedIPs:
- foobar
- foobar
Middleware12:
Middleware13:
inFlightReq:
amount: 42
sourceCriterion:
@ -245,7 +255,7 @@ http:
- foobar
requestHeaderName: foobar
requestHost: true
Middleware13:
Middleware14:
passTLSClientCert:
pem: true
info:
@ -270,11 +280,11 @@ http:
serialNumber: true
domainComponent: true
serialNumber: true
Middleware14:
Middleware15:
plugin:
PluginConf:
foo: bar
Middleware15:
Middleware16:
rateLimit:
average: 42
period: 42s
@ -287,38 +297,38 @@ http:
- foobar
requestHeaderName: foobar
requestHost: true
Middleware16:
Middleware17:
redirectRegex:
regex: foobar
replacement: foobar
permanent: true
Middleware17:
Middleware18:
redirectScheme:
scheme: foobar
port: foobar
permanent: true
Middleware18:
Middleware19:
replacePath:
path: foobar
Middleware19:
Middleware20:
replacePathRegex:
regex: foobar
replacement: foobar
Middleware20:
Middleware21:
retry:
attempts: 42
initialInterval: 42s
Middleware21:
Middleware22:
stripPrefix:
prefixes:
- foobar
- foobar
Middleware22:
Middleware23:
stripPrefixRegex:
regex:
- foobar
- foobar
Middleware23:
Middleware24:
grpcWeb:
allowOrigins:
- foobar

View file

@ -1192,6 +1192,32 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'Deprecated: please use IPAllowList instead.'
properties:
ipStrategy:
description: 'IPStrategy holds the IP strategy configuration used
by Traefik to determine the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/#ipstrategy'
properties:
depth:
description: Depth tells Traefik to use the X-Forwarded-For
header and take the IP located at the depth position (starting
from the right).
type: integer
excludedIPs:
description: ExcludedIPs configures Traefik to scan the X-Forwarded-For
header and select the first IP not in the list.
items:
type: string
type: array
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
passTLSClientCert:
description: 'PassTLSClientCert holds the pass TLS client cert middleware
configuration. This middleware adds the selected data from the passed
@ -1528,6 +1554,17 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'IPWhiteList defines the IPWhiteList middleware configuration.
Deprecated: please use IPAllowList instead.'
properties:
sourceRange:
description: SourceRange defines the allowed IPs (or ranges of
allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
type: object
required:
- metadata

View file

@ -78,64 +78,69 @@
| `traefik/http/middlewares/Middleware10/headers/stsIncludeSubdomains` | `true` |
| `traefik/http/middlewares/Middleware10/headers/stsPreload` | `true` |
| `traefik/http/middlewares/Middleware10/headers/stsSeconds` | `42` |
| `traefik/http/middlewares/Middleware11/ipAllowList/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware11/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipAllowList/rejectStatusCode` | `404` |
| `traefik/http/middlewares/Middleware11/ipAllowList/sourceRange/0` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipAllowList/sourceRange/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/inFlightReq/amount` | `42` |
| `traefik/http/middlewares/Middleware12/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware12/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware12/inFlightReq/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/commonName` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/country` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/locality` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/organization` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/province` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/issuer/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/notAfter` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/notBefore` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/sans` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/commonName` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/country` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/locality` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/organization` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/organizationalUnit` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/province` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/info/subject/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware13/passTLSClientCert/pem` | `true` |
| `traefik/http/middlewares/Middleware14/plugin/PluginConf/foo` | `bar` |
| `traefik/http/middlewares/Middleware15/rateLimit/average` | `42` |
| `traefik/http/middlewares/Middleware15/rateLimit/burst` | `42` |
| `traefik/http/middlewares/Middleware15/rateLimit/period` | `42s` |
| `traefik/http/middlewares/Middleware15/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware15/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware15/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware15/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware15/rateLimit/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware16/redirectRegex/permanent` | `true` |
| `traefik/http/middlewares/Middleware16/redirectRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware16/redirectRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware17/redirectScheme/permanent` | `true` |
| `traefik/http/middlewares/Middleware17/redirectScheme/port` | `foobar` |
| `traefik/http/middlewares/Middleware17/redirectScheme/scheme` | `foobar` |
| `traefik/http/middlewares/Middleware18/replacePath/path` | `foobar` |
| `traefik/http/middlewares/Middleware19/replacePathRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware19/replacePathRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware20/retry/attempts` | `42` |
| `traefik/http/middlewares/Middleware20/retry/initialInterval` | `42s` |
| `traefik/http/middlewares/Middleware21/stripPrefix/prefixes/0` | `foobar` |
| `traefik/http/middlewares/Middleware21/stripPrefix/prefixes/1` | `foobar` |
| `traefik/http/middlewares/Middleware22/stripPrefixRegex/regex/0` | `foobar` |
| `traefik/http/middlewares/Middleware22/stripPrefixRegex/regex/1` | `foobar` |
| `traefik/http/middlewares/Middleware23/grpcWeb/allowOrigins/0` | `foobar` |
| `traefik/http/middlewares/Middleware23/grpcWeb/allowOrigins/1` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/0` | `foobar` |
| `traefik/http/middlewares/Middleware11/ipWhiteList/sourceRange/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware12/ipAllowList/rejectStatusCode` | `404` |
| `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/0` | `foobar` |
| `traefik/http/middlewares/Middleware12/ipAllowList/sourceRange/1` | `foobar` |
| `traefik/http/middlewares/Middleware13/inFlightReq/amount` | `42` |
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware13/inFlightReq/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/commonName` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/country` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/locality` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/organization` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/province` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/issuer/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notAfter` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/notBefore` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/sans` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/commonName` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/country` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/domainComponent` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/locality` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organization` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/organizationalUnit` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/province` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/info/subject/serialNumber` | `true` |
| `traefik/http/middlewares/Middleware14/passTLSClientCert/pem` | `true` |
| `traefik/http/middlewares/Middleware15/plugin/PluginConf/foo` | `bar` |
| `traefik/http/middlewares/Middleware16/rateLimit/average` | `42` |
| `traefik/http/middlewares/Middleware16/rateLimit/burst` | `42` |
| `traefik/http/middlewares/Middleware16/rateLimit/period` | `42s` |
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
| `traefik/http/middlewares/Middleware16/rateLimit/sourceCriterion/requestHost` | `true` |
| `traefik/http/middlewares/Middleware17/redirectRegex/permanent` | `true` |
| `traefik/http/middlewares/Middleware17/redirectRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware17/redirectRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware18/redirectScheme/permanent` | `true` |
| `traefik/http/middlewares/Middleware18/redirectScheme/port` | `foobar` |
| `traefik/http/middlewares/Middleware18/redirectScheme/scheme` | `foobar` |
| `traefik/http/middlewares/Middleware19/replacePath/path` | `foobar` |
| `traefik/http/middlewares/Middleware20/replacePathRegex/regex` | `foobar` |
| `traefik/http/middlewares/Middleware20/replacePathRegex/replacement` | `foobar` |
| `traefik/http/middlewares/Middleware21/retry/attempts` | `42` |
| `traefik/http/middlewares/Middleware21/retry/initialInterval` | `42s` |
| `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/0` | `foobar` |
| `traefik/http/middlewares/Middleware22/stripPrefix/prefixes/1` | `foobar` |
| `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/0` | `foobar` |
| `traefik/http/middlewares/Middleware23/stripPrefixRegex/regex/1` | `foobar` |
| `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/0` | `foobar` |
| `traefik/http/middlewares/Middleware24/grpcWeb/allowOrigins/1` | `foobar` |
| `traefik/http/routers/Router0/entryPoints/0` | `foobar` |
| `traefik/http/routers/Router0/entryPoints/1` | `foobar` |
| `traefik/http/routers/Router0/middlewares/0` | `foobar` |

View file

@ -617,6 +617,32 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'Deprecated: please use IPAllowList instead.'
properties:
ipStrategy:
description: 'IPStrategy holds the IP strategy configuration used
by Traefik to determine the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/#ipstrategy'
properties:
depth:
description: Depth tells Traefik to use the X-Forwarded-For
header and take the IP located at the depth position (starting
from the right).
type: integer
excludedIPs:
description: ExcludedIPs configures Traefik to scan the X-Forwarded-For
header and select the first IP not in the list.
items:
type: string
type: array
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
passTLSClientCert:
description: 'PassTLSClientCert holds the pass TLS client cert middleware
configuration. This middleware adds the selected data from the passed

View file

@ -55,6 +55,17 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'IPWhiteList defines the IPWhiteList middleware configuration.
Deprecated: please use IPAllowList instead.'
properties:
sourceRange:
description: SourceRange defines the allowed IPs (or ranges of
allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
type: object
required:
- metadata

View file

@ -1192,6 +1192,32 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'Deprecated: please use IPAllowList instead.'
properties:
ipStrategy:
description: 'IPStrategy holds the IP strategy configuration used
by Traefik to determine the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/#ipstrategy'
properties:
depth:
description: Depth tells Traefik to use the X-Forwarded-For
header and take the IP located at the depth position (starting
from the right).
type: integer
excludedIPs:
description: ExcludedIPs configures Traefik to scan the X-Forwarded-For
header and select the first IP not in the list.
items:
type: string
type: array
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
passTLSClientCert:
description: 'PassTLSClientCert holds the pass TLS client cert middleware
configuration. This middleware adds the selected data from the passed
@ -1528,6 +1554,17 @@ spec:
type: string
type: array
type: object
ipWhiteList:
description: 'IPWhiteList defines the IPWhiteList middleware configuration.
Deprecated: please use IPAllowList instead.'
properties:
sourceRange:
description: SourceRange defines the allowed IPs (or ranges of
allowed IPs by using CIDR notation).
items:
type: string
type: array
type: object
type: object
required:
- metadata

View file

@ -0,0 +1,18 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.web.ForwardedHeaders]
insecure = true
[api]
insecure = true
[providers]
[providers.docker]

View file

@ -4,6 +4,7 @@
[log]
level = "DEBUG"
noColor = true
[entryPoints]

View file

@ -0,0 +1,52 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
noColor = true
[entryPoints]
[entryPoints.tcp]
address = ":8093"
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[tcp]
[tcp.routers]
[tcp.routers.to-whoami-a]
entryPoints = ["tcp"]
rule = "HostSNI(`whoami-a.test`)"
service = "whoami-a"
middlewares = ["blocking-ipwhitelist"]
[tcp.routers.to-whoami-a.tls]
passthrough = true
[tcp.routers.to-whoami-b]
entryPoints = ["tcp"]
rule = "HostSNI(`whoami-b.test`)"
service = "whoami-b"
middlewares = ["allowing-ipwhitelist"]
[tcp.routers.to-whoami-b.tls]
passthrough = true
[tcp.services]
[tcp.services.whoami-a.loadBalancer]
[[tcp.services.whoami-a.loadBalancer.servers]]
address = "{{ .WhoamiA }}"
[tcp.services.whoami-b.loadBalancer]
[[tcp.services.whoami-b.loadBalancer.servers]]
address = "{{ .WhoamiB }}"
[tcp.middlewares]
[tcp.middlewares.allowing-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32"]
[tcp.middlewares.blocking-ipwhitelist.ipWhiteList]
sourceRange = ["127.127.127.127/32"]

View file

@ -0,0 +1,36 @@
version: "3.8"
services:
noOverrideWhitelist:
image: traefik/whoami
labels:
traefik.enable: true
traefik.http.routers.rt1.rule: Host(`no.override.whitelist.docker.local`)
traefik.http.routers.rt1.middlewares: wl1
traefik.http.middlewares.wl1.ipwhitelist.sourceRange: 8.8.8.8
overrideIPStrategyRemoteAddrWhitelist:
image: traefik/whoami
labels:
traefik.enable: true
traefik.http.routers.rt2.rule: Host(`override.remoteaddr.whitelist.docker.local`)
traefik.http.routers.rt2.middlewares: wl2
traefik.http.middlewares.wl2.ipwhitelist.sourceRange: 8.8.8.8
traefik.http.middlewares.wl2.ipwhitelist.ipStrategy: true
overrideIPStrategyDepthWhitelist:
image: traefik/whoami
labels:
traefik.enable: true
traefik.http.routers.rt3.rule: Host(`override.depth.whitelist.docker.local`)
traefik.http.routers.rt3.middlewares: wl3
traefik.http.middlewares.wl3.ipwhitelist.sourceRange: 8.8.8.8
traefik.http.middlewares.wl3.ipwhitelist.ipStrategy.depth: 3
overrideIPStrategyExcludedIPsWhitelist:
image: traefik/whoami
labels:
traefik.enable: true
traefik.http.routers.rt4.rule: Host(`override.excludedips.whitelist.docker.local`)
traefik.http.routers.rt4.middlewares: wl4
traefik.http.middlewares.wl4.ipwhitelist.sourceRange: 8.8.8.8
traefik.http.middlewares.wl4.ipwhitelist.ipStrategy.excludedIPs: 10.0.0.1,10.0.0.2

View file

@ -483,6 +483,69 @@ func (s *SimpleSuite) TestIPStrategyAllowlist() {
}
}
func (s *SimpleSuite) TestIPStrategyWhitelist() {
s.createComposeProject("whitelist")
s.composeUp()
defer s.composeDown()
s.traefikCmd(withConfigFile("fixtures/simple_whitelist.toml"))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("override"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("override.remoteaddr.whitelist.docker.local"))
require.NoError(s.T(), err)
testCases := []struct {
desc string
xForwardedFor string
host string
expectedStatusCode int
}{
{
desc: "override remote addr reject",
xForwardedFor: "8.8.8.8,8.8.8.8",
host: "override.remoteaddr.whitelist.docker.local",
expectedStatusCode: 403,
},
{
desc: "override depth accept",
xForwardedFor: "8.8.8.8,10.0.0.1,127.0.0.1",
host: "override.depth.whitelist.docker.local",
expectedStatusCode: 200,
},
{
desc: "override depth reject",
xForwardedFor: "10.0.0.1,8.8.8.8,127.0.0.1",
host: "override.depth.whitelist.docker.local",
expectedStatusCode: 403,
},
{
desc: "override excludedIPs reject",
xForwardedFor: "10.0.0.3,10.0.0.1,10.0.0.2",
host: "override.excludedips.whitelist.docker.local",
expectedStatusCode: 403,
},
{
desc: "override excludedIPs accept",
xForwardedFor: "8.8.8.8,10.0.0.1,10.0.0.2",
host: "override.excludedips.whitelist.docker.local",
expectedStatusCode: 200,
},
}
for _, test := range testCases {
req := httptest.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
req.Header.Set("X-Forwarded-For", test.xForwardedFor)
req.Host = test.host
req.RequestURI = ""
err = try.Request(req, 1*time.Second, try.StatusCodeIs(test.expectedStatusCode))
require.NoErrorf(s.T(), err, "Error during %s: %v", test.desc, err)
}
}
func (s *SimpleSuite) TestXForwardedHeaders() {
s.createComposeProject("allowlist")

View file

@ -248,6 +248,30 @@ func (s *TCPSuite) TestMiddlewareAllowList() {
assert.Contains(s.T(), out, "whoami-b")
}
func (s *TCPSuite) TestMiddlewareWhiteList() {
file := s.adaptFile("fixtures/tcp/ip-whitelist.toml", struct {
WhoamiA string
WhoamiB string
}{
WhoamiA: s.getComposeServiceIP("whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP("whoami-b") + ":8080",
})
s.traefikCmd(withConfigFile(file))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-a.test`)"))
require.NoError(s.T(), err)
// Traefik not passes through, ipWhiteList closes connection
_, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
assert.ErrorIs(s.T(), err, io.EOF)
// Traefik passes through, termination handled by whoami-b
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-b")
}
func (s *TCPSuite) TestWRR() {
file := s.adaptFile("fixtures/tcp/wrr.toml", struct {
WhoamiB string

View file

@ -45,7 +45,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.6:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -59,7 +59,7 @@
],
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.6:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"noop@internal": {

View file

@ -139,7 +139,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.7:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -153,7 +153,7 @@
],
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.7:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"default-test2-route-23c7f4c450289ee29016@kubernetescrd": {
@ -163,7 +163,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.7:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -177,7 +177,7 @@
],
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.7:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"default-testst-route-60ad45fcb5fc1f5f3629@kubernetescrd": {
@ -187,7 +187,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.7:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -202,7 +202,7 @@
],
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.7:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"default-whoami-80@kubernetescrd": {
@ -212,7 +212,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.7:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -223,7 +223,7 @@
"status": "enabled",
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.7:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"default-wrr1@kubernetescrd": {
@ -295,7 +295,7 @@
"address": "10.42.0.2:8080"
},
{
"address": "10.42.0.4:8080"
"address": "10.42.0.6:8080"
}
]
},
@ -347,10 +347,10 @@
"loadBalancer": {
"servers": [
{
"address": "10.42.0.5:8090"
"address": "10.42.0.4:8090"
},
{
"address": "10.42.0.6:8090"
"address": "10.42.0.7:8090"
}
]
},

View file

@ -127,7 +127,7 @@
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.4:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -138,7 +138,7 @@
"status": "enabled",
"serverStatus": {
"http://10.42.0.3:80": "UP",
"http://10.42.0.4:80": "UP"
"http://10.42.0.5:80": "UP"
}
},
"noop@internal": {

View file

@ -83,10 +83,10 @@
"loadBalancer": {
"servers": [
{
"url": "http://10.42.0.2:80"
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.7:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -99,8 +99,8 @@
"default-test-ingress-whoami-test-whoami@kubernetes"
],
"serverStatus": {
"http://10.42.0.2:80": "UP",
"http://10.42.0.7:80": "UP"
"http://10.42.0.3:80": "UP",
"http://10.42.0.5:80": "UP"
}
},
"noop@internal": {

View file

@ -119,10 +119,10 @@
"loadBalancer": {
"servers": [
{
"url": "XXXX"
"url": "http://10.42.0.3:80"
},
{
"url": "XXXX"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -136,18 +136,18 @@
"default-whoami-keep-route-whoami-test-keep-keep@kubernetes"
],
"serverStatus": {
"http://XXXX": "UP",
"http://XXXX": "UP"
"http://10.42.0.3:80": "UP",
"http://10.42.0.5:80": "UP"
}
},
"default-whoami-http@kubernetes": {
"loadBalancer": {
"servers": [
{
"url": "http://10.42.0.10:80"
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.8:80"
"url": "http://10.42.0.5:80"
}
],
"passHostHeader": true,
@ -161,8 +161,8 @@
"default-test-ingress-whoami-test-whoami@kubernetes"
],
"serverStatus": {
"http://10.42.0.10:80": "UP",
"http://10.42.0.8:80": "UP"
"http://10.42.0.3:80": "UP",
"http://10.42.0.5:80": "UP"
}
},
"noop@internal": {

View file

@ -83,7 +83,7 @@
"loadBalancer": {
"servers": [
{
"url": "http://10.42.0.4:80"
"url": "http://10.42.0.3:80"
},
{
"url": "http://10.42.0.5:80"
@ -99,7 +99,7 @@
"default-whoami-keep-route-whoami-test-keep-keep@kubernetes"
],
"serverStatus": {
"http://10.42.0.4:80": "UP",
"http://10.42.0.3:80": "UP",
"http://10.42.0.5:80": "UP"
}
},

View file

@ -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/

View file

@ -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).

View file

@ -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)

View 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()
}
}

View 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)
})
}
}

View 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)
}

View 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()
}

View file

@ -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,
}
}

View file

@ -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"`

View file

@ -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"`
}

View file

@ -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)

View file

@ -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 {

View file

@ -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) {