Support SPIFFE mTLS between Traefik and Backend servers
This commit is contained in:
parent
33f0aed5ea
commit
b39ce8cc58
30 changed files with 736 additions and 24 deletions
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
gokitmetrics "github.com/go-kit/kit/metrics"
|
gokitmetrics "github.com/go-kit/kit/metrics"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/workloadapi"
|
||||||
"github.com/traefik/paerser/cli"
|
"github.com/traefik/paerser/cli"
|
||||||
"github.com/traefik/traefik/v2/cmd"
|
"github.com/traefik/traefik/v2/cmd"
|
||||||
"github.com/traefik/traefik/v2/cmd/healthcheck"
|
"github.com/traefik/traefik/v2/cmd/healthcheck"
|
||||||
|
@ -257,7 +258,28 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||||
|
|
||||||
// Service manager factory
|
// Service manager factory
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
var spiffeX509Source *workloadapi.X509Source
|
||||||
|
if staticConfiguration.Spiffe != nil && staticConfiguration.Spiffe.WorkloadAPIAddr != "" {
|
||||||
|
log.WithoutContext().
|
||||||
|
WithField("workloadAPIAddr", staticConfiguration.Spiffe.WorkloadAPIAddr).
|
||||||
|
Info("Waiting on SPIFFE SVID delivery")
|
||||||
|
|
||||||
|
spiffeX509Source, err = workloadapi.NewX509Source(
|
||||||
|
ctx,
|
||||||
|
workloadapi.WithClientOptions(
|
||||||
|
workloadapi.WithAddr(
|
||||||
|
staticConfiguration.Spiffe.WorkloadAPIAddr,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create SPIFFE x509 source: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithoutContext().Info("Successfully obtained SPIFFE SVID.")
|
||||||
|
}
|
||||||
|
|
||||||
|
roundTripperManager := service.NewRoundTripperManager(spiffeX509Source)
|
||||||
acmeHTTPHandler := getHTTPChallengeHandler(acmeProviders, httpChallengeProvider)
|
acmeHTTPHandler := getHTTPChallengeHandler(acmeProviders, httpChallengeProvider)
|
||||||
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry, roundTripperManager, acmeHTTPHandler)
|
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry, roundTripperManager, acmeHTTPHandler)
|
||||||
|
|
||||||
|
|
54
docs/content/https/spiffe.md
Normal file
54
docs/content/https/spiffe.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
title: "Traefik SPIFFE Documentation"
|
||||||
|
description: "Learn how to configure Traefik to use SPIFFE. Read the technical documentation."
|
||||||
|
---
|
||||||
|
|
||||||
|
# SPIFFE
|
||||||
|
|
||||||
|
Secure the backend connection with SPIFFE.
|
||||||
|
{: .subtitle }
|
||||||
|
|
||||||
|
[SPIFFE](https://spiffe.io/docs/latest/spiffe-about/overview/) (Secure Production Identity Framework For Everyone),
|
||||||
|
provides a secure identity in the form of a specially crafted X.509 certificate,
|
||||||
|
to every workload in an environment.
|
||||||
|
|
||||||
|
Traefik is able to connect to the Workload API to obtain an x509-SVID used to secure the connection with SPIFFE enabled backends.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
Enabling SPIFFE is part of the [static configuration](../getting-started/configuration-overview.md#the-static-configuration).
|
||||||
|
It can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||||
|
|
||||||
|
### Workload API
|
||||||
|
|
||||||
|
The `workloadAPIAddr` configuration defines the address of the SPIFFE [Workload API](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-workload-api).
|
||||||
|
|
||||||
|
!!! info "Enabling SPIFFE in ServersTransports"
|
||||||
|
|
||||||
|
Enabling SPIFFE does not imply that backend connections are going to use it automatically.
|
||||||
|
Each [ServersTransport](../routing/services/index.md#serverstransport_1) that is meant to be secured with SPIFFE must [explicitly](../routing/services/index.md#spiffe) enable it.
|
||||||
|
|
||||||
|
!!! warning "SPIFFE can cause Traefik to stall"
|
||||||
|
When using SPIFFE,
|
||||||
|
Traefik will wait for the first SVID to be delivered before starting.
|
||||||
|
If Traefik is hanging when waiting on SPIFFE SVID delivery,
|
||||||
|
please double check that it is correctly registered as workload in your SPIFFE infrastructure.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Static configuration
|
||||||
|
spiffe:
|
||||||
|
workloadAPIAddr: localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Static configuration
|
||||||
|
[spiffe]
|
||||||
|
workloadAPIAddr: localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
## Static configuration
|
||||||
|
--spiffe.workloadAPIAddr=localhost
|
||||||
|
```
|
|
@ -301,12 +301,18 @@
|
||||||
[[http.serversTransports.ServersTransport0.certificates]]
|
[[http.serversTransports.ServersTransport0.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport0.forwardingTimeouts]
|
[http.serversTransports.ServersTransport0.forwardingTimeouts]
|
||||||
dialTimeout = "42s"
|
dialTimeout = "42s"
|
||||||
responseHeaderTimeout = "42s"
|
responseHeaderTimeout = "42s"
|
||||||
idleConnTimeout = "42s"
|
idleConnTimeout = "42s"
|
||||||
readIdleTimeout = "42s"
|
readIdleTimeout = "42s"
|
||||||
pingTimeout = "42s"
|
pingTimeout = "42s"
|
||||||
|
|
||||||
|
[http.serversTransports.ServersTransport0.spiffe]
|
||||||
|
ids = ["foobar", "foobar"]
|
||||||
|
trustDomain = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport1]
|
[http.serversTransports.ServersTransport1]
|
||||||
serverName = "foobar"
|
serverName = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
|
@ -322,6 +328,7 @@
|
||||||
[[http.serversTransports.ServersTransport1.certificates]]
|
[[http.serversTransports.ServersTransport1.certificates]]
|
||||||
certFile = "foobar"
|
certFile = "foobar"
|
||||||
keyFile = "foobar"
|
keyFile = "foobar"
|
||||||
|
|
||||||
[http.serversTransports.ServersTransport1.forwardingTimeouts]
|
[http.serversTransports.ServersTransport1.forwardingTimeouts]
|
||||||
dialTimeout = "42s"
|
dialTimeout = "42s"
|
||||||
responseHeaderTimeout = "42s"
|
responseHeaderTimeout = "42s"
|
||||||
|
@ -329,6 +336,10 @@
|
||||||
readIdleTimeout = "42s"
|
readIdleTimeout = "42s"
|
||||||
pingTimeout = "42s"
|
pingTimeout = "42s"
|
||||||
|
|
||||||
|
[http.serversTransports.ServersTransport1.spiffe]
|
||||||
|
ids = ["foobar", "foobar"]
|
||||||
|
trustDomain = "foobar"
|
||||||
|
|
||||||
[tcp]
|
[tcp]
|
||||||
[tcp.routers]
|
[tcp.routers]
|
||||||
[tcp.routers.TCPRouter0]
|
[tcp.routers.TCPRouter0]
|
||||||
|
|
|
@ -345,6 +345,12 @@ http:
|
||||||
pingTimeout: 42s
|
pingTimeout: 42s
|
||||||
disableHTTP2: true
|
disableHTTP2: true
|
||||||
peerCertURI: foobar
|
peerCertURI: foobar
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
trustDomain: foobar
|
||||||
|
|
||||||
ServersTransport1:
|
ServersTransport1:
|
||||||
serverName: foobar
|
serverName: foobar
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
@ -365,6 +371,12 @@ http:
|
||||||
pingTimeout: 42s
|
pingTimeout: 42s
|
||||||
disableHTTP2: true
|
disableHTTP2: true
|
||||||
peerCertURI: foobar
|
peerCertURI: foobar
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
trustDomain: foobar
|
||||||
|
|
||||||
tcp:
|
tcp:
|
||||||
routers:
|
routers:
|
||||||
TCPRouter0:
|
TCPRouter0:
|
||||||
|
|
|
@ -1679,6 +1679,19 @@ spec:
|
||||||
description: ServerName defines the server name used to contact the
|
description: ServerName defines the server name used to contact the
|
||||||
server.
|
server.
|
||||||
type: string
|
type: string
|
||||||
|
spiffe:
|
||||||
|
description: Spiffe defines the SPIFFE configuration.
|
||||||
|
properties:
|
||||||
|
ids:
|
||||||
|
description: IDs defines the allowed SPIFFE IDs (takes precedence
|
||||||
|
over the SPIFFE TrustDomain).
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
trustDomain:
|
||||||
|
description: TrustDomain defines the allowed SPIFFE trust domain.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- metadata
|
- metadata
|
||||||
|
|
|
@ -186,6 +186,9 @@
|
||||||
| `traefik/http/serversTransports/ServersTransport0/rootCAs/0` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport0/rootCAs/0` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport0/rootCAs/1` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport0/rootCAs/1` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport0/serverName` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport0/serverName` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport0/spiffe/ids/0` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport0/spiffe/ids/1` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport0/spiffe/trustDomain` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/certificates/0/certFile` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/certificates/0/certFile` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/certificates/0/keyFile` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/certificates/0/keyFile` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/certificates/1/certFile` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/certificates/1/certFile` | `foobar` |
|
||||||
|
@ -202,6 +205,9 @@
|
||||||
| `traefik/http/serversTransports/ServersTransport1/rootCAs/0` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/rootCAs/0` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/rootCAs/1` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/rootCAs/1` | `foobar` |
|
||||||
| `traefik/http/serversTransports/ServersTransport1/serverName` | `foobar` |
|
| `traefik/http/serversTransports/ServersTransport1/serverName` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/0` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/ids/1` | `foobar` |
|
||||||
|
| `traefik/http/serversTransports/ServersTransport1/spiffe/trustDomain` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/followRedirects` | `true` |
|
| `traefik/http/services/Service01/loadBalancer/healthCheck/followRedirects` | `true` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name0` | `foobar` |
|
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name0` | `foobar` |
|
||||||
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name1` | `foobar` |
|
| `traefik/http/services/Service01/loadBalancer/healthCheck/headers/name1` | `foobar` |
|
||||||
|
|
|
@ -113,6 +113,19 @@ spec:
|
||||||
description: ServerName defines the server name used to contact the
|
description: ServerName defines the server name used to contact the
|
||||||
server.
|
server.
|
||||||
type: string
|
type: string
|
||||||
|
spiffe:
|
||||||
|
description: Spiffe defines the SPIFFE configuration.
|
||||||
|
properties:
|
||||||
|
ids:
|
||||||
|
description: IDs defines the allowed SPIFFE IDs (takes precedence
|
||||||
|
over the SPIFFE TrustDomain).
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
trustDomain:
|
||||||
|
description: TrustDomain defines the allowed SPIFFE trust domain.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- metadata
|
- metadata
|
||||||
|
|
|
@ -984,6 +984,18 @@ If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, D
|
||||||
`--serverstransport.rootcas`:
|
`--serverstransport.rootcas`:
|
||||||
Add cert file for self-signed certificate.
|
Add cert file for self-signed certificate.
|
||||||
|
|
||||||
|
`--serverstransport.spiffe`:
|
||||||
|
Defines the SPIFFE configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
`--serverstransport.spiffe.ids`:
|
||||||
|
Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain).
|
||||||
|
|
||||||
|
`--serverstransport.spiffe.trustdomain`:
|
||||||
|
Defines the allowed SPIFFE trust domain.
|
||||||
|
|
||||||
|
`--spiffe.workloadapiaddr`:
|
||||||
|
Defines the workload API address.
|
||||||
|
|
||||||
`--tracing`:
|
`--tracing`:
|
||||||
OpenTracing configuration. (Default: ```false```)
|
OpenTracing configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -984,6 +984,18 @@ If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, D
|
||||||
`TRAEFIK_SERVERSTRANSPORT_ROOTCAS`:
|
`TRAEFIK_SERVERSTRANSPORT_ROOTCAS`:
|
||||||
Add cert file for self-signed certificate.
|
Add cert file for self-signed certificate.
|
||||||
|
|
||||||
|
`TRAEFIK_SERVERSTRANSPORT_SPIFFE`:
|
||||||
|
Defines the SPIFFE configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
`TRAEFIK_SERVERSTRANSPORT_SPIFFE_IDS`:
|
||||||
|
Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain).
|
||||||
|
|
||||||
|
`TRAEFIK_SERVERSTRANSPORT_SPIFFE_TRUSTDOMAIN`:
|
||||||
|
Defines the allowed SPIFFE trust domain.
|
||||||
|
|
||||||
|
`TRAEFIK_SPIFFE_WORKLOADAPIADDR`:
|
||||||
|
Defines the workload API address.
|
||||||
|
|
||||||
`TRAEFIK_TRACING`:
|
`TRAEFIK_TRACING`:
|
||||||
OpenTracing configuration. (Default: ```false```)
|
OpenTracing configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -325,6 +325,61 @@ serversTransport:
|
||||||
--serversTransport.maxIdleConnsPerHost=7
|
--serversTransport.maxIdleConnsPerHost=7
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `spiffe`
|
||||||
|
|
||||||
|
Please note that [SPIFFE](../https/spiffe.md) must be enabled in the static configuration
|
||||||
|
before using it to secure the connection between Traefik and the backends.
|
||||||
|
|
||||||
|
#### `spiffe.ids`
|
||||||
|
|
||||||
|
_Optional_
|
||||||
|
|
||||||
|
`ids` defines the allowed SPIFFE IDs.
|
||||||
|
This takes precedence over the SPIFFE TrustDomain.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Static configuration
|
||||||
|
serversTransport:
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- spiffe://trust-domain/id1
|
||||||
|
- spiffe://trust-domain/id2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Static configuration
|
||||||
|
[serversTransport.spiffe]
|
||||||
|
ids = ["spiffe://trust-domain/id1", "spiffe://trust-domain/id2"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
## Static configuration
|
||||||
|
--serversTransport.spiffe.ids=spiffe://trust-domain/id1,spiffe://trust-domain/id2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `spiffe.trustDomain`
|
||||||
|
|
||||||
|
_Optional_
|
||||||
|
|
||||||
|
`trustDomain` defines the allowed SPIFFE trust domain.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Static configuration
|
||||||
|
serversTransport:
|
||||||
|
trustDomain: spiffe://trust-domain
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Static configuration
|
||||||
|
[serversTransport.spiffe]
|
||||||
|
trustDomain = "spiffe://trust-domain"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
## Static configuration
|
||||||
|
--serversTransport.spiffe.trustDomain=spiffe://trust-domain
|
||||||
|
```
|
||||||
|
|
||||||
### `forwardingTimeouts`
|
### `forwardingTimeouts`
|
||||||
|
|
||||||
`forwardingTimeouts` is about a number of timeouts relevant to when forwarding requests to the backend servers.
|
`forwardingTimeouts` is about a number of timeouts relevant to when forwarding requests to the backend servers.
|
||||||
|
|
|
@ -776,6 +776,82 @@ spec:
|
||||||
peerCertURI: foobar
|
peerCertURI: foobar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `spiffe`
|
||||||
|
|
||||||
|
Please note that [SPIFFE](../../https/spiffe.md) must be enabled in the static configuration
|
||||||
|
before using it to secure the connection between Traefik and the backends.
|
||||||
|
|
||||||
|
##### `spiffe.ids`
|
||||||
|
|
||||||
|
_Optional_
|
||||||
|
|
||||||
|
`ids` defines the allowed SPIFFE IDs.
|
||||||
|
This takes precedence over the SPIFFE TrustDomain.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
http:
|
||||||
|
serversTransports:
|
||||||
|
mytransport:
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- spiffe://trust-domain/id1
|
||||||
|
- spiffe://trust-domain/id2
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
[http.serversTransports.mytransport.spiffe]
|
||||||
|
ids = ["spiffe://trust-domain/id1", "spiffe://trust-domain/id2"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: ServersTransport
|
||||||
|
metadata:
|
||||||
|
name: mytransport
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- spiffe://trust-domain/id1
|
||||||
|
- spiffe://trust-domain/id2
|
||||||
|
```
|
||||||
|
|
||||||
|
##### `spiffe.trustDomain`
|
||||||
|
|
||||||
|
_Optional_
|
||||||
|
|
||||||
|
`trustDomain` defines the allowed SPIFFE trust domain.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
http:
|
||||||
|
serversTransports:
|
||||||
|
mytransport:
|
||||||
|
spiffe:
|
||||||
|
trustDomain: spiffe://trust-domain
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
## Dynamic configuration
|
||||||
|
[http.serversTransports.mytransport.spiffe]
|
||||||
|
trustDomain = "spiffe://trust-domain"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: ServersTransport
|
||||||
|
metadata:
|
||||||
|
name: mytransport
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
spiffe:
|
||||||
|
trustDomain: "spiffe://trust-domain"
|
||||||
|
```
|
||||||
|
|
||||||
#### `forwardingTimeouts`
|
#### `forwardingTimeouts`
|
||||||
|
|
||||||
`forwardingTimeouts` are the timeouts applied when forwarding requests to the servers.
|
`forwardingTimeouts` are the timeouts applied when forwarding requests to the servers.
|
||||||
|
|
|
@ -110,6 +110,7 @@ nav:
|
||||||
- 'TLS': 'https/tls.md'
|
- 'TLS': 'https/tls.md'
|
||||||
- 'Let''s Encrypt': 'https/acme.md'
|
- 'Let''s Encrypt': 'https/acme.md'
|
||||||
- 'Tailscale': 'https/tailscale.md'
|
- 'Tailscale': 'https/tailscale.md'
|
||||||
|
- 'SPIFFE': 'https/spiffe.md'
|
||||||
- 'Middlewares':
|
- 'Middlewares':
|
||||||
- 'Overview': 'middlewares/overview.md'
|
- 'Overview': 'middlewares/overview.md'
|
||||||
- 'HTTP':
|
- 'HTTP':
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -57,6 +57,7 @@ require (
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.2.0
|
||||||
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
|
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
|
github.com/spiffe/go-spiffe/v2 v2.1.1
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
||||||
github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2
|
github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2
|
||||||
|
@ -76,7 +77,7 @@ require (
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.46.0
|
||||||
gopkg.in/DataDog/dd-trace-go.v1 v1.38.1
|
gopkg.in/DataDog/dd-trace-go.v1 v1.38.1
|
||||||
gopkg.in/fsnotify.v1 v1.4.7
|
gopkg.in/fsnotify.v1 v1.4.7
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
@ -111,7 +112,7 @@ require (
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.8.23 // indirect
|
github.com/Microsoft/hcsshim v0.8.23 // indirect
|
||||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
||||||
github.com/Shopify/sarama v1.23.1 // indirect
|
github.com/Shopify/sarama v1.23.1 // indirect
|
||||||
|
@ -311,6 +312,7 @@ require (
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f // indirect
|
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f // indirect
|
||||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect
|
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect
|
||||||
|
github.com/zeebo/errs v1.2.2 // indirect
|
||||||
go.elastic.co/apm/module/apmhttp v1.13.1 // indirect
|
go.elastic.co/apm/module/apmhttp v1.13.1 // indirect
|
||||||
go.elastic.co/fastjson v1.1.0 // indirect
|
go.elastic.co/fastjson v1.1.0 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
||||||
|
|
18
go.sum
18
go.sum
|
@ -153,8 +153,9 @@ github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JP
|
||||||
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
|
||||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||||
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
||||||
|
@ -338,8 +339,12 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
||||||
github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
|
@ -629,6 +634,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
|
@ -1890,6 +1896,8 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
|
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
|
||||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||||
|
github.com/spiffe/go-spiffe/v2 v2.1.1 h1:RT9kM8MZLZIsPTH+HKQEP5yaAk3yd/VBzlINaRjXs8k=
|
||||||
|
github.com/spiffe/go-spiffe/v2 v2.1.1/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
|
||||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
|
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
|
||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
@ -2059,6 +2067,8 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go
|
||||||
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||||
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
|
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
|
||||||
github.com/zclconf/go-cty v1.7.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
|
github.com/zclconf/go-cty v1.7.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
|
||||||
|
github.com/zeebo/errs v1.2.2 h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g=
|
||||||
|
github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
|
@ -2676,6 +2686,7 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
|
||||||
google.golang.org/genproto v0.0.0-20200726014623-da3ae01ef02d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200726014623-da3ae01ef02d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
@ -2724,8 +2735,10 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||||
|
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
|
||||||
|
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc/examples v0.0.0-20201130180447-c456688b1860/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -2794,6 +2807,7 @@ gopkg.in/olivere/elastic.v5 v5.0.84/go.mod h1:LXF6q9XNBxpMqrcgax95C6xyARXWbbCXUr
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
|
|
@ -1679,6 +1679,19 @@ spec:
|
||||||
description: ServerName defines the server name used to contact the
|
description: ServerName defines the server name used to contact the
|
||||||
server.
|
server.
|
||||||
type: string
|
type: string
|
||||||
|
spiffe:
|
||||||
|
description: Spiffe defines the SPIFFE configuration.
|
||||||
|
properties:
|
||||||
|
ids:
|
||||||
|
description: IDs defines the allowed SPIFFE IDs (takes precedence
|
||||||
|
over the SPIFFE TrustDomain).
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
trustDomain:
|
||||||
|
description: TrustDomain defines the allowed SPIFFE trust domain.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- metadata
|
- metadata
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/traefik/traefik/v2/pkg/log"
|
"github.com/traefik/traefik/v2/pkg/log"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -94,7 +95,7 @@ func getHelloClientGRPC() (helloworld.GreeterClient, func() error, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHelloClientGRPCh2c() (helloworld.GreeterClient, func() error, error) {
|
func getHelloClientGRPCh2c() (helloworld.GreeterClient, func() error, error) {
|
||||||
conn, err := grpc.Dial("127.0.0.1:8081", grpc.WithInsecure())
|
conn, err := grpc.Dial("127.0.0.1:8081", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, func() error { return nil }, err
|
return nil, func() error { return nil }, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,6 +250,17 @@ type ServersTransport struct {
|
||||||
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
||||||
DisableHTTP2 bool `description:"Disable HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,omitempty" export:"true"`
|
DisableHTTP2 bool `description:"Disable HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,omitempty" export:"true"`
|
||||||
PeerCertURI string `description:"URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
|
PeerCertURI string `description:"URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
|
||||||
|
Spiffe *Spiffe `description:"Define the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// Spiffe holds the SPIFFE configuration.
|
||||||
|
type Spiffe struct {
|
||||||
|
// IDs defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain).
|
||||||
|
IDs []string `description:"Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain)." json:"ids,omitempty" toml:"ids,omitempty" yaml:"ids,omitempty"`
|
||||||
|
// TrustDomain defines the allowed SPIFFE trust domain.
|
||||||
|
TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" yaml:"trustDomain,omitempty" toml:"trustDomain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -1161,6 +1161,11 @@ func (in *ServersTransport) DeepCopyInto(out *ServersTransport) {
|
||||||
*out = new(ForwardingTimeouts)
|
*out = new(ForwardingTimeouts)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.Spiffe != nil {
|
||||||
|
in, out := &in.Spiffe, &out.Spiffe
|
||||||
|
*out = new(Spiffe)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1231,6 +1236,27 @@ func (in *SourceCriterion) DeepCopy() *SourceCriterion {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Spiffe) DeepCopyInto(out *Spiffe) {
|
||||||
|
*out = *in
|
||||||
|
if in.IDs != nil {
|
||||||
|
in, out := &in.IDs, &out.IDs
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spiffe.
|
||||||
|
func (in *Spiffe) DeepCopy() *Spiffe {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Spiffe)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Sticky) DeepCopyInto(out *Sticky) {
|
func (in *Sticky) DeepCopyInto(out *Sticky) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
|
@ -84,6 +84,13 @@ type Configuration struct {
|
||||||
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
|
||||||
Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
||||||
|
|
||||||
|
Spiffe *SpiffeClientConfig `description:"SPIFFE integration configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpiffeClientConfig defines the SPIFFE client configuration.
|
||||||
|
type SpiffeClientConfig struct {
|
||||||
|
WorkloadAPIAddr string `description:"Defines the workload API address." json:"workloadAPIAddr,omitempty" toml:"workloadAPIAddr,omitempty" yaml:"workloadAPIAddr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateResolver contains the configuration for the different types of certificates resolver.
|
// CertificateResolver contains the configuration for the different types of certificates resolver.
|
||||||
|
@ -104,6 +111,13 @@ type ServersTransport struct {
|
||||||
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
||||||
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
|
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
|
||||||
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
||||||
|
Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spiffe holds the SPIFFE configuration.
|
||||||
|
type Spiffe struct {
|
||||||
|
IDs []string `description:"Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain)." json:"ids,omitempty" toml:"ids,omitempty" yaml:"ids,omitempty"`
|
||||||
|
TrustDomain string `description:"Defines the allowed SPIFFE trust domain." json:"trustDomain,omitempty" yaml:"trustDomain,omitempty" toml:"trustDomain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// API holds the API configuration.
|
// API holds the API configuration.
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/vulcand/oxy/roundrobin"
|
"github.com/vulcand/oxy/roundrobin"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
@ -317,7 +318,7 @@ func checkHealthGRPC(serverURL *url.URL, backend *BackendConfig) error {
|
||||||
var opts []grpc.DialOption
|
var opts []grpc.DialOption
|
||||||
switch backend.Options.Scheme {
|
switch backend.Options.Scheme {
|
||||||
case "http", "h2c", "":
|
case "http", "h2c", "":
|
||||||
opts = append(opts, grpc.WithInsecure())
|
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), backend.Options.Timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), backend.Options.Timeout)
|
||||||
|
|
|
@ -112,6 +112,11 @@ spec:
|
||||||
idleConnTimeout: 42ms
|
idleConnTimeout: 42ms
|
||||||
readIdleTimeout: 42s
|
readIdleTimeout: 42s
|
||||||
pingTimeout: 42s
|
pingTimeout: 42s
|
||||||
|
spiffe:
|
||||||
|
ids:
|
||||||
|
- spiffe://foo/buz
|
||||||
|
- spiffe://bar/biz
|
||||||
|
trustDomain: spiffe://lol
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
@ -144,4 +149,3 @@ spec:
|
||||||
- name: whoamitls
|
- name: whoamitls
|
||||||
port: 443
|
port: 443
|
||||||
serversTransport: default-test
|
serversTransport: default-test
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
MaxIdleConnsPerHost: serversTransport.Spec.MaxIdleConnsPerHost,
|
MaxIdleConnsPerHost: serversTransport.Spec.MaxIdleConnsPerHost,
|
||||||
ForwardingTimeouts: forwardingTimeout,
|
ForwardingTimeouts: forwardingTimeout,
|
||||||
PeerCertURI: serversTransport.Spec.PeerCertURI,
|
PeerCertURI: serversTransport.Spec.PeerCertURI,
|
||||||
|
Spiffe: serversTransport.Spec.Spiffe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3916,6 +3916,13 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
PingTimeout: ptypes.Duration(42 * time.Second),
|
PingTimeout: ptypes.Duration(42 * time.Second),
|
||||||
},
|
},
|
||||||
PeerCertURI: "foo://bar",
|
PeerCertURI: "foo://bar",
|
||||||
|
Spiffe: &dynamic.Spiffe{
|
||||||
|
IDs: []string{
|
||||||
|
"spiffe://foo/buz",
|
||||||
|
"spiffe://bar/biz",
|
||||||
|
},
|
||||||
|
TrustDomain: "spiffe://lol",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"default-test": {
|
"default-test": {
|
||||||
ServerName: "test",
|
ServerName: "test",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
)
|
)
|
||||||
|
@ -42,6 +43,8 @@ type ServersTransportSpec struct {
|
||||||
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
|
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
|
||||||
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
|
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
|
||||||
PeerCertURI string `json:"peerCertURI,omitempty"`
|
PeerCertURI string `json:"peerCertURI,omitempty"`
|
||||||
|
// Spiffe defines the SPIFFE configuration.
|
||||||
|
Spiffe *dynamic.Spiffe `json:"spiffe,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -1142,6 +1142,11 @@ func (in *ServersTransportSpec) DeepCopyInto(out *ServersTransportSpec) {
|
||||||
*out = new(ForwardingTimeouts)
|
*out = new(ForwardingTimeouts)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.Spiffe != nil {
|
||||||
|
in, out := &in.Spiffe, &out.Spiffe
|
||||||
|
*out = new(dynamic.Spiffe)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -322,6 +322,13 @@ func (i *Provider) serverTransport(cfg *dynamic.Configuration) {
|
||||||
MaxIdleConnsPerHost: i.staticCfg.ServersTransport.MaxIdleConnsPerHost,
|
MaxIdleConnsPerHost: i.staticCfg.ServersTransport.MaxIdleConnsPerHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if i.staticCfg.Spiffe != nil {
|
||||||
|
st.Spiffe = &dynamic.Spiffe{
|
||||||
|
IDs: i.staticCfg.ServersTransport.Spiffe.IDs,
|
||||||
|
TrustDomain: i.staticCfg.ServersTransport.Spiffe.TrustDomain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if i.staticCfg.ServersTransport.ForwardingTimeouts != nil {
|
if i.staticCfg.ServersTransport.ForwardingTimeouts != nil {
|
||||||
st.ForwardingTimeouts = &dynamic.ForwardingTimeouts{
|
st.ForwardingTimeouts = &dynamic.ForwardingTimeouts{
|
||||||
DialTimeout: i.staticCfg.ServersTransport.ForwardingTimeouts.DialTimeout,
|
DialTimeout: i.staticCfg.ServersTransport.ForwardingTimeouts.DialTimeout,
|
||||||
|
|
|
@ -312,7 +312,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||||
|
@ -418,7 +418,7 @@ func TestAccessLog(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||||
|
@ -713,7 +713,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||||
|
@ -788,7 +788,7 @@ func TestProviderOnMiddlewares(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||||
|
|
|
@ -48,7 +48,7 @@ func TestReuseService(t *testing.T) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
||||||
tlsManager := tls.NewManager()
|
tlsManager := tls.NewManager()
|
||||||
|
@ -184,7 +184,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
||||||
tlsManager := tls.NewManager()
|
tlsManager := tls.NewManager()
|
||||||
|
@ -225,7 +225,7 @@ func TestInternalServices(t *testing.T) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
roundTripperManager := service.NewRoundTripperManager()
|
roundTripperManager := service.NewRoundTripperManager(nil)
|
||||||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||||
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
||||||
tlsManager := tls.NewManager()
|
tlsManager := tls.NewManager()
|
||||||
|
|
|
@ -11,6 +11,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v2/pkg/log"
|
"github.com/traefik/traefik/v2/pkg/log"
|
||||||
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
|
||||||
|
@ -26,11 +30,18 @@ func (t *h2cTransportWrapper) RoundTrip(req *http.Request) (*http.Response, erro
|
||||||
return t.Transport.RoundTrip(req)
|
return t.Transport.RoundTrip(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SpiffeX509Source allows to retrieve a x509 SVID and bundle.
|
||||||
|
type SpiffeX509Source interface {
|
||||||
|
x509svid.Source
|
||||||
|
x509bundle.Source
|
||||||
|
}
|
||||||
|
|
||||||
// NewRoundTripperManager creates a new RoundTripperManager.
|
// NewRoundTripperManager creates a new RoundTripperManager.
|
||||||
func NewRoundTripperManager() *RoundTripperManager {
|
func NewRoundTripperManager(spiffeX509Source SpiffeX509Source) *RoundTripperManager {
|
||||||
return &RoundTripperManager{
|
return &RoundTripperManager{
|
||||||
roundTrippers: make(map[string]http.RoundTripper),
|
roundTrippers: make(map[string]http.RoundTripper),
|
||||||
configs: make(map[string]*dynamic.ServersTransport),
|
configs: make(map[string]*dynamic.ServersTransport),
|
||||||
|
spiffeX509Source: spiffeX509Source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +50,8 @@ type RoundTripperManager struct {
|
||||||
rtLock sync.RWMutex
|
rtLock sync.RWMutex
|
||||||
roundTrippers map[string]http.RoundTripper
|
roundTrippers map[string]http.RoundTripper
|
||||||
configs map[string]*dynamic.ServersTransport
|
configs map[string]*dynamic.ServersTransport
|
||||||
|
|
||||||
|
spiffeX509Source SpiffeX509Source
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the roundtrippers configurations.
|
// Update updates the roundtrippers configurations.
|
||||||
|
@ -59,7 +72,7 @@ func (r *RoundTripperManager) Update(newConfigs map[string]*dynamic.ServersTrans
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
r.roundTrippers[configName], err = createRoundTripper(newConfig)
|
r.roundTrippers[configName], err = r.createRoundTripper(newConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithoutContext().Errorf("Could not configure HTTP Transport %s, fallback on default transport: %v", configName, err)
|
log.WithoutContext().Errorf("Could not configure HTTP Transport %s, fallback on default transport: %v", configName, err)
|
||||||
r.roundTrippers[configName] = http.DefaultTransport
|
r.roundTrippers[configName] = http.DefaultTransport
|
||||||
|
@ -72,7 +85,7 @@ func (r *RoundTripperManager) Update(newConfigs map[string]*dynamic.ServersTrans
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
r.roundTrippers[newConfigName], err = createRoundTripper(newConfig)
|
r.roundTrippers[newConfigName], err = r.createRoundTripper(newConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithoutContext().Errorf("Could not configure HTTP Transport %s, fallback on default transport: %v", newConfigName, err)
|
log.WithoutContext().Errorf("Could not configure HTTP Transport %s, fallback on default transport: %v", newConfigName, err)
|
||||||
r.roundTrippers[newConfigName] = http.DefaultTransport
|
r.roundTrippers[newConfigName] = http.DefaultTransport
|
||||||
|
@ -102,7 +115,7 @@ func (r *RoundTripperManager) Get(name string) (http.RoundTripper, error) {
|
||||||
// For the settings that can't be configured in Traefik it uses the default http.Transport settings.
|
// For the settings that can't be configured in Traefik it uses the default http.Transport settings.
|
||||||
// An exception to this is the MaxIdleConns setting as we only provide the option MaxIdleConnsPerHost in Traefik at this point in time.
|
// An exception to this is the MaxIdleConns setting as we only provide the option MaxIdleConnsPerHost in Traefik at this point in time.
|
||||||
// Setting this value to the default of 100 could lead to confusing behavior and backwards compatibility issues.
|
// Setting this value to the default of 100 could lead to confusing behavior and backwards compatibility issues.
|
||||||
func createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error) {
|
func (r *RoundTripperManager) createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, errors.New("no transport configuration given")
|
return nil, errors.New("no transport configuration given")
|
||||||
}
|
}
|
||||||
|
@ -132,7 +145,24 @@ func createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error
|
||||||
transport.IdleConnTimeout = time.Duration(cfg.ForwardingTimeouts.IdleConnTimeout)
|
transport.IdleConnTimeout = time.Duration(cfg.ForwardingTimeouts.IdleConnTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Spiffe != nil {
|
||||||
|
if r.spiffeX509Source == nil {
|
||||||
|
return nil, errors.New("SPIFFE is enabled for this transport, but not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
spiffeAuthorizer, err := buildSpiffeAuthorizer(cfg.Spiffe)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to build SPIFFE authorizer: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
transport.TLSClientConfig = tlsconfig.MTLSClientConfig(r.spiffeX509Source, r.spiffeX509Source, spiffeAuthorizer)
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.InsecureSkipVerify || len(cfg.RootCAs) > 0 || len(cfg.ServerName) > 0 || len(cfg.Certificates) > 0 || cfg.PeerCertURI != "" {
|
if cfg.InsecureSkipVerify || len(cfg.RootCAs) > 0 || len(cfg.ServerName) > 0 || len(cfg.Certificates) > 0 || cfg.PeerCertURI != "" {
|
||||||
|
if transport.TLSClientConfig != nil {
|
||||||
|
return nil, errors.New("TLS and SPIFFE configuration cannot be defined at the same time")
|
||||||
|
}
|
||||||
|
|
||||||
transport.TLSClientConfig = &tls.Config{
|
transport.TLSClientConfig = &tls.Config{
|
||||||
ServerName: cfg.ServerName,
|
ServerName: cfg.ServerName,
|
||||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||||
|
@ -173,3 +203,31 @@ func createRootCACertPool(rootCAs []traefiktls.FileOrContent) *x509.CertPool {
|
||||||
|
|
||||||
return roots
|
return roots
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSpiffeAuthorizer(cfg *dynamic.Spiffe) (tlsconfig.Authorizer, error) {
|
||||||
|
switch {
|
||||||
|
case len(cfg.IDs) > 0:
|
||||||
|
spiffeIDs := make([]spiffeid.ID, 0, len(cfg.IDs))
|
||||||
|
for _, rawID := range cfg.IDs {
|
||||||
|
id, err := spiffeid.FromString(rawID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid SPIFFE ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spiffeIDs = append(spiffeIDs, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlsconfig.AuthorizeOneOf(spiffeIDs...), nil
|
||||||
|
|
||||||
|
case cfg.TrustDomain != "":
|
||||||
|
trustDomain, err := spiffeid.TrustDomainFromString(cfg.TrustDomain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid SPIFFE trust domain: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlsconfig.AuthorizeMemberOf(trustDomain), nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return tlsconfig.AuthorizeAny(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,24 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
|
||||||
|
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
|
@ -129,7 +139,7 @@ func TestKeepConnectionWhenSameConfiguration(t *testing.T) {
|
||||||
srv.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
|
srv.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||||
srv.StartTLS()
|
srv.StartTLS()
|
||||||
|
|
||||||
rtManager := NewRoundTripperManager()
|
rtManager := NewRoundTripperManager(nil)
|
||||||
|
|
||||||
dynamicConf := map[string]*dynamic.ServersTransport{
|
dynamicConf := map[string]*dynamic.ServersTransport{
|
||||||
"test": {
|
"test": {
|
||||||
|
@ -197,7 +207,7 @@ func TestMTLS(t *testing.T) {
|
||||||
}
|
}
|
||||||
srv.StartTLS()
|
srv.StartTLS()
|
||||||
|
|
||||||
rtManager := NewRoundTripperManager()
|
rtManager := NewRoundTripperManager(nil)
|
||||||
|
|
||||||
dynamicConf := map[string]*dynamic.ServersTransport{
|
dynamicConf := map[string]*dynamic.ServersTransport{
|
||||||
"test": {
|
"test": {
|
||||||
|
@ -228,6 +238,141 @@ func TestMTLS(t *testing.T) {
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSpiffeMTLS(t *testing.T) {
|
||||||
|
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
|
||||||
|
trustDomain := spiffeid.RequireTrustDomainFromString("spiffe://traefik.test")
|
||||||
|
|
||||||
|
pki, err := newFakeSpiffePKI(trustDomain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
clientSVID, err := pki.genSVID(spiffeid.RequireFromPath(trustDomain, "/client"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
serverSVID, err := pki.genSVID(spiffeid.RequireFromPath(trustDomain, "/server"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
serverSource := fakeSpiffeSource{
|
||||||
|
svid: serverSVID,
|
||||||
|
bundle: pki.bundle,
|
||||||
|
}
|
||||||
|
|
||||||
|
// go-spiffe's `tlsconfig.MTLSServerConfig` (that should be used here) does not set a certificate on
|
||||||
|
// the returned `tls.Config` and relies instead on `GetCertificate` being always called.
|
||||||
|
// But it turns out that `StartTLS` from `httptest.Server`, enforces a default certificate
|
||||||
|
// if no certificate is previously set on the configured TLS config.
|
||||||
|
// It makes the test server always serve the httptest default certificate, and not the SPIFFE certificate,
|
||||||
|
// as GetCertificate is in that case never called (there's a default cert, and SNI is not used).
|
||||||
|
// To bypass this issue, we're manually extracting the server ceritificate from the server SVID
|
||||||
|
// and use another initialization method that forces serving the server SPIFFE certificate.
|
||||||
|
serverCert, err := tlsconfig.GetCertificate(&serverSource)(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
srv.TLS = tlsconfig.MTLSWebServerConfig(
|
||||||
|
serverCert,
|
||||||
|
&serverSource,
|
||||||
|
tlsconfig.AuthorizeAny(),
|
||||||
|
)
|
||||||
|
srv.StartTLS()
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
clientSource := fakeSpiffeSource{
|
||||||
|
svid: clientSVID,
|
||||||
|
bundle: pki.bundle,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
config dynamic.Spiffe
|
||||||
|
clientSource SpiffeX509Source
|
||||||
|
wantStatusCode int
|
||||||
|
wantErrorMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "supports SPIFFE mTLS",
|
||||||
|
config: dynamic.Spiffe{},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "allows expected server SPIFFE ID",
|
||||||
|
config: dynamic.Spiffe{
|
||||||
|
IDs: []string{"spiffe://traefik.test/server"},
|
||||||
|
},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "blocks unexpected server SPIFFE ID",
|
||||||
|
config: dynamic.Spiffe{
|
||||||
|
IDs: []string{"spiffe://traefik.test/not-server"},
|
||||||
|
},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantErrorMessage: `unexpected ID "spiffe://traefik.test/server"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "allows expected server trust domain",
|
||||||
|
config: dynamic.Spiffe{
|
||||||
|
TrustDomain: "spiffe://traefik.test",
|
||||||
|
},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "denies unexpected server trust domain",
|
||||||
|
config: dynamic.Spiffe{
|
||||||
|
TrustDomain: "spiffe://not-traefik.test",
|
||||||
|
},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantErrorMessage: `unexpected trust domain "traefik.test"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "spiffe IDs allowlist takes precedence",
|
||||||
|
config: dynamic.Spiffe{
|
||||||
|
IDs: []string{"spiffe://traefik.test/not-server"},
|
||||||
|
TrustDomain: "spiffe://not-traefik.test",
|
||||||
|
},
|
||||||
|
clientSource: &clientSource,
|
||||||
|
wantErrorMessage: `unexpected ID "spiffe://traefik.test/server"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "raises an error when spiffe is enabled on the transport but no workloadapi address is given",
|
||||||
|
config: dynamic.Spiffe{},
|
||||||
|
clientSource: nil,
|
||||||
|
wantErrorMessage: `remote error: tls: bad certificate`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
rtManager := NewRoundTripperManager(test.clientSource)
|
||||||
|
|
||||||
|
dynamicConf := map[string]*dynamic.ServersTransport{
|
||||||
|
"test": {
|
||||||
|
Spiffe: &test.config,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rtManager.Update(dynamicConf)
|
||||||
|
|
||||||
|
tr, err := rtManager.Get("test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
client := http.Client{Transport: tr}
|
||||||
|
|
||||||
|
resp, err := client.Get(srv.URL)
|
||||||
|
if test.wantErrorMessage != "" {
|
||||||
|
assert.ErrorContains(t, err, test.wantErrorMessage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, test.wantStatusCode, resp.StatusCode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDisableHTTP2(t *testing.T) {
|
func TestDisableHTTP2(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -269,7 +414,7 @@ func TestDisableHTTP2(t *testing.T) {
|
||||||
srv.EnableHTTP2 = test.serverHTTP2
|
srv.EnableHTTP2 = test.serverHTTP2
|
||||||
srv.StartTLS()
|
srv.StartTLS()
|
||||||
|
|
||||||
rtManager := NewRoundTripperManager()
|
rtManager := NewRoundTripperManager(nil)
|
||||||
|
|
||||||
dynamicConf := map[string]*dynamic.ServersTransport{
|
dynamicConf := map[string]*dynamic.ServersTransport{
|
||||||
"test": {
|
"test": {
|
||||||
|
@ -293,3 +438,116 @@ func TestDisableHTTP2(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fakeSpiffePKI simulates a SPIFFE aware PKI and allows generating multiple valid SVIDs.
|
||||||
|
type fakeSpiffePKI struct {
|
||||||
|
caPrivateKey *rsa.PrivateKey
|
||||||
|
|
||||||
|
bundle *x509bundle.Bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeSpiffePKI(trustDomain spiffeid.TrustDomain) (fakeSpiffePKI, error) {
|
||||||
|
caPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return fakeSpiffePKI{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caTemplate := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(2000),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Organization: []string{"spiffe"},
|
||||||
|
},
|
||||||
|
URIs: []*url.URL{spiffeid.RequireFromPath(trustDomain, "/ca").URL()},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().Add(time.Hour),
|
||||||
|
SubjectKeyId: []byte("ca"),
|
||||||
|
KeyUsage: x509.KeyUsageCertSign |
|
||||||
|
x509.KeyUsageCRLSign,
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
IsCA: true,
|
||||||
|
PublicKey: caPrivateKey.Public(),
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fakeSpiffePKI{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertDER, err := x509.CreateCertificate(
|
||||||
|
rand.Reader,
|
||||||
|
&caTemplate,
|
||||||
|
&caTemplate,
|
||||||
|
caPrivateKey.Public(),
|
||||||
|
caPrivateKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fakeSpiffePKI{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle, err := x509bundle.ParseRaw(
|
||||||
|
trustDomain,
|
||||||
|
caCertDER,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fakeSpiffePKI{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fakeSpiffePKI{
|
||||||
|
bundle: bundle,
|
||||||
|
caPrivateKey: caPrivateKey,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeSpiffePKI) genSVID(id spiffeid.ID) (*x509svid.SVID, error) {
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(200001),
|
||||||
|
URIs: []*url.URL{id.URL()},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().Add(time.Hour),
|
||||||
|
SubjectKeyId: []byte("svid"),
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment |
|
||||||
|
x509.KeyUsageKeyAgreement |
|
||||||
|
x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||||
|
x509.ExtKeyUsageServerAuth,
|
||||||
|
x509.ExtKeyUsageClientAuth,
|
||||||
|
},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
PublicKey: privateKey.PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
certDER, err := x509.CreateCertificate(
|
||||||
|
rand.Reader,
|
||||||
|
&template,
|
||||||
|
f.bundle.X509Authorities()[0],
|
||||||
|
privateKey.Public(),
|
||||||
|
f.caPrivateKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPKCS8, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return x509svid.ParseRaw(certDER, keyPKCS8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fakeSpiffeSource allows retrieving staticly an SVID and its associated bundle.
|
||||||
|
type fakeSpiffeSource struct {
|
||||||
|
bundle *x509bundle.Bundle
|
||||||
|
svid *x509svid.SVID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *fakeSpiffeSource) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
|
||||||
|
return s.bundle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *fakeSpiffeSource) GetX509SVID() (*x509svid.SVID, error) {
|
||||||
|
return s.svid, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue