From 980dac45720229bc8a7a042af5f19dc12c80054c Mon Sep 17 00:00:00 2001 From: Suyash Choudhary <57896905+sssash18@users.noreply.github.com> Date: Thu, 11 Jan 2024 21:36:06 +0530 Subject: [PATCH] Support file path as input param for Kubernetes token value --- cmd/internal/gen/main.go | 4 +- .../reference/static-configuration/cli-ref.md | 6 +- .../reference/static-configuration/env-ref.md | 6 +- integration/https_test.go | 5 +- pkg/config/dynamic/http_config.go | 18 +++--- pkg/config/dynamic/tcp_config.go | 12 ++-- pkg/config/dynamic/zz_generated.deepcopy.go | 4 +- pkg/config/static/static_config.go | 17 +++-- pkg/provider/acme/challenge_tls.go | 4 +- pkg/provider/acme/provider.go | 4 +- pkg/provider/consulcatalog/config_test.go | 9 +-- pkg/provider/consulcatalog/connect_tls.go | 11 ++-- pkg/provider/file/file.go | 29 ++++----- pkg/provider/kubernetes/crd/client.go | 10 ++- pkg/provider/kubernetes/crd/kubernetes.go | 50 +++++++-------- .../kubernetes/crd/kubernetes_test.go | 62 +++++++++---------- pkg/provider/kubernetes/gateway/client.go | 10 ++- pkg/provider/kubernetes/gateway/kubernetes.go | 9 +-- .../kubernetes/gateway/kubernetes_test.go | 53 ++++++++-------- pkg/provider/kubernetes/ingress/client.go | 10 ++- pkg/provider/kubernetes/ingress/kubernetes.go | 29 ++++----- .../kubernetes/ingress/kubernetes_test.go | 12 ++-- pkg/provider/kv/kv_test.go | 28 ++++----- pkg/provider/tailscale/provider.go | 5 +- pkg/redactor/redactor.go | 6 +- pkg/redactor/redactor_config_test.go | 10 +-- pkg/server/configurationwatcher.go | 7 ++- .../server_entrypoint_tcp_http3_test.go | 6 +- pkg/server/service/roundtripper.go | 3 +- pkg/server/service/roundtripper_test.go | 11 ++-- pkg/tcp/dialer.go | 3 +- pkg/tcp/dialer_test.go | 11 ++-- pkg/tls/certificate.go | 37 ++--------- pkg/tls/tls.go | 2 +- pkg/tls/tlsmanager_test.go | 11 ++-- pkg/tls/zz_generated.deepcopy.go | 2 +- pkg/types/file_or_content.go | 32 ++++++++++ 37 files changed, 292 insertions(+), 256 deletions(-) create mode 100644 pkg/types/file_or_content.go diff --git a/cmd/internal/gen/main.go b/cmd/internal/gen/main.go index f5fd5bb35..a85544688 100644 --- a/cmd/internal/gen/main.go +++ b/cmd/internal/gen/main.go @@ -87,11 +87,11 @@ func run(dest string) error { } 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" } - if typ.String() == "[]github.com/traefik/traefik/v3/pkg/tls.FileOrContent" { + if typ.String() == "[]github.com/traefik/traefik/v3/pkg/types.FileOrContent" { return "[]string" } diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index efb874437..aabed9139 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -691,7 +691,7 @@ Kubernetes namespaces. Ingress refresh throttle duration (Default: ```0```) `--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`: Enable Kubernetes gateway api provider with default settings. (Default: ```false```) @@ -712,7 +712,7 @@ Kubernetes namespaces. Kubernetes refresh throttle duration (Default: ```0```) `--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`: Enable Kubernetes backend with default settings. (Default: ```false```) @@ -754,7 +754,7 @@ Kubernetes namespaces. Ingress refresh throttle duration (Default: ```0```) `--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`: Enable Nomad backend with default settings. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index 10659e2e1..892fb2369 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -691,7 +691,7 @@ Kubernetes namespaces. Ingress refresh throttle duration (Default: ```0```) `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`: Enable Kubernetes gateway api provider with default settings. (Default: ```false```) @@ -712,7 +712,7 @@ Kubernetes namespaces. Kubernetes refresh throttle duration (Default: ```0```) `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`: Enable Kubernetes backend with default settings. (Default: ```false```) @@ -754,7 +754,7 @@ Kubernetes namespaces. Ingress refresh throttle duration (Default: ```0```) `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`: Enable Nomad backend with default settings. (Default: ```false```) diff --git a/integration/https_test.go b/integration/https_test.go index 5d7aa85d7..e4a68dfb8 100644 --- a/integration/https_test.go +++ b/integration/https_test.go @@ -18,6 +18,7 @@ import ( "github.com/traefik/traefik/v3/integration/try" "github.com/traefik/traefik/v3/pkg/config/dynamic" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) // HTTPSSuite tests suite. @@ -891,8 +892,8 @@ func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName Certificates: []*traefiktls.CertAndStores{ { Certificate: traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"), - KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"), + CertFile: types.FileOrContent("fixtures/https/" + certFileName + ".cert"), + KeyFile: types.FileOrContent("fixtures/https/" + certFileName + ".key"), }, }, }, diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go index 162ebc3d4..0c31c8871 100644 --- a/pkg/config/dynamic/http_config.go +++ b/pkg/config/dynamic/http_config.go @@ -265,15 +265,15 @@ type HealthCheck struct{} // ServersTransport options to configure communication between Traefik and the servers. type ServersTransport struct { - 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"` - 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"` - 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"` - ForwardingTimeouts *ForwardingTimeouts `description:"Defines the timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"` - DisableHTTP2 bool `description:"Disables HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,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 configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + 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"` + 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"` + 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"` + DisableHTTP2 bool `description:"Disables HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,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 configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } // +k8s:deepcopy-gen=true diff --git a/pkg/config/dynamic/tcp_config.go b/pkg/config/dynamic/tcp_config.go index 7789c5169..adedd0882 100644 --- a/pkg/config/dynamic/tcp_config.go +++ b/pkg/config/dynamic/tcp_config.go @@ -138,12 +138,12 @@ type TCPServersTransport struct { // TLSClientConfig options to configure TLS communication between Traefik and the servers. type TLSClientConfig struct { - 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"` - 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"` - 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"` - Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + 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"` + 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"` + 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"` } // SetDefaults sets the default values for a TCPServersTransport. diff --git a/pkg/config/dynamic/zz_generated.deepcopy.go b/pkg/config/dynamic/zz_generated.deepcopy.go index 2f2a11e2e..0a4e70d45 100644 --- a/pkg/config/dynamic/zz_generated.deepcopy.go +++ b/pkg/config/dynamic/zz_generated.deepcopy.go @@ -1205,7 +1205,7 @@ func (in *ServersTransport) DeepCopyInto(out *ServersTransport) { *out = *in if in.RootCAs != nil { in, out := &in.RootCAs, &out.RootCAs - *out = make([]tls.FileOrContent, len(*in)) + *out = make([]types.FileOrContent, len(*in)) copy(*out, *in) } if in.Certificates != nil { @@ -1769,7 +1769,7 @@ func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) { *out = *in if in.RootCAs != nil { in, out := &in.RootCAs, &out.RootCAs - *out = make([]tls.FileOrContent, len(*in)) + *out = make([]types.FileOrContent, len(*in)) copy(*out, *in) } if in.Certificates != nil { diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 1c141a5a8..9f0ce294f 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -27,7 +27,6 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/kv/zk" "github.com/traefik/traefik/v3/pkg/provider/nomad" "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/types" ) @@ -96,11 +95,11 @@ type Global struct { // ServersTransport options to configure communication between Traefik and the servers. type ServersTransport struct { - 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"` - 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"` - Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"` + 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"` + ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"` + Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } // Spiffe holds the SPIFFE configuration. @@ -124,9 +123,9 @@ type TCPServersTransport struct { // TLSClientConfig options to configure TLS communication between Traefik and the servers. type TLSClientConfig struct { - 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"` - Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"` + 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"` } // API holds the API configuration. diff --git a/pkg/provider/acme/challenge_tls.go b/pkg/provider/acme/challenge_tls.go index b4ce624d5..4de4f0916 100644 --- a/pkg/provider/acme/challenge_tls.go +++ b/pkg/provider/acme/challenge_tls.go @@ -152,8 +152,8 @@ func createMessage(certs map[string]*Certificate) dynamic.Message { for _, cert := range certs { certConf := &traefiktls.CertAndStores{ Certificate: traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(cert.Certificate), - KeyFile: traefiktls.FileOrContent(cert.Key), + CertFile: types.FileOrContent(cert.Certificate), + KeyFile: types.FileOrContent(cert.Key), }, Stores: []string{tlsalpn01.ACMETLS1Protocol}, } diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index 2032e8af4..12d5a0b6d 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -783,8 +783,8 @@ func (p *Provider) buildMessage() dynamic.Message { for _, cert := range p.certificates { certConf := &traefiktls.CertAndStores{ Certificate: traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(cert.Certificate.Certificate), - KeyFile: traefiktls.FileOrContent(cert.Key), + CertFile: types.FileOrContent(cert.Certificate.Certificate), + KeyFile: types.FileOrContent(cert.Key), }, Stores: []string{cert.Store}, } diff --git a/pkg/provider/consulcatalog/config_test.go b/pkg/provider/consulcatalog/config_test.go index c15908d96..5370a75ca 100644 --- a/pkg/provider/consulcatalog/config_test.go +++ b/pkg/provider/consulcatalog/config_test.go @@ -12,6 +12,7 @@ import ( ptypes "github.com/traefik/paerser/types" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) func Int(v int) *int { return &v } @@ -428,7 +429,7 @@ func Test_buildConfiguration(t *testing.T) { "tls-ns-dc1-dev-Test": { ServerName: "ns-dc1-dev/Test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{ + RootCAs: []types.FileOrContent{ "root", }, Certificates: []tls.Certificate{ @@ -519,7 +520,7 @@ func Test_buildConfiguration(t *testing.T) { "tls-ns-dc1-dev-Test": { ServerName: "ns-dc1-dev/Test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{ + RootCAs: []types.FileOrContent{ "root", }, Certificates: []tls.Certificate{ @@ -2280,7 +2281,7 @@ func Test_buildConfiguration(t *testing.T) { TLS: &dynamic.TLSClientConfig{ ServerName: "ns-dc1-Test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{ + RootCAs: []types.FileOrContent{ "root", }, Certificates: []tls.Certificate{ @@ -2899,7 +2900,7 @@ func Test_buildConfiguration(t *testing.T) { "tls-ns-dc1-Test": { ServerName: "ns-dc1-Test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{ + RootCAs: []types.FileOrContent{ "root", }, Certificates: []tls.Certificate{ diff --git a/pkg/provider/consulcatalog/connect_tls.go b/pkg/provider/consulcatalog/connect_tls.go index 55e49fd06..b73acb1a1 100644 --- a/pkg/provider/consulcatalog/connect_tls.go +++ b/pkg/provider/consulcatalog/connect_tls.go @@ -5,6 +5,7 @@ import ( "github.com/traefik/traefik/v3/pkg/config/dynamic" 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. @@ -13,18 +14,18 @@ type connectCert struct { leaf keyPair } -func (c *connectCert) getRoot() []traefiktls.FileOrContent { - var result []traefiktls.FileOrContent +func (c *connectCert) getRoot() []types.FileOrContent { + var result []types.FileOrContent for _, r := range c.root { - result = append(result, traefiktls.FileOrContent(r)) + result = append(result, types.FileOrContent(r)) } return result } func (c *connectCert) getLeaf() traefiktls.Certificate { return traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(c.leaf.cert), - KeyFile: traefiktls.FileOrContent(c.leaf.key), + CertFile: types.FileOrContent(c.leaf.cert), + KeyFile: types.FileOrContent(c.leaf.key), } } diff --git a/pkg/provider/file/file.go b/pkg/provider/file/file.go index 7ba814c88..ad19f573e 100644 --- a/pkg/provider/file/file.go +++ b/pkg/provider/file/file.go @@ -19,6 +19,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) const providerName = "file" @@ -180,7 +181,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem // TLS Options if configuration.TLS.Options != nil { for name, options := range configuration.TLS.Options { - var caCerts []tls.FileOrContent + var caCerts []types.FileOrContent for _, caFile := range options.ClientAuth.CAFiles { content, err := caFile.Read() @@ -189,7 +190,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem continue } - caCerts = append(caCerts, tls.FileOrContent(content)) + caCerts = append(caCerts, types.FileOrContent(content)) } 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() continue } - store.DefaultCertificate.CertFile = tls.FileOrContent(content) + store.DefaultCertificate.CertFile = types.FileOrContent(content) content, err = store.DefaultCertificate.KeyFile.Read() if err != nil { log.Ctx(ctx).Error().Err(err).Send() continue } - store.DefaultCertificate.KeyFile = tls.FileOrContent(content) + store.DefaultCertificate.KeyFile = types.FileOrContent(content) 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() continue } - cert.CertFile = tls.FileOrContent(content) + cert.CertFile = types.FileOrContent(content) content, err = cert.KeyFile.Read() if err != nil { log.Ctx(ctx).Error().Err(err).Send() continue } - cert.KeyFile = tls.FileOrContent(content) + cert.KeyFile = types.FileOrContent(content) certificates = append(certificates, cert) } configuration.HTTP.ServersTransports[name].Certificates = certificates - var rootCAs []tls.FileOrContent + var rootCAs []types.FileOrContent for _, rootCA := range st.RootCAs { content, err := rootCA.Read() if err != nil { @@ -255,7 +256,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem continue } - rootCAs = append(rootCAs, tls.FileOrContent(content)) + rootCAs = append(rootCAs, types.FileOrContent(content)) } st.RootCAs = rootCAs @@ -275,21 +276,21 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem log.Ctx(ctx).Error().Err(err).Send() continue } - cert.CertFile = tls.FileOrContent(content) + cert.CertFile = types.FileOrContent(content) content, err = cert.KeyFile.Read() if err != nil { log.Ctx(ctx).Error().Err(err).Send() continue } - cert.KeyFile = tls.FileOrContent(content) + cert.KeyFile = types.FileOrContent(content) certificates = append(certificates, cert) } configuration.TCP.ServersTransports[name].TLS.Certificates = certificates - var rootCAs []tls.FileOrContent + var rootCAs []types.FileOrContent for _, rootCA := range st.TLS.RootCAs { content, err := rootCA.Read() if err != nil { @@ -297,7 +298,7 @@ func (p *Provider) loadFileConfig(ctx context.Context, filename string, parseTem continue } - rootCAs = append(rootCAs, tls.FileOrContent(content)) + rootCAs = append(rootCAs, types.FileOrContent(content)) } st.TLS.RootCAs = rootCAs @@ -315,14 +316,14 @@ func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguratio log.Ctx(ctx).Error().Err(err).Send() continue } - cert.Certificate.CertFile = tls.FileOrContent(string(content)) + cert.Certificate.CertFile = types.FileOrContent(string(content)) content, err = cert.Certificate.KeyFile.Read() if err != nil { log.Ctx(ctx).Error().Err(err).Send() continue } - cert.Certificate.KeyFile = tls.FileOrContent(string(content)) + cert.Certificate.KeyFile = types.FileOrContent(string(content)) certs = append(certs, cert) } diff --git a/pkg/provider/kubernetes/crd/client.go b/pkg/provider/kubernetes/crd/client.go index d52588536..83c4834ba 100644 --- a/pkg/provider/kubernetes/crd/client.go +++ b/pkg/provider/kubernetes/crd/client.go @@ -13,6 +13,7 @@ import ( 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" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" + "github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/version" corev1 "k8s.io/api/core/v1" 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 // of the cluster. // 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 == "" { 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{ Host: endpoint, - BearerToken: token, + BearerToken: string(tokenData), } if caFilePath != "" { diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 9922ed989..1f7ec671f 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -48,16 +48,16 @@ const ( // Provider holds configurations of the provider. type Provider struct { - 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"` - 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"` - AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"` - AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"` - LabelSelector string `description:"Kubernetes label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"` - IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"` - ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"` - AllowEmptyServices bool `description:"Allow the creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"` + Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"` + 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"` + 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"` + AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"` + LabelSelector string `description:"Kubernetes label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"` + IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"` + ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"` + AllowEmptyServices bool `description:"Allow the creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"` lastConfiguration safe.Safe @@ -101,7 +101,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) { client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG")) default: 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 { @@ -339,7 +339,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) for _, serversTransport := range client.GetServersTransports() { 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 { caSecret, err := loadCASecret(serversTransport.Namespace, secret, client) if err != nil { @@ -347,7 +347,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) continue } - rootCAs = append(rootCAs, tls.FileOrContent(caSecret)) + rootCAs = append(rootCAs, types.FileOrContent(caSecret)) } var certs tls.Certificates @@ -359,8 +359,8 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) } certs = append(certs, tls.Certificate{ - CertFile: tls.FileOrContent(tlsSecret), - KeyFile: tls.FileOrContent(tlsKey), + CertFile: types.FileOrContent(tlsSecret), + KeyFile: types.FileOrContent(tlsKey), }) } @@ -446,7 +446,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) } if serversTransportTCP.Spec.TLS != nil { - var rootCAs []tls.FileOrContent + var rootCAs []types.FileOrContent for _, secret := range serversTransportTCP.Spec.TLS.RootCAsSecrets { caSecret, err := loadCASecret(serversTransportTCP.Namespace, secret, client) if err != nil { @@ -457,7 +457,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) continue } - rootCAs = append(rootCAs, tls.FileOrContent(caSecret)) + rootCAs = append(rootCAs, types.FileOrContent(caSecret)) } var certs tls.Certificates @@ -472,8 +472,8 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) } certs = append(certs, tls.Certificate{ - CertFile: tls.FileOrContent(tlsCert), - KeyFile: tls.FileOrContent(tlsKey), + CertFile: types.FileOrContent(tlsCert), + KeyFile: types.FileOrContent(tlsKey), }) } @@ -963,7 +963,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options for _, tlsOption := range tlsOptionsCRD { 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 { secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName) @@ -983,7 +983,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options continue } - clientCAs = append(clientCAs, tls.FileOrContent(cert)) + clientCAs = append(clientCAs, types.FileOrContent(cert)) } 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{ - CertFile: tls.FileOrContent(cert), - KeyFile: tls.FileOrContent(key), + CertFile: types.FileOrContent(cert), + KeyFile: types.FileOrContent(key), } } @@ -1149,8 +1149,8 @@ func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores, return &tls.CertAndStores{ Certificate: tls.Certificate{ - CertFile: tls.FileOrContent(cert), - KeyFile: tls.FileOrContent(key), + CertFile: types.FileOrContent(cert), + KeyFile: types.FileOrContent(key), }, }, nil } diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index ca833c2ee..a6d2c64ca 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -571,8 +571,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + 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", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -741,9 +741,9 @@ func TestLoadIngressRouteTCPs(t *testing.T) { "TLS_RSA_WITH_AES_256_GCM_SHA384", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -809,8 +809,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) { "TLS_RSA_WITH_AES_256_GCM_SHA384", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -1064,8 +1064,8 @@ func TestLoadIngressRouteTCPs(t *testing.T) { Stores: map[string]tls.Store{ "default": { DefaultCertificate: &tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -1405,7 +1405,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) { TLS: &dynamic.TLSClientConfig{ ServerName: "test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"}, + RootCAs: []types.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"}, Certificates: tls.Certificates{ {CertFile: "TESTCERT1", KeyFile: "TESTKEY1"}, {CertFile: "TESTCERT2", KeyFile: "TESTKEY2"}, @@ -2917,8 +2917,8 @@ func TestLoadIngressRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + 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", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -3100,9 +3100,9 @@ func TestLoadIngressRoutes(t *testing.T) { "TLS_RSA_WITH_AES_256_GCM_SHA384", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -3178,9 +3178,9 @@ func TestLoadIngressRoutes(t *testing.T) { "TLS_RSA_WITH_AES_256_GCM_SHA384", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -3251,8 +3251,8 @@ func TestLoadIngressRoutes(t *testing.T) { "TLS_RSA_WITH_AES_256_GCM_SHA384", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), }, ClientAuthType: "VerifyClientCertIfGiven", }, @@ -3881,8 +3881,8 @@ func TestLoadIngressRoutes(t *testing.T) { Stores: map[string]tls.Store{ "default": { DefaultCertificate: &tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -3938,8 +3938,8 @@ func TestLoadIngressRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, Stores: []string{"default"}, }, @@ -4215,7 +4215,7 @@ func TestLoadIngressRoutes(t *testing.T) { "foo-test": { ServerName: "test", InsecureSkipVerify: true, - RootCAs: []tls.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"}, + RootCAs: []types.FileOrContent{"TESTROOTCAS0", "TESTROOTCAS1", "TESTROOTCAS2", "TESTROOTCAS3", "TESTROOTCAS5", "TESTALLCERTS"}, Certificates: tls.Certificates{ {CertFile: "TESTCERT1", KeyFile: "TESTKEY1"}, {CertFile: "TESTCERT2", KeyFile: "TESTKEY2"}, diff --git a/pkg/provider/kubernetes/gateway/client.go b/pkg/provider/kubernetes/gateway/client.go index ce4e02588..709be079d 100644 --- a/pkg/provider/kubernetes/gateway/client.go +++ b/pkg/provider/kubernetes/gateway/client.go @@ -8,6 +8,7 @@ import ( "time" "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v3/pkg/types" corev1 "k8s.io/api/core/v1" kerror "k8s.io/apimachinery/pkg/api/errors" 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. // 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 == "" { 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{ Host: endpoint, - BearerToken: token, + BearerToken: string(tokenData), } if caFilePath != "" { diff --git a/pkg/provider/kubernetes/gateway/kubernetes.go b/pkg/provider/kubernetes/gateway/kubernetes.go index 2379b2cfa..c86467b0f 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes.go +++ b/pkg/provider/kubernetes/gateway/kubernetes.go @@ -27,6 +27,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -48,7 +49,7 @@ const ( // Provider holds configurations of the provider. type Provider struct { 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"` 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"` @@ -101,7 +102,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) { client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG")) default: 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 { @@ -1428,8 +1429,8 @@ func getTLS(k8sClient Client, secretName gatev1.ObjectName, namespace string) (* return &tls.CertAndStores{ Certificate: tls.Certificate{ - CertFile: tls.FileOrContent(cert), - KeyFile: tls.FileOrContent(key), + CertFile: types.FileOrContent(cert), + KeyFile: types.FileOrContent(key), }, }, nil } diff --git a/pkg/provider/kubernetes/gateway/kubernetes_test.go b/pkg/provider/kubernetes/gateway/kubernetes_test.go index 1238576d2..7c747a270 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes_test.go +++ b/pkg/provider/kubernetes/gateway/kubernetes_test.go @@ -11,6 +11,7 @@ import ( "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/provider" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" gatev1 "sigs.k8s.io/gateway-api/apis/v1" @@ -492,8 +493,8 @@ func TestLoadHTTPRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -741,8 +742,8 @@ func TestLoadHTTPRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -1176,8 +1177,8 @@ func TestLoadHTTPRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -1265,8 +1266,8 @@ func TestLoadHTTPRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -2240,8 +2241,8 @@ func TestLoadTCPRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -2735,8 +2736,8 @@ func TestLoadTLSRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -2947,8 +2948,8 @@ func TestLoadTLSRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -3016,8 +3017,8 @@ func TestLoadTLSRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -3823,8 +3824,8 @@ func TestLoadMixedRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -4002,8 +4003,8 @@ func TestLoadMixedRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -4243,8 +4244,8 @@ func TestLoadMixedRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -4394,8 +4395,8 @@ func TestLoadMixedRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -4526,8 +4527,8 @@ func TestLoadMixedRoutes(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, diff --git a/pkg/provider/kubernetes/ingress/client.go b/pkg/provider/kubernetes/ingress/client.go index 8bbdbc637..c29f3c6b3 100644 --- a/pkg/provider/kubernetes/ingress/client.go +++ b/pkg/provider/kubernetes/ingress/client.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/go-version" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" + "github.com/traefik/traefik/v3/pkg/types" traefikversion "github.com/traefik/traefik/v3/pkg/version" corev1 "k8s.io/api/core/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 // of the cluster. // 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 == "" { 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{ Host: endpoint, - BearerToken: token, + BearerToken: string(tokenData), } if caFilePath != "" { diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index 9bd582feb..8ccbf4f58 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -25,6 +25,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/labels" @@ -39,17 +40,17 @@ const ( // Provider holds configurations of the provider. type Provider struct { - 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"` - 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"` - LabelSelector string `description:"Kubernetes Ingress label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"` - IngressClass string `description:"Value of kubernetes.io/ingress.class annotation or IngressClass name to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"` - IngressEndpoint *EndpointIngress `description:"Kubernetes Ingress Endpoint." json:"ingressEndpoint,omitempty" toml:"ingressEndpoint,omitempty" yaml:"ingressEndpoint,omitempty" export:"true"` - ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"` - AllowEmptyServices bool `description:"Allow creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"` - AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"` - DisableIngressClassLookup bool `description:"Disables the lookup of IngressClasses." json:"disableIngressClassLookup,omitempty" toml:"disableIngressClassLookup,omitempty" yaml:"disableIngressClassLookup,omitempty" export:"true"` + Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"` + 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"` + 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"` + IngressClass string `description:"Value of kubernetes.io/ingress.class annotation or IngressClass name to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"` + IngressEndpoint *EndpointIngress `description:"Kubernetes Ingress Endpoint." json:"ingressEndpoint,omitempty" toml:"ingressEndpoint,omitempty" yaml:"ingressEndpoint,omitempty" export:"true"` + ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"` + AllowEmptyServices bool `description:"Allow creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"` + AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"` + DisableIngressClassLookup bool `description:"Disables the lookup of IngressClasses." json:"disableIngressClassLookup,omitempty" toml:"disableIngressClassLookup,omitempty" yaml:"disableIngressClassLookup,omitempty" export:"true"` lastConfiguration safe.Safe @@ -103,7 +104,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) { cl, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG")) default: 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 { @@ -463,8 +464,8 @@ func getCertificates(ctx context.Context, ingress *netv1.Ingress, k8sClient Clie tlsConfigs[configKey] = &tls.CertAndStores{ Certificate: tls.Certificate{ - CertFile: tls.FileOrContent(cert), - KeyFile: tls.FileOrContent(key), + CertFile: types.FileOrContent(cert), + KeyFile: types.FileOrContent(key), }, } } diff --git a/pkg/provider/kubernetes/ingress/kubernetes_test.go b/pkg/provider/kubernetes/ingress/kubernetes_test.go index e044cf577..cffccbbcb 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes_test.go +++ b/pkg/provider/kubernetes/ingress/kubernetes_test.go @@ -877,8 +877,8 @@ func TestLoadConfigurationFromIngresses(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), - KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"), + KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), }, }, }, @@ -1834,14 +1834,14 @@ func TestGetCertificates(t *testing.T) { result: map[string]*tls.CertAndStores{ "testing-test-secret": { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("tls-crt"), - KeyFile: tls.FileOrContent("tls-key"), + CertFile: types.FileOrContent("tls-crt"), + KeyFile: types.FileOrContent("tls-key"), }, }, "testing-test-secret2": { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("tls-crt"), - KeyFile: tls.FileOrContent("tls-key"), + CertFile: types.FileOrContent("tls-crt"), + KeyFile: types.FileOrContent("tls-key"), }, }, }, diff --git a/pkg/provider/kv/kv_test.go b/pkg/provider/kv/kv_test.go index 8ba2cde99..cfe901037 100644 --- a/pkg/provider/kv/kv_test.go +++ b/pkg/provider/kv/kv_test.go @@ -811,8 +811,8 @@ func Test_buildConfiguration(t *testing.T) { Certificates: []*tls.CertAndStores{ { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("foobar"), - KeyFile: tls.FileOrContent("foobar"), + CertFile: types.FileOrContent("foobar"), + KeyFile: types.FileOrContent("foobar"), }, Stores: []string{ "foobar", @@ -821,8 +821,8 @@ func Test_buildConfiguration(t *testing.T) { }, { Certificate: tls.Certificate{ - CertFile: tls.FileOrContent("foobar"), - KeyFile: tls.FileOrContent("foobar"), + CertFile: types.FileOrContent("foobar"), + KeyFile: types.FileOrContent("foobar"), }, Stores: []string{ "foobar", @@ -843,9 +843,9 @@ func Test_buildConfiguration(t *testing.T) { "foobar", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("foobar"), - tls.FileOrContent("foobar"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("foobar"), + types.FileOrContent("foobar"), }, ClientAuthType: "foobar", }, @@ -868,9 +868,9 @@ func Test_buildConfiguration(t *testing.T) { "foobar", }, ClientAuth: tls.ClientAuth{ - CAFiles: []tls.FileOrContent{ - tls.FileOrContent("foobar"), - tls.FileOrContent("foobar"), + CAFiles: []types.FileOrContent{ + types.FileOrContent("foobar"), + types.FileOrContent("foobar"), }, ClientAuthType: "foobar", }, @@ -885,14 +885,14 @@ func Test_buildConfiguration(t *testing.T) { Stores: map[string]tls.Store{ "Store0": { DefaultCertificate: &tls.Certificate{ - CertFile: tls.FileOrContent("foobar"), - KeyFile: tls.FileOrContent("foobar"), + CertFile: types.FileOrContent("foobar"), + KeyFile: types.FileOrContent("foobar"), }, }, "Store1": { DefaultCertificate: &tls.Certificate{ - CertFile: tls.FileOrContent("foobar"), - KeyFile: tls.FileOrContent("foobar"), + CertFile: types.FileOrContent("foobar"), + KeyFile: types.FileOrContent("foobar"), }, }, }, diff --git a/pkg/provider/tailscale/provider.go b/pkg/provider/tailscale/provider.go index b0b439b86..8e795e5be 100644 --- a/pkg/provider/tailscale/provider.go +++ b/pkg/provider/tailscale/provider.go @@ -17,6 +17,7 @@ import ( "github.com/traefik/traefik/v3/pkg/muxer/tcp" "github.com/traefik/traefik/v3/pkg/safe" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) // 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.certByDomain[domain] = traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(cert), - KeyFile: traefiktls.FileOrContent(key), + CertFile: types.FileOrContent(cert), + KeyFile: types.FileOrContent(key), } p.certByDomainMu.Unlock() } diff --git a/pkg/redactor/redactor.go b/pkg/redactor/redactor.go index 45be897a1..6761d9eb9 100644 --- a/pkg/redactor/redactor.go +++ b/pkg/redactor/redactor.go @@ -7,7 +7,7 @@ import ( "github.com/mitchellh/copystructure" "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" ) @@ -164,8 +164,8 @@ func reset(field reflect.Value, name string) error { } case reflect.String: if field.String() != "" { - if field.Type().AssignableTo(reflect.TypeOf(tls.FileOrContent(""))) { - field.Set(reflect.ValueOf(tls.FileOrContent(maskShort))) + if field.Type().AssignableTo(reflect.TypeOf(types.FileOrContent(""))) { + field.Set(reflect.ValueOf(types.FileOrContent(maskShort))) } else { field.Set(reflect.ValueOf(maskShort)) } diff --git a/pkg/redactor/redactor_config_test.go b/pkg/redactor/redactor_config_test.go index 0a6b174e9..c3ef9ef9d 100644 --- a/pkg/redactor/redactor_config_test.go +++ b/pkg/redactor/redactor_config_test.go @@ -130,7 +130,7 @@ func init() { "foo": { ServerName: "foo", InsecureSkipVerify: true, - RootCAs: []traefiktls.FileOrContent{"rootca.pem"}, + RootCAs: []types.FileOrContent{"rootca.pem"}, Certificates: []traefiktls.Certificate{ { CertFile: "cert.pem", @@ -390,7 +390,7 @@ func init() { TLS: &dynamic.TLSClientConfig{ ServerName: "foo", InsecureSkipVerify: true, - RootCAs: []traefiktls.FileOrContent{"rootca.pem"}, + RootCAs: []types.FileOrContent{"rootca.pem"}, Certificates: []traefiktls.Certificate{ { CertFile: "cert.pem", @@ -441,7 +441,7 @@ func init() { CipherSuites: []string{"foo"}, CurvePreferences: []string{"foo"}, ClientAuth: traefiktls.ClientAuth{ - CAFiles: []traefiktls.FileOrContent{"ca.pem"}, + CAFiles: []types.FileOrContent{"ca.pem"}, ClientAuthType: "RequireAndVerifyClientCert", }, SniStrict: true, @@ -560,7 +560,7 @@ func TestDo_staticConfiguration(t *testing.T) { config.ServersTransport = &static.ServersTransport{ InsecureSkipVerify: true, - RootCAs: []traefiktls.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"}, + RootCAs: []types.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"}, MaxIdleConnsPerHost: 111, ForwardingTimeouts: &static.ForwardingTimeouts{ DialTimeout: ptypes.Duration(111 * time.Second), @@ -574,7 +574,7 @@ func TestDo_staticConfiguration(t *testing.T) { DialKeepAlive: ptypes.Duration(111 * time.Second), TLS: &static.TLSClientConfig{ InsecureSkipVerify: true, - RootCAs: []traefiktls.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"}, + RootCAs: []types.FileOrContent{"RootCAs 1", "RootCAs 2", "RootCAs 3"}, }, } diff --git a/pkg/server/configurationwatcher.go b/pkg/server/configurationwatcher.go index da2d66f17..5071f2498 100644 --- a/pkg/server/configurationwatcher.go +++ b/pkg/server/configurationwatcher.go @@ -12,6 +12,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) // ConfigurationWatcher watches configuration changes. @@ -188,7 +189,7 @@ func logConfiguration(logger zerolog.Logger, configMsg dynamic.Message) { if copyConf.TLS.Options != nil { cleanedOptions := make(map[string]tls.Options, len(copyConf.TLS.Options)) for name, option := range copyConf.TLS.Options { - option.ClientAuth.CAFiles = []tls.FileOrContent{} + option.ClientAuth.CAFiles = []types.FileOrContent{} cleanedOptions[name] = option } @@ -205,7 +206,7 @@ func logConfiguration(logger zerolog.Logger, configMsg dynamic.Message) { if copyConf.HTTP != nil { for _, transport := range copyConf.HTTP.ServersTransports { 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 { if transport.TLS != nil { transport.TLS.Certificates = tls.Certificates{} - transport.TLS.RootCAs = []tls.FileOrContent{} + transport.TLS.RootCAs = []types.FileOrContent{} } } } diff --git a/pkg/server/server_entrypoint_tcp_http3_test.go b/pkg/server/server_entrypoint_tcp_http3_test.go index 9b440be4b..66aa48ce4 100644 --- a/pkg/server/server_entrypoint_tcp_http3_test.go +++ b/pkg/server/server_entrypoint_tcp_http3_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/traefik/traefik/v3/pkg/config/static" 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 @@ -20,7 +20,7 @@ import ( // 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 var ( - localhostCert = traefiktls.FileOrContent(`-----BEGIN CERTIFICATE----- + localhostCert = types.FileOrContent(`-----BEGIN CERTIFICATE----- MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A @@ -42,7 +42,7 @@ WkBKOclmOV2xlTVuPw== -----END CERTIFICATE-----`) // LocalhostKey is the private key for localhostCert. - localhostKey = traefiktls.FileOrContent(`-----BEGIN RSA PRIVATE KEY----- + localhostKey = types.FileOrContent(`-----BEGIN RSA PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi 4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW diff --git a/pkg/server/service/roundtripper.go b/pkg/server/service/roundtripper.go index d7ab54c7a..7b7786a07 100644 --- a/pkg/server/service/roundtripper.go +++ b/pkg/server/service/roundtripper.go @@ -18,6 +18,7 @@ import ( "github.com/spiffe/go-spiffe/v2/svid/x509svid" "github.com/traefik/traefik/v3/pkg/config/dynamic" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" "golang.org/x/net/http2" ) @@ -185,7 +186,7 @@ func (r *RoundTripperManager) createRoundTripper(cfg *dynamic.ServersTransport) return newSmartRoundTripper(transport, cfg.ForwardingTimeouts) } -func createRootCACertPool(rootCAs []traefiktls.FileOrContent) *x509.CertPool { +func createRootCACertPool(rootCAs []types.FileOrContent) *x509.CertPool { if len(rootCAs) == 0 { return nil } diff --git a/pkg/server/service/roundtripper_test.go b/pkg/server/service/roundtripper_test.go index c9af07a17..2d7763888 100644 --- a/pkg/server/service/roundtripper_test.go +++ b/pkg/server/service/roundtripper_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/require" "github.com/traefik/traefik/v3/pkg/config/dynamic" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) func Int32(i int32) *int32 { @@ -144,7 +145,7 @@ func TestKeepConnectionWhenSameConfiguration(t *testing.T) { dynamicConf := map[string]*dynamic.ServersTransport{ "test": { 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{ "test": { 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": { ServerName: "example.com", // For TLS - RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)}, + RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)}, // For mTLS Certificates: traefiktls.Certificates{ traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(mTLSCert), - KeyFile: traefiktls.FileOrContent(mTLSKey), + CertFile: types.FileOrContent(mTLSCert), + KeyFile: types.FileOrContent(mTLSKey), }, }, }, diff --git a/pkg/tcp/dialer.go b/pkg/tcp/dialer.go index 267d1b05b..ca08f7d2e 100644 --- a/pkg/tcp/dialer.go +++ b/pkg/tcp/dialer.go @@ -16,6 +16,7 @@ import ( "github.com/spiffe/go-spiffe/v2/svid/x509svid" "github.com/traefik/traefik/v3/pkg/config/dynamic" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" "golang.org/x/net/proxy" ) @@ -156,7 +157,7 @@ func (d *DialerManager) createDialers(name string, cfg *dynamic.TCPServersTransp return nil } -func createRootCACertPool(rootCAs []traefiktls.FileOrContent) *x509.CertPool { +func createRootCACertPool(rootCAs []types.FileOrContent) *x509.CertPool { if len(rootCAs) == 0 { return nil } diff --git a/pkg/tcp/dialer_test.go b/pkg/tcp/dialer_test.go index 603f012b5..2dad7bf38 100644 --- a/pkg/tcp/dialer_test.go +++ b/pkg/tcp/dialer_test.go @@ -22,6 +22,7 @@ import ( "github.com/stretchr/testify/require" "github.com/traefik/traefik/v3/pkg/config/dynamic" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/types" ) // LocalhostCert is a PEM-encoded TLS cert @@ -196,7 +197,7 @@ func TestTLS(t *testing.T) { "test": { TLS: &dynamic.TLSClientConfig{ 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": { TLS: &dynamic.TLSClientConfig{ ServerName: "bad-domain.com", - RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)}, + RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)}, InsecureSkipVerify: true, }, }, @@ -308,13 +309,13 @@ func TestMTLS(t *testing.T) { TLS: &dynamic.TLSClientConfig{ ServerName: "example.com", // For TLS - RootCAs: []traefiktls.FileOrContent{traefiktls.FileOrContent(LocalhostCert)}, + RootCAs: []types.FileOrContent{types.FileOrContent(LocalhostCert)}, // For mTLS Certificates: traefiktls.Certificates{ traefiktls.Certificate{ - CertFile: traefiktls.FileOrContent(mTLSCert), - KeyFile: traefiktls.FileOrContent(mTLSKey), + CertFile: types.FileOrContent(mTLSCert), + KeyFile: types.FileOrContent(mTLSKey), }, }, }, diff --git a/pkg/tls/certificate.go b/pkg/tls/certificate.go index 7cddcd526..5649c5ba8 100644 --- a/pkg/tls/certificate.go +++ b/pkg/tls/certificate.go @@ -6,11 +6,11 @@ import ( "errors" "fmt" "net/url" - "os" "sort" "strings" "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v3/pkg/types" ) var ( @@ -48,8 +48,8 @@ var ( // Certificate holds a SSL cert/key pair // Certs and Key could be either a file path, or the file content itself. type Certificate struct { - CertFile FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"` - KeyFile FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"` + CertFile types.FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"` + KeyFile types.FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"` } // Certificates defines traefik certificates type @@ -73,33 +73,6 @@ func (c Certificates) GetCertificates() []tls.Certificate { 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. func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certificate, storeName string) error { certContent, err := c.CertFile.Read() @@ -229,8 +202,8 @@ func (c *Certificates) Set(value string) error { return fmt.Errorf("bad certificates format: %s", value) } *c = append(*c, Certificate{ - CertFile: FileOrContent(files[0]), - KeyFile: FileOrContent(files[1]), + CertFile: types.FileOrContent(files[0]), + KeyFile: types.FileOrContent(files[1]), }) } return nil diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go index 93a9cab36..fa12cbc85 100644 --- a/pkg/tls/tls.go +++ b/pkg/tls/tls.go @@ -8,7 +8,7 @@ const certificateHeader = "-----BEGIN CERTIFICATE-----\n" // ClientAuth defines the parameters of the client authentication part of the TLS connection, if any. 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. // The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert". ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty" export:"true"` diff --git a/pkg/tls/tlsmanager_test.go b/pkg/tls/tlsmanager_test.go index 983ab2401..0ec367883 100644 --- a/pkg/tls/tlsmanager_test.go +++ b/pkg/tls/tlsmanager_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/traefik/traefik/v3/pkg/types" ) // LocalhostCert is a PEM-encoded TLS cert with SAN IPs @@ -16,7 +17,7 @@ import ( // 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 var ( - localhostCert = FileOrContent(`-----BEGIN CERTIFICATE----- + localhostCert = types.FileOrContent(`-----BEGIN CERTIFICATE----- MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A @@ -38,7 +39,7 @@ WkBKOclmOV2xlTVuPw== -----END CERTIFICATE-----`) // LocalhostKey is the private key for localhostCert. - localhostKey = FileOrContent(`-----BEGIN RSA PRIVATE KEY----- + localhostKey = types.FileOrContent(`-----BEGIN RSA PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi 4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW @@ -197,7 +198,7 @@ func TestClientAuth(t *testing.T) { }, "vccig": { ClientAuth: ClientAuth{ - CAFiles: []FileOrContent{localhostCert}, + CAFiles: []types.FileOrContent{localhostCert}, ClientAuthType: "VerifyClientCertIfGiven", }, }, @@ -209,13 +210,13 @@ func TestClientAuth(t *testing.T) { }, "ravccwca": { ClientAuth: ClientAuth{ - CAFiles: []FileOrContent{localhostCert}, + CAFiles: []types.FileOrContent{localhostCert}, ClientAuthType: "RequireAndVerifyClientCert", }, }, "ravccwbca": { ClientAuth: ClientAuth{ - CAFiles: []FileOrContent{"Bad content"}, + CAFiles: []types.FileOrContent{"Bad content"}, ClientAuthType: "RequireAndVerifyClientCert", }, }, diff --git a/pkg/tls/zz_generated.deepcopy.go b/pkg/tls/zz_generated.deepcopy.go index 63d18bcb5..26461ab0d 100644 --- a/pkg/tls/zz_generated.deepcopy.go +++ b/pkg/tls/zz_generated.deepcopy.go @@ -60,7 +60,7 @@ func (in *ClientAuth) DeepCopyInto(out *ClientAuth) { *out = *in if in.CAFiles != nil { in, out := &in.CAFiles, &out.CAFiles - *out = make([]FileOrContent, len(*in)) + *out = make([]types.FileOrContent, len(*in)) copy(*out, *in) } return diff --git a/pkg/types/file_or_content.go b/pkg/types/file_or_content.go new file mode 100644 index 000000000..7b1f679bc --- /dev/null +++ b/pkg/types/file_or_content.go @@ -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 +}