Support file path as input param for Kubernetes token value
This commit is contained in:
parent
ff7966f9cd
commit
980dac4572
37 changed files with 292 additions and 256 deletions
|
@ -87,11 +87,11 @@ func run(dest string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanType(typ types.Type, base string) string {
|
func cleanType(typ types.Type, base string) string {
|
||||||
if typ.String() == "github.com/traefik/traefik/v3/pkg/tls.FileOrContent" {
|
if typ.String() == "github.com/traefik/traefik/v3/pkg/types.FileOrContent" {
|
||||||
return "string"
|
return "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
if typ.String() == "[]github.com/traefik/traefik/v3/pkg/tls.FileOrContent" {
|
if typ.String() == "[]github.com/traefik/traefik/v3/pkg/types.FileOrContent" {
|
||||||
return "[]string"
|
return "[]string"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -691,7 +691,7 @@ Kubernetes namespaces.
|
||||||
Ingress refresh throttle duration (Default: ```0```)
|
Ingress refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`--providers.kubernetescrd.token`:
|
`--providers.kubernetescrd.token`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`--providers.kubernetesgateway`:
|
`--providers.kubernetesgateway`:
|
||||||
Enable Kubernetes gateway api provider with default settings. (Default: ```false```)
|
Enable Kubernetes gateway api provider with default settings. (Default: ```false```)
|
||||||
|
@ -712,7 +712,7 @@ Kubernetes namespaces.
|
||||||
Kubernetes refresh throttle duration (Default: ```0```)
|
Kubernetes refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`--providers.kubernetesgateway.token`:
|
`--providers.kubernetesgateway.token`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`--providers.kubernetesingress`:
|
`--providers.kubernetesingress`:
|
||||||
Enable Kubernetes backend with default settings. (Default: ```false```)
|
Enable Kubernetes backend with default settings. (Default: ```false```)
|
||||||
|
@ -754,7 +754,7 @@ Kubernetes namespaces.
|
||||||
Ingress refresh throttle duration (Default: ```0```)
|
Ingress refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`--providers.kubernetesingress.token`:
|
`--providers.kubernetesingress.token`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`--providers.nomad`:
|
`--providers.nomad`:
|
||||||
Enable Nomad backend with default settings. (Default: ```false```)
|
Enable Nomad backend with default settings. (Default: ```false```)
|
||||||
|
|
|
@ -691,7 +691,7 @@ Kubernetes namespaces.
|
||||||
Ingress refresh throttle duration (Default: ```0```)
|
Ingress refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_KUBERNETESCRD_TOKEN`:
|
`TRAEFIK_PROVIDERS_KUBERNETESCRD_TOKEN`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY`:
|
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY`:
|
||||||
Enable Kubernetes gateway api provider with default settings. (Default: ```false```)
|
Enable Kubernetes gateway api provider with default settings. (Default: ```false```)
|
||||||
|
@ -712,7 +712,7 @@ Kubernetes namespaces.
|
||||||
Kubernetes refresh throttle duration (Default: ```0```)
|
Kubernetes refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_TOKEN`:
|
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_TOKEN`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_KUBERNETESINGRESS`:
|
`TRAEFIK_PROVIDERS_KUBERNETESINGRESS`:
|
||||||
Enable Kubernetes backend with default settings. (Default: ```false```)
|
Enable Kubernetes backend with default settings. (Default: ```false```)
|
||||||
|
@ -754,7 +754,7 @@ Kubernetes namespaces.
|
||||||
Ingress refresh throttle duration (Default: ```0```)
|
Ingress refresh throttle duration (Default: ```0```)
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_KUBERNETESINGRESS_TOKEN`:
|
`TRAEFIK_PROVIDERS_KUBERNETESINGRESS_TOKEN`:
|
||||||
Kubernetes bearer token (not needed for in-cluster client).
|
Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_NOMAD`:
|
`TRAEFIK_PROVIDERS_NOMAD`:
|
||||||
Enable Nomad backend with default settings. (Default: ```false```)
|
Enable Nomad backend with default settings. (Default: ```false```)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/integration/try"
|
"github.com/traefik/traefik/v3/integration/try"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTPSSuite tests suite.
|
// HTTPSSuite tests suite.
|
||||||
|
@ -891,8 +892,8 @@ func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName
|
||||||
Certificates: []*traefiktls.CertAndStores{
|
Certificates: []*traefiktls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: traefiktls.Certificate{
|
Certificate: traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
CertFile: types.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||||
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
KeyFile: types.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -267,7 +267,7 @@ type HealthCheck struct{}
|
||||||
type ServersTransport struct {
|
type ServersTransport struct {
|
||||||
ServerName string `description:"Defines the serverName used to contact the server." json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
|
ServerName string `description:"Defines the serverName used to contact the server." json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
|
||||||
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||||
RootCAs []traefiktls.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
RootCAs []types.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
||||||
Certificates traefiktls.Certificates `description:"Defines a list of secret storing client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
|
Certificates traefiktls.Certificates `description:"Defines a list of secret storing client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,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"`
|
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:"Defines the timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
ForwardingTimeouts *ForwardingTimeouts `description:"Defines the timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
|
||||||
|
|
|
@ -140,7 +140,7 @@ type TCPServersTransport struct {
|
||||||
type TLSClientConfig struct {
|
type TLSClientConfig struct {
|
||||||
ServerName string `description:"Defines the serverName used to contact the server." json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
|
ServerName string `description:"Defines the serverName used to contact the server." json:"serverName,omitempty" toml:"serverName,omitempty" yaml:"serverName,omitempty"`
|
||||||
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||||
RootCAs []traefiktls.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
RootCAs []types.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
||||||
Certificates traefiktls.Certificates `description:"Defines a list of secret storing client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
|
Certificates traefiktls.Certificates `description:"Defines a list of secret storing client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
|
||||||
PeerCertURI string `description:"Defines the 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:"Defines the 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:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
|
|
@ -1205,7 +1205,7 @@ func (in *ServersTransport) DeepCopyInto(out *ServersTransport) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.RootCAs != nil {
|
if in.RootCAs != nil {
|
||||||
in, out := &in.RootCAs, &out.RootCAs
|
in, out := &in.RootCAs, &out.RootCAs
|
||||||
*out = make([]tls.FileOrContent, len(*in))
|
*out = make([]types.FileOrContent, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
if in.Certificates != nil {
|
if in.Certificates != nil {
|
||||||
|
@ -1769,7 +1769,7 @@ func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.RootCAs != nil {
|
if in.RootCAs != nil {
|
||||||
in, out := &in.RootCAs, &out.RootCAs
|
in, out := &in.RootCAs, &out.RootCAs
|
||||||
*out = make([]tls.FileOrContent, len(*in))
|
*out = make([]types.FileOrContent, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
if in.Certificates != nil {
|
if in.Certificates != nil {
|
||||||
|
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/kv/zk"
|
"github.com/traefik/traefik/v3/pkg/provider/kv/zk"
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/nomad"
|
"github.com/traefik/traefik/v3/pkg/provider/nomad"
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/rest"
|
"github.com/traefik/traefik/v3/pkg/provider/rest"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
|
||||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||||
"github.com/traefik/traefik/v3/pkg/types"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -97,7 +96,7 @@ type Global struct {
|
||||||
// ServersTransport options to configure communication between Traefik and the servers.
|
// ServersTransport options to configure communication between Traefik and the servers.
|
||||||
type ServersTransport struct {
|
type ServersTransport struct {
|
||||||
InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||||
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
RootCAs []types.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 *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
@ -125,7 +124,7 @@ type TCPServersTransport struct {
|
||||||
// TLSClientConfig options to configure TLS communication between Traefik and the servers.
|
// TLSClientConfig options to configure TLS communication between Traefik and the servers.
|
||||||
type TLSClientConfig struct {
|
type TLSClientConfig struct {
|
||||||
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
|
||||||
RootCAs []tls.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
RootCAs []types.FileOrContent `description:"Defines a list of CA secret used to validate self-signed certificate" json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
|
||||||
Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,8 +152,8 @@ func createMessage(certs map[string]*Certificate) dynamic.Message {
|
||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
certConf := &traefiktls.CertAndStores{
|
certConf := &traefiktls.CertAndStores{
|
||||||
Certificate: traefiktls.Certificate{
|
Certificate: traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(cert.Certificate),
|
CertFile: types.FileOrContent(cert.Certificate),
|
||||||
KeyFile: traefiktls.FileOrContent(cert.Key),
|
KeyFile: types.FileOrContent(cert.Key),
|
||||||
},
|
},
|
||||||
Stores: []string{tlsalpn01.ACMETLS1Protocol},
|
Stores: []string{tlsalpn01.ACMETLS1Protocol},
|
||||||
}
|
}
|
||||||
|
|
|
@ -783,8 +783,8 @@ func (p *Provider) buildMessage() dynamic.Message {
|
||||||
for _, cert := range p.certificates {
|
for _, cert := range p.certificates {
|
||||||
certConf := &traefiktls.CertAndStores{
|
certConf := &traefiktls.CertAndStores{
|
||||||
Certificate: traefiktls.Certificate{
|
Certificate: traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(cert.Certificate.Certificate),
|
CertFile: types.FileOrContent(cert.Certificate.Certificate),
|
||||||
KeyFile: traefiktls.FileOrContent(cert.Key),
|
KeyFile: types.FileOrContent(cert.Key),
|
||||||
},
|
},
|
||||||
Stores: []string{cert.Store},
|
Stores: []string{cert.Store},
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
ptypes "github.com/traefik/paerser/types"
|
ptypes "github.com/traefik/paerser/types"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Int(v int) *int { return &v }
|
func Int(v int) *int { return &v }
|
||||||
|
@ -428,7 +429,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"tls-ns-dc1-dev-Test": {
|
"tls-ns-dc1-dev-Test": {
|
||||||
ServerName: "ns-dc1-dev/Test",
|
ServerName: "ns-dc1-dev/Test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{
|
RootCAs: []types.FileOrContent{
|
||||||
"root",
|
"root",
|
||||||
},
|
},
|
||||||
Certificates: []tls.Certificate{
|
Certificates: []tls.Certificate{
|
||||||
|
@ -519,7 +520,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"tls-ns-dc1-dev-Test": {
|
"tls-ns-dc1-dev-Test": {
|
||||||
ServerName: "ns-dc1-dev/Test",
|
ServerName: "ns-dc1-dev/Test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{
|
RootCAs: []types.FileOrContent{
|
||||||
"root",
|
"root",
|
||||||
},
|
},
|
||||||
Certificates: []tls.Certificate{
|
Certificates: []tls.Certificate{
|
||||||
|
@ -2280,7 +2281,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "ns-dc1-Test",
|
ServerName: "ns-dc1-Test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{
|
RootCAs: []types.FileOrContent{
|
||||||
"root",
|
"root",
|
||||||
},
|
},
|
||||||
Certificates: []tls.Certificate{
|
Certificates: []tls.Certificate{
|
||||||
|
@ -2899,7 +2900,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"tls-ns-dc1-Test": {
|
"tls-ns-dc1-Test": {
|
||||||
ServerName: "ns-dc1-Test",
|
ServerName: "ns-dc1-Test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{
|
RootCAs: []types.FileOrContent{
|
||||||
"root",
|
"root",
|
||||||
},
|
},
|
||||||
Certificates: []tls.Certificate{
|
Certificates: []tls.Certificate{
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// connectCert holds our certificates as a client of the Consul Connect protocol.
|
// connectCert holds our certificates as a client of the Consul Connect protocol.
|
||||||
|
@ -13,18 +14,18 @@ type connectCert struct {
|
||||||
leaf keyPair
|
leaf keyPair
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connectCert) getRoot() []traefiktls.FileOrContent {
|
func (c *connectCert) getRoot() []types.FileOrContent {
|
||||||
var result []traefiktls.FileOrContent
|
var result []types.FileOrContent
|
||||||
for _, r := range c.root {
|
for _, r := range c.root {
|
||||||
result = append(result, traefiktls.FileOrContent(r))
|
result = append(result, types.FileOrContent(r))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connectCert) getLeaf() traefiktls.Certificate {
|
func (c *connectCert) getLeaf() traefiktls.Certificate {
|
||||||
return traefiktls.Certificate{
|
return traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(c.leaf.cert),
|
CertFile: types.FileOrContent(c.leaf.cert),
|
||||||
KeyFile: traefiktls.FileOrContent(c.leaf.key),
|
KeyFile: types.FileOrContent(c.leaf.key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/provider"
|
"github.com/traefik/traefik/v3/pkg/provider"
|
||||||
"github.com/traefik/traefik/v3/pkg/safe"
|
"github.com/traefik/traefik/v3/pkg/safe"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const providerName = "file"
|
const providerName = "file"
|
||||||
|
@ -180,7 +181,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
// TLS Options
|
// TLS Options
|
||||||
if configuration.TLS.Options != nil {
|
if configuration.TLS.Options != nil {
|
||||||
for name, options := range configuration.TLS.Options {
|
for name, options := range configuration.TLS.Options {
|
||||||
var caCerts []tls.FileOrContent
|
var caCerts []types.FileOrContent
|
||||||
|
|
||||||
for _, caFile := range options.ClientAuth.CAFiles {
|
for _, caFile := range options.ClientAuth.CAFiles {
|
||||||
content, err := caFile.Read()
|
content, err := caFile.Read()
|
||||||
|
@ -189,7 +190,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
caCerts = append(caCerts, tls.FileOrContent(content))
|
caCerts = append(caCerts, types.FileOrContent(content))
|
||||||
}
|
}
|
||||||
options.ClientAuth.CAFiles = caCerts
|
options.ClientAuth.CAFiles = caCerts
|
||||||
|
|
||||||
|
@ -209,14 +210,14 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.DefaultCertificate.CertFile = tls.FileOrContent(content)
|
store.DefaultCertificate.CertFile = types.FileOrContent(content)
|
||||||
|
|
||||||
content, err = store.DefaultCertificate.KeyFile.Read()
|
content, err = store.DefaultCertificate.KeyFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.DefaultCertificate.KeyFile = tls.FileOrContent(content)
|
store.DefaultCertificate.KeyFile = types.FileOrContent(content)
|
||||||
|
|
||||||
configuration.TLS.Stores[name] = store
|
configuration.TLS.Stores[name] = store
|
||||||
}
|
}
|
||||||
|
@ -233,21 +234,21 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.CertFile = tls.FileOrContent(content)
|
cert.CertFile = types.FileOrContent(content)
|
||||||
|
|
||||||
content, err = cert.KeyFile.Read()
|
content, err = cert.KeyFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.KeyFile = tls.FileOrContent(content)
|
cert.KeyFile = types.FileOrContent(content)
|
||||||
|
|
||||||
certificates = append(certificates, cert)
|
certificates = append(certificates, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration.HTTP.ServersTransports[name].Certificates = certificates
|
configuration.HTTP.ServersTransports[name].Certificates = certificates
|
||||||
|
|
||||||
var rootCAs []tls.FileOrContent
|
var rootCAs []types.FileOrContent
|
||||||
for _, rootCA := range st.RootCAs {
|
for _, rootCA := range st.RootCAs {
|
||||||
content, err := rootCA.Read()
|
content, err := rootCA.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -255,7 +256,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCAs = append(rootCAs, tls.FileOrContent(content))
|
rootCAs = append(rootCAs, types.FileOrContent(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
st.RootCAs = rootCAs
|
st.RootCAs = rootCAs
|
||||||
|
@ -275,21 +276,21 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.CertFile = tls.FileOrContent(content)
|
cert.CertFile = types.FileOrContent(content)
|
||||||
|
|
||||||
content, err = cert.KeyFile.Read()
|
content, err = cert.KeyFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.KeyFile = tls.FileOrContent(content)
|
cert.KeyFile = types.FileOrContent(content)
|
||||||
|
|
||||||
certificates = append(certificates, cert)
|
certificates = append(certificates, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration.TCP.ServersTransports[name].TLS.Certificates = certificates
|
configuration.TCP.ServersTransports[name].TLS.Certificates = certificates
|
||||||
|
|
||||||
var rootCAs []tls.FileOrContent
|
var rootCAs []types.FileOrContent
|
||||||
for _, rootCA := range st.TLS.RootCAs {
|
for _, rootCA := range st.TLS.RootCAs {
|
||||||
content, err := rootCA.Read()
|
content, err := rootCA.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -297,7 +298,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCAs = append(rootCAs, tls.FileOrContent(content))
|
rootCAs = append(rootCAs, types.FileOrContent(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
st.TLS.RootCAs = rootCAs
|
st.TLS.RootCAs = rootCAs
|
||||||
|
@ -315,14 +316,14 @@ func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguratio
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.Certificate.CertFile = tls.FileOrContent(string(content))
|
cert.Certificate.CertFile = types.FileOrContent(string(content))
|
||||||
|
|
||||||
content, err = cert.Certificate.KeyFile.Read()
|
content, err = cert.Certificate.KeyFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Ctx(ctx).Error().Err(err).Send()
|
log.Ctx(ctx).Error().Err(err).Send()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert.Certificate.KeyFile = tls.FileOrContent(string(content))
|
cert.Certificate.KeyFile = types.FileOrContent(string(content))
|
||||||
|
|
||||||
certs = append(certs, cert)
|
certs = append(certs, cert)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
traefikinformers "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions"
|
traefikinformers "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions"
|
||||||
traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"github.com/traefik/traefik/v3/pkg/version"
|
"github.com/traefik/traefik/v3/pkg/version"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
@ -120,14 +121,19 @@ func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||||
// newExternalClusterClient returns a new Provider client that may run outside
|
// newExternalClusterClient returns a new Provider client that may run outside
|
||||||
// of the cluster.
|
// of the cluster.
|
||||||
// The endpoint parameter must not be empty.
|
// The endpoint parameter must not be empty.
|
||||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrContent) (*clientWrapper, error) {
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
return nil, errors.New("endpoint missing for external cluster client")
|
return nil, errors.New("endpoint missing for external cluster client")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenData, err := token.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
config := &rest.Config{
|
config := &rest.Config{
|
||||||
Host: endpoint,
|
Host: endpoint,
|
||||||
BearerToken: token,
|
BearerToken: string(tokenData),
|
||||||
}
|
}
|
||||||
|
|
||||||
if caFilePath != "" {
|
if caFilePath != "" {
|
||||||
|
|
|
@ -49,7 +49,7 @@ const (
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
Token types.FileOrContent `description:"Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
||||||
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
||||||
AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"`
|
AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"`
|
||||||
|
@ -101,7 +101,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
|
||||||
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
||||||
default:
|
default:
|
||||||
log.Ctx(ctx).Info().Msgf("Creating cluster-external Provider client%s", withEndpoint)
|
log.Ctx(ctx).Info().Msgf("Creating cluster-external Provider client%s", withEndpoint)
|
||||||
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
|
client, err = newExternalClusterClient(p.Endpoint, p.CertAuthFilePath, p.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -339,7 +339,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
for _, serversTransport := range client.GetServersTransports() {
|
for _, serversTransport := range client.GetServersTransports() {
|
||||||
logger := log.Ctx(ctx).With().Str(logs.ServersTransportName, serversTransport.Name).Logger()
|
logger := log.Ctx(ctx).With().Str(logs.ServersTransportName, serversTransport.Name).Logger()
|
||||||
|
|
||||||
var rootCAs []tls.FileOrContent
|
var rootCAs []types.FileOrContent
|
||||||
for _, secret := range serversTransport.Spec.RootCAsSecrets {
|
for _, secret := range serversTransport.Spec.RootCAsSecrets {
|
||||||
caSecret, err := loadCASecret(serversTransport.Namespace, secret, client)
|
caSecret, err := loadCASecret(serversTransport.Namespace, secret, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -347,7 +347,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCAs = append(rootCAs, tls.FileOrContent(caSecret))
|
rootCAs = append(rootCAs, types.FileOrContent(caSecret))
|
||||||
}
|
}
|
||||||
|
|
||||||
var certs tls.Certificates
|
var certs tls.Certificates
|
||||||
|
@ -359,8 +359,8 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
certs = append(certs, tls.Certificate{
|
certs = append(certs, tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(tlsSecret),
|
CertFile: types.FileOrContent(tlsSecret),
|
||||||
KeyFile: tls.FileOrContent(tlsKey),
|
KeyFile: types.FileOrContent(tlsKey),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
if serversTransportTCP.Spec.TLS != nil {
|
if serversTransportTCP.Spec.TLS != nil {
|
||||||
var rootCAs []tls.FileOrContent
|
var rootCAs []types.FileOrContent
|
||||||
for _, secret := range serversTransportTCP.Spec.TLS.RootCAsSecrets {
|
for _, secret := range serversTransportTCP.Spec.TLS.RootCAsSecrets {
|
||||||
caSecret, err := loadCASecret(serversTransportTCP.Namespace, secret, client)
|
caSecret, err := loadCASecret(serversTransportTCP.Namespace, secret, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -457,7 +457,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCAs = append(rootCAs, tls.FileOrContent(caSecret))
|
rootCAs = append(rootCAs, types.FileOrContent(caSecret))
|
||||||
}
|
}
|
||||||
|
|
||||||
var certs tls.Certificates
|
var certs tls.Certificates
|
||||||
|
@ -472,8 +472,8 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
certs = append(certs, tls.Certificate{
|
certs = append(certs, tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(tlsCert),
|
CertFile: types.FileOrContent(tlsCert),
|
||||||
KeyFile: tls.FileOrContent(tlsKey),
|
KeyFile: types.FileOrContent(tlsKey),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,7 +963,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
||||||
|
|
||||||
for _, tlsOption := range tlsOptionsCRD {
|
for _, tlsOption := range tlsOptionsCRD {
|
||||||
logger := log.Ctx(ctx).With().Str("tlsOption", tlsOption.Name).Str("namespace", tlsOption.Namespace).Logger()
|
logger := log.Ctx(ctx).With().Str("tlsOption", tlsOption.Name).Str("namespace", tlsOption.Namespace).Logger()
|
||||||
var clientCAs []tls.FileOrContent
|
var clientCAs []types.FileOrContent
|
||||||
|
|
||||||
for _, secretName := range tlsOption.Spec.ClientAuth.SecretNames {
|
for _, secretName := range tlsOption.Spec.ClientAuth.SecretNames {
|
||||||
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
||||||
|
@ -983,7 +983,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCAs = append(clientCAs, tls.FileOrContent(cert))
|
clientCAs = append(clientCAs, types.FileOrContent(cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
id := makeID(tlsOption.Namespace, tlsOption.Name)
|
id := makeID(tlsOption.Namespace, tlsOption.Name)
|
||||||
|
@ -1063,8 +1063,8 @@ func buildTLSStores(ctx context.Context, client Client) (map[string]tls.Store, m
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsStore.DefaultCertificate = &tls.Certificate{
|
tlsStore.DefaultCertificate = &tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(cert),
|
CertFile: types.FileOrContent(cert),
|
||||||
KeyFile: tls.FileOrContent(key),
|
KeyFile: types.FileOrContent(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1149,8 +1149,8 @@ func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores,
|
||||||
|
|
||||||
return &tls.CertAndStores{
|
return &tls.CertAndStores{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(cert),
|
CertFile: types.FileOrContent(cert),
|
||||||
KeyFile: tls.FileOrContent(key),
|
KeyFile: types.FileOrContent(key),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -571,8 +571,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -673,9 +673,9 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -741,9 +741,9 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -809,8 +809,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -1064,8 +1064,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
Stores: map[string]tls.Store{
|
Stores: map[string]tls.Store{
|
||||||
"default": {
|
"default": {
|
||||||
DefaultCertificate: &tls.Certificate{
|
DefaultCertificate: &tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1405,7 +1405,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "test",
|
ServerName: "test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"},
|
RootCAs: []types.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"},
|
||||||
Certificates: tls.Certificates{
|
Certificates: tls.Certificates{
|
||||||
{CertFile: "TESTCERT1", KeyFile: "TESTKEY1"},
|
{CertFile: "TESTCERT1", KeyFile: "TESTKEY1"},
|
||||||
{CertFile: "TESTCERT2", KeyFile: "TESTKEY2"},
|
{CertFile: "TESTCERT2", KeyFile: "TESTKEY2"},
|
||||||
|
@ -2917,8 +2917,8 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2979,9 +2979,9 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -3100,9 +3100,9 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -3178,9 +3178,9 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -3251,8 +3251,8 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
|
@ -3881,8 +3881,8 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Stores: map[string]tls.Store{
|
Stores: map[string]tls.Store{
|
||||||
"default": {
|
"default": {
|
||||||
DefaultCertificate: &tls.Certificate{
|
DefaultCertificate: &tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3938,8 +3938,8 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
Stores: []string{"default"},
|
Stores: []string{"default"},
|
||||||
},
|
},
|
||||||
|
@ -4215,7 +4215,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"foo-test": {
|
"foo-test": {
|
||||||
ServerName: "test",
|
ServerName: "test",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []tls.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"},
|
RootCAs: []types.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"},
|
||||||
Certificates: tls.Certificates{
|
Certificates: tls.Certificates{
|
||||||
{CertFile: "TESTCERT1", KeyFile: "TESTKEY1"},
|
{CertFile: "TESTCERT1", KeyFile: "TESTKEY1"},
|
||||||
{CertFile: "TESTCERT2", KeyFile: "TESTKEY2"},
|
{CertFile: "TESTCERT2", KeyFile: "TESTKEY2"},
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -129,14 +130,19 @@ func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||||
|
|
||||||
// newExternalClusterClient returns a new Provider client that may run outside of the cluster.
|
// newExternalClusterClient returns a new Provider client that may run outside of the cluster.
|
||||||
// The endpoint parameter must not be empty.
|
// The endpoint parameter must not be empty.
|
||||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrContent) (*clientWrapper, error) {
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
return nil, errors.New("endpoint missing for external cluster client")
|
return nil, errors.New("endpoint missing for external cluster client")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenData, err := token.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
config := &rest.Config{
|
config := &rest.Config{
|
||||||
Host: endpoint,
|
Host: endpoint,
|
||||||
BearerToken: token,
|
BearerToken: string(tokenData),
|
||||||
}
|
}
|
||||||
|
|
||||||
if caFilePath != "" {
|
if caFilePath != "" {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||||
"github.com/traefik/traefik/v3/pkg/safe"
|
"github.com/traefik/traefik/v3/pkg/safe"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
@ -48,7 +49,7 @@ const (
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
Token types.FileOrContent `description:"Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
||||||
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
||||||
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
||||||
|
@ -101,7 +102,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
|
||||||
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
||||||
default:
|
default:
|
||||||
logger.Info().Str("endpoint", p.Endpoint).Msg("Creating cluster-external Provider client")
|
logger.Info().Str("endpoint", p.Endpoint).Msg("Creating cluster-external Provider client")
|
||||||
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
|
client, err = newExternalClusterClient(p.Endpoint, p.CertAuthFilePath, p.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1428,8 +1429,8 @@ func getTLS(k8sClient Client, secretName gatev1.ObjectName, namespace string) (*
|
||||||
|
|
||||||
return &tls.CertAndStores{
|
return &tls.CertAndStores{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(cert),
|
CertFile: types.FileOrContent(cert),
|
||||||
KeyFile: tls.FileOrContent(key),
|
KeyFile: types.FileOrContent(key),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v3/pkg/provider"
|
"github.com/traefik/traefik/v3/pkg/provider"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/utils/ptr"
|
"k8s.io/utils/ptr"
|
||||||
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
|
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
|
||||||
|
@ -492,8 +493,8 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -741,8 +742,8 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1176,8 +1177,8 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1265,8 +1266,8 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2240,8 +2241,8 @@ func TestLoadTCPRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2735,8 +2736,8 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2947,8 +2948,8 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3016,8 +3017,8 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3823,8 +3824,8 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4002,8 +4003,8 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4243,8 +4244,8 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4394,8 +4395,8 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4526,8 +4527,8 @@ func TestLoadMixedRoutes(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
traefikversion "github.com/traefik/traefik/v3/pkg/version"
|
traefikversion "github.com/traefik/traefik/v3/pkg/version"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
netv1 "k8s.io/api/networking/v1"
|
netv1 "k8s.io/api/networking/v1"
|
||||||
|
@ -81,14 +82,19 @@ func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||||
// newExternalClusterClient returns a new Provider client that may run outside
|
// newExternalClusterClient returns a new Provider client that may run outside
|
||||||
// of the cluster.
|
// of the cluster.
|
||||||
// The endpoint parameter must not be empty.
|
// The endpoint parameter must not be empty.
|
||||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrContent) (*clientWrapper, error) {
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
return nil, errors.New("endpoint missing for external cluster client")
|
return nil, errors.New("endpoint missing for external cluster client")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenData, err := token.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
config := &rest.Config{
|
config := &rest.Config{
|
||||||
Host: endpoint,
|
Host: endpoint,
|
||||||
BearerToken: token,
|
BearerToken: string(tokenData),
|
||||||
}
|
}
|
||||||
|
|
||||||
if caFilePath != "" {
|
if caFilePath != "" {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||||
"github.com/traefik/traefik/v3/pkg/safe"
|
"github.com/traefik/traefik/v3/pkg/safe"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
netv1 "k8s.io/api/networking/v1"
|
netv1 "k8s.io/api/networking/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
@ -40,7 +41,7 @@ const (
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
Token types.FileOrContent `description:"Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
|
||||||
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
||||||
LabelSelector string `description:"Kubernetes Ingress label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
LabelSelector string `description:"Kubernetes Ingress label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
||||||
|
@ -103,7 +104,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
|
||||||
cl, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
cl, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
||||||
default:
|
default:
|
||||||
logger.Info().Msgf("Creating cluster-external Provider client%s", withEndpoint)
|
logger.Info().Msgf("Creating cluster-external Provider client%s", withEndpoint)
|
||||||
cl, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
|
cl, err = newExternalClusterClient(p.Endpoint, p.CertAuthFilePath, p.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -463,8 +464,8 @@ func getCertificates(ctx context.Context, ingress *netv1.Ingress, k8sClient Clie
|
||||||
|
|
||||||
tlsConfigs[configKey] = &tls.CertAndStores{
|
tlsConfigs[configKey] = &tls.CertAndStores{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent(cert),
|
CertFile: types.FileOrContent(cert),
|
||||||
KeyFile: tls.FileOrContent(key),
|
KeyFile: types.FileOrContent(key),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -877,8 +877,8 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1834,14 +1834,14 @@ func TestGetCertificates(t *testing.T) {
|
||||||
result: map[string]*tls.CertAndStores{
|
result: map[string]*tls.CertAndStores{
|
||||||
"testing-test-secret": {
|
"testing-test-secret": {
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("tls-crt"),
|
CertFile: types.FileOrContent("tls-crt"),
|
||||||
KeyFile: tls.FileOrContent("tls-key"),
|
KeyFile: types.FileOrContent("tls-key"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"testing-test-secret2": {
|
"testing-test-secret2": {
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("tls-crt"),
|
CertFile: types.FileOrContent("tls-crt"),
|
||||||
KeyFile: tls.FileOrContent("tls-key"),
|
KeyFile: types.FileOrContent("tls-key"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -811,8 +811,8 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Certificates: []*tls.CertAndStores{
|
Certificates: []*tls.CertAndStores{
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("foobar"),
|
CertFile: types.FileOrContent("foobar"),
|
||||||
KeyFile: tls.FileOrContent("foobar"),
|
KeyFile: types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
Stores: []string{
|
Stores: []string{
|
||||||
"foobar",
|
"foobar",
|
||||||
|
@ -821,8 +821,8 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Certificate: tls.Certificate{
|
Certificate: tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("foobar"),
|
CertFile: types.FileOrContent("foobar"),
|
||||||
KeyFile: tls.FileOrContent("foobar"),
|
KeyFile: types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
Stores: []string{
|
Stores: []string{
|
||||||
"foobar",
|
"foobar",
|
||||||
|
@ -843,9 +843,9 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"foobar",
|
"foobar",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("foobar"),
|
types.FileOrContent("foobar"),
|
||||||
tls.FileOrContent("foobar"),
|
types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "foobar",
|
ClientAuthType: "foobar",
|
||||||
},
|
},
|
||||||
|
@ -868,9 +868,9 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"foobar",
|
"foobar",
|
||||||
},
|
},
|
||||||
ClientAuth: tls.ClientAuth{
|
ClientAuth: tls.ClientAuth{
|
||||||
CAFiles: []tls.FileOrContent{
|
CAFiles: []types.FileOrContent{
|
||||||
tls.FileOrContent("foobar"),
|
types.FileOrContent("foobar"),
|
||||||
tls.FileOrContent("foobar"),
|
types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
ClientAuthType: "foobar",
|
ClientAuthType: "foobar",
|
||||||
},
|
},
|
||||||
|
@ -885,14 +885,14 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Stores: map[string]tls.Store{
|
Stores: map[string]tls.Store{
|
||||||
"Store0": {
|
"Store0": {
|
||||||
DefaultCertificate: &tls.Certificate{
|
DefaultCertificate: &tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("foobar"),
|
CertFile: types.FileOrContent("foobar"),
|
||||||
KeyFile: tls.FileOrContent("foobar"),
|
KeyFile: types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Store1": {
|
"Store1": {
|
||||||
DefaultCertificate: &tls.Certificate{
|
DefaultCertificate: &tls.Certificate{
|
||||||
CertFile: tls.FileOrContent("foobar"),
|
CertFile: types.FileOrContent("foobar"),
|
||||||
KeyFile: tls.FileOrContent("foobar"),
|
KeyFile: types.FileOrContent("foobar"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/muxer/tcp"
|
"github.com/traefik/traefik/v3/pkg/muxer/tcp"
|
||||||
"github.com/traefik/traefik/v3/pkg/safe"
|
"github.com/traefik/traefik/v3/pkg/safe"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider is the Tailscale certificates provider implementation. It receives
|
// Provider is the Tailscale certificates provider implementation. It receives
|
||||||
|
@ -254,8 +255,8 @@ func (p *Provider) fetchCerts(ctx context.Context, domains []string) {
|
||||||
|
|
||||||
p.certByDomainMu.Lock()
|
p.certByDomainMu.Lock()
|
||||||
p.certByDomain[domain] = traefiktls.Certificate{
|
p.certByDomain[domain] = traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(cert),
|
CertFile: types.FileOrContent(cert),
|
||||||
KeyFile: traefiktls.FileOrContent(key),
|
KeyFile: types.FileOrContent(key),
|
||||||
}
|
}
|
||||||
p.certByDomainMu.Unlock()
|
p.certByDomainMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/mitchellh/copystructure"
|
"github.com/mitchellh/copystructure"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"mvdan.cc/xurls/v2"
|
"mvdan.cc/xurls/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -164,8 +164,8 @@ func reset(field reflect.Value, name string) error {
|
||||||
}
|
}
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if field.String() != "" {
|
if field.String() != "" {
|
||||||
if field.Type().AssignableTo(reflect.TypeOf(tls.FileOrContent(""))) {
|
if field.Type().AssignableTo(reflect.TypeOf(types.FileOrContent(""))) {
|
||||||
field.Set(reflect.ValueOf(tls.FileOrContent(maskShort)))
|
field.Set(reflect.ValueOf(types.FileOrContent(maskShort)))
|
||||||
} else {
|
} else {
|
||||||
field.Set(reflect.ValueOf(maskShort))
|
field.Set(reflect.ValueOf(maskShort))
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ func init() {
|
||||||
"foo": {
|
"foo": {
|
||||||
ServerName: "foo",
|
ServerName: "foo",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []traefiktls.FileOrContent{"rootca.pem"},
|
RootCAs: []types.FileOrContent{"rootca.pem"},
|
||||||
Certificates: []traefiktls.Certificate{
|
Certificates: []traefiktls.Certificate{
|
||||||
{
|
{
|
||||||
CertFile: "cert.pem",
|
CertFile: "cert.pem",
|
||||||
|
@ -390,7 +390,7 @@ func init() {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "foo",
|
ServerName: "foo",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []traefiktls.FileOrContent{"rootca.pem"},
|
RootCAs: []types.FileOrContent{"rootca.pem"},
|
||||||
Certificates: []traefiktls.Certificate{
|
Certificates: []traefiktls.Certificate{
|
||||||
{
|
{
|
||||||
CertFile: "cert.pem",
|
CertFile: "cert.pem",
|
||||||
|
@ -441,7 +441,7 @@ func init() {
|
||||||
CipherSuites: []string{"foo"},
|
CipherSuites: []string{"foo"},
|
||||||
CurvePreferences: []string{"foo"},
|
CurvePreferences: []string{"foo"},
|
||||||
ClientAuth: traefiktls.ClientAuth{
|
ClientAuth: traefiktls.ClientAuth{
|
||||||
CAFiles: []traefiktls.FileOrContent{"ca.pem"},
|
CAFiles: []types.FileOrContent{"ca.pem"},
|
||||||
ClientAuthType: "RequireAndVerifyClientCert",
|
ClientAuthType: "RequireAndVerifyClientCert",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
|
@ -560,7 +560,7 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||||
|
|
||||||
config.ServersTransport = &static.ServersTransport{
|
config.ServersTransport = &static.ServersTransport{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []traefiktls.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
|
RootCAs: []types.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
|
||||||
MaxIdleConnsPerHost: 111,
|
MaxIdleConnsPerHost: 111,
|
||||||
ForwardingTimeouts: &static.ForwardingTimeouts{
|
ForwardingTimeouts: &static.ForwardingTimeouts{
|
||||||
DialTimeout: ptypes.Duration(111 * time.Second),
|
DialTimeout: ptypes.Duration(111 * time.Second),
|
||||||
|
@ -574,7 +574,7 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||||
DialKeepAlive: ptypes.Duration(111 * time.Second),
|
DialKeepAlive: ptypes.Duration(111 * time.Second),
|
||||||
TLS: &static.TLSClientConfig{
|
TLS: &static.TLSClientConfig{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
RootCAs: []traefiktls.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
|
RootCAs: []types.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/provider"
|
"github.com/traefik/traefik/v3/pkg/provider"
|
||||||
"github.com/traefik/traefik/v3/pkg/safe"
|
"github.com/traefik/traefik/v3/pkg/safe"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigurationWatcher watches configuration changes.
|
// ConfigurationWatcher watches configuration changes.
|
||||||
|
@ -188,7 +189,7 @@ func logConfiguration(logger zerolog.Logger, configMsg dynamic.Message) {
|
||||||
if copyConf.TLS.Options != nil {
|
if copyConf.TLS.Options != nil {
|
||||||
cleanedOptions := make(map[string]tls.Options, len(copyConf.TLS.Options))
|
cleanedOptions := make(map[string]tls.Options, len(copyConf.TLS.Options))
|
||||||
for name, option := range copyConf.TLS.Options {
|
for name, option := range copyConf.TLS.Options {
|
||||||
option.ClientAuth.CAFiles = []tls.FileOrContent{}
|
option.ClientAuth.CAFiles = []types.FileOrContent{}
|
||||||
cleanedOptions[name] = option
|
cleanedOptions[name] = option
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +206,7 @@ func logConfiguration(logger zerolog.Logger, configMsg dynamic.Message) {
|
||||||
if copyConf.HTTP != nil {
|
if copyConf.HTTP != nil {
|
||||||
for _, transport := range copyConf.HTTP.ServersTransports {
|
for _, transport := range copyConf.HTTP.ServersTransports {
|
||||||
transport.Certificates = tls.Certificates{}
|
transport.Certificates = tls.Certificates{}
|
||||||
transport.RootCAs = []tls.FileOrContent{}
|
transport.RootCAs = []types.FileOrContent{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ func logConfiguration(logger zerolog.Logger, configMsg dynamic.Message) {
|
||||||
for _, transport := range copyConf.TCP.ServersTransports {
|
for _, transport := range copyConf.TCP.ServersTransports {
|
||||||
if transport.TLS != nil {
|
if transport.TLS != nil {
|
||||||
transport.TLS.Certificates = tls.Certificates{}
|
transport.TLS.Certificates = tls.Certificates{}
|
||||||
transport.TLS.RootCAs = []tls.FileOrContent{}
|
transport.TLS.RootCAs = []types.FileOrContent{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||||
tcprouter "github.com/traefik/traefik/v3/pkg/server/router/tcp"
|
tcprouter "github.com/traefik/traefik/v3/pkg/server/router/tcp"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||||
|
@ -20,7 +20,7 @@ import (
|
||||||
// generated from src/crypto/tls:
|
// generated from src/crypto/tls:
|
||||||
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||||
var (
|
var (
|
||||||
localhostCert = traefiktls.FileOrContent(`-----BEGIN CERTIFICATE-----
|
localhostCert = types.FileOrContent(`-----BEGIN CERTIFICATE-----
|
||||||
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||||
|
@ -42,7 +42,7 @@ WkBKOclmOV2xlTVuPw==
|
||||||
-----END CERTIFICATE-----`)
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
// LocalhostKey is the private key for localhostCert.
|
// LocalhostKey is the private key for localhostCert.
|
||||||
localhostKey = traefiktls.FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
|
localhostKey = types.FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
||||||
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
||||||
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -185,7 +186,7 @@ func (r *RoundTripperManager) createRoundTripper(cfg *dynamic.ServersTransport)
|
||||||
return newSmartRoundTripper(transport, cfg.ForwardingTimeouts)
|
return newSmartRoundTripper(transport, cfg.ForwardingTimeouts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootCACertPool(rootCAs []traefiktls.FileOrContent) *x509.CertPool {
|
func createRootCACertPool(rootCAs []types.FileOrContent) *x509.CertPool {
|
||||||
if len(rootCAs) == 0 {
|
if len(rootCAs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Int32(i int32) *int32 {
|
func Int32(i int32) *int32 {
|
||||||
|
@ -144,7 +145,7 @@ func TestKeepConnectionWhenSameConfiguration(t *testing.T) {
|
||||||
dynamicConf := map[string]*dynamic.ServersTransport{
|
dynamicConf := map[string]*dynamic.ServersTransport{
|
||||||
"test": {
|
"test": {
|
||||||
ServerName: "example.com",
|
ServerName: "example.com",
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ func TestKeepConnectionWhenSameConfiguration(t *testing.T) {
|
||||||
dynamicConf = map[string]*dynamic.ServersTransport{
|
dynamicConf = map[string]*dynamic.ServersTransport{
|
||||||
"test": {
|
"test": {
|
||||||
ServerName: "www.example.com",
|
ServerName: "www.example.com",
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,13 +214,13 @@ func TestMTLS(t *testing.T) {
|
||||||
"test": {
|
"test": {
|
||||||
ServerName: "example.com",
|
ServerName: "example.com",
|
||||||
// For TLS
|
// For TLS
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
|
|
||||||
// For mTLS
|
// For mTLS
|
||||||
Certificates: traefiktls.Certificates{
|
Certificates: traefiktls.Certificates{
|
||||||
traefiktls.Certificate{
|
traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(mTLSCert),
|
CertFile: types.FileOrContent(mTLSCert),
|
||||||
KeyFile: traefiktls.FileOrContent(mTLSKey),
|
KeyFile: types.FileOrContent(mTLSKey),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ func (d *DialerManager) createDialers(name string, cfg *dynamic.TCPServersTransp
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootCACertPool(rootCAs []traefiktls.FileOrContent) *x509.CertPool {
|
func createRootCACertPool(rootCAs []types.FileOrContent) *x509.CertPool {
|
||||||
if len(rootCAs) == 0 {
|
if len(rootCAs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalhostCert is a PEM-encoded TLS cert
|
// LocalhostCert is a PEM-encoded TLS cert
|
||||||
|
@ -196,7 +197,7 @@ func TestTLS(t *testing.T) {
|
||||||
"test": {
|
"test": {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "example.com",
|
ServerName: "example.com",
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -246,7 +247,7 @@ func TestTLSWithInsecureSkipVerify(t *testing.T) {
|
||||||
"test": {
|
"test": {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "bad-domain.com",
|
ServerName: "bad-domain.com",
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -308,13 +309,13 @@ func TestMTLS(t *testing.T) {
|
||||||
TLS: &dynamic.TLSClientConfig{
|
TLS: &dynamic.TLSClientConfig{
|
||||||
ServerName: "example.com",
|
ServerName: "example.com",
|
||||||
// For TLS
|
// For TLS
|
||||||
RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)},
|
RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)},
|
||||||
|
|
||||||
// For mTLS
|
// For mTLS
|
||||||
Certificates: traefiktls.Certificates{
|
Certificates: traefiktls.Certificates{
|
||||||
traefiktls.Certificate{
|
traefiktls.Certificate{
|
||||||
CertFile: traefiktls.FileOrContent(mTLSCert),
|
CertFile: types.FileOrContent(mTLSCert),
|
||||||
KeyFile: traefiktls.FileOrContent(mTLSKey),
|
KeyFile: types.FileOrContent(mTLSKey),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -48,8 +48,8 @@ var (
|
||||||
// Certificate holds a SSL cert/key pair
|
// Certificate holds a SSL cert/key pair
|
||||||
// Certs and Key could be either a file path, or the file content itself.
|
// Certs and Key could be either a file path, or the file content itself.
|
||||||
type Certificate struct {
|
type Certificate struct {
|
||||||
CertFile FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"`
|
CertFile types.FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"`
|
||||||
KeyFile FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"`
|
KeyFile types.FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificates defines traefik certificates type
|
// Certificates defines traefik certificates type
|
||||||
|
@ -73,33 +73,6 @@ func (c Certificates) GetCertificates() []tls.Certificate {
|
||||||
return certs
|
return certs
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileOrContent hold a file path or content.
|
|
||||||
type FileOrContent string
|
|
||||||
|
|
||||||
func (f FileOrContent) String() string {
|
|
||||||
return string(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPath returns true if the FileOrContent is a file path, otherwise returns false.
|
|
||||||
func (f FileOrContent) IsPath() bool {
|
|
||||||
_, err := os.Stat(f.String())
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FileOrContent) Read() ([]byte, error) {
|
|
||||||
var content []byte
|
|
||||||
if f.IsPath() {
|
|
||||||
var err error
|
|
||||||
content, err = os.ReadFile(f.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content = []byte(f)
|
|
||||||
}
|
|
||||||
return content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendCertificate appends a Certificate to a certificates map keyed by store name.
|
// AppendCertificate appends a Certificate to a certificates map keyed by store name.
|
||||||
func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certificate, storeName string) error {
|
func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certificate, storeName string) error {
|
||||||
certContent, err := c.CertFile.Read()
|
certContent, err := c.CertFile.Read()
|
||||||
|
@ -229,8 +202,8 @@ func (c *Certificates) Set(value string) error {
|
||||||
return fmt.Errorf("bad certificates format: %s", value)
|
return fmt.Errorf("bad certificates format: %s", value)
|
||||||
}
|
}
|
||||||
*c = append(*c, Certificate{
|
*c = append(*c, Certificate{
|
||||||
CertFile: FileOrContent(files[0]),
|
CertFile: types.FileOrContent(files[0]),
|
||||||
KeyFile: FileOrContent(files[1]),
|
KeyFile: types.FileOrContent(files[1]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -8,7 +8,7 @@ const certificateHeader = "-----BEGIN CERTIFICATE-----\n"
|
||||||
|
|
||||||
// ClientAuth defines the parameters of the client authentication part of the TLS connection, if any.
|
// ClientAuth defines the parameters of the client authentication part of the TLS connection, if any.
|
||||||
type ClientAuth struct {
|
type ClientAuth struct {
|
||||||
CAFiles []FileOrContent `json:"caFiles,omitempty" toml:"caFiles,omitempty" yaml:"caFiles,omitempty"`
|
CAFiles []types.FileOrContent `json:"caFiles,omitempty" toml:"caFiles,omitempty" yaml:"caFiles,omitempty"`
|
||||||
// ClientAuthType defines the client authentication type to apply.
|
// ClientAuthType defines the client authentication type to apply.
|
||||||
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
||||||
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty" export:"true"`
|
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty" export:"true"`
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||||
|
@ -16,7 +17,7 @@ import (
|
||||||
// generated from src/crypto/tls:
|
// generated from src/crypto/tls:
|
||||||
// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||||
var (
|
var (
|
||||||
localhostCert = FileOrContent(`-----BEGIN CERTIFICATE-----
|
localhostCert = types.FileOrContent(`-----BEGIN CERTIFICATE-----
|
||||||
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||||
|
@ -38,7 +39,7 @@ WkBKOclmOV2xlTVuPw==
|
||||||
-----END CERTIFICATE-----`)
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
// LocalhostKey is the private key for localhostCert.
|
// LocalhostKey is the private key for localhostCert.
|
||||||
localhostKey = FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
|
localhostKey = types.FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
||||||
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
||||||
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
||||||
|
@ -197,7 +198,7 @@ func TestClientAuth(t *testing.T) {
|
||||||
},
|
},
|
||||||
"vccig": {
|
"vccig": {
|
||||||
ClientAuth: ClientAuth{
|
ClientAuth: ClientAuth{
|
||||||
CAFiles: []FileOrContent{localhostCert},
|
CAFiles: []types.FileOrContent{localhostCert},
|
||||||
ClientAuthType: "VerifyClientCertIfGiven",
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -209,13 +210,13 @@ func TestClientAuth(t *testing.T) {
|
||||||
},
|
},
|
||||||
"ravccwca": {
|
"ravccwca": {
|
||||||
ClientAuth: ClientAuth{
|
ClientAuth: ClientAuth{
|
||||||
CAFiles: []FileOrContent{localhostCert},
|
CAFiles: []types.FileOrContent{localhostCert},
|
||||||
ClientAuthType: "RequireAndVerifyClientCert",
|
ClientAuthType: "RequireAndVerifyClientCert",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ravccwbca": {
|
"ravccwbca": {
|
||||||
ClientAuth: ClientAuth{
|
ClientAuth: ClientAuth{
|
||||||
CAFiles: []FileOrContent{"Bad content"},
|
CAFiles: []types.FileOrContent{"Bad content"},
|
||||||
ClientAuthType: "RequireAndVerifyClientCert",
|
ClientAuthType: "RequireAndVerifyClientCert",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (in *ClientAuth) DeepCopyInto(out *ClientAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.CAFiles != nil {
|
if in.CAFiles != nil {
|
||||||
in, out := &in.CAFiles, &out.CAFiles
|
in, out := &in.CAFiles, &out.CAFiles
|
||||||
*out = make([]FileOrContent, len(*in))
|
*out = make([]types.FileOrContent, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
32
pkg/types/file_or_content.go
Normal file
32
pkg/types/file_or_content.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// FileOrContent holds a file path or content.
|
||||||
|
type FileOrContent string
|
||||||
|
|
||||||
|
// String returns the FileOrContent in string format.
|
||||||
|
func (f FileOrContent) String() string {
|
||||||
|
return string(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPath returns true if the FileOrContent is a file path, otherwise returns false.
|
||||||
|
func (f FileOrContent) IsPath() bool {
|
||||||
|
_, err := os.Stat(f.String())
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read returns the content after reading the FileOrContent variable.
|
||||||
|
func (f FileOrContent) Read() ([]byte, error) {
|
||||||
|
var content []byte
|
||||||
|
if f.IsPath() {
|
||||||
|
var err error
|
||||||
|
content, err = os.ReadFile(f.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content = []byte(f)
|
||||||
|
}
|
||||||
|
return content, nil
|
||||||
|
}
|
Loading…
Reference in a new issue