diff --git a/app/kuma-cp/cmd/cmd_standalone_postgres_test.go b/app/kuma-cp/cmd/cmd_standalone_postgres_test.go index 73fb06db76e4..2ccff9207cec 100644 --- a/app/kuma-cp/cmd/cmd_standalone_postgres_test.go +++ b/app/kuma-cp/cmd/cmd_standalone_postgres_test.go @@ -19,7 +19,8 @@ apiServer: sdsServer: grpcPort: 0 dataplaneTokenServer: - port: 0 + local: + port: 0 environment: universal store: type: postgres diff --git a/app/kuma-cp/cmd/cmd_universal_memory_test.go b/app/kuma-cp/cmd/cmd_universal_memory_test.go index 582fd3328417..2fbfafb91215 100644 --- a/app/kuma-cp/cmd/cmd_universal_memory_test.go +++ b/app/kuma-cp/cmd/cmd_universal_memory_test.go @@ -16,7 +16,8 @@ apiServer: sdsServer: grpcPort: 0 dataplaneTokenServer: - port: 0 + local: + port: 0 environment: universal store: type: memory diff --git a/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml b/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml index da7926b4a1a1..2e64fdb517d7 100644 --- a/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml +++ b/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml @@ -56,8 +56,22 @@ sdsServer: # Dataplane Token server configuration dataplaneTokenServer: - # Port of the server - port: 5679 + # Local configuration of server that is available only on localhost + local: + # Port on which the server will be exposed + port: 5679 # ENV: KUMA_DATAPLANE_TOKEN_SERVER_LOCAL_PORT + # Public configuration of server that is available on public interface + public: + # Port on which the server will be exposed. If not specified (0) then port from local configuration will be used + port: 0 # ENV: KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_PORT + # Public interface on which the server will be exposed + interface: # ENV: KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_INTERFACE + # Path to TLS certificate file + tlsCertFile: # ENV: KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_TLS_CERT_FILE + # Path to TLS key file + tlsKeyFile: # ENV: KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_TLS_KEY_FILE + # Paths to authorized client certificates + clientCertFiles: # ENV: KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_CLIENT_CERT_FILES # Envoy XDS server configuration xdsServer: diff --git a/pkg/config/loader_test.go b/pkg/config/loader_test.go index cc47e4eeab74..8dea8d2dfa9f 100644 --- a/pkg/config/loader_test.go +++ b/pkg/config/loader_test.go @@ -8,7 +8,9 @@ import ( kuma_cp "github.com/Kong/kuma/pkg/config/app/kuma-cp" config_core "github.com/Kong/kuma/pkg/config/core" "github.com/Kong/kuma/pkg/config/core/resources/store" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" ) @@ -30,7 +32,71 @@ var _ = Describe("Config loader", func() { } }) - sampleConfigYaml := ` + setEnv := func(key, value string) { + err := os.Setenv(key, value) + Expect(err).ToNot(HaveOccurred()) + } + + type testCase struct { + yamlFileConfig string + envVars map[string]string + } + DescribeTable("should load config", + func(given testCase) { + // given file with sample config + file, err := ioutil.TempFile("", "*") + Expect(err).ToNot(HaveOccurred()) + _, err = file.WriteString(given.yamlFileConfig) + Expect(err).ToNot(HaveOccurred()) + + // and config from environment variables + for key, value := range given.envVars { + setEnv(key, value) + } + + // when + cfg := kuma_cp.DefaultConfig() + err = config.Load(file.Name(), &cfg) + Expect(err).ToNot(HaveOccurred()) + + // then + Expect(cfg.XdsServer.GrpcPort).To(Equal(5000)) + Expect(cfg.XdsServer.DiagnosticsPort).To(Equal(5003)) + + Expect(cfg.BootstrapServer.Port).To(Equal(uint32(5004))) + Expect(cfg.BootstrapServer.Params.AdminPort).To(Equal(uint32(1234))) + Expect(cfg.BootstrapServer.Params.XdsHost).To(Equal("kuma-control-plane")) + Expect(cfg.BootstrapServer.Params.XdsPort).To(Equal(uint32(4321))) + + Expect(cfg.Environment).To(Equal(config_core.KubernetesEnvironment)) + + Expect(cfg.Store.Type).To(Equal(store.PostgresStore)) + Expect(cfg.Store.Postgres.Host).To(Equal("postgres.host")) + Expect(int(cfg.Store.Postgres.Port)).To(Equal(5432)) + Expect(cfg.Store.Postgres.User).To(Equal("kuma")) + Expect(cfg.Store.Postgres.Password).To(Equal("kuma")) + Expect(cfg.Store.Postgres.DbName).To(Equal("kuma")) + Expect(cfg.Store.Postgres.ConnectionTimeout).To(Equal(10)) + + Expect(cfg.ApiServer.Port).To(Equal(9090)) + Expect(cfg.ApiServer.ReadOnly).To(Equal(true)) + + Expect(cfg.DataplaneTokenServer.Local.Port).To(Equal(uint32(1111))) + Expect(cfg.DataplaneTokenServer.Public.Port).To(Equal(uint32(2222))) + Expect(cfg.DataplaneTokenServer.Public.Interface).To(Equal("192.168.0.1")) + Expect(cfg.DataplaneTokenServer.Public.TlsKeyFile).To(Equal("/tmp/key")) + Expect(cfg.DataplaneTokenServer.Public.TlsCertFile).To(Equal("/tmp/cert")) + Expect(cfg.DataplaneTokenServer.Public.ClientCertFiles).To(Equal([]string{"/tmp/cert1", "/tmp/cert2"})) + + Expect(cfg.Runtime.Kubernetes.AdmissionServer.Address).To(Equal("127.0.0.2")) + Expect(cfg.Runtime.Kubernetes.AdmissionServer.Port).To(Equal(uint32(9443))) + Expect(cfg.Runtime.Kubernetes.AdmissionServer.CertDir).To(Equal("/var/run/secrets/kuma.io/kuma-admission-server/tls-cert")) + + Expect(cfg.Reports.Enabled).To(BeFalse()) + }, + Entry("from config file", testCase{ + envVars: map[string]string{}, + yamlFileConfig: ` environment: kubernetes store: type: postgres @@ -54,7 +120,16 @@ apiServer: port: 9090 readOnly: true dataplaneTokenServer: - port: 1111 + local: + port: 1111 + public: + interface: 192.168.0.1 + port: 2222 + tlsCertFile: /tmp/cert + tlsKeyFile: /tmp/key + clientCertFiles: + - /tmp/cert1 + - /tmp/cert2 runtime: kubernetes: admissionServer: @@ -63,126 +138,50 @@ runtime: certDir: /var/run/secrets/kuma.io/kuma-admission-server/tls-cert reports: enabled: false -` - - It("should load config from file", func() { - // given file with sample config - file, err := ioutil.TempFile("", "*") - Expect(err).ToNot(HaveOccurred()) - _, err = file.WriteString(sampleConfigYaml) - Expect(err).ToNot(HaveOccurred()) - - // when - cfg := kuma_cp.DefaultConfig() - err = config.Load(file.Name(), &cfg) - Expect(err).ToNot(HaveOccurred()) - - // then - Expect(cfg.XdsServer.GrpcPort).To(Equal(5000)) - Expect(cfg.XdsServer.DiagnosticsPort).To(Equal(5003)) - - Expect(cfg.BootstrapServer.Port).To(Equal(uint32(5004))) - Expect(cfg.BootstrapServer.Params.AdminPort).To(Equal(uint32(1234))) - Expect(cfg.BootstrapServer.Params.XdsHost).To(Equal("kuma-control-plane")) - Expect(cfg.BootstrapServer.Params.XdsPort).To(Equal(uint32(4321))) - - Expect(cfg.Environment).To(Equal(config_core.KubernetesEnvironment)) - - Expect(cfg.Store.Type).To(Equal(store.PostgresStore)) - - Expect(cfg.Store.Postgres.Host).To(Equal("postgres.host")) - Expect(int(cfg.Store.Postgres.Port)).To(Equal(5432)) - Expect(cfg.Store.Postgres.User).To(Equal("kuma")) - Expect(cfg.Store.Postgres.Password).To(Equal("kuma")) - Expect(cfg.Store.Postgres.DbName).To(Equal("kuma")) - Expect(cfg.Store.Postgres.ConnectionTimeout).To(Equal(10)) - - Expect(cfg.ApiServer.Port).To(Equal(9090)) - Expect(cfg.ApiServer.ReadOnly).To(Equal(true)) - - Expect(cfg.DataplaneTokenServer.Port).To(Equal(uint32(1111))) - - Expect(cfg.Runtime.Kubernetes.AdmissionServer.Address).To(Equal("127.0.0.2")) - Expect(cfg.Runtime.Kubernetes.AdmissionServer.Port).To(Equal(uint32(9443))) - Expect(cfg.Runtime.Kubernetes.AdmissionServer.CertDir).To(Equal("/var/run/secrets/kuma.io/kuma-admission-server/tls-cert")) - - Expect(cfg.Reports.Enabled).To(BeFalse()) - }) - - setEnv := func(key, value string) { - err := os.Setenv(key, value) - Expect(err).ToNot(HaveOccurred()) - } - - It("should load config from env vars", func() { - // given - setEnv("KUMA_XDS_SERVER_GRPC_PORT", "5000") - setEnv("KUMA_XDS_SERVER_DIAGNOSTICS_PORT", "5003") - setEnv("KUMA_BOOTSTRAP_SERVER_PORT", "5004") - setEnv("KUMA_BOOTSTRAP_SERVER_PARAMS_ADMIN_PORT", "1234") - setEnv("KUMA_BOOTSTRAP_SERVER_PARAMS_XDS_HOST", "kuma-control-plane") - setEnv("KUMA_BOOTSTRAP_SERVER_PARAMS_XDS_PORT", "4321") - setEnv("KUMA_ENVIRONMENT", "kubernetes") - setEnv("KUMA_STORE_TYPE", "postgres") - setEnv("KUMA_STORE_POSTGRES_HOST", "postgres.host") - setEnv("KUMA_STORE_POSTGRES_PORT", "5432") - setEnv("KUMA_STORE_POSTGRES_USER", "kuma") - setEnv("KUMA_STORE_POSTGRES_PASSWORD", "kuma") - setEnv("KUMA_STORE_POSTGRES_DB_NAME", "kuma") - setEnv("KUMA_STORE_POSTGRES_CONNECTION_TIMEOUT", "10") - setEnv("KUMA_API_SERVER_READ_ONLY", "true") - setEnv("KUMA_API_SERVER_PORT", "9090") - setEnv("KUMA_DATAPLANE_TOKEN_SERVER_PORT", "1111") - setEnv("KUMA_REPORTS_ENABLED", "false") - setEnv("KUMA_KUBERNETES_ADMISSION_SERVER_ADDRESS", "127.0.0.2") - setEnv("KUMA_KUBERNETES_ADMISSION_SERVER_PORT", "9443") - setEnv("KUMA_KUBERNETES_ADMISSION_SERVER_CERT_DIR", "/var/run/secrets/kuma.io/kuma-admission-server/tls-cert") - - // when - cfg := kuma_cp.DefaultConfig() - err := config.Load("", &cfg) - Expect(err).ToNot(HaveOccurred()) - - // then - Expect(cfg.XdsServer.GrpcPort).To(Equal(5000)) - Expect(cfg.XdsServer.DiagnosticsPort).To(Equal(5003)) - - Expect(cfg.BootstrapServer.Port).To(Equal(uint32(5004))) - Expect(cfg.BootstrapServer.Params.AdminPort).To(Equal(uint32(1234))) - Expect(cfg.BootstrapServer.Params.XdsHost).To(Equal("kuma-control-plane")) - Expect(cfg.BootstrapServer.Params.XdsPort).To(Equal(uint32(4321))) - - Expect(cfg.Environment).To(Equal(config_core.KubernetesEnvironment)) - - Expect(cfg.Store.Type).To(Equal(store.PostgresStore)) - Expect(cfg.Store.Postgres.Host).To(Equal("postgres.host")) - Expect(int(cfg.Store.Postgres.Port)).To(Equal(5432)) - Expect(cfg.Store.Postgres.User).To(Equal("kuma")) - Expect(cfg.Store.Postgres.Password).To(Equal("kuma")) - Expect(cfg.Store.Postgres.DbName).To(Equal("kuma")) - Expect(cfg.Store.Postgres.ConnectionTimeout).To(Equal(10)) - - Expect(cfg.ApiServer.Port).To(Equal(9090)) - Expect(cfg.ApiServer.ReadOnly).To(Equal(true)) - - Expect(cfg.DataplaneTokenServer.Port).To(Equal(uint32(1111))) - - Expect(cfg.Runtime.Kubernetes.AdmissionServer.Address).To(Equal("127.0.0.2")) - Expect(cfg.Runtime.Kubernetes.AdmissionServer.Port).To(Equal(uint32(9443))) - Expect(cfg.Runtime.Kubernetes.AdmissionServer.CertDir).To(Equal("/var/run/secrets/kuma.io/kuma-admission-server/tls-cert")) - - Expect(cfg.Reports.Enabled).To(BeFalse()) - }) +`, + }), + Entry("from env variables", testCase{ + envVars: map[string]string{ + "KUMA_XDS_SERVER_GRPC_PORT": "5000", + "KUMA_XDS_SERVER_DIAGNOSTICS_PORT": "5003", + "KUMA_BOOTSTRAP_SERVER_PORT": "5004", + "KUMA_BOOTSTRAP_SERVER_PARAMS_ADMIN_PORT": "1234", + "KUMA_BOOTSTRAP_SERVER_PARAMS_XDS_HOST": "kuma-control-plane", + "KUMA_BOOTSTRAP_SERVER_PARAMS_XDS_PORT": "4321", + "KUMA_ENVIRONMENT": "kubernetes", + "KUMA_STORE_TYPE": "postgres", + "KUMA_STORE_POSTGRES_HOST": "postgres.host", + "KUMA_STORE_POSTGRES_PORT": "5432", + "KUMA_STORE_POSTGRES_USER": "kuma", + "KUMA_STORE_POSTGRES_PASSWORD": "kuma", + "KUMA_STORE_POSTGRES_DB_NAME": "kuma", + "KUMA_STORE_POSTGRES_CONNECTION_TIMEOUT": "10", + "KUMA_API_SERVER_READ_ONLY": "true", + "KUMA_API_SERVER_PORT": "9090", + "KUMA_DATAPLANE_TOKEN_SERVER_LOCAL_PORT": "1111", + "KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_INTERFACE": "192.168.0.1", + "KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_PORT": "2222", + "KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_TLS_KEY_FILE": "/tmp/key", + "KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_TLS_CERT_FILE": "/tmp/cert", + "KUMA_DATAPLANE_TOKEN_SERVER_PUBLIC_CLIENT_CERT_FILES": "/tmp/cert1,/tmp/cert2", + "KUMA_REPORTS_ENABLED": "false", + "KUMA_KUBERNETES_ADMISSION_SERVER_ADDRESS": "127.0.0.2", + "KUMA_KUBERNETES_ADMISSION_SERVER_PORT": "9443", + "KUMA_KUBERNETES_ADMISSION_SERVER_CERT_DIR": "/var/run/secrets/kuma.io/kuma-admission-server/tls-cert", + }, + yamlFileConfig: "", + }), + ) It("should override via env var", func() { // given file with sample cfg file, err := ioutil.TempFile("", "*") Expect(err).ToNot(HaveOccurred()) - _, err = file.WriteString(sampleConfigYaml) + _, err = file.WriteString("environment: kubernetes") Expect(err).ToNot(HaveOccurred()) // and overriden config - setEnv("KUMA_STORE_POSTGRES_HOST", "overriden.host") + setEnv("KUMA_ENVIRONMENT", "universal") // when cfg := kuma_cp.DefaultConfig() @@ -190,7 +189,7 @@ reports: Expect(err).ToNot(HaveOccurred()) // then - Expect(cfg.Store.Postgres.Host).To(Equal("overriden.host")) + Expect(cfg.Environment).To(Equal(config_core.UniversalEnvironment)) }) diff --git a/pkg/config/token-server/config.go b/pkg/config/token-server/config.go index beedf47ec9eb..91fb64328513 100644 --- a/pkg/config/token-server/config.go +++ b/pkg/config/token-server/config.go @@ -7,21 +7,94 @@ import ( func DefaultDataplaneTokenServerConfig() *DataplaneTokenServerConfig { return &DataplaneTokenServerConfig{ - Port: 5679, + Local: DefaultLocalDataplaneTokenServerConfig(), + Public: DefaultPublicDataplaneTokenServerConfig(), } } +var _ config.Config = &DataplaneTokenServerConfig{} + // Dataplane Token Server configuration type DataplaneTokenServerConfig struct { - // Port of the server - Port uint32 `yaml:"port" envconfig:"kuma_dataplane_token_server_port"` + // Local configuration of server that is available only on localhost + Local *LocalDataplaneTokenServerConfig `yaml:"local"` + // Public configuration of server that is available on public interface + Public *PublicDataplaneTokenServerConfig `yaml:"public"` } -var _ config.Config = &DataplaneTokenServerConfig{} - func (i *DataplaneTokenServerConfig) Validate() error { - if i.Port > 65535 { + if err := i.Local.Validate(); err != nil { + return errors.Wrap(err, "Local validation failed") + } + if err := i.Public.Validate(); err != nil { + return errors.Wrap(err, "Public validation failed") + } + return nil +} + +// Dataplane Token Server configuration of server that is available only on localhost +type LocalDataplaneTokenServerConfig struct { + // Port on which the server will be exposed + Port uint32 `yaml:"port" envconfig:"kuma_dataplane_token_server_local_port"` +} + +var _ config.Config = &LocalDataplaneTokenServerConfig{} + +func (l *LocalDataplaneTokenServerConfig) Validate() error { + if l.Port > 65535 { return errors.New("Port must be in the range [0, 65535]") } return nil } + +func DefaultLocalDataplaneTokenServerConfig() *LocalDataplaneTokenServerConfig { + return &LocalDataplaneTokenServerConfig{ + Port: 5679, + } +} + +// Dataplane Token Server configuration of server that is available on public interface +type PublicDataplaneTokenServerConfig struct { + // Interface on which the server will be exposed + Interface string `yaml:"interface" envconfig:"kuma_dataplane_token_server_public_interface"` + // Port on which the server will be exposed. If not specified (0) then port from local configuration will be used + Port uint32 `yaml:"port" envconfig:"kuma_dataplane_token_server_public_port"` + // Path to TLS certificate file + TlsCertFile string `yaml:"tlsCertFile" envconfig:"kuma_dataplane_token_server_public_tls_cert_file"` + // Path to TLS key file + TlsKeyFile string `yaml:"tlsKeyFile" envconfig:"kuma_dataplane_token_server_public_tls_key_file"` + // Paths to authorized client certificates + ClientCertFiles []string `yaml:"clientCertFiles" envconfig:"kuma_dataplane_token_server_public_client_cert_files"` +} + +var _ config.Config = &PublicDataplaneTokenServerConfig{} + +func DefaultPublicDataplaneTokenServerConfig() *PublicDataplaneTokenServerConfig { + return &PublicDataplaneTokenServerConfig{ + Interface: "", + Port: 0, + TlsCertFile: "", + TlsKeyFile: "", + ClientCertFiles: nil, + } +} + +func (p *PublicDataplaneTokenServerConfig) Validate() error { + if p.Port > 65535 { + return errors.New("Port must be in the range [0, 65535]") + } + if p.TlsCertFile == "" && p.TlsKeyFile != "" { + return errors.New("TlsCertFile cannot be empty if TlsKeyFile has been set") + } + if p.TlsKeyFile == "" && p.TlsCertFile != "" { + return errors.New("TlsKeyFile cannot be empty if TlsCertFile has been set") + } + if p.Interface != "" && p.TlsCertFile == "" { + return errors.New("TlsCertFile and TlsKeyFile have to be set when PublicInterface is specified") + } + return nil +} + +func (i *DataplaneTokenServerConfig) TlsEnabled() bool { + return i.Public.Interface != "" +} diff --git a/pkg/tokens/builtin/server/dataplane_token_server.go b/pkg/tokens/builtin/server/dataplane_token_server.go index 2a13616ff142..666fbccf2dff 100644 --- a/pkg/tokens/builtin/server/dataplane_token_server.go +++ b/pkg/tokens/builtin/server/dataplane_token_server.go @@ -2,13 +2,17 @@ package server import ( "context" + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" + token_server "github.com/Kong/kuma/pkg/config/token-server" "github.com/Kong/kuma/pkg/core" "github.com/Kong/kuma/pkg/tokens/builtin" "github.com/Kong/kuma/pkg/tokens/builtin/issuer" "github.com/Kong/kuma/pkg/tokens/builtin/server/types" "github.com/pkg/errors" + "go.uber.org/multierr" "io/ioutil" "net/http" @@ -26,7 +30,7 @@ func SetupServer(rt core_runtime.Runtime) error { return err } srv := &DataplaneTokenServer{ - Port: rt.Config().DataplaneTokenServer.Port, + Config: rt.Config().DataplaneTokenServer, Issuer: generator, } if err := core_runtime.Add(rt, srv); err != nil { @@ -41,18 +45,49 @@ func SetupServer(rt core_runtime.Runtime) error { var log = core.Log.WithName("dataplane-token-server") type DataplaneTokenServer struct { - Port uint32 + Config *token_server.DataplaneTokenServerConfig Issuer issuer.DataplaneTokenIssuer } var _ core_runtime.Component = &DataplaneTokenServer{} func (a *DataplaneTokenServer) Start(stop <-chan struct{}) error { + httpServer, httpErrChan := a.startHttpServer() + + var httpsServer *http.Server + var httpsErrChan chan error + if a.Config.TlsEnabled() { + httpsServer, httpsErrChan = a.startHttpsServer() + } else { + httpsErrChan = make(chan error) + } + + select { + case <-stop: + log.Info("stopping") + var multiErr error + if err := httpServer.Shutdown(context.Background()); err != nil { + multiErr = multierr.Combine(err) + } + if httpsServer != nil { + if err := httpsServer.Shutdown(context.Background()); err != nil { + multiErr = multierr.Combine(err) + } + } + return multiErr + case err := <-httpErrChan: + return err + case err := <-httpsErrChan: + return err + } +} + +func (a *DataplaneTokenServer) startHttpServer() (*http.Server, chan error) { mux := http.NewServeMux() mux.HandleFunc("/tokens", a.handleIdentityRequest) server := &http.Server{ - Addr: fmt.Sprintf("127.0.0.1:%d", a.Port), + Addr: fmt.Sprintf("127.0.0.1:%d", a.Config.Local.Port), Handler: mux, } @@ -62,22 +97,68 @@ func (a *DataplaneTokenServer) Start(stop <-chan struct{}) error { defer close(errChan) if err := server.ListenAndServe(); err != nil { if err != http.ErrServerClosed { - log.Error(err, "terminated with an error") + log.Error(err, "http server terminated with an error") errChan <- err return } } - log.Info("terminated normally") + log.Info("http server terminated normally") }() - log.Info("starting", "port", a.Port) + log.Info("starting server", "port", a.Config.Local.Port) + return server, errChan +} - select { - case <-stop: - log.Info("stopping") - return server.Shutdown(context.Background()) - case err := <-errChan: - return err +func (a *DataplaneTokenServer) startHttpsServer() (*http.Server, chan error) { + mux := http.NewServeMux() + mux.HandleFunc("/tokens", a.handleIdentityRequest) + + errChan := make(chan error) + + tlsConfig, err := requireClientCerts(a.Config.Public.ClientCertFiles) + if err != nil { + errChan <- err + } + + port := a.Config.Public.Port + if port == 0 { + port = a.Config.Local.Port + } + server := &http.Server{ + Addr: fmt.Sprintf("%s:%d", a.Config.Public.Interface, port), + Handler: mux, + TLSConfig: tlsConfig, + } + + go func() { + defer close(errChan) + if err := server.ListenAndServeTLS(a.Config.Public.TlsCertFile, a.Config.Public.TlsKeyFile); err != nil { + if err != http.ErrServerClosed { + log.Error(err, "https server terminated with an error") + errChan <- err + return + } + } + log.Info("https server terminated normally") + }() + log.Info("starting server", "interface", a.Config.Public.Interface, "port", port, "tls", true) + return server, errChan +} + +func requireClientCerts(certFiles []string) (*tls.Config, error) { + clientCertPool := x509.NewCertPool() + for _, cert := range certFiles { + caCert, err := ioutil.ReadFile(cert) + if err != nil { + return nil, errors.Wrapf(err, "could not read certificate %s", cert) + } + clientCertPool.AppendCertsFromPEM(caCert) + } + tlsConfig := &tls.Config{ + ClientCAs: clientCertPool, + ClientAuth: tls.RequireAndVerifyClientCert, } + tlsConfig.BuildNameToCertificate() + return tlsConfig, nil } func (a *DataplaneTokenServer) handleIdentityRequest(resp http.ResponseWriter, req *http.Request) { diff --git a/pkg/tokens/builtin/server/dataplane_token_server_test.go b/pkg/tokens/builtin/server/dataplane_token_server_test.go index 8b8e80014c03..8edbb16b51d4 100644 --- a/pkg/tokens/builtin/server/dataplane_token_server_test.go +++ b/pkg/tokens/builtin/server/dataplane_token_server_test.go @@ -2,9 +2,12 @@ package server_test import ( "bytes" + "crypto/tls" + "crypto/x509" "encoding/json" "errors" "fmt" + token_server "github.com/Kong/kuma/pkg/config/token-server" "github.com/Kong/kuma/pkg/core/xds" "github.com/Kong/kuma/pkg/sds/auth" "github.com/Kong/kuma/pkg/test" @@ -16,6 +19,7 @@ import ( . "github.com/onsi/gomega" "io/ioutil" "net/http" + "path/filepath" "strings" ) @@ -36,15 +40,53 @@ func (s *staticTokenIssuer) Validate(credential auth.Credential) (xds.ProxyId, e var _ = Describe("Dataplane Token Server", func() { var port int + var publicPort int const credentials = "test" + httpsClient := func(name string) *http.Client { + caCert, err := ioutil.ReadFile(filepath.Join("testdata", "server-cert.pem")) + Expect(err).ToNot(HaveOccurred()) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + cert, err := tls.LoadX509KeyPair( + filepath.Join("testdata", fmt.Sprintf("%s-cert.pem", name)), + filepath.Join("testdata", fmt.Sprintf("%s-key.pem", name)), + ) + Expect(err).ToNot(HaveOccurred()) + + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + Certificates: []tls.Certificate{cert}, + }, + }, + } + return client + } + BeforeEach(func() { p, err := test.GetFreePort() + Expect(err).ToNot(HaveOccurred()) port = p + p, err = test.GetFreePort() Expect(err).ToNot(HaveOccurred()) + publicPort = p srv := server.DataplaneTokenServer{ - Port: uint32(port), Issuer: &staticTokenIssuer{credentials}, + Config: &token_server.DataplaneTokenServerConfig{ + Local: &token_server.LocalDataplaneTokenServerConfig{ + Port: uint32(port), + }, + Public: &token_server.PublicDataplaneTokenServerConfig{ + Port: uint32(publicPort), + Interface: "localhost", + TlsCertFile: filepath.Join("testdata", "server-cert.pem"), + TlsKeyFile: filepath.Join("testdata", "server-key.pem"), + ClientCertFiles: []string{filepath.Join("testdata", "authorized-client-cert.pem")}, + }, + }, } ch := make(chan struct{}) @@ -54,42 +96,66 @@ var _ = Describe("Dataplane Token Server", func() { errCh <- srv.Start(ch) }() - // wait for the server to be started + // wait for the http server to be started Eventually(func() error { - req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%d/tokens", port), nil) + req, err := http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/tokens", port), nil) Expect(err).ToNot(HaveOccurred()) _, err = http.DefaultClient.Do(req) return err }, "5s", "100ms").ShouldNot(HaveOccurred()) - }) - It("should respond with generated token", func(done Done) { - // given - idReq := types.DataplaneTokenRequest{ - Mesh: "defualt", - Name: "dp-1", - } - reqBytes, err := json.Marshal(idReq) - Expect(err).ToNot(HaveOccurred()) + // wait for the https server to be started + Eventually(func() error { + req, err := http.NewRequest("POST", fmt.Sprintf("https://localhost:%d/tokens", publicPort), nil) + Expect(err).ToNot(HaveOccurred()) + _, err = httpsClient("authorized-client").Do(req) + return err + }, "5s", "100ms").ShouldNot(HaveOccurred()) + }) - // when - req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%d/tokens", port), bytes.NewReader(reqBytes)) - resp, err := http.DefaultClient.Do(req) + type testCase struct { + clientFn func() *http.Client + url string + } + DescribeTable("should respond with generated token", + func(given testCase) { + // given + idReq := types.DataplaneTokenRequest{ + Mesh: "defualt", + Name: "dp-1", + } + reqBytes, err := json.Marshal(idReq) + Expect(err).ToNot(HaveOccurred()) - // then - Expect(err).ToNot(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(200)) + // when + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%d/tokens", port), bytes.NewReader(reqBytes)) + Expect(err).ToNot(HaveOccurred()) + resp, err := http.DefaultClient.Do(req) - // when - respBody, err := ioutil.ReadAll(resp.Body) + // then + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) - // then - Expect(err).ToNot(HaveOccurred()) - Expect(string(respBody)).To(Equal(credentials)) + // when + respBody, err := ioutil.ReadAll(resp.Body) - // finally - close(done) - }) + // then + Expect(err).ToNot(HaveOccurred()) + Expect(string(respBody)).To(Equal(credentials)) + }, + Entry("using http server", testCase{ + clientFn: func() *http.Client { + return http.DefaultClient + }, + url: fmt.Sprintf("http://localhost:%d/tokens", port), + }), + Entry("using https server and authorized client", testCase{ + clientFn: func() *http.Client { + return httpsClient("authorized-client") + }, + url: fmt.Sprintf("https://localhost:%d/tokens", publicPort), + }), + ) DescribeTable("should return bad request on invalid json", func(json string) { @@ -104,4 +170,23 @@ var _ = Describe("Dataplane Token Server", func() { Entry("json does not contain mesh", `{"name": "default"}`), Entry("not valid json", `not-valid-json`), ) + + It("should not let unauthorized clients generate a token", func() { + // given + idReq := types.DataplaneTokenRequest{ + Mesh: "defualt", + Name: "dp-1", + } + reqBytes, err := json.Marshal(idReq) + Expect(err).ToNot(HaveOccurred()) + + // when + req, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%d/tokens", publicPort), bytes.NewReader(reqBytes)) + Expect(err).ToNot(HaveOccurred()) + _, err = httpsClient("unauthorized-client").Do(req) + + // then + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(HaveSuffix("tls: bad certificate")) + }) }) diff --git a/pkg/tokens/builtin/server/testdata/authorized-client-cert.pem b/pkg/tokens/builtin/server/testdata/authorized-client-cert.pem new file mode 100644 index 000000000000..c952f9faed61 --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/authorized-client-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeDCCAmACCQCjSksUaw1jGDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV +UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEa +MBgGA1UECgwRWW91ciBPcmdhbml6YXRpb24xEjAQBgNVBAsMCVlvdXIgVW5pdDES +MBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTAxNzEyMDYxN1oXDTI5MTAxNDEyMDYx +N1owfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM +DU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIgT3JnYW5pemF0aW9uMRIwEAYD +VQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAK3b3G0isAi3wSaCVT5N2EiXyBdRphO0t9lL0gE0 +JqzCNoJbYgm/gi2oAz7d9VvlMsuhZm1i6XOMBOx8mF9OsLXV/IGg+W8fzpxPCaQy +gLhUhIPY66E2TkXG8pDKKfFSfO8GQ7DaPgLbXWKyNd7AoI2ZQeYLYb/ZUrnqfgWW +9g9bpCqXyLZdnJ2MGUDJhOudotL36waSm4Fa9fAaCcX2w7TabRdMlnf4a/djGQkp +MSLq4VjDF5BqpzUxf1ktf4Ncys75g+hQHSYDLg9V19sLQSn4eAe52RX5xdv0rDNJ +7qmSX/G3NKUpdRLAe5E39ITj6bQJMj6mQjLyjzxoK+1WJzcCAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEAD8AImEbly7DRIOZkq9gv9pZ1/crMeWxGHFJhpWto4uOVJwsJ +jsdM9syxNtZEFohkvt9k3RnNtykeeMIvCQT2fg9Du9DIcLsOInuUeYY0OoEHgPF0 +nd6BKOgejaSe6VOFmbAKeZo80ld+G/cllLO9znCTYkwojVw5C4BfUC1pMOqqEVHx +bnW4N8N78rgt9tMAiLlK/v+0V0ZZ2QTojlFJ2Ue53d8G0IeUCHrMMtuadmTkSVWc +CaqYklansJ6yRmKHjX8WSkMjBjs/WY4LePWqYdZtrPK8d3NxBILDPu155KsAxxLh +oEYDWEpIXAa6bExoz7TVKbzSZeu4rDpJx7x/iw== +-----END CERTIFICATE----- diff --git a/pkg/tokens/builtin/server/testdata/authorized-client-key.pem b/pkg/tokens/builtin/server/testdata/authorized-client-key.pem new file mode 100644 index 000000000000..d7c97fe13c20 --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/authorized-client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCt29xtIrAIt8Em +glU+TdhIl8gXUaYTtLfZS9IBNCaswjaCW2IJv4ItqAM+3fVb5TLLoWZtYulzjATs +fJhfTrC11fyBoPlvH86cTwmkMoC4VISD2OuhNk5FxvKQyinxUnzvBkOw2j4C211i +sjXewKCNmUHmC2G/2VK56n4FlvYPW6Qql8i2XZydjBlAyYTrnaLS9+sGkpuBWvXw +GgnF9sO02m0XTJZ3+Gv3YxkJKTEi6uFYwxeQaqc1MX9ZLX+DXMrO+YPoUB0mAy4P +VdfbC0Ep+HgHudkV+cXb9KwzSe6pkl/xtzSlKXUSwHuRN/SE4+m0CTI+pkIy8o88 +aCvtVic3AgMBAAECggEBAJoXBC2CEe0YF8uutiiLTAdC5yeryPssL8oahh1lAGYb +l74/igvDvXgDsiS1CnKRGE0cVrDaerhbQD3tTAskrj/rUWn+pzSTR0aIUq5ByI4W +8n/88RIoFIWJh5FGbJgjGPGsZrBHLbDQhdskwdQUe/gj/iEKs28bCVQX/eusWZdP +lo1tUkOhGA6RPPltHj0B9DFbgLRy1L4dXwt9Ef9L+Kjde0IZW1NC7k9VDhNvtkjT +mrRjII7f7EfvPz8abIqkCvHfLITOBRPxnZL9jvRe/aeD4IXbxNPk4PmGlOw+AQ0z +hfGe5K3zHKouHAW8IvkgGg7gohRlQV/fx08Tge8oYakCgYEA1zj/D8PwYrvKgTvG +ct4ikmgtfbXrMNSwHgVO46WCteFVWOZwV8ZvcuaAD0ERlxXivEyPBIEPWvd5s95K +VEwP/QF5JrpyG1afBlUCxdCwyT9+bneUKdmhm52Kij2YHB7k3fKTydM4ITk1eTBu +QIvgoM45gNGpbEhxjztrhB8DANUCgYEAzsyVlxcN779h0xDss0tfP6GtNeSeeS8E +pqXv8HB9m/sq535XzFjOM2eZfKAxi2hJQZ7WDrSdxwDrvSeXGGsfj1+L9l1u5hDs +3A4+dAUrrPb7fUmg6jq4KWeV35us1iDdLCeDwF8da5K7OqJMPaA1iU+cV+mjh+NV +HqqT2nujLdsCgYEAnd1RwXegcFt8i1SUGJd1VlyR2Z7Bl7y6Phr4paQ2f0B8QMwu +ZUPJZcdK8WVyCJdmC2ZAlTYxVDEoFNYdQT3VkGgvPEgQAJuF47ghY4XS1pr7Gv4d +MKFQl/tzrjjFxQKoL2CKJMUIa94xqeXrSO8Q4gLCTQn8ss9kdIJKN8wjgM0CgYEA +goAOQlt1Gv9N71D13itJPzF6ydCsxNKL/9IleTizu5QjvhQ3uaes8DmHXWMGAPBd +kkB22q7WBjgpi6OJMQqgzuw/uce6bQrvPerrNHHy3uK5T5YAKu/FObO5m3N0/Wed +yvhgpywet7zP1C+JJzaLskv/4GZ7IQyvsXt5dF2jWxMCgYEAgFcvP/LQYV1L2yAq +fPis2ZF9PFUfIq4FBYdTuJzyL3aW1p6BW/3tAf9TKMIUfK0BAfiRrDVMyRdKA39E +AKatwPpYMpXRPNc928lC+U0GUA/xUTwu15N2Gy/AJSayV61g3H+bEknWl67qskcv +rqQBOcmO9ZxgCyhhd7dJixOlGbM= +-----END PRIVATE KEY----- diff --git a/pkg/tokens/builtin/server/testdata/server-cert.pem b/pkg/tokens/builtin/server/testdata/server-cert.pem new file mode 100644 index 000000000000..2b9d309ea93c --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/server-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeDCCAmACCQC4QUy6IbXQkTANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV +UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEa +MBgGA1UECgwRWW91ciBPcmdhbml6YXRpb24xEjAQBgNVBAsMCVlvdXIgVW5pdDES +MBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTAxNzEyMDU1NloXDTI5MTAxNDEyMDU1 +NlowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM +DU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIgT3JnYW5pemF0aW9uMRIwEAYD +VQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMsApYodet9ZEgn30cjaGy7bLK1itgXrY5sdJ8YV +uok98QGOMc5RkH+O+5pNeqBp9G2Jjq2tAfpUDRUBSXAW5Z89l0oN7LRqODrS0U1J +pACnvpIl7G1B3gnoF49d1RsC058uDQZcYqtL3TrTzQxsQfTraNApBHAkleHyEVQP +6rxDm17zZKJXase7Pl0rj2I2dGvkLpNl6fwRotuZIaPGCcyWG1FP+fjTEVQD60GQ +bgUOxuOVns0GEkW7LNc8W/5wYAvIq9Urh1KEyn4Vt8kAfNoRWnYgWU4qbKfUn9xB +giybQMc8PZYO6cFafLx/3dZyV3TJXUwuVP9lPrcDX+N5WZcCAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEApOFRaY1uLfLPnjTm3Y0o/odF2+TAWYLCDIIlBrZfkmR/qMNi +z4PUqepw4bYsf5Rg7mJhnZDIfcuOBpAuvWxToAPMdiLK3cA4nopA5/pV3pYH2uN9 +TQEIMvQC7pm75ZZ1B0q9Gc4OiVql2TYcLYzoGFYLIs3RqOp8xR8fhs7rZHOM7qnW +dT7BiPzGhNwEeLD+XG5M13ABJTNxzqxObCNFEiSzzZHa3f3hm0VnKuh2If3WuazA +X4oboE0H8uzqknfDdjn8gxcs3syuxpbIT17vZ9n+b89x4qd5lGC2miyE5awhxqAP +GVYSB8dFplHot7zMtHZ7KmkQVLen35ZntLkVSA== +-----END CERTIFICATE----- diff --git a/pkg/tokens/builtin/server/testdata/server-key.pem b/pkg/tokens/builtin/server/testdata/server-key.pem new file mode 100644 index 000000000000..3ee29463ee56 --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLAKWKHXrfWRIJ +99HI2hsu2yytYrYF62ObHSfGFbqJPfEBjjHOUZB/jvuaTXqgafRtiY6trQH6VA0V +AUlwFuWfPZdKDey0ajg60tFNSaQAp76SJextQd4J6BePXdUbAtOfLg0GXGKrS906 +080MbEH062jQKQRwJJXh8hFUD+q8Q5te82SiV2rHuz5dK49iNnRr5C6TZen8EaLb +mSGjxgnMlhtRT/n40xFUA+tBkG4FDsbjlZ7NBhJFuyzXPFv+cGALyKvVK4dShMp+ +FbfJAHzaEVp2IFlOKmyn1J/cQYIsm0DHPD2WDunBWny8f93Wcld0yV1MLlT/ZT63 +A1/jeVmXAgMBAAECggEAa4o2J8qiMvuegMVVzw8r41CchGWMg+pE5AE39sm//cBg +kjBf1iqDX+/A/ecZlS1MHVMH0J2cNJ6eJ4h8/PJERm18XfCueoziqNbRph3i0a4L +WKTacK66D4lyIbLVl++RZ/wfTkVWx+PymJ1nPLOE5VhoOA3imf3noMB5yYx9D6nW +3+Y5mzP3KbLd2lrZ/XUI5Y+rLjWv5aZUUHkKmu/kEp+Jb7ybySa8qpdlSKjtDWPY +cw9MpNKqPWNp36zP06Shrig9/5jPDewywcDVye2rKDdARi8+yW0k4rRmH674qtja +H8h4+ouRMxC0t68X3wE/PJuQMFo8OioWfLnPoLZ1AQKBgQD0dc7kjJNyj8VD0/jB +U/KtK51wOJTUM+oS7O7nAPyIexoW+e5SY4m2hA3SfRuoYwd6qTr7ZSbdqpXMn019 +nAeTGs8p/L7S4WbC9EojwNnxx6Idkl4ZKXkEduGbDeeaFsLAoxLdX8auSkU6y2ce +FHfm0kLT/Yz9qXvHbvr16k9v1wKBgQDUlddYek04jJiOplWIUCJBQHqH7EsartEc +//uviePOmwhWhOgFimJlq9+9mT6mtI8yOLvTaFlSIULn09ZkRcvKQGALcJUQTEio +vgxaKE3K9WTWWu+fAiPu1gWrCb7hIDs9736JUf0NTRkQYz4uZFa9/Gt0SvC1FPKH +4YWDc/MsQQKBgGRIs+AUPySfEBicK477pjEeFE8GFx/aUCsFYZgIUpCWl4RXcUoB +JWxnTdhMlH0GavoJ1HVu8Hu80AkKTNq7mGvjcprR4WJXLzXIy2VRZtcFw16IPevq +lIedUT2vfZQ7xBcMjt+bu8CiHTZaXOn9EZbyKJIYkK86yNlukKszPPUvAoGAWits +ehT2KCRKmUcoRHdo8DB/SKQLfzfjbt+NS/m67OmJcdlR6Pe3oNR0RKF5l5BCpNS3 +poY+TL3a+SY7a7DHLfR8SJ3qPE1/DEQATUWHKa1IpjtQJCvuPeH96XxqwGbBehXZ +oDlsknW/Sdouh9L7j/4/PcaDrutBrC0WSpml7YECgYEAvS0p1HCzJC/q47mpMFFO +alDGMoqWZpSHTm4bFJ5F72y3S93L8sheTDbelcPSXcIBG7OcI5AMVBsfOwM2kfnf +xAaUKFbb/2/k68i9OEB+AUoFG/vMK3Fi3o7qDd6teIhgKWQQYyI64B4yGOle7D8f +Kwp51hSJsc5QZA5qKkW2404= +-----END PRIVATE KEY----- diff --git a/pkg/tokens/builtin/server/testdata/unauthorized-client-cert.pem b/pkg/tokens/builtin/server/testdata/unauthorized-client-cert.pem new file mode 100644 index 000000000000..dcabbdad75fd --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/unauthorized-client-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeDCCAmACCQDkA2XD4ptHnzANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV +UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEa +MBgGA1UECgwRWW91ciBPcmdhbml6YXRpb24xEjAQBgNVBAsMCVlvdXIgVW5pdDES +MBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTAxNzEyMTYxMloXDTI5MTAxNDEyMTYx +MlowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM +DU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIgT3JnYW5pemF0aW9uMRIwEAYD +VQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMUTyTfkXluQfbkrT01e5YfJOZwRPAsaoP/HSwws +BomwNfllkmcFVHY1Aou/rFy/35hnl/AdX8V9PlxRwdV4yGtRgF7RrczLB5UbKVqq +qC6PDIeIGypeQY/o/dVMI5z3NLhxWkUAQKJEjy3G5uWHvRZRI5E5RevalpbYTMke +rkzP1VXepYv97zuQa+8I3qZVTXGbegwPKZ82yifbEM5SBmcEMl4w7eh7oG9VjDe5 +dZ4PdHrllRey2ubVI5IUJ3RkEdRPm4JTYCxfeaHI51zdioKCL16ktWQJrZy+1u/O +906V0CzdzxnvRh8umgjL/fUm0Sz5xDtOCNRUlrSB+m5E228CAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEAuEeXMBerkUJu4uvZeQ5ED86kMyT1lgi0Ujg8XRaw1kOP+pfy +cYuvWGKrsXVhdjiGjVfu90CL8eFhgr+mQ/RvhwFETZOhspaRbNH9HzRLQARh76UZ +Ab0AdeQ1J9hBK+v7EEW3UKIR8+dULR3AUe2fLMkvrktDjBgpV/N6tgetDYqGc5pC +NLFJNWLl6DlDpqYMuvYNAgklRqu4eFC5NHpeXAS83NyaTjHwL9RaK12eV6PAwETc +NELaFooZtWZgFo+Zgj480xXLXiP51GNpjNYR1xt66hfdheQ2nHd/OeEG0k4s6P74 +jh8FeJGhz+zKLTU+C1oXiwgUq4q5bsDtHeFeaQ== +-----END CERTIFICATE----- diff --git a/pkg/tokens/builtin/server/testdata/unauthorized-client-key.pem b/pkg/tokens/builtin/server/testdata/unauthorized-client-key.pem new file mode 100644 index 000000000000..539176aa3693 --- /dev/null +++ b/pkg/tokens/builtin/server/testdata/unauthorized-client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDFE8k35F5bkH25 +K09NXuWHyTmcETwLGqD/x0sMLAaJsDX5ZZJnBVR2NQKLv6xcv9+YZ5fwHV/FfT5c +UcHVeMhrUYBe0a3MyweVGylaqqgujwyHiBsqXkGP6P3VTCOc9zS4cVpFAECiRI8t +xublh70WUSOROUXr2paW2EzJHq5Mz9VV3qWL/e87kGvvCN6mVU1xm3oMDymfNson +2xDOUgZnBDJeMO3oe6BvVYw3uXWeD3R65ZUXstrm1SOSFCd0ZBHUT5uCU2AsX3mh +yOdc3YqCgi9epLVkCa2cvtbvzvdOldAs3c8Z70YfLpoIy/31JtEs+cQ7TgjUVJa0 +gfpuRNtvAgMBAAECggEAbKEHXMOILzhp1FNHFwKjykDkfF4TlptK+zHC8CakQ+jZ +F2shU5/genelu5ofS9CHUt5nJXdLfvQWF5UJHr3A20bFV36EKkoPF+Us2kkPAvre +kSY4sxXZVZW7tIKPbsnkSXZRp48IEWlw8m6cfxBe7Zoz3KyRGfwW3XbEfGdo8/Tz +p9eVPfNMIHaZTz+PBHhZD3Oli9QDVcUrOCF6APO9RINKal+FVYg8Qeq7KcX6p0bL +wuOqIi7xtldvX26+grRFwndnfPbv8xJBpNny17tpPuMls7znycsnpw0x4M28UYr3 +jrC6dbFIZFW4ta84JFbjo1qEIR0IXJAB7DPtblt6gQKBgQDhWk7vYI6UfbARmp96 ++NbpZD6lGecqhbi1UeTLOhEprz/P+X7OK1jjuTOE3ZZkgvRyCVL6UapQe4ogsB0P +EvFwlGl4m+thZ2reOxjCxSmTBF2t1XgCRJBwOjyrzGGrHscM+dMlhF4Dz11Gq+uv +1gAC9oMQWAwRr9LIG+/hVGXz0QKBgQDf4RAAZiptvFrMaZvjJzDofWmb8bhQ5VSw +I4OQxBcl9tW2Oz0yCxtMMA9IqNkUIU2di6ChBm3+ocR3FZHa4twMYZEVAenuM1nF +jyRPcOiZkEDggWreGx2c11kWX9YzgHWan5Rc8hfc/SS268XffLszgiJnJ9IDbw55 +f1Q0lM3rPwKBgH/tmGnj0o0RXOZhdK+Gm9oagkWPkt9c0iJ8vvlvmVakmgEijY3U +pb2A4XJHqJyeis5B5M0dlyXhO+SalaR9CHr0hXtmaBT/dHd77O6EprlC/Ts1t87x +xV0wckjE2Z0e97iyCd9+aTCYg0cfScikH5WPA5A/q3pO6cWXtnGgS9BBAoGAPnWf +7TyTocHm4xijsSAB+RrkF+m8LnWMxwdhcUYD30eaIBku3YNTvlG6Md9JkOAps0Z9 +Le+JSH0BPuf5pUOdeKbPvzildxtEdGWXD8LEYfNo5jm1Avo1rMg3xpI+RGgWZ2kW +D0hLeA/36kClF9DIuXoY9waZBPQ66ZKof3L0cCkCgYEArvOmiVjVNQXl8lqYwb20 +o55nchUpZIDXwPCz3lQP5i5dsbHEOZaCA/IQn3Pn/mne4zeDPZYUgHSQuG8Gkq/q +IT1GM6QXpB/UmiTOQDZ33xeqMvmaMAaH450ulmpbv4/RJnEuTa6GjAetntZgEDWq +IPO659+CAKyLuJh3h7R7B3c= +-----END PRIVATE KEY-----