Fix entry point redirect behavior
This commit is contained in:
parent
63d7ed74f1
commit
44221fba49
5 changed files with 184 additions and 38 deletions
|
@ -575,20 +575,23 @@ This whole section is dedicated to options, keyed by entry point, that will appl
|
|||
|
||||
#### `entryPoint`
|
||||
|
||||
This section is a convenience to enable (permanent) redirecting of all incoming requests on an entry point (e.g. port `80`) to another entry point (e.g. port `443`).
|
||||
This section is a convenience to enable (permanent) redirecting of all incoming requests on an entry point (e.g. port `80`) to another entry point (e.g. port `443`) or an explicit port (`:443`).
|
||||
|
||||
??? info "`entryPoint.to`"
|
||||
|
||||
_Required_
|
||||
|
||||
The target entry point.
|
||||
The target element, it can be:
|
||||
|
||||
- an entry point name (ex: `websecure`)
|
||||
- a port (`:443`)
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints.foo]
|
||||
# ...
|
||||
[entryPoints.foo.http.redirections]
|
||||
[entryPoints.foo.http.redirections.entryPoint]
|
||||
to = "bar"
|
||||
to = "websecure"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
|
@ -598,7 +601,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
|
|||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: bar
|
||||
to: websecure
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
|
@ -607,7 +610,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
|
|||
|
||||
??? info "`entryPoint.scheme`"
|
||||
|
||||
_Optional, Default="http"_
|
||||
_Optional, Default="https"_
|
||||
|
||||
The redirection target scheme.
|
||||
|
||||
|
@ -635,6 +638,66 @@ This section is a convenience to enable (permanent) redirecting of all incoming
|
|||
--entrypoints.foo.http.redirections.entryPoint.scheme=https
|
||||
```
|
||||
|
||||
??? info "`entryPoint.permanent`"
|
||||
|
||||
_Optional, Default=true_
|
||||
|
||||
To apply a permanent redirection.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints.foo]
|
||||
# ...
|
||||
[entryPoints.foo.http.redirections]
|
||||
[entryPoints.foo.http.redirections.entryPoint]
|
||||
# ...
|
||||
permanent = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
foo:
|
||||
# ...
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
# ...
|
||||
permanent: true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.foo.http.redirections.entrypoint.permanent=true
|
||||
```
|
||||
|
||||
??? info "`entryPoint.priority`"
|
||||
|
||||
_Optional, Default=1_
|
||||
|
||||
Priority of the generated router.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints.foo]
|
||||
# ...
|
||||
[entryPoints.foo.http.redirections]
|
||||
[entryPoints.foo.http.redirections.entryPoint]
|
||||
# ...
|
||||
priority = 10
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
foo:
|
||||
# ...
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
# ...
|
||||
priority: 10
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.foo.http.redirections.entrypoint.priority=10
|
||||
```
|
||||
|
||||
### Middlewares
|
||||
|
||||
The list of middlewares that are prepended by default to the list of middlewares of each router associated to the named entry point.
|
||||
|
|
|
@ -62,11 +62,15 @@ type Redirections struct {
|
|||
type RedirectEntryPoint struct {
|
||||
To string `description:"Targeted entry point of the redirection." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty"`
|
||||
Scheme string `description:"Scheme used for the redirection. Defaults to https." json:"https,omitempty" toml:"https,omitempty" yaml:"https,omitempty"`
|
||||
Permanent bool `description:"Applied a permanent redirection. Defaults to true." json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
|
||||
Priority int `description:"Priority of the generated router. Defaults to 1." json:"priority,omitempty" toml:"priority,omitempty" yaml:"priority,omitempty"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (r *RedirectEntryPoint) SetDefaults() {
|
||||
r.Scheme = "https"
|
||||
r.Permanent = true
|
||||
r.Priority = 1
|
||||
}
|
||||
|
||||
// TLSConfig is the default TLS configuration for all the routers associated to the concerned entry point.
|
||||
|
|
30
pkg/provider/traefik/fixtures/redirection_port.json
Normal file
30
pkg/provider/traefik/fixtures/redirection_port.json
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"http": {
|
||||
"routers": {
|
||||
"web-to-443": {
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"middlewares": [
|
||||
"redirect-web-to-443"
|
||||
],
|
||||
"service": "noop@internal",
|
||||
"rule": "HostRegexp(`{host:.+}`)"
|
||||
}
|
||||
},
|
||||
"middlewares": {
|
||||
"redirect-web-to-443": {
|
||||
"redirectScheme": {
|
||||
"scheme": "https",
|
||||
"port": "443",
|
||||
"permanent": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"noop": {}
|
||||
}
|
||||
},
|
||||
"tcp": {},
|
||||
"tls": {}
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"regexp"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/config/static"
|
||||
|
@ -30,9 +31,11 @@ func New(staticCfg static.Configuration) *Provider {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik using the given configuration channel.
|
||||
func (i *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Pool) error {
|
||||
ctx := log.With(context.Background(), log.Str(log.ProviderName, "internal"))
|
||||
|
||||
configurationChan <- dynamic.Message{
|
||||
ProviderName: "internal",
|
||||
Configuration: i.createConfiguration(),
|
||||
Configuration: i.createConfiguration(ctx),
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -43,7 +46,7 @@ func (i *Provider) Init() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (i *Provider) createConfiguration() *dynamic.Configuration {
|
||||
func (i *Provider) createConfiguration(ctx context.Context) *dynamic.Configuration {
|
||||
cfg := &dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: make(map[string]*dynamic.Router),
|
||||
|
@ -66,20 +69,33 @@ func (i *Provider) createConfiguration() *dynamic.Configuration {
|
|||
i.restConfiguration(cfg)
|
||||
i.prometheusConfiguration(cfg)
|
||||
i.entryPointModels(cfg)
|
||||
i.redirection(cfg)
|
||||
i.redirection(ctx, cfg)
|
||||
|
||||
cfg.HTTP.Services["noop"] = &dynamic.Service{}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (i *Provider) redirection(cfg *dynamic.Configuration) {
|
||||
func (i *Provider) redirection(ctx context.Context, cfg *dynamic.Configuration) {
|
||||
for name, ep := range i.staticCfg.EntryPoints {
|
||||
if ep.HTTP.Redirections == nil || ep.HTTP.Redirections.EntryPoint == nil {
|
||||
if ep.HTTP.Redirections == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
logger := log.FromContext(log.With(ctx, log.Str(log.EntryPointName, name)))
|
||||
|
||||
def := ep.HTTP.Redirections
|
||||
if def.EntryPoint == nil || def.EntryPoint.To == "" {
|
||||
logger.Error("Unable to create redirection: the entry point or the port is missing")
|
||||
continue
|
||||
}
|
||||
|
||||
port, err := i.getRedirectPort(name, def)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
rtName := provider.Normalize(name + "-to-" + def.EntryPoint.To)
|
||||
mdName := "redirect-" + rtName
|
||||
|
||||
|
@ -88,12 +104,7 @@ func (i *Provider) redirection(cfg *dynamic.Configuration) {
|
|||
EntryPoints: []string{name},
|
||||
Middlewares: []string{mdName},
|
||||
Service: "noop@internal",
|
||||
}
|
||||
|
||||
port, err := i.getEntryPointPort(name, def)
|
||||
if err != nil {
|
||||
log.FromContext(context.Background()).WithField(log.EntryPointName, name).Error(err)
|
||||
continue
|
||||
Priority: def.EntryPoint.Priority,
|
||||
}
|
||||
|
||||
cfg.HTTP.Routers[rtName] = rt
|
||||
|
@ -102,7 +113,7 @@ func (i *Provider) redirection(cfg *dynamic.Configuration) {
|
|||
RedirectScheme: &dynamic.RedirectScheme{
|
||||
Scheme: def.EntryPoint.Scheme,
|
||||
Port: port,
|
||||
Permanent: true,
|
||||
Permanent: def.EntryPoint.Permanent,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -110,6 +121,36 @@ func (i *Provider) redirection(cfg *dynamic.Configuration) {
|
|||
}
|
||||
}
|
||||
|
||||
func (i *Provider) getRedirectPort(name string, def *static.Redirections) (string, error) {
|
||||
exp := regexp.MustCompile(`^:(\d+)$`)
|
||||
|
||||
if exp.MatchString(def.EntryPoint.To) {
|
||||
_, port, err := net.SplitHostPort(def.EntryPoint.To)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid port value: %w", err)
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
||||
return i.getEntryPointPort(name, def)
|
||||
}
|
||||
|
||||
func (i *Provider) getEntryPointPort(name string, def *static.Redirections) (string, error) {
|
||||
dst, ok := i.staticCfg.EntryPoints[def.EntryPoint.To]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("'to' entry point field references a non-existing entry point: %s", def.EntryPoint.To)
|
||||
}
|
||||
|
||||
_, port, err := net.SplitHostPort(dst.Address)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid entry point %q address %q: %v",
|
||||
name, i.staticCfg.EntryPoints[def.EntryPoint.To].Address, err)
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func (i *Provider) entryPointModels(cfg *dynamic.Configuration) {
|
||||
for name, ep := range i.staticCfg.EntryPoints {
|
||||
if len(ep.HTTP.Middlewares) == 0 && ep.HTTP.TLS == nil {
|
||||
|
@ -233,18 +274,3 @@ func (i *Provider) prometheusConfiguration(cfg *dynamic.Configuration) {
|
|||
|
||||
cfg.HTTP.Services["prometheus"] = &dynamic.Service{}
|
||||
}
|
||||
|
||||
func (i *Provider) getEntryPointPort(name string, def *static.Redirections) (string, error) {
|
||||
dst, ok := i.staticCfg.EntryPoints[def.EntryPoint.To]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("'to' entry point field references a non-existing entry point: %s", name)
|
||||
}
|
||||
|
||||
_, port, err := net.SplitHostPort(dst.Address)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid entry point %q address %q: %v",
|
||||
name, i.staticCfg.EntryPoints[def.EntryPoint.To].Address, err)
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package traefik
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
|
@ -198,6 +199,28 @@ func Test_createConfiguration(t *testing.T) {
|
|||
EntryPoint: &static.RedirectEntryPoint{
|
||||
To: "websecure",
|
||||
Scheme: "https",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"websecure": {
|
||||
Address: ":443",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
desc: "redirection_port.json",
|
||||
staticCfg: static.Configuration{
|
||||
EntryPoints: map[string]*static.EntryPoint{
|
||||
"web": {
|
||||
Address: ":80",
|
||||
HTTP: static.HTTPConfig{
|
||||
Redirections: &static.Redirections{
|
||||
EntryPoint: &static.RedirectEntryPoint{
|
||||
To: ":443",
|
||||
Scheme: "https",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -217,7 +240,7 @@ func Test_createConfiguration(t *testing.T) {
|
|||
|
||||
provider := Provider{staticCfg: test.staticCfg}
|
||||
|
||||
cfg := provider.createConfiguration()
|
||||
cfg := provider.createConfiguration(context.Background())
|
||||
|
||||
filename := filepath.Join("fixtures", test.desc)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue