mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Change SANs for etcd serving and peer certs
- Place etcd server and peer certs & keys into pki subdir - Move certs.altName functions to pkiutil + add appendSANstoAltNames() Share the append logic for the getAltName functions as suggested by @jamiehannaford. Move functions/tests to certs/pkiutil as suggested by @luxas. Update Bazel BUILD deps - Warn when an APIServerCertSANs or EtcdCertSANs entry is unusable - Add MasterConfiguration.EtcdPeerCertSANs - Move EtcdServerCertSANs and EtcdPeerCertSANs under MasterConfiguration.Etcd
This commit is contained in:
parent
bb689eb2bb
commit
f5e11a0ce0
@ -43,6 +43,8 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
obj.AuthorizationModes = []string{"foo"}
|
||||
obj.CertificatesDir = "foo"
|
||||
obj.APIServerCertSANs = []string{"foo"}
|
||||
obj.Etcd.ServerCertSANs = []string{"foo"}
|
||||
obj.Etcd.PeerCertSANs = []string{"foo"}
|
||||
obj.Token = "foo"
|
||||
obj.CRISocket = "foo"
|
||||
obj.Etcd.Image = "foo"
|
||||
|
@ -178,6 +178,12 @@ type Etcd struct {
|
||||
Image string
|
||||
// SelfHosted holds configuration for self-hosting etcd.
|
||||
SelfHosted *SelfHostedEtcd
|
||||
// ServerCertSANs sets extra Subject Alternative Names for the etcd server
|
||||
// signing cert. This is currently used for the etcd static-pod.
|
||||
ServerCertSANs []string
|
||||
// PeerCertSANs sets extra Subject Alternative Names for the etcd peer
|
||||
// signing cert. This is currently used for the etcd static-pod.
|
||||
PeerCertSANs []string
|
||||
}
|
||||
|
||||
// SelfHostedEtcd describes options required to configure self-hosted etcd.
|
||||
|
@ -170,6 +170,10 @@ type Etcd struct {
|
||||
Image string `json:"image"`
|
||||
// SelfHosted holds configuration for self-hosting etcd.
|
||||
SelfHosted *SelfHostedEtcd `json:"selfHosted,omitempty"`
|
||||
// ServerCertSANs sets extra Subject Alternative Names for the etcd server signing cert.
|
||||
ServerCertSANs []string `json:"serverCertSANs,omitempty"`
|
||||
// PeerCertSANs sets extra Subject Alternative Names for the etcd peer signing cert.
|
||||
PeerCertSANs []string `json:"peerCertSANs,omitempty"`
|
||||
}
|
||||
|
||||
// SelfHostedEtcd describes options required to configure self-hosted etcd.
|
||||
|
@ -122,6 +122,8 @@ func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s co
|
||||
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
|
||||
out.Image = in.Image
|
||||
out.SelfHosted = (*kubeadm.SelfHostedEtcd)(unsafe.Pointer(in.SelfHosted))
|
||||
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
|
||||
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -139,6 +141,8 @@ func autoConvert_kubeadm_Etcd_To_v1alpha1_Etcd(in *kubeadm.Etcd, out *Etcd, s co
|
||||
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
|
||||
out.Image = in.Image
|
||||
out.SelfHosted = (*SelfHostedEtcd)(unsafe.Pointer(in.SelfHosted))
|
||||
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
|
||||
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,16 @@ func (in *Etcd) DeepCopyInto(out *Etcd) {
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ServerCertSANs != nil {
|
||||
in, out := &in.ServerCertSANs, &out.ServerCertSANs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PeerCertSANs != nil {
|
||||
in, out := &in.PeerCertSANs, &out.PeerCertSANs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,9 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
|
||||
allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudprovider"))...)
|
||||
allErrs = append(allErrs, ValidateAuthorizationModes(c.AuthorizationModes, field.NewPath("authorization-modes"))...)
|
||||
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
|
||||
allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...)
|
||||
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("api-server-cert-altnames"))...)
|
||||
allErrs = append(allErrs, ValidateCertSANs(c.Etcd.ServerCertSANs, field.NewPath("etcd-server-cert-altnames"))...)
|
||||
allErrs = append(allErrs, ValidateCertSANs(c.Etcd.PeerCertSANs, field.NewPath("etcd-peer-cert-altnames"))...)
|
||||
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...)
|
||||
allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("node-name"))...)
|
||||
allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...)
|
||||
@ -228,8 +230,8 @@ func ValidateToken(t string, fldPath *field.Path) field.ErrorList {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateAPIServerCertSANs validates alternative names
|
||||
func ValidateAPIServerCertSANs(altnames []string, fldPath *field.Path) field.ErrorList {
|
||||
// ValidateCertSANs validates alternative names
|
||||
func ValidateCertSANs(altnames []string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
for _, altname := range altnames {
|
||||
if len(validation.IsDNS1123Subdomain(altname)) != 0 && net.ParseIP(altname) == nil {
|
||||
|
@ -134,7 +134,7 @@ func TestValidateCloudProvider(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAPIServerCertSANs(t *testing.T) {
|
||||
func TestValidateCertSANs(t *testing.T) {
|
||||
var tests = []struct {
|
||||
sans []string
|
||||
expected bool
|
||||
@ -148,10 +148,10 @@ func TestValidateAPIServerCertSANs(t *testing.T) {
|
||||
{[]string{"my-hostname2", "my.other.subdomain", "2001:db8::10"}, true}, // supported
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := ValidateAPIServerCertSANs(rt.sans, nil)
|
||||
actual := ValidateCertSANs(rt.sans, nil)
|
||||
if (len(actual) == 0) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed ValidateAPIServerCertSANs:\n\texpected: %t\n\t actual: %t",
|
||||
"failed ValidateCertSANs:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(len(actual) == 0),
|
||||
)
|
||||
|
@ -92,6 +92,16 @@ func (in *Etcd) DeepCopyInto(out *Etcd) {
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ServerCertSANs != nil {
|
||||
in, out := &in.ServerCertSANs, &out.ServerCertSANs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PeerCertSANs != nil {
|
||||
in, out := &in.PeerCertSANs, &out.PeerCertSANs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -60,8 +60,8 @@ var (
|
||||
apiServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
Generates the API server serving certificate and key and saves them into %s and %s files.
|
||||
|
||||
The certificate includes default subject alternative names and additional sans eventually provided by the user;
|
||||
default sans are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
|
||||
The certificate includes default subject alternative names and additional SANs provided by the user;
|
||||
default SANs are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
|
||||
kubernetes.default.svc.<service-dns-domain>, <internalAPIServerVirtualIP> (that is the .10 address in <service-cidr> address space).
|
||||
|
||||
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
||||
@ -74,27 +74,25 @@ var (
|
||||
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
||||
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName)
|
||||
|
||||
etcdCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
etcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
Generates the etcd serving certificate and key and saves them into %s and %s files.
|
||||
|
||||
The certificate includes default subject alternative names and additional sans eventually provided by the user;
|
||||
default sans are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
|
||||
kubernetes.default.svc.<service-dns-domain>, <internalAPIServerVirtualIP> (that is the .10 address in <service-cidr> address space).
|
||||
The certificate includes default subject alternative names and additional SANs provided by the user;
|
||||
default SANs are: localhost, 127.0.0.1.
|
||||
|
||||
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
||||
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdCertName, kubeadmconstants.EtcdKeyName)
|
||||
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName)
|
||||
|
||||
etcdPeerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
Generates the etcd peer certificate and key and saves them into %s and %s files.
|
||||
|
||||
The certificate includes default subject alternative names and additional sans eventually provided by the user;
|
||||
default sans are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
|
||||
kubernetes.default.svc.<service-dns-domain>, <internalAPIServerVirtualIP> (that is the .10 address in <service-cidr> address space).
|
||||
The certificate includes default subject alternative names and additional SANs provided by the user;
|
||||
default SANs are: <node-name>, <apiserver-advertise-address>.
|
||||
|
||||
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
||||
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName)
|
||||
|
||||
apiServerEtcdCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
apiServerEtcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
||||
Generates the client certificate for the API server to connect to etcd securely and the respective key,
|
||||
and saves them into %s and %s files.
|
||||
|
||||
@ -187,8 +185,8 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
|
||||
{
|
||||
use: "etcd-server",
|
||||
short: "Generates etcd serving certificate and key",
|
||||
long: etcdCertLongDesc,
|
||||
cmdFunc: certsphase.CreateEtcdCertAndKeyFiles,
|
||||
long: etcdServerCertLongDesc,
|
||||
cmdFunc: certsphase.CreateEtcdServerCertAndKeyFiles,
|
||||
},
|
||||
{
|
||||
use: "etcd-peer",
|
||||
@ -199,7 +197,7 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
|
||||
{
|
||||
use: "apiserver-etcd-client",
|
||||
short: "Generates client certificate for the API server to connect to etcd securely",
|
||||
long: apiServerEtcdCertLongDesc,
|
||||
long: apiServerEtcdServerCertLongDesc,
|
||||
cmdFunc: certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
},
|
||||
{
|
||||
|
@ -65,21 +65,21 @@ const (
|
||||
// APIServerKubeletClientCertCommonName defines kubelet client certificate common name (CN)
|
||||
APIServerKubeletClientCertCommonName = "kube-apiserver-kubelet-client"
|
||||
|
||||
// EtcdCertAndKeyBaseName defines etcd's server certificate and key base name
|
||||
EtcdCertAndKeyBaseName = "etcd-server"
|
||||
// EtcdCertName defines etcd's server certificate name
|
||||
EtcdCertName = "etcd-server.crt"
|
||||
// EtcdKeyName defines etcd's server key name
|
||||
EtcdKeyName = "etcd-server.key"
|
||||
// EtcdCertCommonName defines etcd's server certificate common name (CN)
|
||||
EtcdCertCommonName = "kube-etcd"
|
||||
// EtcdServerCertAndKeyBaseName defines etcd's server certificate and key base name
|
||||
EtcdServerCertAndKeyBaseName = "etcd/server"
|
||||
// EtcdServerCertName defines etcd's server certificate name
|
||||
EtcdServerCertName = "etcd/server.crt"
|
||||
// EtcdServerKeyName defines etcd's server key name
|
||||
EtcdServerKeyName = "etcd/server.key"
|
||||
// EtcdServerCertCommonName defines etcd's server certificate common name (CN)
|
||||
EtcdServerCertCommonName = "kube-etcd"
|
||||
|
||||
// EtcdPeerCertAndKeyBaseName defines etcd's peer certificate and key base name
|
||||
EtcdPeerCertAndKeyBaseName = "etcd-peer"
|
||||
EtcdPeerCertAndKeyBaseName = "etcd/peer"
|
||||
// EtcdPeerCertName defines etcd's peer certificate name
|
||||
EtcdPeerCertName = "etcd-peer.crt"
|
||||
EtcdPeerCertName = "etcd/peer.crt"
|
||||
// EtcdPeerKeyName defines etcd's peer key name
|
||||
EtcdPeerKeyName = "etcd-peer.key"
|
||||
EtcdPeerKeyName = "etcd/peer.key"
|
||||
// EtcdPeerCertCommonName defines etcd's peer certificate common name (CN)
|
||||
EtcdPeerCertCommonName = "kube-etcd-peer"
|
||||
|
||||
|
@ -30,8 +30,6 @@ go_library(
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -20,16 +20,13 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"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"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
)
|
||||
|
||||
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
|
||||
@ -40,7 +37,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
CreateCACertAndKeyfiles,
|
||||
CreateAPIServerCertAndKeyFiles,
|
||||
CreateAPIServerKubeletClientCertAndKeyFiles,
|
||||
CreateEtcdCertAndKeyFiles,
|
||||
CreateEtcdServerCertAndKeyFiles,
|
||||
CreateEtcdPeerCertAndKeyFiles,
|
||||
CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
@ -125,27 +122,27 @@ func CreateAPIServerKubeletClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfigura
|
||||
)
|
||||
}
|
||||
|
||||
// CreateEtcdCertAndKeyFiles create a new certificate and key file for etcd.
|
||||
// CreateEtcdServerCertAndKeyFiles create a new certificate and key file for etcd.
|
||||
// If the etcd serving certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
||||
// It assumes the cluster CA certificate and key file exist in the CertificatesDir
|
||||
func CreateEtcdCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
func CreateEtcdServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
|
||||
caCert, caKey, err := loadCertificateAuthorithy(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
etcdCert, etcdKey, err := NewEtcdCertAndKey(cfg, caCert, caKey)
|
||||
etcdServerCert, etcdServerKey, err := NewEtcdServerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.EtcdCertAndKeyBaseName,
|
||||
kubeadmconstants.EtcdServerCertAndKeyBaseName,
|
||||
caCert,
|
||||
etcdCert,
|
||||
etcdKey,
|
||||
etcdServerCert,
|
||||
etcdServerKey,
|
||||
)
|
||||
}
|
||||
|
||||
@ -271,7 +268,7 @@ func NewCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// NewAPIServerCertAndKey generate CA certificate for apiserver, signed by the given CA.
|
||||
func NewAPIServerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := getAltNames(cfg)
|
||||
altNames, err := pkiutil.GetAPIServerAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for API server: %v", err)
|
||||
}
|
||||
@ -305,31 +302,31 @@ func NewAPIServerKubeletClientCertAndKey(caCert *x509.Certificate, caKey *rsa.Pr
|
||||
return apiClientCert, apiClientKey, nil
|
||||
}
|
||||
|
||||
// NewEtcdCertAndKey generate CA certificate for etcd, signed by the given CA.
|
||||
func NewEtcdCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// NewEtcdServerCertAndKey generate CA certificate for etcd, signed by the given CA.
|
||||
func NewEtcdServerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := getAltNames(cfg)
|
||||
altNames, err := pkiutil.GetEtcdAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for etcd: %v", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: kubeadmconstants.EtcdCertCommonName,
|
||||
CommonName: kubeadmconstants.EtcdServerCertCommonName,
|
||||
AltNames: *altNames,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
etcdCert, etcdKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
etcdServerCert, etcdServerKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating etcd key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return etcdCert, etcdKey, nil
|
||||
return etcdServerCert, etcdServerKey, nil
|
||||
}
|
||||
|
||||
// NewEtcdPeerCertAndKey generate CA certificate for etcd peering, signed by the given CA.
|
||||
func NewEtcdPeerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := getAltNames(cfg)
|
||||
altNames, err := pkiutil.GetEtcdPeerAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for etcd peering: %v", err)
|
||||
}
|
||||
@ -636,55 +633,3 @@ func validatePrivatePublicKey(l certKeyLocation) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAltNames builds an AltNames object for to be used when generating apiserver certificate
|
||||
func getAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
|
||||
// advertise address
|
||||
advertiseAddress := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if advertiseAddress == nil {
|
||||
return nil, fmt.Errorf("error parsing API AdvertiseAddress %v: is not a valid textual representation of an IP address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// internal IP address for the API server
|
||||
_, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing CIDR %q: %v", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
|
||||
internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(svcSubnet, 1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get first IP address from the given CIDR (%s): %v", svcSubnet.String(), err)
|
||||
}
|
||||
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{
|
||||
cfg.NodeName,
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
|
||||
},
|
||||
IPs: []net.IP{
|
||||
internalAPIServerVirtualIP,
|
||||
advertiseAddress,
|
||||
},
|
||||
}
|
||||
|
||||
// adds additional SAN
|
||||
for _, altname := range cfg.APIServerCertSANs {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// add api server dns advertise address
|
||||
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||
altNames.DNSNames = append(altNames.DNSNames, cfg.API.ControlPlaneEndpoint)
|
||||
}
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
@ -258,53 +258,6 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAltNames(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
advertiseIP := "1.2.3.4"
|
||||
controlPlaneEndpoint := "api.k8s.io"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: advertiseIP, ControlPlaneEndpoint: controlPlaneEndpoint},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeName: hostname,
|
||||
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95"},
|
||||
}
|
||||
|
||||
altNames, err := getAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling getAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", controlPlaneEndpoint}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{"10.96.0.1", advertiseIP, "10.1.245.94", "10.1.245.95"}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCACertAndKey(t *testing.T) {
|
||||
caCert, _, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
@ -357,42 +310,50 @@ func TestNewAPIServerKubeletClientCertAndKey(t *testing.T) {
|
||||
certstestutil.AssertCertificateHasOrganizations(t, apiClientCert, kubeadmconstants.MastersGroup)
|
||||
}
|
||||
|
||||
func TestNewEtcdCertAndKey(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
func TestNewEtcdServerCertAndKey(t *testing.T) {
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
|
||||
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
|
||||
for _, addr := range advertiseAddresses {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: addr},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeName: "valid-hostname",
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
etcdCert, _, err := NewEtcdCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, etcdCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdCert, hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local")
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdCert, net.ParseIP("10.96.0.1"), net.ParseIP(addr))
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
ServerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
},
|
||||
},
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
etcdServerCert, _, err := NewEtcdServerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, etcdServerCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdServerCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdServerCert, "localhost", proxy)
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdServerCert, net.ParseIP("127.0.0.1"), net.ParseIP(proxyIP))
|
||||
}
|
||||
|
||||
func TestNewEtcdPeerCertAndKey(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
|
||||
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
|
||||
for _, addr := range advertiseAddresses {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: addr},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeName: "valid-hostname",
|
||||
API: kubeadmapi.API{AdvertiseAddress: addr},
|
||||
NodeName: hostname,
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
PeerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
},
|
||||
},
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
@ -407,8 +368,8 @@ func TestNewEtcdPeerCertAndKey(t *testing.T) {
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, etcdPeerCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdPeerCert)
|
||||
certstestutil.AssertCertificateHasClientAuthUsage(t, etcdPeerCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdPeerCert, hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local")
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdPeerCert, net.ParseIP("10.96.0.1"), net.ParseIP(addr))
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdPeerCert, hostname, proxy)
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdPeerCert, net.ParseIP(addr), net.ParseIP(proxyIP))
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,6 +583,9 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
kubeadmconstants.CACertName, kubeadmconstants.CAKeyName,
|
||||
kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName,
|
||||
kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName,
|
||||
kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
|
||||
kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
|
||||
kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
|
||||
kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName,
|
||||
kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName,
|
||||
kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
|
||||
@ -643,8 +607,8 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
},
|
||||
{
|
||||
setupFunc: CreateCACertAndKeyfiles,
|
||||
createFunc: CreateEtcdCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdCertName, kubeadmconstants.EtcdKeyName},
|
||||
createFunc: CreateEtcdServerCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateCACertAndKeyfiles,
|
||||
|
@ -24,6 +24,8 @@ package certs
|
||||
From MasterConfiguration
|
||||
.API.AdvertiseAddress is an optional parameter that can be passed for an extra addition to the SAN IPs
|
||||
.APIServerCertSANs is an optional parameter for adding DNS names and IPs to the API Server serving cert SAN
|
||||
.Etcd.ServerCertSANs is an optional parameter for adding DNS names and IPs to the etcd serving cert SAN
|
||||
.Etcd.PeerCertSANs is an optional parameter for adding DNS names and IPs to the etcd peer cert SAN
|
||||
.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
|
||||
.CertificatesDir is required for knowing where all certificates should be stored
|
||||
@ -36,12 +38,12 @@ package certs
|
||||
- apiserver.key
|
||||
- apiserver-kubelet-client.crt
|
||||
- apiserver-kubelet-client.key
|
||||
- etcd-server.crt
|
||||
- etcd-server.key
|
||||
- etcd-peer.crt
|
||||
- etcd-peer.key
|
||||
- apiserver-etcd-client.crt
|
||||
- apiserver-etcd-client.key
|
||||
- etcd/server.crt
|
||||
- etcd/server.key
|
||||
- etcd/peer.crt
|
||||
- etcd/peer.key
|
||||
- sa.pub
|
||||
- sa.key
|
||||
- front-proxy-ca.crt
|
||||
|
@ -10,14 +10,23 @@ go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["pki_helpers_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//vendor/k8s.io/client-go/util/cert:go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["pki_helpers.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil",
|
||||
deps = ["//vendor/k8s.io/client-go/util/cert:go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
|
@ -20,11 +20,16 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
)
|
||||
|
||||
// NewCertificateAuthority creates new certificate and private key for the certificate authority
|
||||
@ -246,3 +251,106 @@ func pathForKey(pkiPath, name string) string {
|
||||
func pathForPublicKey(pkiPath, name string) string {
|
||||
return filepath.Join(pkiPath, fmt.Sprintf("%s.pub", name))
|
||||
}
|
||||
|
||||
// GetAPIServerAltNames builds an AltNames object for to be used when generating apiserver certificate
|
||||
func GetAPIServerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// advertise address
|
||||
advertiseAddress := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if advertiseAddress == nil {
|
||||
return nil, fmt.Errorf("error parsing API AdvertiseAddress %v: is not a valid textual representation of an IP address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// internal IP address for the API server
|
||||
_, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing CIDR %q: %v", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
|
||||
internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(svcSubnet, 1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get first IP address from the given CIDR (%s): %v", svcSubnet.String(), err)
|
||||
}
|
||||
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{
|
||||
cfg.NodeName,
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
|
||||
},
|
||||
IPs: []net.IP{
|
||||
internalAPIServerVirtualIP,
|
||||
advertiseAddress,
|
||||
},
|
||||
}
|
||||
|
||||
// add api server dns advertise address
|
||||
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||
altNames.DNSNames = append(altNames.DNSNames, cfg.API.ControlPlaneEndpoint)
|
||||
}
|
||||
|
||||
appendSANsToAltNames(altNames, cfg.APIServerCertSANs, kubeadmconstants.APIServerCertName)
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// GetEtcdAltNames builds an AltNames object for generating the etcd server certificate.
|
||||
// `localhost` is included in the SAN since this is the interface the etcd static pod listens on.
|
||||
// Hostname and `API.AdvertiseAddress` are excluded since etcd does not listen on this interface by default.
|
||||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.ServerCertSANs`.
|
||||
func GetEtcdAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{"localhost"},
|
||||
IPs: []net.IP{net.IPv4(127, 0, 0, 1)},
|
||||
}
|
||||
|
||||
appendSANsToAltNames(altNames, cfg.Etcd.ServerCertSANs, kubeadmconstants.EtcdServerCertName)
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// GetEtcdPeerAltNames builds an AltNames object for generating the etcd peer certificate.
|
||||
// `localhost` is excluded from the SAN since etcd will not refer to itself as a peer.
|
||||
// Hostname and `API.AdvertiseAddress` are included if the user chooses to promote the single node etcd cluster into a multi-node one.
|
||||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.PeerCertSANs`.
|
||||
func GetEtcdPeerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// advertise address
|
||||
advertiseAddress := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if advertiseAddress == nil {
|
||||
return nil, fmt.Errorf("error parsing API AdvertiseAddress %v: is not a valid textual representation of an IP address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{cfg.NodeName},
|
||||
IPs: []net.IP{advertiseAddress},
|
||||
}
|
||||
|
||||
appendSANsToAltNames(altNames, cfg.Etcd.PeerCertSANs, kubeadmconstants.EtcdPeerCertName)
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// appendSANsToAltNames parses SANs from as list of strings and adds them to altNames for use on a specific cert
|
||||
// altNames is passed in with a pointer, and the struct is modified
|
||||
// valid IP address strings are parsed and added to altNames.IPs as net.IP's
|
||||
// RFC-1123 compliant DNS strings are added to altNames.DNSNames as strings
|
||||
// certNames is used to print user facing warnings and should be the name of the cert the altNames will be used for
|
||||
func appendSANsToAltNames(altNames *certutil.AltNames, SANs []string, certName string) {
|
||||
for _, altname := range SANs {
|
||||
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)
|
||||
} else {
|
||||
fmt.Printf(
|
||||
"[certificates] WARNING: '%s' was not added to the '%s' SAN, because it is not a valid IP or RFC-1123 compliant DNS entry\n",
|
||||
altname,
|
||||
certName,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,12 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestNewCertificateAuthority(t *testing.T) {
|
||||
@ -432,3 +434,154 @@ func TestPathForPublicKey(t *testing.T) {
|
||||
t.Errorf("unexpected certificate path: %s", pubPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIServerAltNames(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
advertiseIP := "1.2.3.4"
|
||||
controlPlaneEndpoint := "api.k8s.io"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: advertiseIP, ControlPlaneEndpoint: controlPlaneEndpoint},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeName: hostname,
|
||||
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
|
||||
}
|
||||
|
||||
altNames, err := GetAPIServerAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetAPIServerAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", controlPlaneEndpoint}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{"10.96.0.1", advertiseIP, "10.1.245.94", "10.1.245.95"}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdAltNames(t *testing.T) {
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
ServerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
"1.2.3.L",
|
||||
"invalid,commas,in,DNS",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
altNames, err := GetEtcdAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetEtcdAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{"localhost", proxy}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{"127.0.0.1", proxyIP}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdPeerAltNames(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
advertiseIP := "1.2.3.4"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: advertiseIP},
|
||||
NodeName: hostname,
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
PeerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
"1.2.3.L",
|
||||
"invalid,commas,in,DNS",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
altNames, err := GetEtcdPeerAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetEtcdPeerAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{hostname, proxy}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{advertiseIP, proxyIP}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,13 +213,13 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *versio
|
||||
|
||||
// Warn for unused user supplied variables
|
||||
if cfg.Etcd.CAFile != "" {
|
||||
fmt.Printf("[controlplane] Configuration for %s CAFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CAFile, kubeadmconstants.Etcd)
|
||||
fmt.Printf("[controlplane] WARNING: Configuration for %s CAFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CAFile, kubeadmconstants.Etcd)
|
||||
}
|
||||
if cfg.Etcd.CertFile != "" {
|
||||
fmt.Printf("[controlplane] Configuration for %s CertFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CertFile, kubeadmconstants.Etcd)
|
||||
fmt.Printf("[controlplane] WARNING: Configuration for %s CertFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CertFile, kubeadmconstants.Etcd)
|
||||
}
|
||||
if cfg.Etcd.KeyFile != "" {
|
||||
fmt.Printf("[controlplane] Configuration for %s KeyFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.KeyFile, kubeadmconstants.Etcd)
|
||||
fmt.Printf("[controlplane] WARNING: Configuration for %s KeyFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.KeyFile, kubeadmconstants.Etcd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +75,8 @@ func getEtcdCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
"listen-client-urls": "https://127.0.0.1:2379",
|
||||
"advertise-client-urls": "https://127.0.0.1:2379",
|
||||
"data-dir": cfg.Etcd.DataDir,
|
||||
"cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCertName),
|
||||
"key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdKeyName),
|
||||
"cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName),
|
||||
"key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName),
|
||||
"trusted-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
|
||||
"client-cert-auth": "true",
|
||||
"peer-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerCertName),
|
||||
|
@ -82,13 +82,13 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--listen-client-urls=https://127.0.0.1:2379",
|
||||
"--advertise-client-urls=https://127.0.0.1:2379",
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=etcd-server.crt",
|
||||
"--key-file=etcd-server.key",
|
||||
"--trusted-ca-file=ca.crt",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
"--trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--client-cert-auth=true",
|
||||
"--peer-cert-file=etcd-peer.crt",
|
||||
"--peer-key-file=etcd-peer.key",
|
||||
"--peer-trusted-ca-file=ca.crt",
|
||||
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
|
||||
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--peer-client-cert-auth=true",
|
||||
},
|
||||
},
|
||||
@ -107,13 +107,13 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--listen-client-urls=https://10.0.1.10:2379",
|
||||
"--advertise-client-urls=https://10.0.1.10:2379",
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=etcd-server.crt",
|
||||
"--key-file=etcd-server.key",
|
||||
"--trusted-ca-file=ca.crt",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
"--trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--client-cert-auth=true",
|
||||
"--peer-cert-file=etcd-peer.crt",
|
||||
"--peer-key-file=etcd-peer.key",
|
||||
"--peer-trusted-ca-file=ca.crt",
|
||||
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
|
||||
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--peer-client-cert-auth=true",
|
||||
},
|
||||
},
|
||||
@ -126,13 +126,13 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--listen-client-urls=https://127.0.0.1:2379",
|
||||
"--advertise-client-urls=https://127.0.0.1:2379",
|
||||
"--data-dir=/etc/foo",
|
||||
"--cert-file=etcd-server.crt",
|
||||
"--key-file=etcd-server.key",
|
||||
"--trusted-ca-file=ca.crt",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
"--trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--client-cert-auth=true",
|
||||
"--peer-cert-file=etcd-peer.crt",
|
||||
"--peer-key-file=etcd-peer.key",
|
||||
"--peer-trusted-ca-file=ca.crt",
|
||||
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
|
||||
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
|
||||
"--peer-client-cert-auth=true",
|
||||
},
|
||||
},
|
||||
|
@ -137,7 +137,7 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
||||
|
||||
// ensure etcd certs are generated for etcd and kube-apiserver
|
||||
if component == constants.Etcd {
|
||||
if err := certsphase.CreateEtcdCertAndKeyFiles(cfg); err != nil {
|
||||
if err := certsphase.CreateEtcdServerCertAndKeyFiles(cfg); err != nil {
|
||||
return fmt.Errorf("failed to upgrade the %s certificate: %v", constants.Etcd, err)
|
||||
}
|
||||
if err := certsphase.CreateEtcdPeerCertAndKeyFiles(cfg); err != nil {
|
||||
|
@ -61,6 +61,8 @@ etcd:
|
||||
extraArgs: null
|
||||
image: ""
|
||||
keyFile: ""
|
||||
serverCertSANs: null
|
||||
peerCertSANs: null
|
||||
featureFlags: null
|
||||
imageRepository: k8s.gcr.io
|
||||
kubernetesVersion: %s
|
||||
@ -322,7 +324,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
certsphase.CreateCACertAndKeyfiles,
|
||||
certsphase.CreateAPIServerCertAndKeyFiles,
|
||||
certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdServerCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdPeerCertAndKeyFiles,
|
||||
// certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
|
Loading…
Reference in New Issue
Block a user