Merge pull request #67763 from rosti/join-discovery-split

kubeadm: Split discovery from JoinConfiguration
This commit is contained in:
k8s-ci-robot 2018-10-16 19:25:47 -07:00 committed by GitHub
commit 1e4ad048fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 789 additions and 378 deletions

View File

@ -133,7 +133,9 @@ func fuzzJoinConfiguration(obj *kubeadm.JoinConfiguration, c fuzz.Continue) {
// Pinning values for fields that get defaults if fuzz value is empty string or nil (thus making the round trip test fail)
obj.CACertPath = "foo"
obj.ClusterName = "bar"
obj.DiscoveryTimeout = &metav1.Duration{Duration: 1234}
obj.DiscoveryToken = "baz"
obj.TLSBootstrapToken = "qux"
obj.Discovery = kubeadm.Discovery{
BootstrapToken: &kubeadm.BootstrapTokenDiscovery{Token: "baz"},
TLSBootstrapToken: "qux",
Timeout: &metav1.Duration{Duration: 1234},
}
}

View File

@ -280,41 +280,13 @@ type JoinConfiguration struct {
// secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt".
CACertPath string
// DiscoveryFile is a file or url to a kubeconfig file from which to
// load cluster information.
DiscoveryFile string
// DiscoveryToken is a token used to validate cluster information
// fetched from the master.
DiscoveryToken string
// DiscoveryTokenAPIServers is a set of IPs to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
DiscoveryTokenAPIServers []string
// DiscoveryTimeout modifies the discovery timeout
DiscoveryTimeout *metav1.Duration
// TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token.
TLSBootstrapToken string
// Token is used for both discovery and TLS bootstrapping.
Token string
// Discovery specifies the options for the kubelet to use during the TLS Bootstrap process
Discovery Discovery
// The cluster name
ClusterName string
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
// must match one of these values. Specifying an empty set disables root CA
// pinning, which can be unsafe. Each hash is specified as "<type>:<value>",
// where the only currently supported type is "sha256". This is a hex-encoded
// SHA-256 hash of the Subject Public Key Info (SPKI) object in DER-encoded
// ASN.1. These hashes can be calculated using, for example, OpenSSL:
// openssl x509 -pubkey -in ca.crt openssl rsa -pubin -outform der 2>&/dev/null | openssl dgst -sha256 -hex
DiscoveryTokenCACertHashes []string
// DiscoveryTokenUnsafeSkipCAVerification allows token-based discovery
// without CA verification via DiscoveryTokenCACertHashes. This can weaken
// the security of kubeadm since other nodes can impersonate the master.
DiscoveryTokenUnsafeSkipCAVerification bool
// ControlPlane flag specifies that the joining node should host an additional
// control plane instance.
ControlPlane bool
@ -326,6 +298,58 @@ type JoinConfiguration struct {
FeatureGates map[string]bool
}
// Discovery specifies the options for the kubelet to use during the TLS Bootstrap process
type Discovery struct {
// BootstrapToken is used to set the options for bootstrap token based discovery
// BootstrapToken and File are mutually exclusive
BootstrapToken *BootstrapTokenDiscovery
// File is used to specify a file or URL to a kubeconfig file from which to load cluster information
// BootstrapToken and File are mutually exclusive
File *FileDiscovery
// TLSBootstrapToken is a token used for TLS bootstrapping.
// If .BootstrapToken is set, this field is defaulted to .BootstrapToken.Token, but can be overridden.
// If .File is set, this field **must be set** in case the KubeConfigFile does not contain any other authentication information
TLSBootstrapToken string
// Timeout modifies the discovery timeout
Timeout *metav1.Duration
}
// BootstrapTokenDiscovery is used to set the options for bootstrap token based discovery
type BootstrapTokenDiscovery struct {
// Token is a token used to validate cluster information
// fetched from the master.
Token string
// APIServerEndpoints is a set of IPs or domain names to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
APIServerEndpoints []string
// CACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
// must match one of these values. Specifying an empty set disables root CA
// pinning, which can be unsafe. Each hash is specified as "<type>:<value>",
// where the only currently supported type is "sha256". This is a hex-encoded
// SHA-256 hash of the Subject Public Key Info (SPKI) object in DER-encoded
// ASN.1. These hashes can be calculated using, for example, OpenSSL:
// openssl x509 -pubkey -in ca.crt openssl rsa -pubin -outform der 2>&/dev/null | openssl dgst -sha256 -hex
CACertHashes []string
// UnsafeSkipCAVerification allows token-based discovery
// without CA verification via CACertHashes. This can weaken
// the security of kubeadm since other nodes can impersonate the master.
UnsafeSkipCAVerification bool
}
// FileDiscovery is used to specify a file or URL to a kubeconfig file from which to load cluster information
type FileDiscovery struct {
// KubeConfigPath is used to specify the actual file path or URL to the kubeconfig file from which to load cluster information
KubeConfigPath string
}
// GetControlPlaneImageRepository returns name of image repository
// for control plane images (API,Controller Manager,Scheduler and Proxy)
// It will override location with CI registry name in case user requests special

View File

@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"bootstraptokenstring.go",
"conversion.go",
"defaults.go",
"defaults_unix.go",
"defaults_windows.go",

View File

@ -0,0 +1,76 @@
/*
Copyright 2018 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 v1alpha3
import (
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
func Convert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in *JoinConfiguration, out *kubeadm.JoinConfiguration, s conversion.Scope) error {
if err := autoConvert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in, out, s); err != nil {
return err
}
out.Discovery.Timeout = in.DiscoveryTimeout
if len(in.TLSBootstrapToken) != 0 {
out.Discovery.TLSBootstrapToken = in.TLSBootstrapToken
} else {
out.Discovery.TLSBootstrapToken = in.Token
}
if len(in.DiscoveryFile) != 0 {
out.Discovery.File = &kubeadm.FileDiscovery{
KubeConfigPath: in.DiscoveryFile,
}
} else {
out.Discovery.BootstrapToken = &kubeadm.BootstrapTokenDiscovery{
APIServerEndpoints: in.DiscoveryTokenAPIServers,
CACertHashes: in.DiscoveryTokenCACertHashes,
UnsafeSkipCAVerification: in.DiscoveryTokenUnsafeSkipCAVerification,
}
if len(in.DiscoveryToken) != 0 {
out.Discovery.BootstrapToken.Token = in.DiscoveryToken
} else {
out.Discovery.BootstrapToken.Token = in.Token
}
}
return nil
}
func Convert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in *kubeadm.JoinConfiguration, out *JoinConfiguration, s conversion.Scope) error {
if err := autoConvert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in, out, s); err != nil {
return err
}
out.DiscoveryTimeout = in.Discovery.Timeout
out.TLSBootstrapToken = in.Discovery.TLSBootstrapToken
if in.Discovery.BootstrapToken != nil {
out.DiscoveryToken = in.Discovery.BootstrapToken.Token
out.DiscoveryTokenAPIServers = in.Discovery.BootstrapToken.APIServerEndpoints
out.DiscoveryTokenCACertHashes = in.Discovery.BootstrapToken.CACertHashes
out.DiscoveryTokenUnsafeSkipCAVerification = in.Discovery.BootstrapToken.UnsafeSkipCAVerification
} else if in.Discovery.File != nil {
out.DiscoveryFile = in.Discovery.File.KubeConfigPath
}
return nil
}

View File

@ -177,6 +177,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*kubeadm.JoinConfiguration)(nil), (*JoinConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(a.(*kubeadm.JoinConfiguration), b.(*JoinConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*JoinConfiguration)(nil), (*kubeadm.JoinConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(a.(*JoinConfiguration), b.(*kubeadm.JoinConfiguration), scope)
}); err != nil {
return err
}
return nil
}
@ -483,15 +493,15 @@ func autoConvert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in *Joi
return err
}
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
out.DiscoveryTimeout = (*v1.Duration)(unsafe.Pointer(in.DiscoveryTimeout))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
// WARNING: in.DiscoveryFile requires manual conversion: does not exist in peer-type
// WARNING: in.DiscoveryToken requires manual conversion: does not exist in peer-type
// WARNING: in.DiscoveryTokenAPIServers requires manual conversion: does not exist in peer-type
// WARNING: in.DiscoveryTimeout requires manual conversion: does not exist in peer-type
// WARNING: in.TLSBootstrapToken requires manual conversion: does not exist in peer-type
// WARNING: in.Token requires manual conversion: does not exist in peer-type
out.ClusterName = in.ClusterName
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
// WARNING: in.DiscoveryTokenCACertHashes requires manual conversion: does not exist in peer-type
// WARNING: in.DiscoveryTokenUnsafeSkipCAVerification requires manual conversion: does not exist in peer-type
out.ControlPlane = in.ControlPlane
if err := Convert_v1alpha3_APIEndpoint_To_kubeadm_APIEndpoint(&in.APIEndpoint, &out.APIEndpoint, s); err != nil {
return err
@ -500,25 +510,13 @@ func autoConvert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in *Joi
return nil
}
// Convert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration is an autogenerated conversion function.
func Convert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in *JoinConfiguration, out *kubeadm.JoinConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in, out, s)
}
func autoConvert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in *kubeadm.JoinConfiguration, out *JoinConfiguration, s conversion.Scope) error {
if err := Convert_kubeadm_NodeRegistrationOptions_To_v1alpha3_NodeRegistrationOptions(&in.NodeRegistration, &out.NodeRegistration, s); err != nil {
return err
}
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
out.DiscoveryTimeout = (*v1.Duration)(unsafe.Pointer(in.DiscoveryTimeout))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
// WARNING: in.Discovery requires manual conversion: does not exist in peer-type
out.ClusterName = in.ClusterName
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
out.ControlPlane = in.ControlPlane
if err := Convert_kubeadm_APIEndpoint_To_v1alpha3_APIEndpoint(&in.APIEndpoint, &out.APIEndpoint, s); err != nil {
return err
@ -527,11 +525,6 @@ func autoConvert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in *kub
return nil
}
// Convert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration is an autogenerated conversion function.
func Convert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in *kubeadm.JoinConfiguration, out *JoinConfiguration, s conversion.Scope) error {
return autoConvert_kubeadm_JoinConfiguration_To_v1alpha3_JoinConfiguration(in, out, s)
}
func autoConvert_v1alpha3_LocalEtcd_To_kubeadm_LocalEtcd(in *LocalEtcd, out *kubeadm.LocalEtcd, s conversion.Scope) error {
out.Image = in.Image
out.DataDir = in.DataDir

View File

@ -120,30 +120,14 @@ func SetDefaults_JoinConfiguration(obj *JoinConfiguration) {
if obj.CACertPath == "" {
obj.CACertPath = DefaultCACertPath
}
if len(obj.TLSBootstrapToken) == 0 {
obj.TLSBootstrapToken = obj.Token
}
if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 {
obj.DiscoveryToken = obj.Token
}
// Make sure file URLs become paths
if len(obj.DiscoveryFile) != 0 {
u, err := url.Parse(obj.DiscoveryFile)
if err == nil && u.Scheme == "file" {
obj.DiscoveryFile = u.Path
}
}
if obj.DiscoveryTimeout == nil {
obj.DiscoveryTimeout = &metav1.Duration{
Duration: DefaultDiscoveryTimeout,
}
}
if obj.ClusterName == "" {
obj.ClusterName = DefaultClusterName
}
SetDefaults_NodeRegistrationOptions(&obj.NodeRegistration)
SetDefaults_APIEndpoint(&obj.APIEndpoint)
SetDefaults_Discovery(&obj.Discovery)
}
func SetDefaults_NodeRegistrationOptions(obj *NodeRegistrationOptions) {
@ -152,6 +136,34 @@ func SetDefaults_NodeRegistrationOptions(obj *NodeRegistrationOptions) {
}
}
// SetDefaults_Discovery assigns default values for the discovery process
func SetDefaults_Discovery(obj *Discovery) {
if len(obj.TLSBootstrapToken) == 0 && obj.BootstrapToken != nil {
obj.TLSBootstrapToken = obj.BootstrapToken.Token
}
if obj.Timeout == nil {
obj.Timeout = &metav1.Duration{
Duration: DefaultDiscoveryTimeout,
}
}
if obj.File != nil {
SetDefaults_FileDiscovery(obj.File)
}
}
// SetDefaults_FileDiscovery assigns default values for file based discovery
func SetDefaults_FileDiscovery(obj *FileDiscovery) {
// Make sure file URL becomes path
if len(obj.KubeConfigPath) != 0 {
u, err := url.Parse(obj.KubeConfigPath)
if err == nil && u.Scheme == "file" {
obj.KubeConfigPath = u.Path
}
}
}
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
func SetDefaults_AuditPolicyConfiguration(obj *ClusterConfiguration) {
if obj.AuditPolicyConfiguration.LogDir == "" {

View File

@ -258,42 +258,13 @@ type JoinConfiguration struct {
// secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt".
CACertPath string `json:"caCertPath"`
// DiscoveryFile is a file or url to a kubeconfig file from which to
// load cluster information.
DiscoveryFile string `json:"discoveryFile"`
// DiscoveryToken is a token used to validate cluster information
// fetched from the master.
DiscoveryToken string `json:"discoveryToken"`
// DiscoveryTokenAPIServers is a set of IPs to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"`
// DiscoveryTimeout modifies the discovery timeout
DiscoveryTimeout *metav1.Duration `json:"discoveryTimeout,omitempty"`
// TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token.
TLSBootstrapToken string `json:"tlsBootstrapToken"`
// Token is used for both discovery and TLS bootstrapping.
Token string `json:"token"`
// Discovery specifies the options for the kubelet to use during the TLS Bootstrap process
Discovery Discovery `json:"discovery"`
// ClusterName is the name for the cluster in kubeconfig.
ClusterName string `json:"clusterName,omitempty"`
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
// must match one of these values. Specifying an empty set disables root CA
// pinning, which can be unsafe. Each hash is specified as "<type>:<value>",
// where the only currently supported type is "sha256". This is a hex-encoded
// SHA-256 hash of the Subject Public Key Info (SPKI) object in DER-encoded
// ASN.1. These hashes can be calculated using, for example, OpenSSL:
// openssl x509 -pubkey -in ca.crt openssl rsa -pubin -outform der 2>&/dev/null | openssl dgst -sha256 -hex
DiscoveryTokenCACertHashes []string `json:"discoveryTokenCACertHashes,omitempty"`
// DiscoveryTokenUnsafeSkipCAVerification allows token-based discovery
// without CA verification via DiscoveryTokenCACertHashes. This can weaken
// the security of kubeadm since other nodes can impersonate the master.
DiscoveryTokenUnsafeSkipCAVerification bool `json:"discoveryTokenUnsafeSkipCAVerification"`
// ControlPlane flag specifies that the joining node should host an additional
// control plane instance.
ControlPlane bool `json:"controlPlane,omitempty"`
@ -305,6 +276,58 @@ type JoinConfiguration struct {
FeatureGates map[string]bool `json:"featureGates,omitempty"`
}
// Discovery specifies the options for the kubelet to use during the TLS Bootstrap process
type Discovery struct {
// BootstrapToken is used to set the options for bootstrap token based discovery
// BootstrapToken and File are mutually exclusive
BootstrapToken *BootstrapTokenDiscovery `json:"bootstrapToken,omitempty"`
// File is used to specify a file or URL to a kubeconfig file from which to load cluster information
// BootstrapToken and File are mutually exclusive
File *FileDiscovery `json:"file,omitempty"`
// TLSBootstrapToken is a token used for TLS bootstrapping.
// If .BootstrapToken is set, this field is defaulted to .BootstrapToken.Token, but can be overridden.
// If .File is set, this field **must be set** in case the KubeConfigFile does not contain any other authentication information
TLSBootstrapToken string `json:"tlsBootstrapToken"`
// Timeout modifies the discovery timeout
Timeout *metav1.Duration `json:"timeout,omitempty"`
}
// BootstrapTokenDiscovery is used to set the options for bootstrap token based discovery
type BootstrapTokenDiscovery struct {
// Token is a token used to validate cluster information
// fetched from the master.
Token string `json:"token"`
// APIServerEndpoints is a set of IPs or domain names to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
APIServerEndpoints []string `json:"apiServerEndpoints,omitempty"`
// CACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
// must match one of these values. Specifying an empty set disables root CA
// pinning, which can be unsafe. Each hash is specified as "<type>:<value>",
// where the only currently supported type is "sha256". This is a hex-encoded
// SHA-256 hash of the Subject Public Key Info (SPKI) object in DER-encoded
// ASN.1. These hashes can be calculated using, for example, OpenSSL:
// openssl x509 -pubkey -in ca.crt openssl rsa -pubin -outform der 2>&/dev/null | openssl dgst -sha256 -hex
CACertHashes []string `json:"caCertHashes,omitempty"`
// UnsafeSkipCAVerification allows token-based discovery
// without CA verification via CACertHashes. This can weaken
// the security of kubeadm since other nodes can impersonate the master.
UnsafeSkipCAVerification bool `json:"unsafeSkipCAVerification"`
}
// FileDiscovery is used to specify a file or URL to a kubeconfig file from which to load cluster information
type FileDiscovery struct {
// KubeConfigPath is used to specify the actual file path or URL to the kubeconfig file from which to load cluster information
KubeConfigPath string `json:"kubeConfigPath"`
}
// HostPathMount contains elements describing volumes that are mounted from the
// host.
type HostPathMount struct {

View File

@ -67,6 +67,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*BootstrapTokenDiscovery)(nil), (*kubeadm.BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(a.(*BootstrapTokenDiscovery), b.(*kubeadm.BootstrapTokenDiscovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kubeadm.BootstrapTokenDiscovery)(nil), (*BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_BootstrapTokenDiscovery_To_v1beta1_BootstrapTokenDiscovery(a.(*kubeadm.BootstrapTokenDiscovery), b.(*BootstrapTokenDiscovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*BootstrapTokenString)(nil), (*kubeadm.BootstrapTokenString)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_BootstrapTokenString_To_kubeadm_BootstrapTokenString(a.(*BootstrapTokenString), b.(*kubeadm.BootstrapTokenString), scope)
}); err != nil {
@ -97,6 +107,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Discovery)(nil), (*kubeadm.Discovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_Discovery_To_kubeadm_Discovery(a.(*Discovery), b.(*kubeadm.Discovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kubeadm.Discovery)(nil), (*Discovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_Discovery_To_v1beta1_Discovery(a.(*kubeadm.Discovery), b.(*Discovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Etcd)(nil), (*kubeadm.Etcd)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_Etcd_To_kubeadm_Etcd(a.(*Etcd), b.(*kubeadm.Etcd), scope)
}); err != nil {
@ -117,6 +137,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*FileDiscovery)(nil), (*kubeadm.FileDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_FileDiscovery_To_kubeadm_FileDiscovery(a.(*FileDiscovery), b.(*kubeadm.FileDiscovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kubeadm.FileDiscovery)(nil), (*FileDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_FileDiscovery_To_v1beta1_FileDiscovery(a.(*kubeadm.FileDiscovery), b.(*FileDiscovery), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*HostPathMount)(nil), (*kubeadm.HostPathMount)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_HostPathMount_To_kubeadm_HostPathMount(a.(*HostPathMount), b.(*kubeadm.HostPathMount), scope)
}); err != nil {
@ -256,6 +286,32 @@ func Convert_kubeadm_BootstrapToken_To_v1beta1_BootstrapToken(in *kubeadm.Bootst
return autoConvert_kubeadm_BootstrapToken_To_v1beta1_BootstrapToken(in, out, s)
}
func autoConvert_v1beta1_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error {
out.Token = in.Token
out.APIServerEndpoints = *(*[]string)(unsafe.Pointer(&in.APIServerEndpoints))
out.CACertHashes = *(*[]string)(unsafe.Pointer(&in.CACertHashes))
out.UnsafeSkipCAVerification = in.UnsafeSkipCAVerification
return nil
}
// Convert_v1beta1_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery is an autogenerated conversion function.
func Convert_v1beta1_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error {
return autoConvert_v1beta1_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in, out, s)
}
func autoConvert_kubeadm_BootstrapTokenDiscovery_To_v1beta1_BootstrapTokenDiscovery(in *kubeadm.BootstrapTokenDiscovery, out *BootstrapTokenDiscovery, s conversion.Scope) error {
out.Token = in.Token
out.APIServerEndpoints = *(*[]string)(unsafe.Pointer(&in.APIServerEndpoints))
out.CACertHashes = *(*[]string)(unsafe.Pointer(&in.CACertHashes))
out.UnsafeSkipCAVerification = in.UnsafeSkipCAVerification
return nil
}
// Convert_kubeadm_BootstrapTokenDiscovery_To_v1beta1_BootstrapTokenDiscovery is an autogenerated conversion function.
func Convert_kubeadm_BootstrapTokenDiscovery_To_v1beta1_BootstrapTokenDiscovery(in *kubeadm.BootstrapTokenDiscovery, out *BootstrapTokenDiscovery, s conversion.Scope) error {
return autoConvert_kubeadm_BootstrapTokenDiscovery_To_v1beta1_BootstrapTokenDiscovery(in, out, s)
}
func autoConvert_v1beta1_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in *BootstrapTokenString, out *kubeadm.BootstrapTokenString, s conversion.Scope) error {
out.ID = in.ID
out.Secret = in.Secret
@ -364,6 +420,32 @@ func Convert_kubeadm_ClusterStatus_To_v1beta1_ClusterStatus(in *kubeadm.ClusterS
return autoConvert_kubeadm_ClusterStatus_To_v1beta1_ClusterStatus(in, out, s)
}
func autoConvert_v1beta1_Discovery_To_kubeadm_Discovery(in *Discovery, out *kubeadm.Discovery, s conversion.Scope) error {
out.BootstrapToken = (*kubeadm.BootstrapTokenDiscovery)(unsafe.Pointer(in.BootstrapToken))
out.File = (*kubeadm.FileDiscovery)(unsafe.Pointer(in.File))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Timeout = (*v1.Duration)(unsafe.Pointer(in.Timeout))
return nil
}
// Convert_v1beta1_Discovery_To_kubeadm_Discovery is an autogenerated conversion function.
func Convert_v1beta1_Discovery_To_kubeadm_Discovery(in *Discovery, out *kubeadm.Discovery, s conversion.Scope) error {
return autoConvert_v1beta1_Discovery_To_kubeadm_Discovery(in, out, s)
}
func autoConvert_kubeadm_Discovery_To_v1beta1_Discovery(in *kubeadm.Discovery, out *Discovery, s conversion.Scope) error {
out.BootstrapToken = (*BootstrapTokenDiscovery)(unsafe.Pointer(in.BootstrapToken))
out.File = (*FileDiscovery)(unsafe.Pointer(in.File))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Timeout = (*v1.Duration)(unsafe.Pointer(in.Timeout))
return nil
}
// Convert_kubeadm_Discovery_To_v1beta1_Discovery is an autogenerated conversion function.
func Convert_kubeadm_Discovery_To_v1beta1_Discovery(in *kubeadm.Discovery, out *Discovery, s conversion.Scope) error {
return autoConvert_kubeadm_Discovery_To_v1beta1_Discovery(in, out, s)
}
func autoConvert_v1beta1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
out.Local = (*kubeadm.LocalEtcd)(unsafe.Pointer(in.Local))
out.External = (*kubeadm.ExternalEtcd)(unsafe.Pointer(in.External))
@ -412,6 +494,26 @@ func Convert_kubeadm_ExternalEtcd_To_v1beta1_ExternalEtcd(in *kubeadm.ExternalEt
return autoConvert_kubeadm_ExternalEtcd_To_v1beta1_ExternalEtcd(in, out, s)
}
func autoConvert_v1beta1_FileDiscovery_To_kubeadm_FileDiscovery(in *FileDiscovery, out *kubeadm.FileDiscovery, s conversion.Scope) error {
out.KubeConfigPath = in.KubeConfigPath
return nil
}
// Convert_v1beta1_FileDiscovery_To_kubeadm_FileDiscovery is an autogenerated conversion function.
func Convert_v1beta1_FileDiscovery_To_kubeadm_FileDiscovery(in *FileDiscovery, out *kubeadm.FileDiscovery, s conversion.Scope) error {
return autoConvert_v1beta1_FileDiscovery_To_kubeadm_FileDiscovery(in, out, s)
}
func autoConvert_kubeadm_FileDiscovery_To_v1beta1_FileDiscovery(in *kubeadm.FileDiscovery, out *FileDiscovery, s conversion.Scope) error {
out.KubeConfigPath = in.KubeConfigPath
return nil
}
// Convert_kubeadm_FileDiscovery_To_v1beta1_FileDiscovery is an autogenerated conversion function.
func Convert_kubeadm_FileDiscovery_To_v1beta1_FileDiscovery(in *kubeadm.FileDiscovery, out *FileDiscovery, s conversion.Scope) error {
return autoConvert_kubeadm_FileDiscovery_To_v1beta1_FileDiscovery(in, out, s)
}
func autoConvert_v1beta1_HostPathMount_To_kubeadm_HostPathMount(in *HostPathMount, out *kubeadm.HostPathMount, s conversion.Scope) error {
out.Name = in.Name
out.HostPath = in.HostPath
@ -483,15 +585,10 @@ func autoConvert_v1beta1_JoinConfiguration_To_kubeadm_JoinConfiguration(in *Join
return err
}
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
out.DiscoveryTimeout = (*v1.Duration)(unsafe.Pointer(in.DiscoveryTimeout))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
if err := Convert_v1beta1_Discovery_To_kubeadm_Discovery(&in.Discovery, &out.Discovery, s); err != nil {
return err
}
out.ClusterName = in.ClusterName
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
out.ControlPlane = in.ControlPlane
if err := Convert_v1beta1_APIEndpoint_To_kubeadm_APIEndpoint(&in.APIEndpoint, &out.APIEndpoint, s); err != nil {
return err
@ -510,15 +607,10 @@ func autoConvert_kubeadm_JoinConfiguration_To_v1beta1_JoinConfiguration(in *kube
return err
}
out.CACertPath = in.CACertPath
out.DiscoveryFile = in.DiscoveryFile
out.DiscoveryToken = in.DiscoveryToken
out.DiscoveryTokenAPIServers = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenAPIServers))
out.DiscoveryTimeout = (*v1.Duration)(unsafe.Pointer(in.DiscoveryTimeout))
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
if err := Convert_kubeadm_Discovery_To_v1beta1_Discovery(&in.Discovery, &out.Discovery, s); err != nil {
return err
}
out.ClusterName = in.ClusterName
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
out.ControlPlane = in.ControlPlane
if err := Convert_kubeadm_APIEndpoint_To_v1beta1_APIEndpoint(&in.APIEndpoint, &out.APIEndpoint, s); err != nil {
return err

View File

@ -103,6 +103,32 @@ func (in *BootstrapToken) DeepCopy() *BootstrapToken {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) {
*out = *in
if in.APIServerEndpoints != nil {
in, out := &in.APIServerEndpoints, &out.APIServerEndpoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.CACertHashes != nil {
in, out := &in.CACertHashes, &out.CACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenDiscovery.
func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery {
if in == nil {
return nil
}
out := new(BootstrapTokenDiscovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) {
*out = *in
@ -227,6 +253,37 @@ func (in *ClusterStatus) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Discovery) DeepCopyInto(out *Discovery) {
*out = *in
if in.BootstrapToken != nil {
in, out := &in.BootstrapToken, &out.BootstrapToken
*out = new(BootstrapTokenDiscovery)
(*in).DeepCopyInto(*out)
}
if in.File != nil {
in, out := &in.File, &out.File
*out = new(FileDiscovery)
**out = **in
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Discovery.
func (in *Discovery) DeepCopy() *Discovery {
if in == nil {
return nil
}
out := new(Discovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) {
*out = *in
@ -274,6 +331,22 @@ func (in *ExternalEtcd) DeepCopy() *ExternalEtcd {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileDiscovery) DeepCopyInto(out *FileDiscovery) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileDiscovery.
func (in *FileDiscovery) DeepCopy() *FileDiscovery {
if in == nil {
return nil
}
out := new(FileDiscovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostPathMount) DeepCopyInto(out *HostPathMount) {
*out = *in
@ -330,21 +403,7 @@ func (in *JoinConfiguration) DeepCopyInto(out *JoinConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
in.NodeRegistration.DeepCopyInto(&out.NodeRegistration)
if in.DiscoveryTokenAPIServers != nil {
in, out := &in.DiscoveryTokenAPIServers, &out.DiscoveryTokenAPIServers
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.DiscoveryTimeout != nil {
in, out := &in.DiscoveryTimeout, &out.DiscoveryTimeout
*out = new(v1.Duration)
**out = **in
}
if in.DiscoveryTokenCACertHashes != nil {
in, out := &in.DiscoveryTokenCACertHashes, &out.DiscoveryTokenCACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}
in.Discovery.DeepCopyInto(&out.Discovery)
out.APIEndpoint = in.APIEndpoint
if in.FeatureGates != nil {
in, out := &in.FeatureGates, &out.FeatureGates

View File

@ -56,5 +56,9 @@ func SetObjectDefaults_InitConfiguration(in *InitConfiguration) {
func SetObjectDefaults_JoinConfiguration(in *JoinConfiguration) {
SetDefaults_JoinConfiguration(in)
SetDefaults_NodeRegistrationOptions(&in.NodeRegistration)
SetDefaults_Discovery(&in.Discovery)
if in.Discovery.File != nil {
SetDefaults_FileDiscovery(in.Discovery.File)
}
SetDefaults_APIEndpoint(&in.APIEndpoint)
}

View File

@ -68,7 +68,7 @@ func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorLi
// ValidateJoinConfiguration validates node configuration and collects all encountered errors
func ValidateJoinConfiguration(c *kubeadm.JoinConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateDiscovery(c)...)
allErrs = append(allErrs, ValidateDiscovery(&c.Discovery, field.NewPath("discovery"))...)
allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
allErrs = append(allErrs, ValidateAPIEndpoint(&c.APIEndpoint, field.NewPath("apiEndpoint"))...)
@ -92,56 +92,66 @@ func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPa
}
// ValidateDiscovery validates discovery related configuration and collects all encountered errors
func ValidateDiscovery(c *kubeadm.JoinConfiguration) field.ErrorList {
func ValidateDiscovery(d *kubeadm.Discovery, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(c.DiscoveryToken) != 0 {
allErrs = append(allErrs, ValidateToken(c.DiscoveryToken, field.NewPath("discoveryToken"))...)
if d.BootstrapToken == nil && d.File == nil {
allErrs = append(allErrs, field.Invalid(fldPath, "", "bootstrapToken or file must be set"))
}
if len(c.DiscoveryFile) != 0 {
allErrs = append(allErrs, ValidateDiscoveryFile(c.DiscoveryFile, field.NewPath("discoveryFile"))...)
if len(c.TLSBootstrapToken) != 0 {
allErrs = append(allErrs, ValidateToken(c.TLSBootstrapToken, field.NewPath("tlsBootstrapToken"))...)
if d.BootstrapToken != nil && d.File != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "", "bootstrapToken and file cannot both be set"))
}
if d.BootstrapToken != nil {
allErrs = append(allErrs, ValidateDiscoveryBootstrapToken(d.BootstrapToken, fldPath.Child("bootstrapToken"))...)
allErrs = append(allErrs, ValidateToken(d.TLSBootstrapToken, fldPath.Child("tlsBootstrapToken"))...)
}
if d.File != nil {
allErrs = append(allErrs, ValidateDiscoveryFile(d.File, fldPath.Child("file"))...)
if len(d.TLSBootstrapToken) != 0 {
allErrs = append(allErrs, ValidateToken(d.TLSBootstrapToken, fldPath.Child("tlsBootstrapToken"))...)
}
} else {
allErrs = append(allErrs, ValidateToken(c.TLSBootstrapToken, field.NewPath("tlsBootstrapToken"))...)
}
allErrs = append(allErrs, ValidateArgSelection(c, field.NewPath("discovery"))...)
allErrs = append(allErrs, ValidateJoinDiscoveryTokenAPIServer(c.DiscoveryTokenAPIServers, field.NewPath("discoveryTokenAPIServers"))...)
return allErrs
}
// ValidateArgSelection validates discovery related configuration and collects all encountered errors
func ValidateArgSelection(cfg *kubeadm.JoinConfiguration, fldPath *field.Path) field.ErrorList {
// ValidateDiscoveryBootstrapToken validates bootstrap token discovery configuration
func ValidateDiscoveryBootstrapToken(b *kubeadm.BootstrapTokenDiscovery, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(cfg.DiscoveryToken) != 0 && len(cfg.DiscoveryFile) != 0 {
allErrs = append(allErrs, field.Invalid(fldPath, "", "discoveryToken and discoveryFile cannot both be set"))
}
if len(cfg.DiscoveryToken) == 0 && len(cfg.DiscoveryFile) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath, "", "discoveryToken or discoveryFile must be set"))
}
if len(cfg.DiscoveryTokenAPIServers) < 1 && len(cfg.DiscoveryToken) != 0 {
allErrs = append(allErrs, field.Required(fldPath, "discoveryTokenAPIServers not set"))
}
if len(cfg.DiscoveryFile) != 0 && len(cfg.DiscoveryTokenCACertHashes) != 0 {
allErrs = append(allErrs, field.Invalid(fldPath, "", "discoveryTokenCACertHashes cannot be used with discoveryFile"))
}
if len(cfg.DiscoveryFile) == 0 && len(cfg.DiscoveryToken) != 0 &&
len(cfg.DiscoveryTokenCACertHashes) == 0 && !cfg.DiscoveryTokenUnsafeSkipCAVerification {
allErrs = append(allErrs, field.Invalid(fldPath, "", "using token-based discovery without discoveryTokenCACertHashes can be unsafe. set --discovery-token-unsafe-skip-ca-verification to continue"))
if len(b.APIServerEndpoints) < 1 {
allErrs = append(allErrs, field.Required(fldPath, "APIServerEndpoints not set"))
}
// TODO remove once we support multiple api servers
if len(cfg.DiscoveryTokenAPIServers) > 1 {
if len(b.APIServerEndpoints) > 1 {
fmt.Println("[validation] WARNING: kubeadm doesn't fully support multiple API Servers yet")
}
if len(b.CACertHashes) == 0 && !b.UnsafeSkipCAVerification {
allErrs = append(allErrs, field.Invalid(fldPath, "", "using token-based discovery without caCertHashes can be unsafe. Set unsafeSkipCAVerification to continue"))
}
allErrs = append(allErrs, ValidateToken(b.Token, fldPath.Child("token"))...)
allErrs = append(allErrs, ValidateDiscoveryTokenAPIServer(b.APIServerEndpoints, fldPath.Child("apiServerEndpoints"))...)
return allErrs
}
// ValidateJoinDiscoveryTokenAPIServer validates discovery token for API server
func ValidateJoinDiscoveryTokenAPIServer(apiServers []string, fldPath *field.Path) field.ErrorList {
// ValidateDiscoveryFile validates file discovery configuration
func ValidateDiscoveryFile(f *kubeadm.FileDiscovery, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateDiscoveryKubeConfigPath(f.KubeConfigPath, fldPath.Child("kubeConfigPath"))...)
return allErrs
}
// ValidateDiscoveryTokenAPIServer validates discovery token for API server
func ValidateDiscoveryTokenAPIServer(apiServers []string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, m := range apiServers {
_, _, err := net.SplitHostPort(m)
@ -152,8 +162,8 @@ func ValidateJoinDiscoveryTokenAPIServer(apiServers []string, fldPath *field.Pat
return allErrs
}
// ValidateDiscoveryFile validates location of a discovery file
func ValidateDiscoveryFile(discoveryFile string, fldPath *field.Path) field.ErrorList {
// ValidateDiscoveryKubeConfigPath validates location of a discovery file
func ValidateDiscoveryKubeConfigPath(discoveryFile string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
u, err := url.Parse(discoveryFile)
if err != nil {

View File

@ -34,20 +34,19 @@ import (
func TestValidateToken(t *testing.T) {
var tests = []struct {
c *kubeadm.JoinConfiguration
f *field.Path
token string
expected bool
}{
{&kubeadm.JoinConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, true},
{&kubeadm.JoinConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
{&kubeadm.JoinConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
{&kubeadm.JoinConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, true},
{&kubeadm.JoinConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, false},
{&kubeadm.JoinConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, false},
{&kubeadm.JoinConfiguration{Token: "abcdef.1234567890123456@foobar", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
{"772ef5.6b6baab1d4a0a171", true},
{".6b6baab1d4a0a171", false},
{"772ef5.", false},
{"772ef5.6b6baab1d4a0a171", true},
{".6b6baab1d4a0a171", false},
{"772ef5.", false},
{"abcdef.1234567890123456@foobar", false},
}
for _, rt := range tests {
err := ValidateToken(rt.c.Token, rt.f).ToAggregate()
err := ValidateToken(rt.token, nil).ToAggregate()
if (err == nil) != rt.expected {
t.Errorf(
"failed ValidateToken:\n\texpected: %t\n\t actual: %t",
@ -532,9 +531,15 @@ func TestValidateJoinConfiguration(t *testing.T) {
}{
{&kubeadm.JoinConfiguration{}, false},
{&kubeadm.JoinConfiguration{
DiscoveryFile: "foo",
DiscoveryToken: "abcdef.1234567890123456@foobar",
CACertPath: "/some/cert.crt",
CACertPath: "/some/cert.crt",
Discovery: kubeadm.Discovery{
BootstrapToken: &kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456@foobar",
},
File: &kubeadm.FileDiscovery{
KubeConfigPath: "foo",
},
},
}, false},
}
for _, rt := range tests {
@ -642,133 +647,129 @@ func TestValidateIgnorePreflightErrors(t *testing.T) {
}
}
func TestValidateArgSelection(t *testing.T) {
func TestValidateDiscovery(t *testing.T) {
var tests = []struct {
name string
c *kubeadm.JoinConfiguration
d *kubeadm.Discovery
expected bool
}{
{
"invalid: DiscoveryToken and DiscoveryFile cannot both be set",
&kubeadm.JoinConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryToken: "abcdef.1234567890123456",
"invalid: .BootstrapToken and .File cannot both be set",
&kubeadm.Discovery{
BootstrapToken: &kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
},
File: &kubeadm.FileDiscovery{
KubeConfigPath: "https://url/file.conf",
},
},
false,
},
{
"invalid: DiscoveryToken or DiscoveryFile must be set",
&kubeadm.JoinConfiguration{
DiscoveryFile: "",
DiscoveryToken: "",
"invalid: .BootstrapToken or .File must be set",
&kubeadm.Discovery{},
false,
},
}
for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) {
err := ValidateDiscovery(rt.d, nil).ToAggregate()
if (err == nil) != rt.expected {
t.Errorf(
"test case failed: ValidateDiscovery:\n\texpected: %t\n\t actual: %t",
rt.expected,
(err == nil),
)
}
})
}
}
func TestValidateDiscoveryBootstrapToken(t *testing.T) {
var tests = []struct {
name string
btd *kubeadm.BootstrapTokenDiscovery
expected bool
}{
{
"invalid: .APIServerEndpoints not set",
&kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
},
false,
},
{
"invalid: DiscoveryTokenAPIServers not set",
&kubeadm.JoinConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
},
false,
},
{
"invalid: DiscoveryTokenCACertHashes cannot be used with DiscoveryFile",
&kubeadm.JoinConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
},
false,
},
{
"invalid: using token-based discovery without DiscoveryTokenCACertHashes and DiscoveryTokenUnsafeSkipCAVerification",
&kubeadm.JoinConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenUnsafeSkipCAVerification: false,
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
"invalid: using token-based discovery without .BootstrapToken.CACertHashes and .BootstrapToken.UnsafeSkipCAVerification",
&kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
APIServerEndpoints: []string{"192.168.122.100:6443"},
UnsafeSkipCAVerification: false,
},
false,
},
{
"WARNING: kubeadm doesn't fully support multiple API Servers yet",
&kubeadm.JoinConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenUnsafeSkipCAVerification: true,
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443", "192.168.122.88:6443"},
&kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
APIServerEndpoints: []string{"192.168.122.100:6443", "192.168.122.88:6443"},
UnsafeSkipCAVerification: true,
},
true,
},
{
"valid: DiscoveryFile with DiscoveryTokenAPIServers",
&kubeadm.JoinConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
"valid: using token-based discovery with .BootstrapToken.CACertHashes",
&kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
APIServerEndpoints: []string{"192.168.122.100:6443"},
CACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
UnsafeSkipCAVerification: false,
},
true,
},
{
"valid: DiscoveryFile without DiscoveryTokenAPIServers",
&kubeadm.JoinConfiguration{
DiscoveryFile: "https://url/file.conf",
},
true,
},
{
"valid: using token-based discovery with DiscoveryTokenCACertHashes",
&kubeadm.JoinConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
DiscoveryTokenUnsafeSkipCAVerification: false,
},
true,
},
{
"valid: using token-based discovery with DiscoveryTokenCACertHashe but skip ca verification",
&kubeadm.JoinConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
DiscoveryTokenUnsafeSkipCAVerification: true,
"valid: using token-based discovery with .BootstrapToken.CACertHashe but skip ca verification",
&kubeadm.BootstrapTokenDiscovery{
Token: "abcdef.1234567890123456",
APIServerEndpoints: []string{"192.168.122.100:6443"},
CACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
UnsafeSkipCAVerification: true,
},
true,
},
}
for _, rt := range tests {
err := ValidateArgSelection(rt.c, nil).ToAggregate()
if (err == nil) != rt.expected {
t.Errorf(
"%s test case failed: ValidateArgSelection:\n\texpected: %t\n\t actual: %t",
rt.name,
rt.expected,
(err == nil),
)
}
t.Run(rt.name, func(t *testing.T) {
err := ValidateDiscoveryBootstrapToken(rt.btd, nil).ToAggregate()
if (err == nil) != rt.expected {
t.Errorf(
"test case failed: ValidateDiscoveryBootstrapToken:\n\texpected: %t\n\t actual: %t",
rt.expected,
(err == nil),
)
}
})
}
}
func TestValidateJoinDiscoveryTokenAPIServer(t *testing.T) {
func TestValidateDiscoveryTokenAPIServer(t *testing.T) {
var tests = []struct {
s *kubeadm.JoinConfiguration
expected bool
apiServerEndpoints []string
expected bool
}{
{
&kubeadm.JoinConfiguration{
DiscoveryTokenAPIServers: []string{"192.168.122.100"},
},
[]string{"192.168.122.100"},
false,
},
{
&kubeadm.JoinConfiguration{
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
},
[]string{"192.168.122.100:6443"},
true,
},
}
for _, rt := range tests {
actual := ValidateJoinDiscoveryTokenAPIServer(rt.s.DiscoveryTokenAPIServers, nil)
actual := ValidateDiscoveryTokenAPIServer(rt.apiServerEndpoints, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateJoinDiscoveryTokenAPIServer:\n\texpected: %t\n\t actual: %t",
"failed ValidateDiscoveryTokenAPIServer:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
@ -776,7 +777,7 @@ func TestValidateJoinDiscoveryTokenAPIServer(t *testing.T) {
}
}
func TestValidateDiscoveryFile(t *testing.T) {
func TestValidateDiscoveryKubeConfigPath(t *testing.T) {
tmpfile, err := ioutil.TempFile("/tmp", "test_discovery_file")
if err != nil {
t.Errorf("Error creating temporary file: %v", err)
@ -796,10 +797,10 @@ func TestValidateDiscoveryFile(t *testing.T) {
{"https://url/file.conf", true},
}
for i, rt := range tests {
actual := ValidateDiscoveryFile(rt.s, nil)
actual := ValidateDiscoveryKubeConfigPath(rt.s, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"%d: failed ValidateDiscoveryFile:\n\texpected: %t\n\t actual: %t",
"%d: failed ValidateDiscoveryKubeConfigPath:\n\texpected: %t\n\t actual: %t",
i,
rt.expected,
(len(actual) == 0),

View File

@ -105,6 +105,32 @@ func (in *BootstrapToken) DeepCopy() *BootstrapToken {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) {
*out = *in
if in.APIServerEndpoints != nil {
in, out := &in.APIServerEndpoints, &out.APIServerEndpoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.CACertHashes != nil {
in, out := &in.CACertHashes, &out.CACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenDiscovery.
func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery {
if in == nil {
return nil
}
out := new(BootstrapTokenDiscovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) {
*out = *in
@ -256,6 +282,37 @@ func (in *ComponentConfigs) DeepCopy() *ComponentConfigs {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Discovery) DeepCopyInto(out *Discovery) {
*out = *in
if in.BootstrapToken != nil {
in, out := &in.BootstrapToken, &out.BootstrapToken
*out = new(BootstrapTokenDiscovery)
(*in).DeepCopyInto(*out)
}
if in.File != nil {
in, out := &in.File, &out.File
*out = new(FileDiscovery)
**out = **in
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Discovery.
func (in *Discovery) DeepCopy() *Discovery {
if in == nil {
return nil
}
out := new(Discovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) {
*out = *in
@ -303,6 +360,22 @@ func (in *ExternalEtcd) DeepCopy() *ExternalEtcd {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileDiscovery) DeepCopyInto(out *FileDiscovery) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileDiscovery.
func (in *FileDiscovery) DeepCopy() *FileDiscovery {
if in == nil {
return nil
}
out := new(FileDiscovery)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostPathMount) DeepCopyInto(out *HostPathMount) {
*out = *in
@ -359,21 +432,7 @@ func (in *JoinConfiguration) DeepCopyInto(out *JoinConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
in.NodeRegistration.DeepCopyInto(&out.NodeRegistration)
if in.DiscoveryTokenAPIServers != nil {
in, out := &in.DiscoveryTokenAPIServers, &out.DiscoveryTokenAPIServers
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.DiscoveryTimeout != nil {
in, out := &in.DiscoveryTimeout, &out.DiscoveryTimeout
*out = new(v1.Duration)
**out = **in
}
if in.DiscoveryTokenCACertHashes != nil {
in, out := &in.DiscoveryTokenCACertHashes, &out.DiscoveryTokenCACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}
in.Discovery.DeepCopyInto(&out.Discovery)
out.APIEndpoint = in.APIEndpoint
if in.FeatureGates != nil {
in, out := &in.FeatureGates, &out.FeatureGates

View File

@ -195,9 +195,13 @@ func getDefaultInitConfigBytes(kind string) ([]byte, error) {
func getDefaultNodeConfigBytes() ([]byte, error) {
internalcfg, err := configutil.JoinConfigFileAndDefaultsToInternalConfig("", &kubeadmapiv1beta1.JoinConfiguration{
Token: sillyToken.Token.String(),
DiscoveryTokenAPIServers: []string{"kube-apiserver:6443"},
DiscoveryTokenUnsafeSkipCAVerification: true, // TODO: DiscoveryTokenUnsafeSkipCAVerification: true needs to be set for validation to pass, but shouldn't be recommended as the default
Discovery: kubeadmapiv1beta1.Discovery{
BootstrapToken: &kubeadmapiv1beta1.BootstrapTokenDiscovery{
Token: sillyToken.Token.String(),
APIServerEndpoints: []string{"kube-apiserver:6443"},
UnsafeSkipCAVerification: true, // TODO: UnsafeSkipCAVerification: true needs to be set for validation to pass, but shouldn't be recommended as the default
},
},
})
if err != nil {
return []byte{}, err

View File

@ -159,6 +159,10 @@ func NewCmdJoin(out io.Writer) *cobra.Command {
cfg := &kubeadmapiv1beta1.JoinConfiguration{}
kubeadmscheme.Scheme.Default(cfg)
fd := &kubeadmapiv1beta1.FileDiscovery{}
btd := &kubeadmapiv1beta1.BootstrapTokenDiscovery{}
var token string
var cfgPath string
var featureGatesString string
var ignorePreflightErrors []string
@ -168,22 +172,37 @@ func NewCmdJoin(out io.Writer) *cobra.Command {
Short: "Run this on any machine you wish to join an existing cluster",
Long: joinLongDescription,
Run: func(cmd *cobra.Command, args []string) {
j, err := NewValidJoin(cmd.PersistentFlags(), cfg, args, cfgPath, featureGatesString, ignorePreflightErrors)
if len(fd.KubeConfigPath) != 0 {
cfg.Discovery.File = fd
} else {
cfg.Discovery.BootstrapToken = btd
cfg.Discovery.BootstrapToken.APIServerEndpoints = args
if len(cfg.Discovery.BootstrapToken.Token) == 0 {
cfg.Discovery.BootstrapToken.Token = token
}
}
if len(cfg.Discovery.TLSBootstrapToken) == 0 {
cfg.Discovery.TLSBootstrapToken = token
}
j, err := NewValidJoin(cmd.PersistentFlags(), cfg, cfgPath, featureGatesString, ignorePreflightErrors)
kubeadmutil.CheckErr(err)
kubeadmutil.CheckErr(j.Run(out))
},
}
AddJoinConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString)
AddJoinConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString, &token)
AddJoinBootstrapTokenDiscoveryFlags(cmd.PersistentFlags(), btd)
AddJoinFileDiscoveryFlags(cmd.PersistentFlags(), fd)
AddJoinOtherFlags(cmd.PersistentFlags(), &cfgPath, &ignorePreflightErrors)
return cmd
}
// NewValidJoin validates the command line that are passed to the cobra command
func NewValidJoin(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfiguration, args []string, cfgPath, featureGatesString string, ignorePreflightErrors []string) (*Join, error) {
cfg.DiscoveryTokenAPIServers = args
func NewValidJoin(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfiguration, cfgPath, featureGatesString string, ignorePreflightErrors []string) (*Join, error) {
var err error
if cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil {
return nil, err
@ -198,32 +217,17 @@ func NewValidJoin(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfiguratio
return nil, err
}
return NewJoin(cfgPath, args, cfg, ignorePreflightErrorsSet)
return NewJoin(cfgPath, cfg, ignorePreflightErrorsSet)
}
// AddJoinConfigFlags adds join flags bound to the config to the specified flagset
func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfiguration, featureGatesString *string) {
flagSet.StringVar(
&cfg.DiscoveryFile, "discovery-file", "",
"A file or url from which to load cluster information.")
flagSet.StringVar(
&cfg.DiscoveryToken, "discovery-token", "",
"A token used to validate cluster information fetched from the api server.")
func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfiguration, featureGatesString *string, token *string) {
flagSet.StringVar(
&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name,
"Specify the node name.")
flagSet.StringVar(
&cfg.TLSBootstrapToken, "tls-bootstrap-token", "",
"A token used for TLS bootstrapping.")
flagSet.StringSliceVar(
&cfg.DiscoveryTokenCACertHashes, "discovery-token-ca-cert-hash", []string{},
"For token-based discovery, validate that the root CA public key matches this hash (format: \"<type>:<value>\").")
flagSet.BoolVar(
&cfg.DiscoveryTokenUnsafeSkipCAVerification, "discovery-token-unsafe-skip-ca-verification", false,
"For token-based discovery, allow joining without --discovery-token-ca-cert-hash pinning.")
flagSet.StringVar(
&cfg.Token, "token", "",
"Use this token for both discovery-token and tls-bootstrap-token.")
token, "token", "",
"Use this token for both discovery-token and tls-bootstrap-token when those values are not provided.")
flagSet.StringVar(
featureGatesString, "feature-gates", *featureGatesString,
"A set of key=value pairs that describe feature gates for various features. "+
@ -245,6 +249,26 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfig
)
}
// AddJoinBootstrapTokenDiscoveryFlags adds bootstrap token specific discovery flags to the specified flagset
func AddJoinBootstrapTokenDiscoveryFlags(flagSet *flag.FlagSet, btd *kubeadmapiv1beta1.BootstrapTokenDiscovery) {
flagSet.StringVar(
&btd.Token, "discovery-token", "",
"A token used to validate cluster information fetched from the API server.")
flagSet.StringSliceVar(
&btd.CACertHashes, "discovery-token-ca-cert-hash", []string{},
"For token-based discovery, validate that the root CA public key matches this hash (format: \"<type>:<value>\").")
flagSet.BoolVar(
&btd.UnsafeSkipCAVerification, "discovery-token-unsafe-skip-ca-verification", false,
"For token-based discovery, allow joining without --discovery-token-ca-cert-hash pinning.")
}
// AddJoinFileDiscoveryFlags adds file discovery flags to the specified flagset
func AddJoinFileDiscoveryFlags(flagSet *flag.FlagSet, fd *kubeadmapiv1beta1.FileDiscovery) {
flagSet.StringVar(
&fd.KubeConfigPath, "discovery-file", "",
"A file or URL from which to load cluster information.")
}
// AddJoinOtherFlags adds join flags that are not bound to a configuration file to the given flagset
func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, ignorePreflightErrors *[]string) {
flagSet.StringVar(
@ -264,7 +288,7 @@ type Join struct {
}
// NewJoin instantiates Join struct with given arguments
func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1beta1.JoinConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
func NewJoin(cfgPath string, defaultcfg *kubeadmapiv1beta1.JoinConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
if defaultcfg.NodeRegistration.Name == "" {
glog.V(1).Infoln("[join] found NodeName empty; using OS hostname as NodeName")

View File

@ -70,7 +70,6 @@ func TestNewValidJoin(t *testing.T) {
testCases := []struct {
name string
args []string
skipPreFlight bool
cfgPath string
configToWrite string
@ -163,7 +162,7 @@ func TestNewValidJoin(t *testing.T) {
}
}
join, err := NewValidJoin(cmd.PersistentFlags(), cfg, tc.args, tc.cfgPath, tc.featureGatesString, tc.ignorePreflightErrors)
join, err := NewValidJoin(cmd.PersistentFlags(), cfg, tc.cfgPath, tc.featureGatesString, tc.ignorePreflightErrors)
if tc.nodeConfig != nil {
join.cfg = tc.nodeConfig

View File

@ -41,7 +41,7 @@ func For(cfg *kubeadmapi.JoinConfiguration) (*clientcmdapi.Config, error) {
return nil, fmt.Errorf("couldn't validate the identity of the API Server: %v", err)
}
if len(cfg.TLSBootstrapToken) == 0 {
if len(cfg.Discovery.TLSBootstrapToken) == 0 {
return config, nil
}
clusterinfo := kubeconfigutil.GetClusterFromKubeConfig(config)
@ -50,19 +50,20 @@ func For(cfg *kubeadmapi.JoinConfiguration) (*clientcmdapi.Config, error) {
cfg.ClusterName,
TokenUser,
clusterinfo.CertificateAuthorityData,
cfg.TLSBootstrapToken,
cfg.Discovery.TLSBootstrapToken,
), nil
}
// DiscoverValidatedKubeConfig returns a validated Config object that specifies where the cluster is and the CA cert to trust
func DiscoverValidatedKubeConfig(cfg *kubeadmapi.JoinConfiguration) (*clientcmdapi.Config, error) {
switch {
case len(cfg.DiscoveryFile) != 0:
if isHTTPSURL(cfg.DiscoveryFile) {
return https.RetrieveValidatedConfigInfo(cfg.DiscoveryFile, cfg.ClusterName)
case cfg.Discovery.File != nil:
kubeConfigPath := cfg.Discovery.File.KubeConfigPath
if isHTTPSURL(kubeConfigPath) {
return https.RetrieveValidatedConfigInfo(kubeConfigPath, cfg.ClusterName)
}
return file.RetrieveValidatedConfigInfo(cfg.DiscoveryFile, cfg.ClusterName)
case len(cfg.DiscoveryToken) != 0:
return file.RetrieveValidatedConfigInfo(kubeConfigPath, cfg.ClusterName)
case cfg.Discovery.BootstrapToken != nil:
return token.RetrieveValidatedConfigInfo(cfg)
default:
return nil, fmt.Errorf("couldn't find a valid discovery configuration")

View File

@ -30,25 +30,31 @@ func TestFor(t *testing.T) {
{d: kubeadm.JoinConfiguration{}, expect: false},
{
d: kubeadm.JoinConfiguration{
DiscoveryFile: "notnil",
Discovery: kubeadm.Discovery{
File: &kubeadm.FileDiscovery{
KubeConfigPath: "notnil",
},
},
},
expect: false,
},
{
d: kubeadm.JoinConfiguration{
DiscoveryFile: "https://localhost",
Discovery: kubeadm.Discovery{
File: &kubeadm.FileDiscovery{
KubeConfigPath: "https://localhost",
},
},
},
expect: false,
},
{
d: kubeadm.JoinConfiguration{
DiscoveryFile: "notnil",
},
expect: false,
},
{
d: kubeadm.JoinConfiguration{
DiscoveryToken: "foo.bar@foobar",
Discovery: kubeadm.Discovery{
BootstrapToken: &kubeadm.BootstrapTokenDiscovery{
Token: "foo.bar@foobar",
},
},
},
expect: false,
},

View File

@ -44,21 +44,21 @@ const BootstrapUser = "token-bootstrap-client"
// It then makes sure it can trust the API Server by looking at the JWS-signed tokens and (if cfg.DiscoveryTokenCACertHashes is not empty)
// validating the cluster CA against a set of pinned public keys
func RetrieveValidatedConfigInfo(cfg *kubeadmapi.JoinConfiguration) (*clientcmdapi.Config, error) {
token, err := kubeadmapi.NewBootstrapTokenString(cfg.DiscoveryToken)
token, err := kubeadmapi.NewBootstrapTokenString(cfg.Discovery.BootstrapToken.Token)
if err != nil {
return nil, err
}
// Load the cfg.DiscoveryTokenCACertHashes into a pubkeypin.Set
pubKeyPins := pubkeypin.NewSet()
err = pubKeyPins.Allow(cfg.DiscoveryTokenCACertHashes...)
err = pubKeyPins.Allow(cfg.Discovery.BootstrapToken.CACertHashes...)
if err != nil {
return nil, err
}
// The function below runs for every endpoint, and all endpoints races with each other.
// The endpoint that wins the race and completes the task first gets its kubeconfig returned below
baseKubeConfig, err := runForEndpointsAndReturnFirst(cfg.DiscoveryTokenAPIServers, cfg.DiscoveryTimeout.Duration, func(endpoint string) (*clientcmdapi.Config, error) {
baseKubeConfig, err := runForEndpointsAndReturnFirst(cfg.Discovery.BootstrapToken.APIServerEndpoints, cfg.Discovery.Timeout.Duration, func(endpoint string) (*clientcmdapi.Config, error) {
insecureBootstrapConfig := buildInsecureBootstrapKubeConfig(endpoint, cfg.ClusterName)
clusterName := insecureBootstrapConfig.Contexts[insecureBootstrapConfig.CurrentContext].Cluster

View File

@ -928,16 +928,18 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura
}
addIPv6Checks := false
for _, server := range cfg.DiscoveryTokenAPIServers {
ipstr, _, err := net.SplitHostPort(server)
if err == nil {
checks = append(checks,
HTTPProxyCheck{Proto: "https", Host: ipstr},
)
if !addIPv6Checks {
if ip := net.ParseIP(ipstr); ip != nil {
if ip.To4() == nil && ip.To16() != nil {
addIPv6Checks = true
if cfg.Discovery.BootstrapToken != nil {
for _, server := range cfg.Discovery.BootstrapToken.APIServerEndpoints {
ipstr, _, err := net.SplitHostPort(server)
if err == nil {
checks = append(checks,
HTTPProxyCheck{Proto: "https", Host: ipstr},
)
if !addIPv6Checks {
if ip := net.ParseIP(ipstr); ip != nil {
if ip.To4() == nil && ip.To16() != nil {
addIPv6Checks = true
}
}
}
}

View File

@ -254,13 +254,21 @@ func TestRunJoinNodeChecks(t *testing.T) {
},
{
cfg: &kubeadmapi.JoinConfiguration{
DiscoveryTokenAPIServers: []string{"192.168.1.15"},
Discovery: kubeadmapi.Discovery{
BootstrapToken: &kubeadmapi.BootstrapTokenDiscovery{
APIServerEndpoints: []string{"192.168.1.15"},
},
},
},
expected: false,
},
{
cfg: &kubeadmapi.JoinConfiguration{
DiscoveryTokenAPIServers: []string{"2001:1234::1:15"},
Discovery: kubeadmapi.Discovery{
BootstrapToken: &kubeadmapi.BootstrapTokenDiscovery{
APIServerEndpoints: []string{"2001:1234::1:15"},
},
},
},
expected: false,
},

View File

@ -4,18 +4,19 @@ APIEndpoint:
CACertPath: /etc/kubernetes/pki/ca.crt
ClusterName: kubernetes
ControlPlane: false
DiscoveryFile: ""
DiscoveryTimeout: 5m0s
DiscoveryToken: abcdef.0123456789abcdef
DiscoveryTokenAPIServers:
- kube-apiserver:6443
DiscoveryTokenCACertHashes: null
DiscoveryTokenUnsafeSkipCAVerification: true
Discovery:
BootstrapToken:
APIServerEndpoints:
- kube-apiserver:6443
CACertHashes: null
Token: abcdef.0123456789abcdef
UnsafeSkipCAVerification: true
File: null
TLSBootstrapToken: abcdef.0123456789abcdef
Timeout: 5m0s
FeatureGates: null
NodeRegistration:
CRISocket: /var/run/dockershim.sock
KubeletExtraArgs: null
Name: master-1
Taints: null
TLSBootstrapToken: abcdef.0123456789abcdef
Token: abcdef.0123456789abcdef

View File

@ -4,15 +4,15 @@ apiEndpoint:
apiVersion: kubeadm.k8s.io/v1beta1
caCertPath: /etc/kubernetes/pki/ca.crt
clusterName: kubernetes
discoveryFile: ""
discoveryTimeout: 5m0s
discoveryToken: abcdef.0123456789abcdef
discoveryTokenAPIServers:
- kube-apiserver:6443
discoveryTokenUnsafeSkipCAVerification: true
discovery:
bootstrapToken:
apiServerEndpoints:
- kube-apiserver:6443
token: abcdef.0123456789abcdef
unsafeSkipCAVerification: true
timeout: 5m0s
tlsBootstrapToken: abcdef.0123456789abcdef
kind: JoinConfiguration
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: master-1
tlsBootstrapToken: abcdef.0123456789abcdef
token: abcdef.0123456789abcdef

View File

@ -4,15 +4,15 @@ apiEndpoint:
apiVersion: kubeadm.k8s.io/v1beta1
caCertPath: /etc/kubernetes/pki/ca.crt
clusterName: kubernetes
discoveryFile: ""
discoveryTimeout: 5m0s
discoveryToken: abcdef.0123456789abcdef
discoveryTokenAPIServers:
- kube-apiserver:6443
discoveryTokenUnsafeSkipCAVerification: true
discovery:
bootstrapToken:
apiServerEndpoints:
- kube-apiserver:6443
token: abcdef.0123456789abcdef
unsafeSkipCAVerification: true
timeout: 5m0s
tlsBootstrapToken: abcdef.0123456789abcdef
kind: JoinConfiguration
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: thegopher
tlsBootstrapToken: abcdef.0123456789abcdef
token: abcdef.0123456789abcdef

View File

@ -1,5 +1,15 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: NodeConfiguration
apiEndpoint:
advertiseAddress: INVALID-ADDRESS-!!!!
bindPort: 6443
caCertPath: relativepath
discovery:
timeout: not-a-time
bootstrapToken:
token: invalidtoken
apiServerEndpoints:
- INVALID_URL
unsafeSkipCAVerification: false
file:
kubeConfigPath: relativepath
nodeRegistration:
criSocket: relativepath
name: NODE-1