mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #42018 from luxas/kubeadm_cert_phase
Automatic merge from submit-queue (batch tested with PRs 42365, 42429, 41770, 42018, 35055) kubeadm: Add --cert-dir, --cert-altnames instead of --api-external-dns-names **What this PR does / why we need it**: - For the beta kubeadm init UX, we need this change - Also adds the `kubeadm phase certs selfsign` command that makes the phase invokable independently **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # **Special notes for your reviewer**: This PR depends on https://github.com/kubernetes/kubernetes/pull/41897 **Release note**: ```release-note ``` @dmmcquay @pires @jbeda @errordeveloper @mikedanese @deads2k @liggitt
This commit is contained in:
commit
4728a0520f
@ -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,12 +48,18 @@ 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 int32
|
||||
// BindPort sets the secure port for the API Server to bind to
|
||||
BindPort int32
|
||||
}
|
||||
|
||||
type Discovery struct {
|
||||
|
@ -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,13 +39,18 @@ 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 string `json:"advertiseAddress"`
|
||||
ExternalDNSNames []string `json:"externalDNSNames"`
|
||||
BindPort int32 `json:"bindPort"`
|
||||
// AdvertiseAddress sets the address for the API server to advertise.
|
||||
AdvertiseAddress string `json:"advertiseAddress"`
|
||||
// BindPort sets the secure port for the API Server to bind to
|
||||
BindPort int32 `json:"bindPort"`
|
||||
}
|
||||
|
||||
type Discovery struct {
|
||||
|
@ -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 {
|
||||
@ -380,21 +382,22 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadm.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "bar"},
|
||||
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",
|
||||
@ -411,21 +414,22 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadm.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "bar"},
|
||||
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",
|
||||
@ -442,22 +446,23 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadm.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "bar"},
|
||||
Etcd: kubeadm.Etcd{CertFile: "fiz", KeyFile: "faz"},
|
||||
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
|
||||
}
|
||||
|
@ -45,29 +45,32 @@ func TestCreatePKIAssets(t *testing.T) {
|
||||
{
|
||||
// CIDR too small
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
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,
|
||||
},
|
||||
{
|
||||
// CIDR invalid
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "invalid"},
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "invalid"},
|
||||
CertificatesDir: fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/24"},
|
||||
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
|
||||
@ -72,6 +73,7 @@ build-only
|
||||
build-tag
|
||||
ca-cert-path
|
||||
cadvisor-port
|
||||
cert-altnames
|
||||
cert-dir
|
||||
certificate-authority
|
||||
cgroup-driver
|
||||
@ -163,6 +165,7 @@ discovery-file
|
||||
discovery-port
|
||||
discovery-token
|
||||
dns-bind-address
|
||||
dns-domain
|
||||
dns-port
|
||||
dns-provider
|
||||
dns-provider-config
|
||||
|
Loading…
Reference in New Issue
Block a user