mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	kubeadm: Add --cert-dir, --apiserver-cert-extra-sans, remove --api-external-dns-names and add the phase command for certs. Also use the CertificatesDir var everywhere instead of the HostPKIPath variable and fix some bugs in certs.go
This commit is contained in:
		@@ -32,7 +32,6 @@ func SetEnvParams() *EnvParams {
 | 
			
		||||
 | 
			
		||||
	envParams := map[string]string{
 | 
			
		||||
		"kubernetes_dir":  "/etc/kubernetes",
 | 
			
		||||
		"host_pki_path":   "/etc/kubernetes/pki",
 | 
			
		||||
		"host_etcd_path":  "/var/lib/etcd",
 | 
			
		||||
		"hyperkube_image": "",
 | 
			
		||||
		"repo_prefix":     "gcr.io/google_containers",
 | 
			
		||||
@@ -48,7 +47,6 @@ func SetEnvParams() *EnvParams {
 | 
			
		||||
 | 
			
		||||
	return &EnvParams{
 | 
			
		||||
		KubernetesDir:    path.Clean(envParams["kubernetes_dir"]),
 | 
			
		||||
		HostPKIPath:      path.Clean(envParams["host_pki_path"]),
 | 
			
		||||
		HostEtcdPath:     path.Clean(envParams["host_etcd_path"]),
 | 
			
		||||
		HyperkubeImage:   envParams["hyperkube_image"],
 | 
			
		||||
		RepositoryPrefix: envParams["repo_prefix"],
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,8 @@ func KubeadmFuzzerFuncs(t apitesting.TestingCommon) []interface{} {
 | 
			
		||||
			obj.Networking.DNSDomain = "foo"
 | 
			
		||||
			obj.AuthorizationMode = "foo"
 | 
			
		||||
			obj.Discovery.Token = &kubeadm.TokenDiscovery{}
 | 
			
		||||
			obj.CertificatesDir = "foo"
 | 
			
		||||
			obj.APIServerCertSANs = []string{}
 | 
			
		||||
		},
 | 
			
		||||
		func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) {
 | 
			
		||||
			c.FuzzNoCustom(obj)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ import (
 | 
			
		||||
 | 
			
		||||
type EnvParams struct {
 | 
			
		||||
	KubernetesDir    string
 | 
			
		||||
	HostPKIPath      string
 | 
			
		||||
	HostEtcdPath     string
 | 
			
		||||
	HyperkubeImage   string
 | 
			
		||||
	RepositoryPrefix string
 | 
			
		||||
@@ -40,6 +39,7 @@ type MasterConfiguration struct {
 | 
			
		||||
	KubernetesVersion string
 | 
			
		||||
	CloudProvider     string
 | 
			
		||||
	AuthorizationMode string
 | 
			
		||||
 | 
			
		||||
	// SelfHosted enables an alpha deployment type where the apiserver, scheduler, and
 | 
			
		||||
	// controller manager are managed by Kubernetes itself. This option is likely to
 | 
			
		||||
	// become the default in the future.
 | 
			
		||||
@@ -48,11 +48,17 @@ type MasterConfiguration struct {
 | 
			
		||||
	APIServerExtraArgs         map[string]string
 | 
			
		||||
	ControllerManagerExtraArgs map[string]string
 | 
			
		||||
	SchedulerExtraArgs         map[string]string
 | 
			
		||||
 | 
			
		||||
	// APIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert
 | 
			
		||||
	APIServerCertSANs []string
 | 
			
		||||
	// CertificatesDir specifies where to store or look for all required certificates
 | 
			
		||||
	CertificatesDir string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type API struct {
 | 
			
		||||
	// AdvertiseAddress sets the address for the API server to advertise.
 | 
			
		||||
	AdvertiseAddress string
 | 
			
		||||
	ExternalDNSNames []string
 | 
			
		||||
	// BindPort sets the secure port for the API Server to bind to
 | 
			
		||||
	BindPort int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ const (
 | 
			
		||||
	DefaultDiscoveryBindPort         = 9898
 | 
			
		||||
	DefaultAuthorizationMode         = "RBAC"
 | 
			
		||||
	DefaultCACertPath                = "/etc/kubernetes/pki/ca.crt"
 | 
			
		||||
	DefaultCertificatesDir           = "/etc/kubernetes/pki"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
 | 
			
		||||
@@ -66,6 +67,10 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
 | 
			
		||||
	if obj.AuthorizationMode == "" {
 | 
			
		||||
		obj.AuthorizationMode = DefaultAuthorizationMode
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if obj.CertificatesDir == "" {
 | 
			
		||||
		obj.CertificatesDir = DefaultCertificatesDir
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ type MasterConfiguration struct {
 | 
			
		||||
	KubernetesVersion string     `json:"kubernetesVersion"`
 | 
			
		||||
	CloudProvider     string     `json:"cloudProvider"`
 | 
			
		||||
	AuthorizationMode string     `json:"authorizationMode"`
 | 
			
		||||
 | 
			
		||||
	// SelfHosted enables an alpha deployment type where the apiserver, scheduler, and
 | 
			
		||||
	// controller manager are managed by Kubernetes itself. This option is likely to
 | 
			
		||||
	// become the default in the future.
 | 
			
		||||
@@ -38,12 +39,17 @@ type MasterConfiguration struct {
 | 
			
		||||
	APIServerExtraArgs         map[string]string `json:"apiServerExtraArgs"`
 | 
			
		||||
	ControllerManagerExtraArgs map[string]string `json:"controllerManagerExtraArgs"`
 | 
			
		||||
	SchedulerExtraArgs         map[string]string `json:"schedulerExtraArgs"`
 | 
			
		||||
 | 
			
		||||
	// APIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert
 | 
			
		||||
	APIServerCertSANs []string `json:"apiServerCertSANs"`
 | 
			
		||||
	// CertificatesDir specifies where to store or look for all required certificates
 | 
			
		||||
	CertificatesDir string `json:"certificatesDir"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type API struct {
 | 
			
		||||
	// The address for the API server to advertise.
 | 
			
		||||
	// AdvertiseAddress sets the address for the API server to advertise.
 | 
			
		||||
	AdvertiseAddress string `json:"advertiseAddress"`
 | 
			
		||||
	ExternalDNSNames []string `json:"externalDNSNames"`
 | 
			
		||||
	// BindPort sets the secure port for the API Server to bind to
 | 
			
		||||
	BindPort int32 `json:"bindPort"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,10 @@ go_library(
 | 
			
		||||
        "//cmd/kubeadm/app/apis/kubeadm:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/constants:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/util/token:go_default_library",
 | 
			
		||||
        "//pkg/api/validation:go_default_library",
 | 
			
		||||
        "//pkg/kubeapiserver/authorizer/modes:go_default_library",
 | 
			
		||||
        "//pkg/registry/core/service/ipallocator:go_default_library",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/validation",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -21,13 +21,15 @@ import (
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
 | 
			
		||||
	apivalidation "k8s.io/kubernetes/pkg/api/validation"
 | 
			
		||||
	authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
 | 
			
		||||
)
 | 
			
		||||
@@ -49,9 +51,11 @@ var cloudproviders = []string{
 | 
			
		||||
 | 
			
		||||
func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	allErrs = append(allErrs, ValidateServiceSubnet(c.Networking.ServiceSubnet, field.NewPath("service subnet"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudprovider"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateAuthorizationMode(c.AuthorizationMode, field.NewPath("authorization-mode"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...)
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +63,7 @@ func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	allErrs = append(allErrs, ValidateDiscovery(c, field.NewPath("discovery"))...)
 | 
			
		||||
 | 
			
		||||
	if !path.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") {
 | 
			
		||||
	if !filepath.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(field.NewPath("ca-cert-path"), c.CACertPath, "the ca certificate path must be an absolute path"))
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
@@ -142,35 +146,75 @@ func ValidateToken(t string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
 | 
			
		||||
	id, secret, err := tokenutil.ParseToken(t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, nil, err.Error()))
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, t, err.Error()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(id) == 0 || len(secret) == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, nil, "token must be of form '[a-z0-9]{6}.[a-z0-9]{16}'"))
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, t, "token must be of form '[a-z0-9]{6}.[a-z0-9]{16}'"))
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateServiceSubnet(subnet string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
func ValidateAPIServerCertSANs(altnames []string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	for _, altname := range altnames {
 | 
			
		||||
		if len(validation.IsDNS1123Subdomain(altname)) != 0 && net.ParseIP(altname) == nil {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath, altname, "altname is not a valid dns label or ip address"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateIPFromString(ipaddr string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if net.ParseIP(ipaddr) == nil {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, ipaddr, "ip address is not valid"))
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateIPNetFromString(subnet string, minAddrs int64, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	_, svcSubnet, err := net.ParseCIDR(subnet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return field.ErrorList{field.Invalid(fldPath, nil, "couldn't parse the service subnet")}
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, subnet, "couldn't parse subnet"))
 | 
			
		||||
		return allErrs
 | 
			
		||||
	}
 | 
			
		||||
	numAddresses := ipallocator.RangeSize(svcSubnet)
 | 
			
		||||
	if numAddresses < constants.MinimumAddressesInServiceSubnet {
 | 
			
		||||
		return field.ErrorList{field.Invalid(fldPath, nil, "service subnet is too small")}
 | 
			
		||||
	if numAddresses < minAddrs {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, subnet, "subnet is too small"))
 | 
			
		||||
	}
 | 
			
		||||
	return field.ErrorList{}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateNetworking(c *kubeadm.Networking, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	allErrs = append(allErrs, apivalidation.ValidateDNS1123Subdomain(c.DNSDomain, field.NewPath("dns-domain"))...)
 | 
			
		||||
	allErrs = append(allErrs, ValidateIPNetFromString(c.ServiceSubnet, constants.MinimumAddressesInServiceSubnet, field.NewPath("service-subnet"))...)
 | 
			
		||||
	if len(c.PodSubnet) != 0 {
 | 
			
		||||
		allErrs = append(allErrs, ValidateIPNetFromString(c.PodSubnet, constants.MinimumAddressesInServiceSubnet, field.NewPath("pod-subnet"))...)
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateAbsolutePath(path string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if !filepath.IsAbs(path) {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath, path, "path is not absolute"))
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateCloudProvider(provider string, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if len(provider) == 0 {
 | 
			
		||||
		return field.ErrorList{}
 | 
			
		||||
		return allErrs
 | 
			
		||||
	}
 | 
			
		||||
	for _, supported := range cloudproviders {
 | 
			
		||||
		if provider == supported {
 | 
			
		||||
			return field.ErrorList{}
 | 
			
		||||
			return allErrs
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return field.ErrorList{field.Invalid(fldPath, nil, "cloudprovider not supported")}
 | 
			
		||||
	allErrs = append(allErrs, field.Invalid(fldPath, provider, "cloudprovider not supported"))
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,31 +69,6 @@ func TestValidateAuthorizationMode(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateServiceSubnet(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		s        string
 | 
			
		||||
		f        *field.Path
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{"", nil, false},
 | 
			
		||||
		{"this is not a cidr", nil, false}, // not a CIDR
 | 
			
		||||
		{"10.0.0.1", nil, false},           // not a CIDR
 | 
			
		||||
		{"10.96.0.1/29", nil, false},       // CIDR too small, only 8 addresses and we require at least 10
 | 
			
		||||
		{"10.96.0.1/28", nil, true},        // a /28 subnet is ok because it can contain 16 addresses
 | 
			
		||||
		{"10.96.0.1/12", nil, true},        // the default subnet should obviously pass as well
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		actual := ValidateServiceSubnet(rt.s, rt.f)
 | 
			
		||||
		if (len(actual) == 0) != rt.expected {
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"failed ValidateServiceSubnet:\n\texpected: %t\n\t  actual: %t",
 | 
			
		||||
				rt.expected,
 | 
			
		||||
				(len(actual) == 0),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateCloudProvider(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		s        string
 | 
			
		||||
@@ -118,6 +93,78 @@ func TestValidateCloudProvider(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateAPIServerCertSANs(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		sans     []string
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{[]string{}, true},                                                  // ok if not provided
 | 
			
		||||
		{[]string{"1,2,,3"}, false},                                         // not a DNS label or IP
 | 
			
		||||
		{[]string{"my-hostname", "???&?.garbage"}, false},                   // not valid
 | 
			
		||||
		{[]string{"my-hostname", "my.subdomain", "1.2.3.4"}, true},          // supported
 | 
			
		||||
		{[]string{"my-hostname2", "my.other.subdomain", "10.0.0.10"}, true}, // supported
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		actual := ValidateAPIServerCertSANs(rt.sans, nil)
 | 
			
		||||
		if (len(actual) == 0) != rt.expected {
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"failed ValidateAPIServerCertSANs:\n\texpected: %t\n\t  actual: %t",
 | 
			
		||||
				rt.expected,
 | 
			
		||||
				(len(actual) == 0),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateIPFromString(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		ip       string
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{"", false},           // not valid
 | 
			
		||||
		{"1234", false},       // not valid
 | 
			
		||||
		{"1.2", false},        // not valid
 | 
			
		||||
		{"1.2.3.4/16", false}, // not valid
 | 
			
		||||
		{"1.2.3.4", true},     // valid
 | 
			
		||||
		{"16.0.1.1", true},    // valid
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		actual := ValidateIPFromString(rt.ip, nil)
 | 
			
		||||
		if (len(actual) == 0) != rt.expected {
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"failed ValidateIPFromString:\n\texpected: %t\n\t  actual: %t",
 | 
			
		||||
				rt.expected,
 | 
			
		||||
				(len(actual) == 0),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateIPNetFromString(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		subnet   string
 | 
			
		||||
		minaddrs int64
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{"", 0, false},              // not valid
 | 
			
		||||
		{"1234", 0, false},          // not valid
 | 
			
		||||
		{"abc", 0, false},           // not valid
 | 
			
		||||
		{"1.2.3.4", 0, false},       // ip not valid
 | 
			
		||||
		{"10.0.0.16/29", 10, false}, // valid, but too small. At least 10 addrs needed
 | 
			
		||||
		{"10.0.0.16/12", 10, true},  // valid
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		actual := ValidateIPNetFromString(rt.subnet, rt.minaddrs, nil)
 | 
			
		||||
		if (len(actual) == 0) != rt.expected {
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"failed ValidateIPNetFromString:\n\texpected: %t\n\t  actual: %t",
 | 
			
		||||
				rt.expected,
 | 
			
		||||
				(len(actual) == 0),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidateMasterConfiguration(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		s        *kubeadm.MasterConfiguration
 | 
			
		||||
@@ -131,7 +178,9 @@ func TestValidateMasterConfiguration(t *testing.T) {
 | 
			
		||||
			AuthorizationMode: "RBAC",
 | 
			
		||||
			Networking: kubeadm.Networking{
 | 
			
		||||
				ServiceSubnet: "10.96.0.1/12",
 | 
			
		||||
				DNSDomain:     "cluster.local",
 | 
			
		||||
			},
 | 
			
		||||
			CertificatesDir: "/some/cert/dir",
 | 
			
		||||
		}, true},
 | 
			
		||||
		{&kubeadm.MasterConfiguration{
 | 
			
		||||
			Discovery: kubeadm.Discovery{
 | 
			
		||||
@@ -140,7 +189,9 @@ func TestValidateMasterConfiguration(t *testing.T) {
 | 
			
		||||
			AuthorizationMode: "RBAC",
 | 
			
		||||
			Networking: kubeadm.Networking{
 | 
			
		||||
				ServiceSubnet: "10.96.0.1/12",
 | 
			
		||||
				DNSDomain:     "cluster.local",
 | 
			
		||||
			},
 | 
			
		||||
			CertificatesDir: "/some/other/cert/dir",
 | 
			
		||||
		}, true},
 | 
			
		||||
		{&kubeadm.MasterConfiguration{
 | 
			
		||||
			Discovery: kubeadm.Discovery{
 | 
			
		||||
@@ -153,7 +204,9 @@ func TestValidateMasterConfiguration(t *testing.T) {
 | 
			
		||||
			AuthorizationMode: "RBAC",
 | 
			
		||||
			Networking: kubeadm.Networking{
 | 
			
		||||
				ServiceSubnet: "10.96.0.1/12",
 | 
			
		||||
				DNSDomain:     "cluster.local",
 | 
			
		||||
			},
 | 
			
		||||
			CertificatesDir: "/yet/another/cert/dir",
 | 
			
		||||
		}, true},
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
 
 | 
			
		||||
@@ -88,10 +88,6 @@ func NewCmdInit(out io.Writer) *cobra.Command {
 | 
			
		||||
		&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort,
 | 
			
		||||
		"Port for the API Server to bind to",
 | 
			
		||||
	)
 | 
			
		||||
	cmd.PersistentFlags().StringSliceVar(
 | 
			
		||||
		&cfg.API.ExternalDNSNames, "api-external-dns-names", cfg.API.ExternalDNSNames,
 | 
			
		||||
		"The DNS names to advertise, in case you have configured them yourself",
 | 
			
		||||
	)
 | 
			
		||||
	cmd.PersistentFlags().StringVar(
 | 
			
		||||
		&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet,
 | 
			
		||||
		"Use alternative range of IP address for service VIPs",
 | 
			
		||||
@@ -108,6 +104,14 @@ func NewCmdInit(out io.Writer) *cobra.Command {
 | 
			
		||||
		&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion,
 | 
			
		||||
		`Choose a specific Kubernetes version for the control plane`,
 | 
			
		||||
	)
 | 
			
		||||
	cmd.PersistentFlags().StringVar(
 | 
			
		||||
		&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir,
 | 
			
		||||
		`The path where to save and store the certificates`,
 | 
			
		||||
	)
 | 
			
		||||
	cmd.PersistentFlags().StringSliceVar(
 | 
			
		||||
		&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", cfg.APIServerCertSANs,
 | 
			
		||||
		`Optional extra altnames to use for the API Server serving cert. Can be both IP addresses and dns names.`,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	cmd.PersistentFlags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file")
 | 
			
		||||
 | 
			
		||||
@@ -179,7 +183,7 @@ func (i *Init) Validate() error {
 | 
			
		||||
func (i *Init) Run(out io.Writer) error {
 | 
			
		||||
 | 
			
		||||
	// PHASE 1: Generate certificates
 | 
			
		||||
	err := certphase.CreatePKIAssets(i.cfg, kubeadmapi.GlobalEnvParams.HostPKIPath)
 | 
			
		||||
	err := certphase.CreatePKIAssets(i.cfg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -190,7 +194,7 @@ func (i *Init) Run(out io.Writer) error {
 | 
			
		||||
	// so we'll pick the first one, there is much of chance to have an empty
 | 
			
		||||
	// slice by the time this gets called
 | 
			
		||||
	masterEndpoint := fmt.Sprintf("https://%s:%d", i.cfg.API.AdvertiseAddress, i.cfg.API.BindPort)
 | 
			
		||||
	err = kubeconfigphase.CreateInitKubeConfigFiles(masterEndpoint, kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmapi.GlobalEnvParams.KubernetesDir)
 | 
			
		||||
	err = kubeconfigphase.CreateInitKubeConfigFiles(masterEndpoint, i.cfg.CertificatesDir, kubeadmapi.GlobalEnvParams.KubernetesDir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -198,7 +202,7 @@ func (i *Init) Run(out io.Writer) error {
 | 
			
		||||
	// TODO: It's not great to have an exception for token here, but necessary because the apiserver doesn't handle this properly in the API yet
 | 
			
		||||
	// but relies on files on disk for now, which is daunting.
 | 
			
		||||
	if i.cfg.Discovery.Token != nil {
 | 
			
		||||
		if err := tokenphase.CreateTokenAuthFile(tokenutil.BearerToken(i.cfg.Discovery.Token)); err != nil {
 | 
			
		||||
		if err := tokenphase.CreateTokenAuthFile(i.cfg.CertificatesDir, tokenutil.BearerToken(i.cfg.Discovery.Token)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,15 +10,22 @@ load(
 | 
			
		||||
go_library(
 | 
			
		||||
    name = "go_default_library",
 | 
			
		||||
    srcs = [
 | 
			
		||||
        "certs.go",
 | 
			
		||||
        "kubeconfig.go",
 | 
			
		||||
        "phase.go",
 | 
			
		||||
    ],
 | 
			
		||||
    tags = ["automanaged"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//cmd/kubeadm/app/constants:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/apis/kubeadm:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/phases/certs:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
 | 
			
		||||
        "//cmd/kubeadm/app/util:go_default_library",
 | 
			
		||||
        "//vendor:github.com/spf13/cobra",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/net",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
 | 
			
		||||
        "//vendor:k8s.io/client-go/pkg/api",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								cmd/kubeadm/app/cmd/phases/certs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								cmd/kubeadm/app/cmd/phases/certs.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2017 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 phases
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
 | 
			
		||||
	netutil "k8s.io/apimachinery/pkg/util/net"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	"k8s.io/client-go/pkg/api"
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	certphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewCmdCerts() *cobra.Command {
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "certs",
 | 
			
		||||
		Aliases: []string{"certificates"},
 | 
			
		||||
		Short:   "Generate certificates for a Kubernetes cluster.",
 | 
			
		||||
		RunE:    subCmdRunE("certs"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd.AddCommand(NewCmdSelfSign())
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCmdSelfSign() *cobra.Command {
 | 
			
		||||
	// TODO: Move this into a dedicated Certificates Phase API object
 | 
			
		||||
	cfg := &kubeadmapiext.MasterConfiguration{}
 | 
			
		||||
	// Default values for the cobra help text
 | 
			
		||||
	api.Scheme.Default(cfg)
 | 
			
		||||
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:   "selfsign",
 | 
			
		||||
		Short: "Generate the CA, APIServer signing/client cert, the ServiceAccount public/private keys and a CA and client cert for the front proxy",
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
 | 
			
		||||
			// Run the defaulting once again to take passed flags into account
 | 
			
		||||
			api.Scheme.Default(cfg)
 | 
			
		||||
			internalcfg := &kubeadmapi.MasterConfiguration{}
 | 
			
		||||
			api.Scheme.Convert(cfg, internalcfg, nil)
 | 
			
		||||
 | 
			
		||||
			err := RunSelfSign(internalcfg)
 | 
			
		||||
			kubeadmutil.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "dns-domain", cfg.Networking.DNSDomain, "The DNS Domain for the Kubernetes cluster.")
 | 
			
		||||
	cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save and store the certificates")
 | 
			
		||||
	cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The subnet for the Services in the cluster.")
 | 
			
		||||
	cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "cert-altnames", []string{}, "Optional extra altnames to use for the API Server serving cert. Can be both IP addresses and dns names.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunSelfSign generates certificate assets in the specified directory
 | 
			
		||||
func RunSelfSign(config *kubeadmapi.MasterConfiguration) error {
 | 
			
		||||
	if err := validateArgs(config); err != nil {
 | 
			
		||||
		return fmt.Errorf("The argument validation failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's possible to detect the default IP, add it to the SANs as well. Otherwise, just go with the provided ones
 | 
			
		||||
	ip, err := netutil.ChooseBindAddress(net.ParseIP(config.API.AdvertiseAddress))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		config.API.AdvertiseAddress = ip.String()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = certphase.CreatePKIAssets(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateArgs(config *kubeadmapi.MasterConfiguration) error {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	allErrs = append(allErrs, validation.ValidateNetworking(&config.Networking, field.NewPath("networking"))...)
 | 
			
		||||
	allErrs = append(allErrs, validation.ValidateAbsolutePath(config.CertificatesDir, field.NewPath("cert-dir"))...)
 | 
			
		||||
	allErrs = append(allErrs, validation.ValidateAPIServerCertSANs(config.APIServerCertSANs, field.NewPath("cert-altnames"))...)
 | 
			
		||||
	return allErrs.ToAggregate()
 | 
			
		||||
}
 | 
			
		||||
@@ -22,7 +22,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
 | 
			
		||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
 | 
			
		||||
	kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
)
 | 
			
		||||
@@ -74,7 +74,7 @@ func NewCmdClientCerts(out io.Writer) *cobra.Command {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addCommonFlags(cmd *cobra.Command, config *kubeconfigphase.BuildConfigProperties) {
 | 
			
		||||
	cmd.Flags().StringVar(&config.CertDir, "cert-dir", kubeadmconstants.DefaultCertDir, "The path to the directory where the certificates are.")
 | 
			
		||||
	cmd.Flags().StringVar(&config.CertDir, "cert-dir", kubeadmapiext.DefaultCertificatesDir, "The path to the directory where the certificates are.")
 | 
			
		||||
	cmd.Flags().StringVar(&config.ClientName, "client-name", "", "The name of the client for which the KubeConfig file will be generated.")
 | 
			
		||||
	cmd.Flags().StringVar(&config.APIServer, "server", "", "The location of the api server.")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ func NewCmdPhase(out io.Writer) *cobra.Command {
 | 
			
		||||
		RunE:  subCmdRunE("phase"),
 | 
			
		||||
	}
 | 
			
		||||
	cmd.AddCommand(NewCmdKubeConfig(out))
 | 
			
		||||
	cmd.AddCommand(NewCmdCerts())
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ import (
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
 | 
			
		||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
@@ -36,11 +37,12 @@ import (
 | 
			
		||||
// NewCmdReset returns the "kubeadm reset" command
 | 
			
		||||
func NewCmdReset(out io.Writer) *cobra.Command {
 | 
			
		||||
	var skipPreFlight, removeNode bool
 | 
			
		||||
	var certsDir string
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:   "reset",
 | 
			
		||||
		Short: "Run this to revert any changes made to this host by 'kubeadm init' or 'kubeadm join'.",
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			r, err := NewReset(skipPreFlight, removeNode)
 | 
			
		||||
			r, err := NewReset(skipPreFlight, removeNode, certsDir)
 | 
			
		||||
			kubeadmutil.CheckErr(err)
 | 
			
		||||
			kubeadmutil.CheckErr(r.Run(out))
 | 
			
		||||
		},
 | 
			
		||||
@@ -56,14 +58,20 @@ func NewCmdReset(out io.Writer) *cobra.Command {
 | 
			
		||||
		"Remove this node from the pool of nodes in this cluster",
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	cmd.PersistentFlags().StringVar(
 | 
			
		||||
		&certsDir, "cert-dir", kubeadmapiext.DefaultCertificatesDir,
 | 
			
		||||
		"The path to the directory where the certificates are stored. If specified, clean this directory.",
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Reset struct {
 | 
			
		||||
	removeNode bool
 | 
			
		||||
	certsDir   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewReset(skipPreFlight, removeNode bool) (*Reset, error) {
 | 
			
		||||
func NewReset(skipPreFlight, removeNode bool, certsDir string) (*Reset, error) {
 | 
			
		||||
	if !skipPreFlight {
 | 
			
		||||
		fmt.Println("[preflight] Running pre-flight checks")
 | 
			
		||||
 | 
			
		||||
@@ -76,6 +84,7 @@ func NewReset(skipPreFlight, removeNode bool) (*Reset, error) {
 | 
			
		||||
 | 
			
		||||
	return &Reset{
 | 
			
		||||
		removeNode: removeNode,
 | 
			
		||||
		certsDir:   certsDir,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -137,7 +146,7 @@ func (r *Reset) Run(out io.Writer) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove contents from the config and pki directories
 | 
			
		||||
	resetConfigDir(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmapi.GlobalEnvParams.HostPKIPath)
 | 
			
		||||
	resetConfigDir(kubeadmapi.GlobalEnvParams.KubernetesDir, r.certsDir)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,6 @@ const (
 | 
			
		||||
	ControllerManagerKubeConfigFileName = "controller-manager.conf"
 | 
			
		||||
	SchedulerKubeConfigFileName         = "scheduler.conf"
 | 
			
		||||
 | 
			
		||||
	DefaultCertDir = "/etc/kubernetes/pki"
 | 
			
		||||
 | 
			
		||||
	// Important: a "v"-prefix shouldn't exist here; semver doesn't allow that
 | 
			
		||||
	MinimumControlPlaneVersion = "1.6.0-alpha.2"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ func encodeKubeDiscoverySecretData(dcfg *kubeadmapi.TokenDiscovery, apicfg kubea
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateDiscoveryDeploymentAndSecret(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
 | 
			
		||||
	caCertificatePath := path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CACertName)
 | 
			
		||||
	caCertificatePath := path.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)
 | 
			
		||||
	caCerts, err := certutil.CertsFromFile(caCertificatePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("couldn't load the CA certificate file %s: %v", caCertificatePath, err)
 | 
			
		||||
 
 | 
			
		||||
@@ -292,10 +292,6 @@ func getComponentBaseCommand(component string) []string {
 | 
			
		||||
	return []string{"kube-" + component}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCertFilePath(certName string) string {
 | 
			
		||||
	return path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, certName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) []string {
 | 
			
		||||
	var command []string
 | 
			
		||||
 | 
			
		||||
@@ -308,13 +304,13 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) [
 | 
			
		||||
		"insecure-port":                   "0",
 | 
			
		||||
		"admission-control":               kubeadmconstants.DefaultAdmissionControl,
 | 
			
		||||
		"service-cluster-ip-range":        cfg.Networking.ServiceSubnet,
 | 
			
		||||
		"service-account-key-file":        getCertFilePath(kubeadmconstants.ServiceAccountPublicKeyName),
 | 
			
		||||
		"client-ca-file":                  getCertFilePath(kubeadmconstants.CACertName),
 | 
			
		||||
		"tls-cert-file":                   getCertFilePath(kubeadmconstants.APIServerCertName),
 | 
			
		||||
		"tls-private-key-file":            getCertFilePath(kubeadmconstants.APIServerKeyName),
 | 
			
		||||
		"kubelet-client-certificate":      getCertFilePath(kubeadmconstants.APIServerKubeletClientCertName),
 | 
			
		||||
		"kubelet-client-key":              getCertFilePath(kubeadmconstants.APIServerKubeletClientKeyName),
 | 
			
		||||
		"token-auth-file":                 path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CSVTokenFileName),
 | 
			
		||||
		"service-account-key-file":        path.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
 | 
			
		||||
		"client-ca-file":                  path.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
 | 
			
		||||
		"tls-cert-file":                   path.Join(cfg.CertificatesDir, kubeadmconstants.APIServerCertName),
 | 
			
		||||
		"tls-private-key-file":            path.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName),
 | 
			
		||||
		"kubelet-client-certificate":      path.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName),
 | 
			
		||||
		"kubelet-client-key":              path.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName),
 | 
			
		||||
		"token-auth-file":                 path.Join(cfg.CertificatesDir, kubeadmconstants.CSVTokenFileName),
 | 
			
		||||
		"secure-port":                     fmt.Sprintf("%d", cfg.API.BindPort),
 | 
			
		||||
		"allow-privileged":                "true",
 | 
			
		||||
		"storage-backend":                 "etcd3",
 | 
			
		||||
@@ -324,7 +320,7 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) [
 | 
			
		||||
		"requestheader-username-headers":     "X-Remote-User",
 | 
			
		||||
		"requestheader-group-headers":        "X-Remote-Group",
 | 
			
		||||
		"requestheader-extra-headers-prefix": "X-Remote-Extra-",
 | 
			
		||||
		"requestheader-client-ca-file":       getCertFilePath(kubeadmconstants.FrontProxyCACertName),
 | 
			
		||||
		"requestheader-client-ca-file":       path.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName),
 | 
			
		||||
		"requestheader-allowed-names":        "front-proxy-client",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -379,10 +375,10 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted
 | 
			
		||||
		"address":                                                  "127.0.0.1",
 | 
			
		||||
		"leader-elect":                                             "true",
 | 
			
		||||
		"kubeconfig":                                               path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName),
 | 
			
		||||
		"root-ca-file":                                             getCertFilePath(kubeadmconstants.CACertName),
 | 
			
		||||
		"service-account-private-key-file":                         getCertFilePath(kubeadmconstants.ServiceAccountPrivateKeyName),
 | 
			
		||||
		"cluster-signing-cert-file":                                getCertFilePath(kubeadmconstants.CACertName),
 | 
			
		||||
		"cluster-signing-key-file":                                 getCertFilePath(kubeadmconstants.CAKeyName),
 | 
			
		||||
		"root-ca-file":                                             path.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
 | 
			
		||||
		"service-account-private-key-file":                         path.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName),
 | 
			
		||||
		"cluster-signing-cert-file":                                path.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
 | 
			
		||||
		"cluster-signing-key-file":                                 path.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName),
 | 
			
		||||
		"insecure-experimental-approve-all-kubelet-csrs-for-group": kubeadmconstants.CSVTokenBootstrapGroup,
 | 
			
		||||
		"use-service-account-credentials":                          "true",
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,8 @@ import (
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const testCertsDir = "/var/lib/certs"
 | 
			
		||||
 | 
			
		||||
func TestWriteStaticPodManifests(t *testing.T) {
 | 
			
		||||
	tmpdir, err := ioutil.TempDir("", "")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -382,19 +384,20 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				API:             kubeadm.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
 | 
			
		||||
				Networking:      kubeadm.Networking{ServiceSubnet: "bar"},
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-apiserver",
 | 
			
		||||
				"--insecure-port=0",
 | 
			
		||||
				"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds",
 | 
			
		||||
				"--service-cluster-ip-range=bar",
 | 
			
		||||
				"--service-account-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
 | 
			
		||||
				"--service-account-key-file=" + testCertsDir + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + testCertsDir + "/tokens.csv",
 | 
			
		||||
				fmt.Sprintf("--secure-port=%d", 123),
 | 
			
		||||
				"--allow-privileged=true",
 | 
			
		||||
				"--storage-backend=etcd3",
 | 
			
		||||
@@ -402,7 +405,7 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
				"--requestheader-username-headers=X-Remote-User",
 | 
			
		||||
				"--requestheader-group-headers=X-Remote-Group",
 | 
			
		||||
				"--requestheader-extra-headers-prefix=X-Remote-Extra-",
 | 
			
		||||
				"--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-allowed-names=front-proxy-client",
 | 
			
		||||
				"--authorization-mode=RBAC",
 | 
			
		||||
				"--advertise-address=1.2.3.4",
 | 
			
		||||
@@ -413,19 +416,20 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				API:             kubeadm.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
 | 
			
		||||
				Networking:      kubeadm.Networking{ServiceSubnet: "bar"},
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-apiserver",
 | 
			
		||||
				"--insecure-port=0",
 | 
			
		||||
				"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds",
 | 
			
		||||
				"--service-cluster-ip-range=bar",
 | 
			
		||||
				"--service-account-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
 | 
			
		||||
				"--service-account-key-file=" + testCertsDir + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + testCertsDir + "/tokens.csv",
 | 
			
		||||
				fmt.Sprintf("--secure-port=%d", 123),
 | 
			
		||||
				"--allow-privileged=true",
 | 
			
		||||
				"--storage-backend=etcd3",
 | 
			
		||||
@@ -433,7 +437,7 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
				"--requestheader-username-headers=X-Remote-User",
 | 
			
		||||
				"--requestheader-group-headers=X-Remote-Group",
 | 
			
		||||
				"--requestheader-extra-headers-prefix=X-Remote-Extra-",
 | 
			
		||||
				"--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-allowed-names=front-proxy-client",
 | 
			
		||||
				"--authorization-mode=RBAC",
 | 
			
		||||
				"--advertise-address=4.3.2.1",
 | 
			
		||||
@@ -445,19 +449,20 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
				API:             kubeadm.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
 | 
			
		||||
				Networking:      kubeadm.Networking{ServiceSubnet: "bar"},
 | 
			
		||||
				Etcd:            kubeadm.Etcd{CertFile: "fiz", KeyFile: "faz"},
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-apiserver",
 | 
			
		||||
				"--insecure-port=0",
 | 
			
		||||
				"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds",
 | 
			
		||||
				"--service-cluster-ip-range=bar",
 | 
			
		||||
				"--service-account-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
 | 
			
		||||
				"--service-account-key-file=" + testCertsDir + "/sa.pub",
 | 
			
		||||
				"--client-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
 | 
			
		||||
				"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
 | 
			
		||||
				"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
 | 
			
		||||
				"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
 | 
			
		||||
				"--token-auth-file=" + testCertsDir + "/tokens.csv",
 | 
			
		||||
				fmt.Sprintf("--secure-port=%d", 123),
 | 
			
		||||
				"--allow-privileged=true",
 | 
			
		||||
				"--storage-backend=etcd3",
 | 
			
		||||
@@ -465,7 +470,7 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
			
		||||
				"--requestheader-username-headers=X-Remote-User",
 | 
			
		||||
				"--requestheader-group-headers=X-Remote-Group",
 | 
			
		||||
				"--requestheader-extra-headers-prefix=X-Remote-Extra-",
 | 
			
		||||
				"--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
 | 
			
		||||
				"--requestheader-allowed-names=front-proxy-client",
 | 
			
		||||
				"--authorization-mode=RBAC",
 | 
			
		||||
				"--advertise-address=4.3.2.1",
 | 
			
		||||
@@ -492,47 +497,55 @@ func TestGetControllerManagerCommand(t *testing.T) {
 | 
			
		||||
		expected []string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{},
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-controller-manager",
 | 
			
		||||
				"--address=127.0.0.1",
 | 
			
		||||
				"--leader-elect=true",
 | 
			
		||||
				"--kubeconfig=" + kubeadmapi.GlobalEnvParams.KubernetesDir + "/controller-manager.conf",
 | 
			
		||||
				"--root-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.key",
 | 
			
		||||
				"--root-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + testCertsDir + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
 | 
			
		||||
				"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
 | 
			
		||||
				"--use-service-account-credentials=true",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{CloudProvider: "foo"},
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				CloudProvider:   "foo",
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-controller-manager",
 | 
			
		||||
				"--address=127.0.0.1",
 | 
			
		||||
				"--leader-elect=true",
 | 
			
		||||
				"--kubeconfig=" + kubeadmapi.GlobalEnvParams.KubernetesDir + "/controller-manager.conf",
 | 
			
		||||
				"--root-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.key",
 | 
			
		||||
				"--root-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + testCertsDir + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
 | 
			
		||||
				"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
 | 
			
		||||
				"--use-service-account-credentials=true",
 | 
			
		||||
				"--cloud-provider=foo",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{Networking: kubeadm.Networking{PodSubnet: "bar"}},
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				Networking:      kubeadm.Networking{PodSubnet: "bar"},
 | 
			
		||||
				CertificatesDir: testCertsDir,
 | 
			
		||||
			},
 | 
			
		||||
			expected: []string{
 | 
			
		||||
				"kube-controller-manager",
 | 
			
		||||
				"--address=127.0.0.1",
 | 
			
		||||
				"--leader-elect=true",
 | 
			
		||||
				"--kubeconfig=" + kubeadmapi.GlobalEnvParams.KubernetesDir + "/controller-manager.conf",
 | 
			
		||||
				"--root-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.key",
 | 
			
		||||
				"--root-ca-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--service-account-private-key-file=" + testCertsDir + "/sa.key",
 | 
			
		||||
				"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
 | 
			
		||||
				"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
 | 
			
		||||
				"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
 | 
			
		||||
				"--use-service-account-credentials=true",
 | 
			
		||||
				"--allocate-node-cidrs=true",
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ go_library(
 | 
			
		||||
        "//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
 | 
			
		||||
        "//pkg/registry/core/service/ipallocator:go_default_library",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/sets",
 | 
			
		||||
        "//vendor:k8s.io/apimachinery/pkg/util/validation",
 | 
			
		||||
        "//vendor:k8s.io/client-go/util/cert",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	setutil "k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation"
 | 
			
		||||
	certutil "k8s.io/client-go/util/cert"
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
@@ -40,34 +41,22 @@ import (
 | 
			
		||||
 | 
			
		||||
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
 | 
			
		||||
// It generates a self-signed CA certificate and a server certificate (signed by the CA)
 | 
			
		||||
func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
 | 
			
		||||
	altNames := certutil.AltNames{}
 | 
			
		||||
 | 
			
		||||
	// First, define all domains this cert should be signed for
 | 
			
		||||
	internalAPIServerFQDN := []string{
 | 
			
		||||
		"kubernetes",
 | 
			
		||||
		"kubernetes.default",
 | 
			
		||||
		"kubernetes.default.svc",
 | 
			
		||||
		fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
 | 
			
		||||
	}
 | 
			
		||||
func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error {
 | 
			
		||||
	pkiDir := cfg.CertificatesDir
 | 
			
		||||
	hostname, err := os.Hostname()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("couldn't get the hostname: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	altNames.DNSNames = append(cfg.API.ExternalDNSNames, hostname)
 | 
			
		||||
	altNames.DNSNames = append(altNames.DNSNames, internalAPIServerFQDN...)
 | 
			
		||||
 | 
			
		||||
	// and lastly, extract the internal IP address for the API server
 | 
			
		||||
	_, n, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
 | 
			
		||||
	_, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error parsing CIDR %q: %v", cfg.Networking.ServiceSubnet, err)
 | 
			
		||||
	}
 | 
			
		||||
	internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(n, 1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("unable to allocate IP address for the API server from the given CIDR (%q) [%v]", &cfg.Networking.ServiceSubnet, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	altNames.IPs = append(altNames.IPs, internalAPIServerVirtualIP, net.ParseIP(cfg.API.AdvertiseAddress))
 | 
			
		||||
	// Build the list of SANs
 | 
			
		||||
	altNames := getAltNames(cfg.APIServerCertSANs, hostname, cfg.Networking.DNSDomain, svcSubnet)
 | 
			
		||||
	// Append the address the API Server is advertising
 | 
			
		||||
	altNames.IPs = append(altNames.IPs, net.ParseIP(cfg.API.AdvertiseAddress))
 | 
			
		||||
 | 
			
		||||
	var caCert *x509.Certificate
 | 
			
		||||
	var caKey *rsa.PrivateKey
 | 
			
		||||
@@ -126,6 +115,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
 | 
			
		||||
			return fmt.Errorf("failure while saving API server certificate and key [%v]", err)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("[certificates] Generated API server certificate and key.")
 | 
			
		||||
		fmt.Printf("[certificates] API Server serving cert is signed for DNS names %v and IPs %v\n", altNames.DNSNames, altNames.IPs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If at least one of them exists, we should try to load them
 | 
			
		||||
@@ -158,9 +148,9 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the key exists, we should try to load it
 | 
			
		||||
	if pkiutil.CertOrKeyExist(pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName) {
 | 
			
		||||
	if pkiutil.CertOrKeyExist(pkiDir, kubeadmconstants.ServiceAccountKeyBaseName) {
 | 
			
		||||
		// Try to load sa.key from the PKI directory
 | 
			
		||||
		_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, kubeadmconstants.ServiceAccountPrivateKeyName)
 | 
			
		||||
		_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, kubeadmconstants.ServiceAccountKeyBaseName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("certificate and/or key existed but they could not be loaded properly [%v]", err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -176,12 +166,11 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
 | 
			
		||||
		if err = pkiutil.WriteKey(pkiDir, kubeadmconstants.ServiceAccountKeyBaseName, saTokenSigningKey); err != nil {
 | 
			
		||||
			return fmt.Errorf("failure while saving service account token signing key [%v]", err)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("[certificates] Generated service account token signing key.")
 | 
			
		||||
 | 
			
		||||
		if err = pkiutil.WritePublicKey(pkiDir, kubeadmconstants.ServiceAccountKeyBaseName, &saTokenSigningKey.PublicKey); err != nil {
 | 
			
		||||
			return fmt.Errorf("failure while saving service account token signing public key [%v]", err)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("[certificates] Generated service account token signing public key.")
 | 
			
		||||
		fmt.Println("[certificates] Generated service account token signing key and public key.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// front proxy CA and client certs are used to secure a front proxy authenticator which is used to assert identity
 | 
			
		||||
@@ -254,7 +243,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Verify that the cert is valid for all IPs and DNS names it should be valid for
 | 
			
		||||
// checkAltNamesExist verifies that the cert is valid for all IPs and DNS names it should be valid for
 | 
			
		||||
func checkAltNamesExist(IPs []net.IP, DNSNames []string, altNames certutil.AltNames) bool {
 | 
			
		||||
	dnsset := setutil.NewString(DNSNames...)
 | 
			
		||||
 | 
			
		||||
@@ -279,3 +268,33 @@ func checkAltNamesExist(IPs []net.IP, DNSNames []string, altNames certutil.AltNa
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getAltNames builds an AltNames object for the certutil to use when generating the certificates
 | 
			
		||||
func getAltNames(cfgAltNames []string, hostname, dnsdomain string, svcSubnet *net.IPNet) certutil.AltNames {
 | 
			
		||||
	altNames := certutil.AltNames{
 | 
			
		||||
		DNSNames: []string{
 | 
			
		||||
			hostname,
 | 
			
		||||
			"kubernetes",
 | 
			
		||||
			"kubernetes.default",
 | 
			
		||||
			"kubernetes.default.svc",
 | 
			
		||||
			fmt.Sprintf("kubernetes.default.svc.%s", dnsdomain),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Populate IPs/DNSNames from AltNames
 | 
			
		||||
	for _, altname := range cfgAltNames {
 | 
			
		||||
		if ip := net.ParseIP(altname); ip != nil {
 | 
			
		||||
			altNames.IPs = append(altNames.IPs, ip)
 | 
			
		||||
		} else if len(validation.IsDNS1123Subdomain(altname)) == 0 {
 | 
			
		||||
			altNames.DNSNames = append(altNames.DNSNames, altname)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// and lastly, extract the internal IP address for the API server
 | 
			
		||||
	internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(svcSubnet, 1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("[certs] WARNING: Unable to get first IP address from the given CIDR (%s): %v\n", svcSubnet.String(), err)
 | 
			
		||||
	}
 | 
			
		||||
	altNames.IPs = append(altNames.IPs, internalAPIServerVirtualIP)
 | 
			
		||||
	return altNames
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ func TestCreatePKIAssets(t *testing.T) {
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				API:             kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
 | 
			
		||||
				Networking:      kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"},
 | 
			
		||||
				CertificatesDir: fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
@@ -55,6 +56,7 @@ func TestCreatePKIAssets(t *testing.T) {
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				API:             kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
 | 
			
		||||
				Networking:      kubeadmapi.Networking{ServiceSubnet: "invalid"},
 | 
			
		||||
				CertificatesDir: fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
@@ -62,12 +64,13 @@ func TestCreatePKIAssets(t *testing.T) {
 | 
			
		||||
			cfg: &kubeadmapi.MasterConfiguration{
 | 
			
		||||
				API:             kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
 | 
			
		||||
				Networking:      kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/24"},
 | 
			
		||||
				CertificatesDir: fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir),
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		actual := CreatePKIAssets(rt.cfg, fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir))
 | 
			
		||||
		actual := CreatePKIAssets(rt.cfg)
 | 
			
		||||
		if (actual == nil) != rt.expected {
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"failed CreatePKIAssets with an error:\n\texpected: %t\n\t  actual: %t",
 | 
			
		||||
@@ -126,3 +129,46 @@ func TestCheckAltNamesExist(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetAltNames(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		cfgaltnames      []string
 | 
			
		||||
		hostname         string
 | 
			
		||||
		dnsdomain        string
 | 
			
		||||
		servicecidr      string
 | 
			
		||||
		expectedIPs      []string
 | 
			
		||||
		expectedDNSNames []string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			cfgaltnames:      []string{"foo", "192.168.200.1", "bar.baz"},
 | 
			
		||||
			hostname:         "my-node",
 | 
			
		||||
			dnsdomain:        "cluster.external",
 | 
			
		||||
			servicecidr:      "10.96.0.1/12",
 | 
			
		||||
			expectedIPs:      []string{"192.168.200.1", "10.96.0.1"},
 | 
			
		||||
			expectedDNSNames: []string{"my-node", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.external", "foo", "bar.baz"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		_, svcSubnet, _ := net.ParseCIDR(rt.servicecidr)
 | 
			
		||||
		actual := getAltNames(rt.cfgaltnames, rt.hostname, rt.dnsdomain, svcSubnet)
 | 
			
		||||
		for i := range actual.IPs {
 | 
			
		||||
			if rt.expectedIPs[i] != actual.IPs[i].String() {
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"failed getAltNames:\n\texpected: %s\n\t  actual: %s",
 | 
			
		||||
					rt.expectedIPs[i],
 | 
			
		||||
					actual.IPs[i].String(),
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for i := range actual.DNSNames {
 | 
			
		||||
			if rt.expectedDNSNames[i] != actual.DNSNames[i] {
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"failed getAltNames:\n\texpected: %s\n\t  actual: %s",
 | 
			
		||||
					rt.expectedDNSNames[i],
 | 
			
		||||
					actual.DNSNames[i],
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,16 +22,25 @@ package certs
 | 
			
		||||
 | 
			
		||||
	INPUTS:
 | 
			
		||||
		From MasterConfiguration
 | 
			
		||||
			.API.ExternalDNSNames is needed for knowing which DNS names the certs should be signed for
 | 
			
		||||
			.API.AdvertiseAddress is an optional parameter that can be passed for an extra addition to the SAN IPs
 | 
			
		||||
			.APIServerCertSANs is needed for knowing which DNS names and IPs the API Server serving cert should be valid for
 | 
			
		||||
			.Networking.DNSDomain is needed for knowing which DNS name the internal kubernetes service has
 | 
			
		||||
			.Networking.ServiceSubnet is needed for knowing which IP the internal kubernetes service is going to point to
 | 
			
		||||
			The PKIPath is required for knowing where all certificates should be stored
 | 
			
		||||
			.CertificatesDir is required for knowing where all certificates should be stored
 | 
			
		||||
 | 
			
		||||
	OUTPUTS:
 | 
			
		||||
		Files to PKIPath (default /etc/kubernetes/pki):
 | 
			
		||||
		Files to .CertificatesDir (default /etc/kubernetes/pki):
 | 
			
		||||
		 - ca.crt
 | 
			
		||||
		 - ca.key
 | 
			
		||||
		 - apiserver.crt
 | 
			
		||||
		 - apiserver.key
 | 
			
		||||
		 - apiserver-kubelet-client.crt
 | 
			
		||||
		 - apiserver-kubelet-client.key
 | 
			
		||||
		 - sa.pub
 | 
			
		||||
		 - sa.key
 | 
			
		||||
		 - front-proxy-ca.crt
 | 
			
		||||
		 - front-proxy-ca.key
 | 
			
		||||
		 - front-proxy-client.crt
 | 
			
		||||
		 - front-proxy-client.key
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
@@ -23,16 +23,15 @@ import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/uuid"
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CreateTokenAuthFile creates the CSV file that can be used for allowing users with tokens access to the API Server
 | 
			
		||||
func CreateTokenAuthFile(bt string) error {
 | 
			
		||||
	tokenAuthFilePath := path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CSVTokenFileName)
 | 
			
		||||
	if err := os.MkdirAll(kubeadmapi.GlobalEnvParams.HostPKIPath, 0700); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to create directory %q [%v]", kubeadmapi.GlobalEnvParams.HostPKIPath, err)
 | 
			
		||||
func CreateTokenAuthFile(certsDir, bt string) error {
 | 
			
		||||
	tokenAuthFilePath := path.Join(certsDir, kubeadmconstants.CSVTokenFileName)
 | 
			
		||||
	if err := os.MkdirAll(certsDir, 0700); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to create directory %q [%v]", certsDir, err)
 | 
			
		||||
	}
 | 
			
		||||
	serialized := []byte(fmt.Sprintf("%s,%s,%s,%s\n", bt, kubeadmconstants.CSVTokenBootstrapUser, uuid.NewUUID(), kubeadmconstants.CSVTokenBootstrapGroup))
 | 
			
		||||
	// DumpReaderToFile create a file with mode 0600
 | 
			
		||||
 
 | 
			
		||||
@@ -540,7 +540,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
 | 
			
		||||
		PortOpenCheck{port: 10250},
 | 
			
		||||
		DirAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")},
 | 
			
		||||
		DirAvailableCheck{Path: "/var/lib/kubelet"},
 | 
			
		||||
		FileAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CACertName)},
 | 
			
		||||
		FileAvailableCheck{Path: cfg.CACertPath},
 | 
			
		||||
		FileAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)},
 | 
			
		||||
		FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
 | 
			
		||||
		InPathCheck{executable: "ip", mandatory: true},
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ apiserver-advertise-address
 | 
			
		||||
apiserver-arg-overrides
 | 
			
		||||
apiserver-arg-overrides
 | 
			
		||||
apiserver-bind-port
 | 
			
		||||
apiserver-cert-extra-sans
 | 
			
		||||
apiserver-count
 | 
			
		||||
apiserver-count
 | 
			
		||||
apiserver-count
 | 
			
		||||
@@ -67,6 +68,7 @@ build-only
 | 
			
		||||
build-tag
 | 
			
		||||
ca-cert-path
 | 
			
		||||
cadvisor-port
 | 
			
		||||
cert-altnames
 | 
			
		||||
cert-dir
 | 
			
		||||
certificate-authority
 | 
			
		||||
cgroup-driver
 | 
			
		||||
@@ -158,6 +160,7 @@ discovery-file
 | 
			
		||||
discovery-port
 | 
			
		||||
discovery-token
 | 
			
		||||
dns-bind-address
 | 
			
		||||
dns-domain
 | 
			
		||||
dns-port
 | 
			
		||||
dns-provider
 | 
			
		||||
dns-provider-config
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user