mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Merge pull request #37830 from sttts/sttts-stratify-cert-generation
Automatic merge from submit-queue Stratify apiserver cert generation - move self-signed cert generation to `SecureServingOptions.MaybeDefaultWithSelfSignedCerts` - make cert generation only depend on `ServerRunOptions`, not on an unfinished `Config` (this breaks the chicken-egg problem of a finished config in https://github.com/kubernetes/kubernetes/pull/35387#pullrequestreview-5368176) - move loopback client config code into `config_selfclient.go` Replaces https://github.com/kubernetes/kubernetes/pull/35387#event-833649341 by getting rid of duplicated `Complete`.
This commit is contained in:
commit
5e41d0904f
@ -35,7 +35,6 @@ go_library(
|
|||||||
"//pkg/generated/openapi:go_default_library",
|
"//pkg/generated/openapi:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/genericapiserver/authorizer:go_default_library",
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
|
||||||
"//pkg/master:go_default_library",
|
"//pkg/master:go_default_library",
|
||||||
"//pkg/registry/cachesize:go_default_library",
|
"//pkg/registry/cachesize:go_default_library",
|
||||||
"//pkg/runtime/schema:go_default_library",
|
"//pkg/runtime/schema:go_default_library",
|
||||||
|
@ -21,6 +21,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -49,7 +50,6 @@ import (
|
|||||||
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
|
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
|
||||||
"k8s.io/kubernetes/pkg/master"
|
"k8s.io/kubernetes/pkg/master"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
@ -85,20 +85,25 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
|
||||||
genericConfig := genericapiserver.NewConfig(). // create the new config
|
|
||||||
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
|
||||||
ApplySecureServingOptions(s.SecureServing).
|
|
||||||
ApplyInsecureServingOptions(s.InsecureServing).
|
|
||||||
ApplyAuthenticationOptions(s.Authentication).
|
|
||||||
ApplyRBACSuperUser(s.Authorization.RBACSuperUser)
|
|
||||||
|
|
||||||
serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange)
|
serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Error determining service IP ranges: %v", err)
|
return fmt.Errorf("error determining service IP ranges: %v", err)
|
||||||
}
|
}
|
||||||
if err := genericConfig.MaybeGenerateServingCerts(apiServerServiceIP); err != nil {
|
|
||||||
glog.Fatalf("Failed to generate service certificate: %v", err)
|
if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String(), apiServerServiceIP); err != nil {
|
||||||
|
return fmt.Errorf("error creating self-signed certificates: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
||||||
|
|
||||||
|
genericConfig, err := genericapiserver.NewConfig(). // create the new config
|
||||||
|
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
||||||
|
ApplyInsecureServingOptions(s.InsecureServing).
|
||||||
|
ApplyAuthenticationOptions(s.Authentication).
|
||||||
|
ApplyRBACSuperUser(s.Authorization.RBACSuperUser).
|
||||||
|
ApplySecureServingOptions(s.SecureServing)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to configure https: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
capabilities.Initialize(capabilities.Capabilities{
|
capabilities.Initialize(capabilities.Capabilities{
|
||||||
@ -120,7 +125,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
var installSSH genericapiserver.InstallSSHKey
|
var installSSH genericapiserver.InstallSSHKey
|
||||||
cloud, err := cloudprovider.InitCloudProvider(s.GenericServerRunOptions.CloudProvider, s.GenericServerRunOptions.CloudConfigFile)
|
cloud, err := cloudprovider.InitCloudProvider(s.GenericServerRunOptions.CloudProvider, s.GenericServerRunOptions.CloudConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Cloud provider could not be initialized: %v", err)
|
return fmt.Errorf("cloud provider could not be initialized: %v", err)
|
||||||
}
|
}
|
||||||
if cloud != nil {
|
if cloud != nil {
|
||||||
if instances, supported := cloud.Instances(); supported {
|
if instances, supported := cloud.Instances(); supported {
|
||||||
@ -128,7 +133,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.KubeletConfig.Port == 0 {
|
if s.KubeletConfig.Port == 0 {
|
||||||
glog.Fatalf("Must enable kubelet port if proxy ssh-tunneling is specified.")
|
return fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified")
|
||||||
}
|
}
|
||||||
// Set up the tunneler
|
// Set up the tunneler
|
||||||
// TODO(cjcullen): If we want this to handle per-kubelet ports or other
|
// TODO(cjcullen): If we want this to handle per-kubelet ports or other
|
||||||
@ -173,7 +178,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
|
|
||||||
storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
|
storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error generating storage version map: %s", err)
|
return fmt.Errorf("error generating storage version map: %s", err)
|
||||||
}
|
}
|
||||||
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
||||||
s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
||||||
@ -182,7 +187,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
[]schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")},
|
[]schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")},
|
||||||
master.DefaultAPIResourceConfigSource(), s.GenericServerRunOptions.RuntimeConfig)
|
master.DefaultAPIResourceConfigSource(), s.GenericServerRunOptions.RuntimeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error in initializing storage factory: %s", err)
|
return fmt.Errorf("error in initializing storage factory: %s", err)
|
||||||
}
|
}
|
||||||
storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs"))
|
storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs"))
|
||||||
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
||||||
@ -221,20 +226,20 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
// go directly to etcd to avoid recursive auth insanity
|
// go directly to etcd to avoid recursive auth insanity
|
||||||
storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts"))
|
storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Unable to get serviceaccounts storage: %v", err)
|
return fmt.Errorf("unable to get serviceaccounts storage: %v", err)
|
||||||
}
|
}
|
||||||
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
|
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
|
||||||
}
|
}
|
||||||
|
|
||||||
apiAuthenticator, securityDefinitions, err := authenticator.New(authenticatorConfig)
|
apiAuthenticator, securityDefinitions, err := authenticator.New(authenticatorConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authentication Config: %v", err)
|
return fmt.Errorf("invalid Authentication Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
privilegedLoopbackToken := uuid.NewRandom().String()
|
privilegedLoopbackToken := uuid.NewRandom().String()
|
||||||
selfClientConfig, err := genericoptions.NewSelfClientConfig(s.SecureServing, s.InsecureServing, privilegedLoopbackToken)
|
selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create clientset: %v", err)
|
return fmt.Errorf("failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
client, err := internalclientset.NewForConfig(selfClientConfig)
|
client, err := internalclientset.NewForConfig(selfClientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -245,14 +250,14 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
|
authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
|
||||||
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationConfig)
|
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authorization Config: %v", err)
|
return fmt.Errorf("invalid Authorization Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
|
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
|
||||||
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
|
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
|
||||||
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to initialize plugins: %v", err)
|
return fmt.Errorf("failed to initialize plugins: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyTransport := utilnet.SetTransportDefaults(&http.Transport{
|
proxyTransport := utilnet.SetTransportDefaults(&http.Transport{
|
||||||
|
@ -36,6 +36,8 @@ import (
|
|||||||
|
|
||||||
// Install the testgroup API
|
// Install the testgroup API
|
||||||
_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/install"
|
_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/install"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -93,20 +95,21 @@ func (serverOptions *ServerRunOptions) Run(stopCh <-chan struct{}) error {
|
|||||||
if errs := serverOptions.InsecureServing.Validate("insecure-port"); len(errs) > 0 {
|
if errs := serverOptions.InsecureServing.Validate("insecure-port"); len(errs) > 0 {
|
||||||
return utilerrors.NewAggregate(errs)
|
return utilerrors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
if err := serverOptions.SecureServing.MaybeDefaultWithSelfSignedCerts(serverOptions.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
|
||||||
|
glog.Fatalf("Error creating self-signed certificates: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
config := genericapiserver.NewConfig().
|
config, err := genericapiserver.NewConfig().
|
||||||
ApplyOptions(serverOptions.GenericServerRunOptions).
|
ApplyOptions(serverOptions.GenericServerRunOptions).
|
||||||
ApplySecureServingOptions(serverOptions.SecureServing).
|
|
||||||
ApplyInsecureServingOptions(serverOptions.InsecureServing).
|
ApplyInsecureServingOptions(serverOptions.InsecureServing).
|
||||||
ApplyAuthenticationOptions(serverOptions.Authentication).
|
ApplyAuthenticationOptions(serverOptions.Authentication).
|
||||||
Complete()
|
ApplySecureServingOptions(serverOptions.SecureServing)
|
||||||
if err := config.MaybeGenerateServingCerts(); err != nil {
|
if err != nil {
|
||||||
// this wasn't treated as fatal for this process before
|
return fmt.Errorf("failed to configure https: %s", err)
|
||||||
fmt.Printf("Error creating cert: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Authorizer = authorizer.NewAlwaysAllowAuthorizer()
|
config.Authorizer = authorizer.NewAlwaysAllowAuthorizer()
|
||||||
s, err := config.New()
|
s, err := config.Complete().New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error in bringing up the server: %v", err)
|
return fmt.Errorf("Error in bringing up the server: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ go_library(
|
|||||||
"//pkg/generated/openapi:go_default_library",
|
"//pkg/generated/openapi:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/genericapiserver/authorizer:go_default_library",
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
|
||||||
"//pkg/registry/cachesize:go_default_library",
|
"//pkg/registry/cachesize:go_default_library",
|
||||||
"//pkg/registry/core/configmap/etcd:go_default_library",
|
"//pkg/registry/core/configmap/etcd:go_default_library",
|
||||||
"//pkg/registry/core/event/etcd:go_default_library",
|
"//pkg/registry/core/event/etcd:go_default_library",
|
||||||
|
@ -20,6 +20,7 @@ limitations under the License.
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -37,7 +38,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/generated/openapi"
|
"k8s.io/kubernetes/pkg/generated/openapi"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry"
|
genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry"
|
||||||
@ -73,16 +73,19 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
|
||||||
genericConfig := genericapiserver.NewConfig(). // create the new config
|
return fmt.Errorf("error creating self-signed certificates: %v", err)
|
||||||
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
}
|
||||||
ApplySecureServingOptions(s.SecureServing).
|
|
||||||
ApplyInsecureServingOptions(s.InsecureServing).
|
|
||||||
ApplyAuthenticationOptions(s.Authentication).
|
|
||||||
ApplyRBACSuperUser(s.Authorization.RBACSuperUser)
|
|
||||||
|
|
||||||
if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
|
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
||||||
glog.Fatalf("Failed to generate service certificate: %v", err)
|
genericConfig, err := genericapiserver.NewConfig(). // create the new config
|
||||||
|
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
||||||
|
ApplyInsecureServingOptions(s.InsecureServing).
|
||||||
|
ApplyAuthenticationOptions(s.Authentication).
|
||||||
|
ApplyRBACSuperUser(s.Authorization.RBACSuperUser).
|
||||||
|
ApplySecureServingOptions(s.SecureServing)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to configure https: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: register cluster federation resources here.
|
// TODO: register cluster federation resources here.
|
||||||
@ -130,7 +133,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
privilegedLoopbackToken := uuid.NewRandom().String()
|
privilegedLoopbackToken := uuid.NewRandom().String()
|
||||||
selfClientConfig, err := genericoptions.NewSelfClientConfig(s.SecureServing, s.InsecureServing, privilegedLoopbackToken)
|
selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create clientset: %v", err)
|
glog.Fatalf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"config.go",
|
"config.go",
|
||||||
|
"config_selfclient.go",
|
||||||
"default_storage_factory_builder.go",
|
"default_storage_factory_builder.go",
|
||||||
"discovery.go",
|
"discovery.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
@ -117,6 +118,7 @@ go_test(
|
|||||||
"//pkg/storage/storagebackend:go_default_library",
|
"//pkg/storage/storagebackend:go_default_library",
|
||||||
"//pkg/util/cert:go_default_library",
|
"//pkg/util/cert:go_default_library",
|
||||||
"//pkg/util/clock:go_default_library",
|
"//pkg/util/clock:go_default_library",
|
||||||
|
"//pkg/util/config:go_default_library",
|
||||||
"//pkg/util/net:go_default_library",
|
"//pkg/util/net:go_default_library",
|
||||||
"//pkg/util/sets:go_default_library",
|
"//pkg/util/sets:go_default_library",
|
||||||
"//pkg/version:go_default_library",
|
"//pkg/version:go_default_library",
|
||||||
|
@ -17,12 +17,14 @@ limitations under the License.
|
|||||||
package genericapiserver
|
package genericapiserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
goruntime "runtime"
|
goruntime "runtime"
|
||||||
"sort"
|
"sort"
|
||||||
@ -58,7 +60,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/genericapiserver/routes"
|
"k8s.io/kubernetes/pkg/genericapiserver/routes"
|
||||||
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
|
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
|
||||||
@ -169,35 +170,21 @@ type ServingInfo struct {
|
|||||||
type SecureServingInfo struct {
|
type SecureServingInfo struct {
|
||||||
ServingInfo
|
ServingInfo
|
||||||
|
|
||||||
// ServerCert is the TLS cert info for serving secure traffic
|
// Cert is the main server cert which is used if SNI does not match. Cert must be non-nil and is
|
||||||
ServerCert GeneratableKeyCert
|
// allowed to be in SNICerts.
|
||||||
// SNICerts are named CertKeys for serving secure traffic with SNI support.
|
Cert *tls.Certificate
|
||||||
SNICerts []NamedCertKey
|
|
||||||
|
// CACert is an optional certificate authority used for the loopback connection of the Admission controllers.
|
||||||
|
// If this is nil, the certificate authority is extracted from Cert or a matching SNI certificate.
|
||||||
|
CACert *tls.Certificate
|
||||||
|
|
||||||
|
// SNICerts are the TLS certificates by name used for SNI.
|
||||||
|
SNICerts map[string]*tls.Certificate
|
||||||
|
|
||||||
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
||||||
ClientCA string
|
ClientCA string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CertKey struct {
|
|
||||||
// CertFile is a file containing a PEM-encoded certificate
|
|
||||||
CertFile string
|
|
||||||
// KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
|
|
||||||
KeyFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
type NamedCertKey struct {
|
|
||||||
CertKey
|
|
||||||
|
|
||||||
// Names is a list of domain patterns: fully qualified domain names, possibly prefixed with
|
|
||||||
// wildcard segments.
|
|
||||||
Names []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type GeneratableKeyCert struct {
|
|
||||||
CertKey
|
|
||||||
// Generate indicates that the cert/key pair should be generated if its not present.
|
|
||||||
Generate bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfig returns a Config struct with the default values
|
// NewConfig returns a Config struct with the default values
|
||||||
func NewConfig() *Config {
|
func NewConfig() *Config {
|
||||||
longRunningRE := regexp.MustCompile(options.DefaultLongRunningRequestRE)
|
longRunningRE := regexp.MustCompile(options.DefaultLongRunningRequestRE)
|
||||||
@ -238,45 +225,69 @@ func NewConfig() *Config {
|
|||||||
return config.ApplyOptions(defaultOptions)
|
return config.ApplyOptions(defaultOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) ApplySecureServingOptions(secureServing *options.SecureServingOptions) *Config {
|
func (c *Config) ApplySecureServingOptions(secureServing *options.SecureServingOptions) (*Config, error) {
|
||||||
if secureServing == nil || secureServing.ServingOptions.BindPort <= 0 {
|
if secureServing == nil || secureServing.ServingOptions.BindPort <= 0 {
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
secureServingInfo := &SecureServingInfo{
|
secureServingInfo := &SecureServingInfo{
|
||||||
ServingInfo: ServingInfo{
|
ServingInfo: ServingInfo{
|
||||||
BindAddress: net.JoinHostPort(secureServing.ServingOptions.BindAddress.String(), strconv.Itoa(secureServing.ServingOptions.BindPort)),
|
BindAddress: net.JoinHostPort(secureServing.ServingOptions.BindAddress.String(), strconv.Itoa(secureServing.ServingOptions.BindPort)),
|
||||||
},
|
},
|
||||||
ServerCert: GeneratableKeyCert{
|
|
||||||
CertKey: CertKey{
|
|
||||||
CertFile: secureServing.ServerCert.CertKey.CertFile,
|
|
||||||
KeyFile: secureServing.ServerCert.CertKey.KeyFile,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SNICerts: []NamedCertKey{},
|
|
||||||
ClientCA: secureServing.ClientCA,
|
ClientCA: secureServing.ClientCA,
|
||||||
}
|
}
|
||||||
if secureServing.ServerCert.CertKey.CertFile == "" && secureServing.ServerCert.CertKey.KeyFile == "" {
|
|
||||||
secureServingInfo.ServerCert.Generate = true
|
serverCertFile, serverKeyFile := secureServing.ServerCert.CertKey.CertFile, secureServing.ServerCert.CertKey.KeyFile
|
||||||
secureServingInfo.ServerCert.CertFile = path.Join(secureServing.ServerCert.CertDirectory, secureServing.ServerCert.PairName+".crt")
|
|
||||||
secureServingInfo.ServerCert.KeyFile = path.Join(secureServing.ServerCert.CertDirectory, secureServing.ServerCert.PairName+".key")
|
// load main cert
|
||||||
|
if len(serverCertFile) != 0 || len(serverKeyFile) != 0 {
|
||||||
|
tlsCert, err := tls.LoadX509KeyPair(serverCertFile, serverKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to load server certificate: %v", err)
|
||||||
|
}
|
||||||
|
secureServingInfo.Cert = &tlsCert
|
||||||
}
|
}
|
||||||
|
|
||||||
secureServingInfo.SNICerts = nil
|
// optionally load CA cert
|
||||||
for _, nkc := range secureServing.SNICertKeys {
|
if len(secureServing.ServerCert.CACertFile) != 0 {
|
||||||
secureServingInfo.SNICerts = append(secureServingInfo.SNICerts, NamedCertKey{
|
pemData, err := ioutil.ReadFile(secureServing.ServerCert.CACertFile)
|
||||||
CertKey: CertKey{
|
if err != nil {
|
||||||
KeyFile: nkc.KeyFile,
|
return nil, fmt.Errorf("failed to read certificate authority from %q: %v", secureServing.ServerCert.CACertFile, err)
|
||||||
CertFile: nkc.CertFile,
|
}
|
||||||
},
|
block, pemData := pem.Decode(pemData)
|
||||||
Names: nkc.Names,
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("no certificate found in certificate authority file %q", secureServing.ServerCert.CACertFile)
|
||||||
|
}
|
||||||
|
if block.Type != "CERTIFICATE" {
|
||||||
|
return nil, fmt.Errorf("expected CERTIFICATE block in certiticate authority file %q, found: %s", secureServing.ServerCert.CACertFile, block.Type)
|
||||||
|
}
|
||||||
|
secureServingInfo.CACert = &tls.Certificate{
|
||||||
|
Certificate: [][]byte{block.Bytes},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load SNI certs
|
||||||
|
namedTlsCerts := make([]namedTlsCert, 0, len(secureServing.SNICertKeys))
|
||||||
|
for _, nck := range secureServing.SNICertKeys {
|
||||||
|
tlsCert, err := tls.LoadX509KeyPair(nck.CertFile, nck.KeyFile)
|
||||||
|
namedTlsCerts = append(namedTlsCerts, namedTlsCert{
|
||||||
|
tlsCert: tlsCert,
|
||||||
|
names: nck.Names,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load SNI cert and key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
secureServingInfo.SNICerts, err = getNamedCertificateMap(namedTlsCerts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SecureServingInfo = secureServingInfo
|
c.SecureServingInfo = secureServingInfo
|
||||||
c.ReadWritePort = secureServing.ServingOptions.BindPort
|
c.ReadWritePort = secureServing.ServingOptions.BindPort
|
||||||
|
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) ApplyInsecureServingOptions(insecureServing *options.ServingOptions) *Config {
|
func (c *Config) ApplyInsecureServingOptions(insecureServing *options.ServingOptions) *Config {
|
||||||
@ -456,38 +467,6 @@ func (c completedConfig) New() (*GenericAPIServer, error) {
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaybeGenerateServingCerts generates serving certificates if requested and needed.
|
|
||||||
func (c *Config) MaybeGenerateServingCerts(alternateIPs ...net.IP) error {
|
|
||||||
// It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
|
||||||
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
|
||||||
if c.SecureServingInfo != nil && c.SecureServingInfo.ServerCert.Generate {
|
|
||||||
canReadCertAndKey, err := certutil.CanReadCertAndKey(c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if canReadCertAndKey {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// TODO (cjcullen): Is ClusterIP the right address to sign a cert with?
|
|
||||||
alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"}
|
|
||||||
|
|
||||||
if cert, key, err := certutil.GenerateSelfSignedCertKey(c.PublicAddress.String(), alternateIPs, alternateDNS); err != nil {
|
|
||||||
return fmt.Errorf("unable to generate self signed cert: %v", err)
|
|
||||||
} else {
|
|
||||||
if err := certutil.WriteCert(c.SecureServingInfo.ServerCert.CertFile, cert); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := certutil.WriteKey(c.SecureServingInfo.ServerCert.KeyFile, key); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
glog.Infof("Generated self-signed cert (%s, %s)", c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) (secure, insecure http.Handler) {
|
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) (secure, insecure http.Handler) {
|
||||||
generic := func(handler http.Handler) http.Handler {
|
generic := func(handler http.Handler) http.Handler {
|
||||||
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
|
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
|
||||||
|
138
pkg/genericapiserver/config_selfclient.go
Normal file
138
pkg/genericapiserver/config_selfclient.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package genericapiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewSelfClientConfig returns a clientconfig which can be used to talk to this apiserver.
|
||||||
|
func NewSelfClientConfig(secureServingInfo *SecureServingInfo, insecureServingInfo *ServingInfo, token string) (*restclient.Config, error) {
|
||||||
|
if cfg, err := secureServingInfo.NewSelfClientConfig(token); err != nil || cfg != nil {
|
||||||
|
if insecureServingInfo == nil {
|
||||||
|
// be fatal if insecure port is not available
|
||||||
|
return cfg, err
|
||||||
|
} else {
|
||||||
|
glog.Warningf("Failed to create secure local client, falling back to insecure local connection: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg, err := insecureServingInfo.NewSelfClientConfig(token); err != nil || cfg != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("Unable to set url for apiserver local client")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SecureServingInfo) NewSelfClientConfig(token string) (*restclient.Config, error) {
|
||||||
|
if s == nil || (s.Cert == nil && len(s.SNICerts) == 0) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
host, port, err := net.SplitHostPort(s.ServingInfo.BindAddress)
|
||||||
|
if err != nil {
|
||||||
|
// should never happen
|
||||||
|
return nil, fmt.Errorf("invalid secure bind address: %q", s.ServingInfo.BindAddress)
|
||||||
|
}
|
||||||
|
if host == "0.0.0.0" {
|
||||||
|
// compare MaybeDefaultWithSelfSignedCerts which adds "localhost" to the cert as alternateDNS
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig := &restclient.Config{
|
||||||
|
// Increase QPS limits. The client is currently passed to all admission plugins,
|
||||||
|
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
||||||
|
// for more details. Once #22422 is fixed, we may want to remove it.
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
Host: "https://" + net.JoinHostPort(host, port),
|
||||||
|
BearerToken: token,
|
||||||
|
}
|
||||||
|
|
||||||
|
// find certificate for host: either explicitly given, from the server cert bundle or one of the SNI certs
|
||||||
|
var derCA []byte
|
||||||
|
if s.CACert != nil {
|
||||||
|
derCA = s.CACert.Certificate[0]
|
||||||
|
}
|
||||||
|
if derCA == nil && s.Cert != nil {
|
||||||
|
x509Cert, err := x509.ParseCertificate(s.Cert.Certificate[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse server certificate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net.ParseIP(host) != nil && certMatchesIP(x509Cert, host)) || certMatchesName(x509Cert, host) {
|
||||||
|
derCA = s.Cert.Certificate[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if derCA == nil && net.ParseIP(host) == nil {
|
||||||
|
if cert, found := s.SNICerts[host]; found {
|
||||||
|
derCA = cert.Certificate[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if derCA == nil {
|
||||||
|
return nil, fmt.Errorf("failed to find certificate which matches %q", host)
|
||||||
|
}
|
||||||
|
pemCA := bytes.Buffer{}
|
||||||
|
if err := pem.Encode(&pemCA, &pem.Block{Type: "CERTIFICATE", Bytes: derCA}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientConfig.CAData = pemCA.Bytes()
|
||||||
|
|
||||||
|
return clientConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServingInfo) NewSelfClientConfig(token string) (*restclient.Config, error) {
|
||||||
|
if s == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &restclient.Config{
|
||||||
|
Host: s.BindAddress,
|
||||||
|
// Increase QPS limits. The client is currently passed to all admission plugins,
|
||||||
|
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
||||||
|
// for more details. Once #22422 is fixed, we may want to remove it.
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func certMatchesName(cert *x509.Certificate, name string) bool {
|
||||||
|
for _, certName := range cert.DNSNames {
|
||||||
|
if certName == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func certMatchesIP(cert *x509.Certificate, ip string) bool {
|
||||||
|
for _, certIP := range cert.IPAddresses {
|
||||||
|
if certIP.String() == ip {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -28,14 +28,15 @@ go_library(
|
|||||||
"//pkg/apiserver/authenticator:go_default_library",
|
"//pkg/apiserver/authenticator:go_default_library",
|
||||||
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
|
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1:go_default_library",
|
"//pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1:go_default_library",
|
||||||
"//pkg/client/restclient:go_default_library",
|
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||||
"//pkg/controller/informers:go_default_library",
|
"//pkg/controller/informers:go_default_library",
|
||||||
"//pkg/genericapiserver/authorizer:go_default_library",
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/runtime/schema:go_default_library",
|
"//pkg/runtime/schema:go_default_library",
|
||||||
"//pkg/storage/storagebackend:go_default_library",
|
"//pkg/storage/storagebackend:go_default_library",
|
||||||
|
"//pkg/util/cert:go_default_library",
|
||||||
"//pkg/util/config:go_default_library",
|
"//pkg/util/config:go_default_library",
|
||||||
"//pkg/util/net:go_default_library",
|
"//pkg/util/net:go_default_library",
|
||||||
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:github.com/spf13/pflag",
|
"//vendor:github.com/spf13/pflag",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -75,7 +75,6 @@ type ServerRunOptions struct {
|
|||||||
// for testing). This is not actually exposed as a flag.
|
// for testing). This is not actually exposed as a flag.
|
||||||
DefaultStorageVersions string
|
DefaultStorageVersions string
|
||||||
TargetRAMMB int
|
TargetRAMMB int
|
||||||
TLSCAFile string
|
|
||||||
WatchCacheSizes []string
|
WatchCacheSizes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +17,14 @@ limitations under the License.
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"path"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||||
"k8s.io/kubernetes/pkg/util/config"
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
)
|
)
|
||||||
@ -43,14 +43,10 @@ type SecureServingOptions struct {
|
|||||||
SNICertKeys []config.NamedCertKey
|
SNICertKeys []config.NamedCertKey
|
||||||
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
||||||
ClientCA string
|
ClientCA string
|
||||||
|
|
||||||
// ServerCA is the certificate bundle for the signer of your serving certificate. Used for building a loopback
|
|
||||||
// connection to the API server for admission.
|
|
||||||
ServerCA string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CertKey struct {
|
type CertKey struct {
|
||||||
// CertFile is a file containing a PEM-encoded certificate
|
// CertFile is a file containing a PEM-encoded certificate, and possibly the complete certificate chain
|
||||||
CertFile string
|
CertFile string
|
||||||
// KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
|
// KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
|
||||||
KeyFile string
|
KeyFile string
|
||||||
@ -59,6 +55,8 @@ type CertKey struct {
|
|||||||
type GeneratableKeyCert struct {
|
type GeneratableKeyCert struct {
|
||||||
CertKey CertKey
|
CertKey CertKey
|
||||||
|
|
||||||
|
// CACertFile is an optional file containing the certificate chain for CertKey.CertFile
|
||||||
|
CACertFile string
|
||||||
// CertDirectory is a directory that will contain the certificates. If the cert and key aren't specifically set
|
// CertDirectory is a directory that will contain the certificates. If the cert and key aren't specifically set
|
||||||
// this will be used to derive a match with the "pair-name"
|
// this will be used to derive a match with the "pair-name"
|
||||||
CertDirectory string
|
CertDirectory string
|
||||||
@ -80,31 +78,6 @@ func NewSecureServingOptions() *SecureServingOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SecureServingOptions) NewSelfClientConfig(token string) *restclient.Config {
|
|
||||||
if s == nil || s.ServingOptions.BindPort <= 0 || len(s.ServerCA) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
clientConfig := &restclient.Config{
|
|
||||||
// Increase QPS limits. The client is currently passed to all admission plugins,
|
|
||||||
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
|
||||||
// for more details. Once #22422 is fixed, we may want to remove it.
|
|
||||||
QPS: 50,
|
|
||||||
Burst: 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use secure port if the ServerCA is specified
|
|
||||||
host := s.ServingOptions.BindAddress.String()
|
|
||||||
if host == "0.0.0.0" {
|
|
||||||
host = "localhost"
|
|
||||||
}
|
|
||||||
clientConfig.Host = "https://" + net.JoinHostPort(host, strconv.Itoa(s.ServingOptions.BindPort))
|
|
||||||
clientConfig.CAFile = s.ServerCA
|
|
||||||
clientConfig.BearerToken = token
|
|
||||||
|
|
||||||
return clientConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SecureServingOptions) Validate() []error {
|
func (s *SecureServingOptions) Validate() []error {
|
||||||
errors := []error{}
|
errors := []error{}
|
||||||
if s == nil {
|
if s == nil {
|
||||||
@ -138,6 +111,11 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
|||||||
fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile,
|
fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile,
|
||||||
"File containing the default x509 private key matching --tls-cert-file.")
|
"File containing the default x509 private key matching --tls-cert-file.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ServerCert.CACertFile, "tls-ca-file", s.ServerCert.CACertFile, "If set, this "+
|
||||||
|
"certificate authority will used for secure access from Admission "+
|
||||||
|
"Controllers. This must be a valid PEM-encoded CA bundle. Altneratively, the certificate authority "+
|
||||||
|
"can be appended to the certificate provided by --tls-cert-file.")
|
||||||
|
|
||||||
fs.Var(config.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
fs.Var(config.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
||||||
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
||||||
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
||||||
@ -151,18 +129,12 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
|||||||
"If set, any request presenting a client certificate signed by one of "+
|
"If set, any request presenting a client certificate signed by one of "+
|
||||||
"the authorities in the client-ca-file is authenticated with an identity "+
|
"the authorities in the client-ca-file is authenticated with an identity "+
|
||||||
"corresponding to the CommonName of the client certificate.")
|
"corresponding to the CommonName of the client certificate.")
|
||||||
|
|
||||||
fs.StringVar(&s.ServerCA, "tls-ca-file", s.ServerCA, "If set, this "+
|
|
||||||
"certificate authority will used for secure access from Admission "+
|
|
||||||
"Controllers. This must be a valid PEM-encoded CA bundle.")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SecureServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
func (s *SecureServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||||
fs.IPVar(&s.ServingOptions.BindAddress, "public-address-override", s.ServingOptions.BindAddress,
|
fs.IPVar(&s.ServingOptions.BindAddress, "public-address-override", s.ServingOptions.BindAddress,
|
||||||
"DEPRECATED: see --bind-address instead.")
|
"DEPRECATED: see --bind-address instead.")
|
||||||
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInsecureServingOptions() *ServingOptions {
|
func NewInsecureServingOptions() *ServingOptions {
|
||||||
@ -182,23 +154,6 @@ func (s ServingOptions) Validate(portArg string) []error {
|
|||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServingOptions) NewSelfClientConfig(token string) *restclient.Config {
|
|
||||||
if s == nil || s.BindPort <= 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
clientConfig := &restclient.Config{
|
|
||||||
// Increase QPS limits. The client is currently passed to all admission plugins,
|
|
||||||
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
|
||||||
// for more details. Once #22422 is fixed, we may want to remove it.
|
|
||||||
QPS: 50,
|
|
||||||
Burst: 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
clientConfig.Host = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.BindPort))
|
|
||||||
|
|
||||||
return clientConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServingOptions) DefaultExternalAddress() (net.IP, error) {
|
func (s *ServingOptions) DefaultExternalAddress() (net.IP, error) {
|
||||||
return utilnet.ChooseBindAddress(s.BindAddress)
|
return utilnet.ChooseBindAddress(s.BindAddress)
|
||||||
}
|
}
|
||||||
@ -224,14 +179,47 @@ func (s *ServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
|||||||
fs.MarkDeprecated("port", "see --insecure-port instead.")
|
fs.MarkDeprecated("port", "see --insecure-port instead.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a clientconfig which can be used to talk to this apiserver.
|
func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress string, alternateIPs ...net.IP) error {
|
||||||
func NewSelfClientConfig(secureServingOptions *SecureServingOptions, insecureServingOptions *ServingOptions, token string) (*restclient.Config, error) {
|
keyCert := &s.ServerCert.CertKey
|
||||||
if cfg := secureServingOptions.NewSelfClientConfig(token); cfg != nil {
|
|
||||||
return cfg, nil
|
if s == nil || len(keyCert.CertFile) != 0 || len(keyCert.KeyFile) != 0 {
|
||||||
}
|
return nil
|
||||||
if cfg := insecureServingOptions.NewSelfClientConfig(token); cfg != nil {
|
|
||||||
return cfg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("Unable to set url for apiserver local client")
|
keyCert.CertFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".crt")
|
||||||
|
keyCert.KeyFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".key")
|
||||||
|
|
||||||
|
canReadCertAndKey, err := certutil.CanReadCertAndKey(keyCert.CertFile, keyCert.KeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !canReadCertAndKey {
|
||||||
|
// TODO: It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
||||||
|
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
||||||
|
// TODO (cjcullen): Is ClusterIP the right address to sign a cert with?
|
||||||
|
alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}
|
||||||
|
|
||||||
|
// add either the bind address or localhost to the valid alternates
|
||||||
|
bindIP := s.ServingOptions.BindAddress.String()
|
||||||
|
if bindIP == "0.0.0.0" {
|
||||||
|
alternateDNS = append(alternateDNS, "localhost")
|
||||||
|
} else {
|
||||||
|
alternateIPs = append(alternateIPs, s.ServingOptions.BindAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cert, key, err := certutil.GenerateSelfSignedCertKey(publicAddress, alternateIPs, alternateDNS); err != nil {
|
||||||
|
return fmt.Errorf("unable to generate self signed cert: %v", err)
|
||||||
|
} else {
|
||||||
|
if err := certutil.WriteCert(keyCert.CertFile, cert); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := certutil.WriteKey(keyCert.KeyFile, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.Infof("Generated self-signed cert (%s, %s)", keyCert.CertFile, keyCert.KeyFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -42,17 +42,12 @@ const (
|
|||||||
// be loaded or the initial listen call fails. The actual server loop (stoppable by closing
|
// be loaded or the initial listen call fails. The actual server loop (stoppable by closing
|
||||||
// stopCh) runs in a go routine, i.e. serveSecurely does not block.
|
// stopCh) runs in a go routine, i.e. serveSecurely does not block.
|
||||||
func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
|
func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
|
||||||
namedCerts, err := getNamedCertificateMap(s.SecureServingInfo.SNICerts)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to load SNI certificates: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
secureServer := &http.Server{
|
secureServer := &http.Server{
|
||||||
Addr: s.SecureServingInfo.BindAddress,
|
Addr: s.SecureServingInfo.BindAddress,
|
||||||
Handler: s.Handler,
|
Handler: s.Handler,
|
||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
TLSConfig: &tls.Config{
|
TLSConfig: &tls.Config{
|
||||||
NameToCertificate: namedCerts,
|
NameToCertificate: s.SecureServingInfo.SNICerts,
|
||||||
// Can't use SSLv3 because of POODLE and BEAST
|
// Can't use SSLv3 because of POODLE and BEAST
|
||||||
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
||||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||||
@ -62,19 +57,15 @@ func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.SecureServingInfo.ServerCert.CertFile) != 0 || len(s.SecureServingInfo.ServerCert.KeyFile) != 0 {
|
if s.SecureServingInfo.Cert != nil {
|
||||||
secureServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
|
secureServer.TLSConfig.Certificates = []tls.Certificate{*s.SecureServingInfo.Cert}
|
||||||
secureServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(s.SecureServingInfo.ServerCert.CertFile, s.SecureServingInfo.ServerCert.KeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to load server certificate: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// append all named certs. Otherwise, the go tls stack will think no SNI processing
|
// append all named certs. Otherwise, the go tls stack will think no SNI processing
|
||||||
// is necessary because there is only one cert anyway.
|
// is necessary because there is only one cert anyway.
|
||||||
// Moreover, if ServerCert.CertFile/ServerCert.KeyFile are not set, the first SNI
|
// Moreover, if ServerCert.CertFile/ServerCert.KeyFile are not set, the first SNI
|
||||||
// cert will become the default cert. That's what we expect anyway.
|
// cert will become the default cert. That's what we expect anyway.
|
||||||
for _, c := range namedCerts {
|
for _, c := range s.SecureServingInfo.SNICerts {
|
||||||
secureServer.TLSConfig.Certificates = append(secureServer.TLSConfig.Certificates, *c)
|
secureServer.TLSConfig.Certificates = append(secureServer.TLSConfig.Certificates, *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +82,7 @@ func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Serving securely on %s", s.SecureServingInfo.BindAddress)
|
glog.Infof("Serving securely on %s", s.SecureServingInfo.BindAddress)
|
||||||
|
var err error
|
||||||
s.effectiveSecurePort, err = runServer(secureServer, s.SecureServingInfo.BindNetwork, stopCh)
|
s.effectiveSecurePort, err = runServer(secureServer, s.SecureServingInfo.BindNetwork, stopCh)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -186,48 +178,40 @@ func runServer(server *http.Server, network string, stopCh <-chan struct{}) (int
|
|||||||
return tcpAddr.Port, nil
|
return tcpAddr.Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNamedCertificateMap returns a map of strings to *tls.Certificate, suitable for use in
|
type namedTlsCert struct {
|
||||||
// tls.Config#NamedCertificates. Returns an error if any of the certs cannot be loaded.
|
tlsCert tls.Certificate
|
||||||
// Returns nil if len(namedCertKeys) == 0
|
|
||||||
func getNamedCertificateMap(namedCertKeys []NamedCertKey) (map[string]*tls.Certificate, error) {
|
|
||||||
if len(namedCertKeys) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// load keys
|
// names is a list of domain patterns: fully qualified domain names, possibly prefixed with
|
||||||
tlsCerts := make([]tls.Certificate, len(namedCertKeys))
|
// wildcard segments.
|
||||||
for i := range namedCertKeys {
|
names []string
|
||||||
var err error
|
}
|
||||||
nkc := &namedCertKeys[i]
|
|
||||||
tlsCerts[i], err = tls.LoadX509KeyPair(nkc.CertFile, nkc.KeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// getNamedCertificateMap returns a map of *tls.Certificate by name. It's is
|
||||||
|
// suitable for use in tls.Config#NamedCertificates. Returns an error if any of the certs
|
||||||
|
// cannot be loaded. Returns nil if len(certs) == 0
|
||||||
|
func getNamedCertificateMap(certs []namedTlsCert) (map[string]*tls.Certificate, error) {
|
||||||
// register certs with implicit names first, reverse order such that earlier trump over the later
|
// register certs with implicit names first, reverse order such that earlier trump over the later
|
||||||
tlsCertsByName := map[string]*tls.Certificate{}
|
byName := map[string]*tls.Certificate{}
|
||||||
for i := len(namedCertKeys) - 1; i >= 0; i-- {
|
for i := len(certs) - 1; i >= 0; i-- {
|
||||||
nkc := &namedCertKeys[i]
|
if len(certs[i].names) > 0 {
|
||||||
if len(nkc.Names) > 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cert := &tlsCerts[i]
|
cert := &certs[i].tlsCert
|
||||||
|
|
||||||
// read names from certificate common names and DNS names
|
// read names from certificate common names and DNS names
|
||||||
if len(cert.Certificate) == 0 {
|
if len(cert.Certificate) == 0 {
|
||||||
return nil, fmt.Errorf("no certificate found in %q", nkc.CertFile)
|
return nil, fmt.Errorf("empty SNI certificate, skipping")
|
||||||
}
|
}
|
||||||
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse error for certificate in %q: %v", nkc.CertFile, err)
|
return nil, fmt.Errorf("parse error for SNI certificate: %v", err)
|
||||||
}
|
}
|
||||||
cn := x509Cert.Subject.CommonName
|
cn := x509Cert.Subject.CommonName
|
||||||
if cn == "*" || len(validation.IsDNS1123Subdomain(strings.TrimPrefix(cn, "*."))) == 0 {
|
if cn == "*" || len(validation.IsDNS1123Subdomain(strings.TrimPrefix(cn, "*."))) == 0 {
|
||||||
tlsCertsByName[cn] = cert
|
byName[cn] = cert
|
||||||
}
|
}
|
||||||
for _, san := range x509Cert.DNSNames {
|
for _, san := range x509Cert.DNSNames {
|
||||||
tlsCertsByName[san] = cert
|
byName[san] = cert
|
||||||
}
|
}
|
||||||
// intentionally all IPs in the cert are ignored as SNI forbids passing IPs
|
// intentionally all IPs in the cert are ignored as SNI forbids passing IPs
|
||||||
// to select a cert. Before go 1.6 the tls happily passed IPs as SNI values.
|
// to select a cert. Before go 1.6 the tls happily passed IPs as SNI values.
|
||||||
@ -235,17 +219,14 @@ func getNamedCertificateMap(namedCertKeys []NamedCertKey) (map[string]*tls.Certi
|
|||||||
|
|
||||||
// register certs with explicit names last, overwriting every of the implicit ones,
|
// register certs with explicit names last, overwriting every of the implicit ones,
|
||||||
// again in reverse order.
|
// again in reverse order.
|
||||||
for i := len(namedCertKeys) - 1; i >= 0; i-- {
|
for i := len(certs) - 1; i >= 0; i-- {
|
||||||
nkc := &namedCertKeys[i]
|
namedCert := &certs[i]
|
||||||
if len(nkc.Names) == 0 {
|
for _, name := range namedCert.names {
|
||||||
continue
|
byName[name] = &certs[i].tlsCert
|
||||||
}
|
|
||||||
for _, name := range nkc.Names {
|
|
||||||
tlsCertsByName[name] = &tlsCerts[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tlsCertsByName, nil
|
return byName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||||
|
@ -20,15 +20,18 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
utilcert "k8s.io/kubernetes/pkg/util/cert"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||||
|
utilcert "k8s.io/kubernetes/pkg/util/cert"
|
||||||
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestCertSpec struct {
|
type TestCertSpec struct {
|
||||||
@ -41,47 +44,6 @@ type NamedTestCertSpec struct {
|
|||||||
explicitNames []string // as --tls-sni-cert-key explicit names
|
explicitNames []string // as --tls-sni-cert-key explicit names
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestCerts(spec TestCertSpec) (certFilePath, keyFilePath string, err error) {
|
|
||||||
var ips []net.IP
|
|
||||||
for _, ip := range spec.ips {
|
|
||||||
ips = append(ips, net.ParseIP(ip))
|
|
||||||
}
|
|
||||||
|
|
||||||
certPem, keyPem, err := utilcert.GenerateSelfSignedCertKey(spec.host, ips, spec.names)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
certFile, err := ioutil.TempFile(os.TempDir(), "cert")
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
keyFile, err := ioutil.TempFile(os.TempDir(), "key")
|
|
||||||
if err != nil {
|
|
||||||
os.Remove(certFile.Name())
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = certFile.Write(certPem)
|
|
||||||
if err != nil {
|
|
||||||
os.Remove(certFile.Name())
|
|
||||||
os.Remove(keyFile.Name())
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
certFile.Close()
|
|
||||||
|
|
||||||
_, err = keyFile.Write(keyPem)
|
|
||||||
if err != nil {
|
|
||||||
os.Remove(certFile.Name())
|
|
||||||
os.Remove(keyFile.Name())
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
keyFile.Close()
|
|
||||||
|
|
||||||
return certFile.Name(), keyFile.Name(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetNamedCertificateMap(t *testing.T) {
|
func TestGetNamedCertificateMap(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
certs []NamedTestCertSpec
|
certs []NamedTestCertSpec
|
||||||
@ -225,26 +187,21 @@ func TestGetNamedCertificateMap(t *testing.T) {
|
|||||||
|
|
||||||
NextTest:
|
NextTest:
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
var namedCertKeys []NamedCertKey
|
var namedTLSCerts []namedTlsCert
|
||||||
bySignature := map[string]int{} // index in test.certs by cert signature
|
bySignature := map[string]int{} // index in test.certs by cert signature
|
||||||
for j, c := range test.certs {
|
for j, c := range test.certs {
|
||||||
certFile, keyFile, err := createTestCerts(c.TestCertSpec)
|
cert, err := createTestTLSCerts(c.TestCertSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed to create cert %d: %v", i, j, err)
|
t.Errorf("%d - failed to create cert %d: %v", i, j, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
}
|
}
|
||||||
defer os.Remove(certFile)
|
|
||||||
defer os.Remove(keyFile)
|
|
||||||
|
|
||||||
namedCertKeys = append(namedCertKeys, NamedCertKey{
|
namedTLSCerts = append(namedTLSCerts, namedTlsCert{
|
||||||
CertKey: CertKey{
|
tlsCert: cert,
|
||||||
KeyFile: keyFile,
|
names: c.explicitNames,
|
||||||
CertFile: certFile,
|
|
||||||
},
|
|
||||||
Names: c.explicitNames,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
sig, err := certFileSignature(certFile, keyFile)
|
sig, err := certSignature(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed to get signature for %d: %v", i, j, err)
|
t.Errorf("%d - failed to get signature for %d: %v", i, j, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
@ -252,7 +209,7 @@ NextTest:
|
|||||||
bySignature[sig] = j
|
bySignature[sig] = j
|
||||||
}
|
}
|
||||||
|
|
||||||
certMap, err := getNamedCertificateMap(namedCertKeys)
|
certMap, err := getNamedCertificateMap(namedTLSCerts)
|
||||||
if err == nil && len(test.errorString) != 0 {
|
if err == nil && len(test.errorString) != 0 {
|
||||||
t.Errorf("%d - expected no error, got: %v", i, err)
|
t.Errorf("%d - expected no error, got: %v", i, err)
|
||||||
} else if err != nil && err.Error() != test.errorString {
|
} else if err != nil && err.Error() != test.errorString {
|
||||||
@ -363,19 +320,30 @@ func TestServerRunWithSNI(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tempDir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
|
||||||
NextTest:
|
NextTest:
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// create server cert
|
// create server cert
|
||||||
serverCertFile, serverKeyFile, err := createTestCerts(test.Cert)
|
serverCertBundleFile, serverKeyFile, err := createTestCertFiles(tempDir, test.Cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed to create server cert: %v", i, err)
|
t.Errorf("%d - failed to create server cert: %v", i, err)
|
||||||
|
continue NextTest
|
||||||
}
|
}
|
||||||
defer os.Remove(serverCertFile)
|
ca, err := caCertFromBundle(serverCertBundleFile)
|
||||||
defer os.Remove(serverKeyFile)
|
if err != nil {
|
||||||
|
t.Errorf("%d - failed to extract ca cert from server cert bundle: %v", i, err)
|
||||||
|
continue NextTest
|
||||||
|
}
|
||||||
|
caCerts := []*x509.Certificate{ca}
|
||||||
|
|
||||||
// create SNI certs
|
// create SNI certs
|
||||||
var namedCertKeys []NamedCertKey
|
var namedCertKeys []config.NamedCertKey
|
||||||
serverSig, err := certFileSignature(serverCertFile, serverKeyFile)
|
serverSig, err := certFileSignature(serverCertBundleFile, serverKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed to get server cert signature: %v", i, err)
|
t.Errorf("%d - failed to get server cert signature: %v", i, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
@ -384,24 +352,27 @@ NextTest:
|
|||||||
serverSig: -1,
|
serverSig: -1,
|
||||||
}
|
}
|
||||||
for j, c := range test.SNICerts {
|
for j, c := range test.SNICerts {
|
||||||
certFile, keyFile, err := createTestCerts(c.TestCertSpec)
|
certBundleFile, keyFile, err := createTestCertFiles(tempDir, c.TestCertSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed to create SNI cert %d: %v", i, j, err)
|
t.Errorf("%d - failed to create SNI cert %d: %v", i, j, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
}
|
}
|
||||||
defer os.Remove(certFile)
|
|
||||||
defer os.Remove(keyFile)
|
|
||||||
|
|
||||||
namedCertKeys = append(namedCertKeys, NamedCertKey{
|
namedCertKeys = append(namedCertKeys, config.NamedCertKey{
|
||||||
CertKey: CertKey{
|
KeyFile: keyFile,
|
||||||
KeyFile: keyFile,
|
CertFile: certBundleFile,
|
||||||
CertFile: certFile,
|
Names: c.explicitNames,
|
||||||
},
|
|
||||||
Names: c.explicitNames,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ca, err := caCertFromBundle(certBundleFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d - failed to extract ca cert from SNI cert %d: %v", i, j, err)
|
||||||
|
continue NextTest
|
||||||
|
}
|
||||||
|
caCerts = append(caCerts, ca)
|
||||||
|
|
||||||
// store index in namedCertKeys with the signature as the key
|
// store index in namedCertKeys with the signature as the key
|
||||||
sig, err := certFileSignature(certFile, keyFile)
|
sig, err := certFileSignature(certBundleFile, keyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d - failed get SNI cert %d signature: %v", i, j, err)
|
t.Errorf("%d - failed get SNI cert %d signature: %v", i, j, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
@ -416,17 +387,22 @@ NextTest:
|
|||||||
defer etcdserver.Terminate(t)
|
defer etcdserver.Terminate(t)
|
||||||
|
|
||||||
config.EnableIndex = true
|
config.EnableIndex = true
|
||||||
config.SecureServingInfo = &SecureServingInfo{
|
_, err = config.ApplySecureServingOptions(&options.SecureServingOptions{
|
||||||
ServingInfo: ServingInfo{
|
ServingOptions: options.ServingOptions{
|
||||||
BindAddress: "localhost:0",
|
BindAddress: net.ParseIP("127.0.0.1"),
|
||||||
|
BindPort: 6443,
|
||||||
},
|
},
|
||||||
ServerCert: GeneratableKeyCert{
|
ServerCert: options.GeneratableKeyCert{
|
||||||
CertKey: CertKey{
|
CertKey: options.CertKey{
|
||||||
CertFile: serverCertFile,
|
CertFile: serverCertBundleFile,
|
||||||
KeyFile: serverKeyFile,
|
KeyFile: serverKeyFile,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SNICerts: namedCertKeys,
|
SNICertKeys: namedCertKeys,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d - failed applying the SecureServingOptions: %v", i, err)
|
||||||
|
continue NextTest
|
||||||
}
|
}
|
||||||
config.InsecureServingInfo = nil
|
config.InsecureServingInfo = nil
|
||||||
|
|
||||||
@ -436,27 +412,18 @@ NextTest:
|
|||||||
continue NextTest
|
continue NextTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// patch in a 0-port to enable auto port allocation
|
||||||
|
s.SecureServingInfo.BindAddress = "127.0.0.1:0"
|
||||||
|
|
||||||
if err := s.serveSecurely(stopCh); err != nil {
|
if err := s.serveSecurely(stopCh); err != nil {
|
||||||
t.Errorf("%d - failed running the server: %v", i, err)
|
t.Errorf("%d - failed running the server: %v", i, err)
|
||||||
continue NextTest
|
continue NextTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// load certificates into a pool
|
// load ca certificates into a pool
|
||||||
roots := x509.NewCertPool()
|
roots := x509.NewCertPool()
|
||||||
certFiles := []string{serverCertFile}
|
for _, caCert := range caCerts {
|
||||||
for _, c := range namedCertKeys {
|
roots.AddCert(caCert)
|
||||||
certFiles = append(certFiles, c.CertFile)
|
|
||||||
}
|
|
||||||
for _, certFile := range certFiles {
|
|
||||||
bs, err := ioutil.ReadFile(certFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%d - error reading %q: %v", i, certFile, err)
|
|
||||||
continue NextTest
|
|
||||||
}
|
|
||||||
if ok := roots.AppendCertsFromPEM(bs); !ok {
|
|
||||||
t.Errorf("%d - error adding cert %q to the pool", i, certFile)
|
|
||||||
continue NextTest
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to dial
|
// try to dial
|
||||||
@ -485,6 +452,77 @@ NextTest:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseIPList(ips []string) []net.IP {
|
||||||
|
var netIPs []net.IP
|
||||||
|
for _, ip := range ips {
|
||||||
|
netIPs = append(netIPs, net.ParseIP(ip))
|
||||||
|
}
|
||||||
|
return netIPs
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestTLSCerts(spec TestCertSpec) (tlsCert tls.Certificate, err error) {
|
||||||
|
certPem, keyPem, err := utilcert.GenerateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names)
|
||||||
|
if err != nil {
|
||||||
|
return tlsCert, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsCert, err = tls.X509KeyPair(certPem, keyPem)
|
||||||
|
return tlsCert, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestCertFiles(dir string, spec TestCertSpec) (certFilePath, keyFilePath string, err error) {
|
||||||
|
certPem, keyPem, err := utilcert.GenerateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
certFile, err := ioutil.TempFile(dir, "cert")
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
keyFile, err := ioutil.TempFile(dir, "key")
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = certFile.Write(certPem)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
certFile.Close()
|
||||||
|
|
||||||
|
_, err = keyFile.Write(keyPem)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
keyFile.Close()
|
||||||
|
|
||||||
|
return certFile.Name(), keyFile.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func caCertFromBundle(bundlePath string) (*x509.Certificate, error) {
|
||||||
|
pemData, err := ioutil.ReadFile(bundlePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch last block
|
||||||
|
var block *pem.Block
|
||||||
|
for {
|
||||||
|
var nextBlock *pem.Block
|
||||||
|
nextBlock, pemData = pem.Decode(pemData)
|
||||||
|
if nextBlock == nil {
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("no certificate found in %q", bundlePath)
|
||||||
|
|
||||||
|
}
|
||||||
|
return x509.ParseCertificate(block.Bytes)
|
||||||
|
}
|
||||||
|
block = nextBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func x509CertSignature(cert *x509.Certificate) string {
|
func x509CertSignature(cert *x509.Certificate) string {
|
||||||
return base64.StdEncoding.EncodeToString(cert.Signature)
|
return base64.StdEncoding.EncodeToString(cert.Signature)
|
||||||
}
|
}
|
||||||
@ -494,13 +532,13 @@ func certFileSignature(certFile, keyFile string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
return certSignature(cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func certSignature(cert tls.Certificate) (string, error) {
|
||||||
x509Certs, err := x509.ParseCertificates(cert.Certificate[0])
|
x509Certs, err := x509.ParseCertificates(cert.Certificate[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if len(x509Certs) == 0 {
|
|
||||||
return "", fmt.Errorf("expected at least one cert after reparsing cert %q", certFile)
|
|
||||||
}
|
|
||||||
return x509CertSignature(x509Certs[0]), nil
|
return x509CertSignature(x509Certs[0]), nil
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,7 @@ Federated Services DNS non-local federated service missing local service should
|
|||||||
Federated Services DNS non-local federated service should be able to discover a non-local federated service,jlowdermilk,1
|
Federated Services DNS non-local federated service should be able to discover a non-local federated service,jlowdermilk,1
|
||||||
Federated Services DNS should be able to discover a federated service,derekwaynecarr,1
|
Federated Services DNS should be able to discover a federated service,derekwaynecarr,1
|
||||||
Federated Services Service creation should create matching services in underlying clusters,jbeda,1
|
Federated Services Service creation should create matching services in underlying clusters,jbeda,1
|
||||||
|
Federated Services Service creation should not be deleted from underlying clusters when it is deleted,sttts,0
|
||||||
Federated Services Service creation should succeed,rmmh,1
|
Federated Services Service creation should succeed,rmmh,1
|
||||||
Federated ingresses Federated Ingresses Ingress connectivity and DNS should be able to connect to a federated ingress via its load balancer,rmmh,1
|
Federated ingresses Federated Ingresses Ingress connectivity and DNS should be able to connect to a federated ingress via its load balancer,rmmh,1
|
||||||
Federated ingresses Federated Ingresses should be created and deleted successfully,dchen1107,1
|
Federated ingresses Federated Ingresses should be created and deleted successfully,dchen1107,1
|
||||||
@ -444,7 +445,7 @@ Services should be able to create a functioning NodePort service,bprashanth,0
|
|||||||
Services should be able to up and down services,bprashanth,0
|
Services should be able to up and down services,bprashanth,0
|
||||||
Services should check NodePort out-of-range,bprashanth,0
|
Services should check NodePort out-of-range,bprashanth,0
|
||||||
Services should create endpoints for unready pods,maisem,0
|
Services should create endpoints for unready pods,maisem,0
|
||||||
Serivces should only allow access from service loadbalancer source ranges,freehan,0
|
Services should only allow access from service loadbalancer source ranges,sttts,0
|
||||||
Services should preserve source pod IP for traffic thru service cluster IP,Random-Liu,1
|
Services should preserve source pod IP for traffic thru service cluster IP,Random-Liu,1
|
||||||
Services should prevent NodePort collisions,bprashanth,0
|
Services should prevent NodePort collisions,bprashanth,0
|
||||||
Services should provide secure master service,bprashanth,0
|
Services should provide secure master service,bprashanth,0
|
||||||
@ -546,7 +547,6 @@ k8s.io/kubernetes/pkg/api/errors,yifan-gu,1
|
|||||||
k8s.io/kubernetes/pkg/api/events,jlowdermilk,1
|
k8s.io/kubernetes/pkg/api/events,jlowdermilk,1
|
||||||
k8s.io/kubernetes/pkg/api/install,timothysc,1
|
k8s.io/kubernetes/pkg/api/install,timothysc,1
|
||||||
k8s.io/kubernetes/pkg/api/meta,fabioy,1
|
k8s.io/kubernetes/pkg/api/meta,fabioy,1
|
||||||
k8s.io/kubernetes/pkg/api/pod,piosz,1
|
|
||||||
k8s.io/kubernetes/pkg/api/resource,smarterclayton,1
|
k8s.io/kubernetes/pkg/api/resource,smarterclayton,1
|
||||||
k8s.io/kubernetes/pkg/api/service,spxtr,1
|
k8s.io/kubernetes/pkg/api/service,spxtr,1
|
||||||
k8s.io/kubernetes/pkg/api/testapi,caesarxuchao,1
|
k8s.io/kubernetes/pkg/api/testapi,caesarxuchao,1
|
||||||
@ -554,6 +554,9 @@ k8s.io/kubernetes/pkg/api/unversioned,kevin-wangzefeng,1
|
|||||||
k8s.io/kubernetes/pkg/api/unversioned/validation,brendandburns,1
|
k8s.io/kubernetes/pkg/api/unversioned/validation,brendandburns,1
|
||||||
k8s.io/kubernetes/pkg/api/util,ghodss,1
|
k8s.io/kubernetes/pkg/api/util,ghodss,1
|
||||||
k8s.io/kubernetes/pkg/api/v1,vulpecula,1
|
k8s.io/kubernetes/pkg/api/v1,vulpecula,1
|
||||||
|
k8s.io/kubernetes/pkg/api/v1/endpoints,sttts,0
|
||||||
|
k8s.io/kubernetes/pkg/api/v1/pod,sttts,0
|
||||||
|
k8s.io/kubernetes/pkg/api/v1/service,sttts,0
|
||||||
k8s.io/kubernetes/pkg/api/validation,smarterclayton,1
|
k8s.io/kubernetes/pkg/api/validation,smarterclayton,1
|
||||||
k8s.io/kubernetes/pkg/api/validation/path,luxas,1
|
k8s.io/kubernetes/pkg/api/validation/path,luxas,1
|
||||||
k8s.io/kubernetes/pkg/apimachinery,gmarek,1
|
k8s.io/kubernetes/pkg/apimachinery,gmarek,1
|
||||||
@ -787,6 +790,7 @@ k8s.io/kubernetes/pkg/registry/policy/poddisruptionbudget/etcd,xiang90,1
|
|||||||
k8s.io/kubernetes/pkg/registry/storage/storageclass,brendandburns,1
|
k8s.io/kubernetes/pkg/registry/storage/storageclass,brendandburns,1
|
||||||
k8s.io/kubernetes/pkg/registry/storage/storageclass/etcd,eparis,1
|
k8s.io/kubernetes/pkg/registry/storage/storageclass/etcd,eparis,1
|
||||||
k8s.io/kubernetes/pkg/runtime,wojtek-t,0
|
k8s.io/kubernetes/pkg/runtime,wojtek-t,0
|
||||||
|
k8s.io/kubernetes/pkg/runtime/schema,sttts,0
|
||||||
k8s.io/kubernetes/pkg/runtime/serializer,wojtek-t,0
|
k8s.io/kubernetes/pkg/runtime/serializer,wojtek-t,0
|
||||||
k8s.io/kubernetes/pkg/runtime/serializer/json,wojtek-t,0
|
k8s.io/kubernetes/pkg/runtime/serializer/json,wojtek-t,0
|
||||||
k8s.io/kubernetes/pkg/runtime/serializer/protobuf,wojtek-t,0
|
k8s.io/kubernetes/pkg/runtime/serializer/protobuf,wojtek-t,0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user