Add Basic auth for consul catalog
This commit is contained in:
parent
8c5514612f
commit
b705e64a8a
|
@ -114,3 +114,4 @@ Additional settings can be defined using Consul Catalog tags:
|
||||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||||
|
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||||
|
|
|
@ -202,3 +202,42 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultTrueSimpleServiceMultipleNode(c
|
||||||
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ConsulCatalogSuite) TestBasicAuthSimpleService(c *check.C) {
|
||||||
|
cmd, output := s.cmdTraefik(
|
||||||
|
withConfigFile("fixtures/consul_catalog/simple.toml"),
|
||||||
|
"--consulCatalog",
|
||||||
|
"--consulCatalog.exposedByDefault=true",
|
||||||
|
"--consulCatalog.endpoint="+s.consulIP+":8500",
|
||||||
|
"--consulCatalog.domain=consul.localhost")
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
s.displayTraefikLog(c, output)
|
||||||
|
}()
|
||||||
|
|
||||||
|
nginx := s.composeProject.Container(c, "nginx")
|
||||||
|
|
||||||
|
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{
|
||||||
|
"traefik.frontend.auth.basic=test:$2a$06$O5NksJPAcgrC9MuANkSoE.Xe9DSg7KcLLFYNr1Lj6hPcMmvgwxhme,test2:$2y$10$xP1SZ70QbZ4K2bTGKJOhpujkpcLxQcB3kEPF6XAV19IdcqsZTyDEe",
|
||||||
|
})
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||||
|
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = "test.consul.localhost"
|
||||||
|
|
||||||
|
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
req.SetBasicAuth("test", "test")
|
||||||
|
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
req.SetBasicAuth("test2", "test2")
|
||||||
|
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
}
|
||||||
|
|
|
@ -330,6 +330,14 @@ func (p *CatalogProvider) getAttribute(name string, tags []string, defaultValue
|
||||||
return p.getTag(p.getPrefixedName(name), tags, defaultValue)
|
return p.getTag(p.getPrefixedName(name), tags, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getBasicAuth(tags []string) []string {
|
||||||
|
list := p.getAttribute("frontend.auth.basic", tags, "")
|
||||||
|
if list != "" {
|
||||||
|
return strings.Split(list, ",")
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) hasTag(name string, tags []string) bool {
|
func (p *CatalogProvider) hasTag(name string, tags []string) bool {
|
||||||
// Very-very unlikely that a Consul tag would ever start with '=!='
|
// Very-very unlikely that a Consul tag would ever start with '=!='
|
||||||
tag := p.getTag(name, tags, "=!=")
|
tag := p.getTag(name, tags, "=!=")
|
||||||
|
@ -377,6 +385,7 @@ func (p *CatalogProvider) buildConfig(catalog []catalogUpdate) *types.Configurat
|
||||||
"getBackendName": p.getBackendName,
|
"getBackendName": p.getBackendName,
|
||||||
"getBackendAddress": p.getBackendAddress,
|
"getBackendAddress": p.getBackendAddress,
|
||||||
"getAttribute": p.getAttribute,
|
"getAttribute": p.getAttribute,
|
||||||
|
"getBasicAuth": p.getBasicAuth,
|
||||||
"getTag": p.getTag,
|
"getTag": p.getTag,
|
||||||
"hasTag": p.hasTag,
|
"hasTag": p.hasTag,
|
||||||
"getEntryPoints": p.getEntryPoints,
|
"getEntryPoints": p.getEntryPoints,
|
||||||
|
|
|
@ -348,6 +348,7 @@ func TestConsulCatalogBuildConfig(t *testing.T) {
|
||||||
"random.foo=bar",
|
"random.foo=bar",
|
||||||
"traefik.backend.maxconn.amount=1000",
|
"traefik.backend.maxconn.amount=1000",
|
||||||
"traefik.backend.maxconn.extractorfunc=client.ip",
|
"traefik.backend.maxconn.extractorfunc=client.ip",
|
||||||
|
"traefik.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Nodes: []*api.ServiceEntry{
|
Nodes: []*api.ServiceEntry{
|
||||||
|
@ -380,6 +381,7 @@ func TestConsulCatalogBuildConfig(t *testing.T) {
|
||||||
Rule: "Host:test.localhost",
|
Rule: "Host:test.localhost",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedBackends: map[string]*types.Backend{
|
expectedBackends: map[string]*types.Backend{
|
||||||
|
@ -411,6 +413,7 @@ func TestConsulCatalogBuildConfig(t *testing.T) {
|
||||||
t.Fatalf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends)
|
t.Fatalf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) {
|
if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) {
|
||||||
|
t.Fatalf("expected %#v, got %#v", c.expectedFrontends["frontend-test"].BasicAuth, actualConfig.Frontends["frontend-test"].BasicAuth)
|
||||||
t.Fatalf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends)
|
t.Fatalf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,3 +856,38 @@ func TestConsulCatalogFilterEnabled(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConsulCatalogGetBasicAuth(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
desc string
|
||||||
|
tags []string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "label missing",
|
||||||
|
tags: []string{},
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "label existing",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.frontend.auth.basic=user:password",
|
||||||
|
},
|
||||||
|
expected: []string{"user:password"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
c := c
|
||||||
|
t.Run(c.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
provider := &CatalogProvider{
|
||||||
|
Prefix: "traefik",
|
||||||
|
}
|
||||||
|
actual := provider.getBasicAuth(c.tags)
|
||||||
|
if !reflect.DeepEqual(actual, c.expected) {
|
||||||
|
t.Errorf("actual %q, expected %q", actual, c.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
basicAuth = [{{range getBasicAuth .Attributes}}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
[frontends."frontend-{{.ServiceName}}".routes."route-host-{{.ServiceName}}"]
|
[frontends."frontend-{{.ServiceName}}".routes."route-host-{{.ServiceName}}"]
|
||||||
rule = "{{getFrontendRule .}}"
|
rule = "{{getFrontendRule .}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Loading…
Reference in a new issue