Unverified Commit 1e4ad048 authored by k8s-ci-robot's avatar k8s-ci-robot Committed by GitHub

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

kubeadm: Split discovery from JoinConfiguration
parents ee434665 576b8d3f
......@@ -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},
}
}
......@@ -280,27 +280,55 @@ 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
// Discovery specifies the options for the kubelet to use during the TLS Bootstrap process
Discovery Discovery
// The cluster name
ClusterName string
// ControlPlane flag specifies that the joining node should host an additional
// control plane instance.
ControlPlane bool
// APIEndpoint represents the endpoint of the instance of the API server eventually to be deployed on this node.
APIEndpoint APIEndpoint
// FeatureGates enabled by the user.
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.
// Defaults to Token.
// 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
// Token is used for both discovery and TLS bootstrapping.
// 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
// The cluster name
ClusterName string
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// 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>",
......@@ -308,22 +336,18 @@ type JoinConfiguration struct {
// 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
CACertHashes []string
// DiscoveryTokenUnsafeSkipCAVerification allows token-based discovery
// without CA verification via DiscoveryTokenCACertHashes. This can weaken
// UnsafeSkipCAVerification allows token-based discovery
// without CA verification via CACertHashes. 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
// APIEndpoint represents the endpoint of the instance of the API server eventually to be deployed on this node.
APIEndpoint APIEndpoint
UnsafeSkipCAVerification bool
}
// FeatureGates enabled by the user.
FeatureGates map[string]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
......
......@@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"bootstraptokenstring.go",
"conversion.go",
"defaults.go",
"defaults_unix.go",
"defaults_windows.go",
......
/*
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
}
......@@ -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
......
......@@ -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 == "" {
......
......@@ -258,28 +258,55 @@ 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"`
// 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"`
// ControlPlane flag specifies that the joining node should host an additional
// control plane instance.
ControlPlane bool `json:"controlPlane,omitempty"`
// APIEndpoint represents the endpoint of the instance of the API server eventually to be deployed on this node.
APIEndpoint APIEndpoint `json:"apiEndpoint,omitempty"`
// FeatureGates enabled by the user.
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.
// Defaults to Token.
// 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"`
// Token is used for both discovery and TLS bootstrapping.
// 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"`
// ClusterName is the name for the cluster in kubeconfig.
ClusterName string `json:"clusterName,omitempty"`
// 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"`
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// 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>",
......@@ -287,22 +314,18 @@ type JoinConfiguration struct {
// 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"`
CACertHashes []string `json:"caCertHashes,omitempty"`
// DiscoveryTokenUnsafeSkipCAVerification allows token-based discovery
// without CA verification via DiscoveryTokenCACertHashes. This can weaken
// UnsafeSkipCAVerification allows token-based discovery
// without CA verification via CACertHashes. 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"`
// APIEndpoint represents the endpoint of the instance of the API server eventually to be deployed on this node.
APIEndpoint APIEndpoint `json:"apiEndpoint,omitempty"`
UnsafeSkipCAVerification bool `json:"unsafeSkipCAVerification"`
}
// FeatureGates enabled by the user.
FeatureGates map[string]bool `json:"featureGates,omitempty"`
// 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
......
......@@ -104,6 +104,32 @@ func (in *BootstrapToken) DeepCopy() *BootstrapToken {
}
// 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
return
......@@ -228,6 +254,37 @@ func (in *ClusterStatus) DeepCopyObject() runtime.Object {
}
// 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
if in.Local != nil {
......@@ -275,6 +332,22 @@ func (in *ExternalEtcd) DeepCopy() *ExternalEtcd {
}
// 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
return
......@@ -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
......
......@@ -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)
}
......@@ -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 d.BootstrapToken != nil && d.File != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "", "bootstrapToken and file cannot both 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 {
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
}
// 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
}
// ValidateJoinDiscoveryTokenAPIServer validates discovery token for API server
func ValidateJoinDiscoveryTokenAPIServer(apiServers []string, fldPath *field.Path) field.ErrorList {
// 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 {
......
......@@ -106,6 +106,32 @@ func (in *BootstrapToken) DeepCopy() *BootstrapToken {
}
// 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
return
......@@ -257,6 +283,37 @@ func (in *ComponentConfigs) DeepCopy() *ComponentConfigs {
}
// 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
if in.Local != nil {
......@@ -304,6 +361,22 @@ func (in *ExternalEtcd) DeepCopy() *ExternalEtcd {
}
// 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
return
......@@ -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
......
......@@ -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
......
......@@ -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")
......
......@@ -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
......
......@@ -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")
......
......@@ -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,
},
......
......@@ -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
......
......@@ -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
}
}
}
}
......
......@@ -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,
},
......
......@@ -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
......@@ -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
......@@ -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
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment