mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
kubeadm: allow creating a cluster with ECDSA keys
The selected key type is defined by kubeadm's --feature-gates option: if it contains PublicKeysECDSA=true then ECDSA keys will be generated and used. By default RSA keys are used still. Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
This commit is contained in:
parent
ac25069a05
commit
109f5db5a3
@ -19,6 +19,7 @@ go_library(
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
|
@ -17,8 +17,11 @@ limitations under the License.
|
||||
package kubeadm
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
@ -400,6 +403,15 @@ func (cfg *ClusterConfiguration) GetControlPlaneImageRepository() string {
|
||||
return cfg.ImageRepository
|
||||
}
|
||||
|
||||
// PublicKeyAlgorithm returns the type of encryption keys used in the cluster.
|
||||
func (cfg *ClusterConfiguration) PublicKeyAlgorithm() x509.PublicKeyAlgorithm {
|
||||
if features.Enabled(cfg.FeatureGates, features.PublicKeysECDSA) {
|
||||
return x509.ECDSA
|
||||
}
|
||||
|
||||
return x509.RSA
|
||||
}
|
||||
|
||||
// HostPathMount contains elements describing volumes that are mounted from the
|
||||
// host.
|
||||
type HostPathMount struct {
|
||||
|
@ -200,7 +200,7 @@ func runCertsSa(c workflow.RunData) error {
|
||||
}
|
||||
|
||||
// create the new service account key (or use existing)
|
||||
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(data.CertificateWriteDir())
|
||||
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(data.CertificateWriteDir(), data.Cfg().ClusterConfiguration.PublicKeyAlgorithm())
|
||||
}
|
||||
|
||||
func runCerts(c workflow.RunData) error {
|
||||
|
@ -35,7 +35,7 @@ go_test(
|
||||
srcs = ["features_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -30,11 +30,14 @@ import (
|
||||
const (
|
||||
// IPv6DualStack is expected to be alpha in v1.16
|
||||
IPv6DualStack = "IPv6DualStack"
|
||||
// PublicKeysECDSA is expected to be alpha in v1.19
|
||||
PublicKeysECDSA = "PublicKeysECDSA"
|
||||
)
|
||||
|
||||
// InitFeatureGates are the default feature gates for the init command
|
||||
var InitFeatureGates = FeatureList{
|
||||
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
PublicKeysECDSA: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
}
|
||||
|
||||
// Feature represents a feature being gated
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/component-base/featuregate"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
func TestKnownFeatures(t *testing.T) {
|
||||
@ -129,7 +129,7 @@ func TestNewFeatureGate(t *testing.T) {
|
||||
func TestValidateVersion(t *testing.T) {
|
||||
var someFeatures = FeatureList{
|
||||
"feature1": {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Beta}},
|
||||
"feature2": {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Alpha}, MinimumVersion: constants.MinimumControlPlaneVersion.WithPreRelease("alpha.1")},
|
||||
"feature2": {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Alpha}, MinimumVersion: version.MustParseSemantic("v1.17.0").WithPreRelease("alpha.1")},
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
@ -146,7 +146,7 @@ func TestValidateVersion(t *testing.T) {
|
||||
{
|
||||
name: "min version but correct value given",
|
||||
requestedFeatures: map[string]bool{"feature2": true},
|
||||
requestedVersion: constants.MinimumControlPlaneVersion.String(),
|
||||
requestedVersion: "v1.17.0",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ import (
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *certutil.Config) error
|
||||
type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *pkiutil.CertConfig) error
|
||||
|
||||
// KubeadmCert represents a certificate that Kubeadm will create to function properly.
|
||||
type KubeadmCert struct {
|
||||
@ -39,17 +39,18 @@ type KubeadmCert struct {
|
||||
// Some attributes will depend on the InitConfiguration, only known at runtime.
|
||||
// These functions will be run in series, passed both the InitConfiguration and a cert Config.
|
||||
configMutators []configMutatorsFunc
|
||||
config certutil.Config
|
||||
config pkiutil.CertConfig
|
||||
}
|
||||
|
||||
// GetConfig returns the definition for the given cert given the provided InitConfiguration
|
||||
func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*certutil.Config, error) {
|
||||
func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*pkiutil.CertConfig, error) {
|
||||
for _, f := range k.configMutators {
|
||||
if err := f(ic, &k.config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
k.config.PublicKeyAlgorithm = ic.ClusterConfiguration.PublicKeyAlgorithm()
|
||||
return &k.config, nil
|
||||
}
|
||||
|
||||
@ -239,8 +240,10 @@ var (
|
||||
Name: "ca",
|
||||
LongName: "self-signed Kubernetes CA to provision identities for other Kubernetes components",
|
||||
BaseName: kubeadmconstants.CACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "kubernetes",
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "kubernetes",
|
||||
},
|
||||
},
|
||||
}
|
||||
// KubeadmCertAPIServer is the definition of the cert used to serve the Kubernetes API.
|
||||
@ -249,9 +252,11 @@ var (
|
||||
LongName: "certificate for serving the Kubernetes API",
|
||||
BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
|
||||
CAName: "ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetAPIServerAltNames),
|
||||
@ -263,10 +268,12 @@ var (
|
||||
LongName: "certificate for the API server to connect to kubelet",
|
||||
BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
|
||||
CAName: "ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -275,8 +282,10 @@ var (
|
||||
Name: "front-proxy-ca",
|
||||
LongName: "self-signed CA to provision identities for front proxy",
|
||||
BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "front-proxy-ca",
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "front-proxy-ca",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -286,9 +295,11 @@ var (
|
||||
BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
|
||||
LongName: "certificate for the front proxy client",
|
||||
CAName: "front-proxy-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -297,8 +308,10 @@ var (
|
||||
Name: "etcd-ca",
|
||||
LongName: "self-signed CA to provision identities for etcd",
|
||||
BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "etcd-ca",
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "etcd-ca",
|
||||
},
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients.
|
||||
@ -307,12 +320,14 @@ var (
|
||||
LongName: "certificate for serving etcd",
|
||||
BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
// TODO: etcd 3.2 introduced an undocumented requirement for ClientAuth usage on the
|
||||
// server cert: https://github.com/coreos/etcd/issues/9785#issuecomment-396715692
|
||||
// Once the upstream issue is resolved, this should be returned to only allowing
|
||||
// ServerAuth usage.
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
// TODO: etcd 3.2 introduced an undocumented requirement for ClientAuth usage on the
|
||||
// server cert: https://github.com/coreos/etcd/issues/9785#issuecomment-396715692
|
||||
// Once the upstream issue is resolved, this should be returned to only allowing
|
||||
// ServerAuth usage.
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetEtcdAltNames),
|
||||
@ -325,8 +340,10 @@ var (
|
||||
LongName: "certificate for etcd nodes to communicate with each other",
|
||||
BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetEtcdPeerAltNames),
|
||||
@ -339,10 +356,12 @@ var (
|
||||
LongName: "certificate for liveness probes to healthcheck etcd",
|
||||
BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd.
|
||||
@ -351,16 +370,18 @@ var (
|
||||
LongName: "certificate the apiserver uses to access etcd",
|
||||
BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.SystemPrivilegedGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNames, error)) configMutatorsFunc {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
|
||||
altNames, err := f(mc)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -371,7 +392,7 @@ func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNam
|
||||
}
|
||||
|
||||
func setCommonNameToNodeName() configMutatorsFunc {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
|
||||
cc.CommonName = mc.NodeRegistration.Name
|
||||
return nil
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
func TestCertListOrder(t *testing.T) {
|
||||
@ -160,16 +161,18 @@ func TestCreateCertificateChain(t *testing.T) {
|
||||
|
||||
caCfg := Certificates{
|
||||
{
|
||||
config: certutil.Config{},
|
||||
config: pkiutil.CertConfig{},
|
||||
Name: "test-ca",
|
||||
BaseName: "test-ca",
|
||||
},
|
||||
{
|
||||
config: certutil.Config{
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
config: pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
setCommonNameToNodeName(),
|
||||
|
@ -24,7 +24,6 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/client-go/util/keyutil"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
@ -61,12 +60,12 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
|
||||
fmt.Printf("[certs] Valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
|
||||
|
||||
// Service accounts are not x509 certs, so handled separately
|
||||
return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir)
|
||||
return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir, cfg.ClusterConfiguration.PublicKeyAlgorithm())
|
||||
}
|
||||
|
||||
// CreateServiceAccountKeyAndPublicKeyFiles creates new public/private key files for signing service account users.
|
||||
// If the sa public/private key files already exist in the target folder, they are used only if evaluated equals; otherwise an error is returned.
|
||||
func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
|
||||
func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string, keyType x509.PublicKeyAlgorithm) error {
|
||||
klog.V(1).Infoln("creating new public/private key files for signing service account users")
|
||||
_, err := keyutil.PrivateKeyFromFile(filepath.Join(certsDir, kubeadmconstants.ServiceAccountPrivateKeyName))
|
||||
if err == nil {
|
||||
@ -80,7 +79,7 @@ func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
|
||||
}
|
||||
|
||||
// The key does NOT exist, let's generate it now
|
||||
key, err := pkiutil.NewPrivateKey()
|
||||
key, err := pkiutil.NewPrivateKey(keyType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -215,7 +214,7 @@ func writeCertificateAuthorityFilesIfNotExist(pkiDir string, baseName string, ca
|
||||
// If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
|
||||
// existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
|
||||
// otherwise this function returns an error.
|
||||
func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *certutil.Config) error {
|
||||
func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *pkiutil.CertConfig) error {
|
||||
|
||||
// Checks if the signed certificate exists in the PKI directory
|
||||
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
|
||||
@ -426,7 +425,7 @@ func validatePrivatePublicKey(l certKeyLocation) error {
|
||||
|
||||
// validateCertificateWithConfig makes sure that a given certificate is valid at
|
||||
// least for the SANs defined in the configuration.
|
||||
func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *certutil.Config) error {
|
||||
func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *pkiutil.CertConfig) error {
|
||||
for _, dnsName := range cfg.AltNames.DNSNames {
|
||||
if err := cert.VerifyHostname(dnsName); err != nil {
|
||||
return errors.Wrapf(err, "certificate %s is invalid", baseName)
|
||||
|
@ -42,8 +42,10 @@ import (
|
||||
|
||||
func createTestCSR(t *testing.T) (*x509.CertificateRequest, crypto.Signer) {
|
||||
csr, key, err := pkiutil.NewCSRAndKey(
|
||||
&certutil.Config{
|
||||
CommonName: "testCert",
|
||||
&pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "testCert",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create test cert: %v", err)
|
||||
@ -344,7 +346,7 @@ func TestCreateServiceAccountKeyAndPublicKeyFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
err := CreateServiceAccountKeyAndPublicKeyFiles(dir)
|
||||
err := CreateServiceAccountKeyAndPublicKeyFiles(dir, x509.RSA)
|
||||
if (err != nil) != tt.expectedErr {
|
||||
t.Fatalf("expected error: %v, got: %v, error: %v", tt.expectedErr, err != nil, err)
|
||||
} else if tt.expectedErr {
|
||||
|
@ -52,7 +52,7 @@ func NewAPIRenewer(client clientset.Interface) *APIRenewer {
|
||||
}
|
||||
|
||||
// Renew a certificate using the K8s certificate API
|
||||
func (r *APIRenewer) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
func (r *APIRenewer) Renew(cfg *pkiutil.CertConfig) (*x509.Certificate, crypto.Signer, error) {
|
||||
reqTmp := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
@ -62,7 +62,7 @@ func (r *APIRenewer) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.Sign
|
||||
IPAddresses: cfg.AltNames.IPs,
|
||||
}
|
||||
|
||||
key, err := pkiutil.NewPrivateKey()
|
||||
key, err := pkiutil.NewPrivateKey(cfg.PublicKeyAlgorithm)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "couldn't create new private key")
|
||||
}
|
||||
|
@ -33,7 +33,9 @@ import (
|
||||
)
|
||||
|
||||
func TestAPIRenewer(t *testing.T) {
|
||||
caCertCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCertCfg := &pkiutil.CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
}
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority(caCertCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
@ -55,12 +57,14 @@ func TestAPIRenewer(t *testing.T) {
|
||||
// override the timeout so tests are faster
|
||||
watchTimeout = time.Second
|
||||
|
||||
certCfg := &certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
certCfg := &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
renewer := &APIRenewer{
|
||||
@ -92,12 +96,14 @@ func defaultReactionFunc(obj runtime.Object) k8stesting.ReactionFunc {
|
||||
}
|
||||
|
||||
func getCertReq(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer) *certsapi.CertificateSigningRequest {
|
||||
cert, _, err := pkiutil.NewCertAndKey(caCert, caKey, &certutil.Config{
|
||||
CommonName: "testcert",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
cert, _, err := pkiutil.NewCertAndKey(caCert, caKey, &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "testcert",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't generate cert: %v", err)
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
@ -39,6 +38,6 @@ func NewFileRenewer(caCert *x509.Certificate, caKey crypto.Signer) *FileRenewer
|
||||
}
|
||||
|
||||
// Renew a certificate using a given CA cert and key
|
||||
func (r *FileRenewer) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
func (r *FileRenewer) Renew(cfg *pkiutil.CertConfig) (*x509.Certificate, crypto.Signer, error) {
|
||||
return pkiutil.NewCertAndKey(r.caCert, r.caKey, cfg)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"testing"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
func TestFileRenewer(t *testing.T) {
|
||||
@ -28,12 +29,14 @@ func TestFileRenewer(t *testing.T) {
|
||||
fr := NewFileRenewer(testCACert, testCAKey)
|
||||
|
||||
// renews a certificate
|
||||
certCfg := &certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
certCfg := &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
cert, _, err := fr.Renew(certCfg)
|
||||
|
@ -224,7 +224,10 @@ func (rm *Manager) RenewUsingLocalCA(name string) (bool, error) {
|
||||
}
|
||||
|
||||
// extract the certificate config
|
||||
cfg := certToConfig(cert)
|
||||
cfg := &pkiutil.CertConfig{
|
||||
Config: certToConfig(cert),
|
||||
PublicKeyAlgorithm: rm.cfg.PublicKeyAlgorithm(),
|
||||
}
|
||||
|
||||
// reads the CA
|
||||
caCert, caKey, err := certsphase.LoadCertificateAuthority(rm.cfg.CertificatesDir, handler.CABaseName)
|
||||
@ -264,7 +267,10 @@ func (rm *Manager) RenewUsingCSRAPI(name string, client clientset.Interface) err
|
||||
}
|
||||
|
||||
// extract the certificate config
|
||||
cfg := certToConfig(cert)
|
||||
cfg := &pkiutil.CertConfig{
|
||||
Config: certToConfig(cert),
|
||||
PublicKeyAlgorithm: rm.cfg.PublicKeyAlgorithm(),
|
||||
}
|
||||
|
||||
// create a new certificate with the same config
|
||||
newCert, newKey, err := NewAPIRenewer(client).Renew(cfg)
|
||||
@ -298,7 +304,10 @@ func (rm *Manager) CreateRenewCSR(name, outdir string) error {
|
||||
}
|
||||
|
||||
// extracts the certificate config
|
||||
cfg := certToConfig(cert)
|
||||
cfg := &pkiutil.CertConfig{
|
||||
Config: certToConfig(cert),
|
||||
PublicKeyAlgorithm: rm.cfg.PublicKeyAlgorithm(),
|
||||
}
|
||||
|
||||
// generates the CSR request and save it
|
||||
csr, key, err := pkiutil.NewCSRAndKey(cfg)
|
||||
@ -407,8 +416,8 @@ func (rm *Manager) IsExternallyManaged(caBaseName string) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func certToConfig(cert *x509.Certificate) *certutil.Config {
|
||||
return &certutil.Config{
|
||||
func certToConfig(cert *x509.Certificate) certutil.Config {
|
||||
return certutil.Config{
|
||||
CommonName: cert.Subject.CommonName,
|
||||
Organization: cert.Subject.Organization,
|
||||
AltNames: certutil.AltNames{
|
||||
|
@ -34,18 +34,22 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
testCACertCfg = &certutil.Config{CommonName: "kubernetes"}
|
||||
testCACertCfg = &pkiutil.CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
}
|
||||
|
||||
testCACert, testCAKey, _ = pkiutil.NewCertificateAuthority(testCACertCfg)
|
||||
|
||||
testCertCfg = &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
testCertCfg = &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -154,13 +154,15 @@ func writeTestCertificate(t *testing.T, dir, name string, caCert *x509.Certifica
|
||||
// writeTestKubeconfig is a utility for creating a test kubeconfig with an embedded certificate
|
||||
func writeTestKubeconfig(t *testing.T, dir, name string, caCert *x509.Certificate, caKey crypto.Signer) *x509.Certificate {
|
||||
|
||||
cfg := &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
cfg := &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
},
|
||||
}
|
||||
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
|
||||
|
@ -182,10 +182,12 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
|
||||
}
|
||||
|
||||
// otherwise, create a client certs
|
||||
clientCertConfig := certutil.Config{
|
||||
CommonName: spec.ClientName,
|
||||
Organization: spec.ClientCertAuth.Organizations,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
clientCertConfig := pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: spec.ClientName,
|
||||
Organization: spec.ClientCertAuth.Organizations,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
clientCert, clientKey, err := pkiutil.NewCertAndKey(spec.CACert, spec.ClientCertAuth.CAKey, &clientCertConfig)
|
||||
if err != nil {
|
||||
|
@ -32,7 +32,9 @@ import (
|
||||
// SetupCertificateAuthority is a utility function for kubeadm testing that creates a
|
||||
// CertificateAuthority cert/key pair
|
||||
func SetupCertificateAuthority(t *testing.T) (*x509.Certificate, crypto.Signer) {
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority(&pkiutil.CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failure while generating CA certificate and key: %v", err)
|
||||
}
|
||||
@ -132,7 +134,7 @@ func AssertCertificateHasIPAddresses(t *testing.T, cert *x509.Certificate, IPAdd
|
||||
|
||||
// CreateCACert creates a generic CA cert.
|
||||
func CreateCACert(t *testing.T) (*x509.Certificate, crypto.Signer) {
|
||||
certCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
certCfg := &pkiutil.CertConfig{Config: certutil.Config{CommonName: "kubernetes"}}
|
||||
cert, key, err := pkiutil.NewCertificateAuthority(certCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
@ -141,11 +143,13 @@ func CreateCACert(t *testing.T) (*x509.Certificate, crypto.Signer) {
|
||||
}
|
||||
|
||||
// CreateTestCert makes a generic certificate with the given CA and alternative names.
|
||||
func CreateTestCert(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer, altNames certutil.AltNames) (*x509.Certificate, crypto.Signer, *certutil.Config) {
|
||||
config := &certutil.Config{
|
||||
CommonName: "testCert",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
AltNames: altNames,
|
||||
func CreateTestCert(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer, altNames certutil.AltNames) (*x509.Certificate, crypto.Signer, *pkiutil.CertConfig) {
|
||||
config := &pkiutil.CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "testCert",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
AltNames: altNames,
|
||||
},
|
||||
}
|
||||
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
|
@ -19,6 +19,7 @@ package pkiutil
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@ -56,14 +57,20 @@ const (
|
||||
rsaKeySize = 2048
|
||||
)
|
||||
|
||||
// CertConfig is a wrapper around certutil.Config extending it with PublicKeyAlgorithm.
|
||||
type CertConfig struct {
|
||||
certutil.Config
|
||||
PublicKeyAlgorithm x509.PublicKeyAlgorithm
|
||||
}
|
||||
|
||||
// NewCertificateAuthority creates new certificate and private key for the certificate authority
|
||||
func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
func NewCertificateAuthority(config *CertConfig) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey(config.PublicKeyAlgorithm)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key while generating CA certificate")
|
||||
}
|
||||
|
||||
cert, err := certutil.NewSelfSignedCACert(*config, key)
|
||||
cert, err := certutil.NewSelfSignedCACert(config.Config, key)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create self-signed CA certificate")
|
||||
}
|
||||
@ -72,8 +79,8 @@ func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, crypto
|
||||
}
|
||||
|
||||
// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key
|
||||
func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer, config *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer, config *CertConfig) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey(config.PublicKeyAlgorithm)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key")
|
||||
}
|
||||
@ -87,8 +94,8 @@ func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer, config *certut
|
||||
}
|
||||
|
||||
// NewCSRAndKey generates a new key and CSR and that could be signed to create the given certificate
|
||||
func NewCSRAndKey(config *certutil.Config) (*x509.CertificateRequest, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
func NewCSRAndKey(config *CertConfig) (*x509.CertificateRequest, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey(config.PublicKeyAlgorithm)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key")
|
||||
}
|
||||
@ -496,7 +503,7 @@ func CertificateRequestFromFile(file string) (*x509.CertificateRequest, error) {
|
||||
}
|
||||
|
||||
// NewCSR creates a new CSR
|
||||
func NewCSR(cfg certutil.Config, key crypto.Signer) (*x509.CertificateRequest, error) {
|
||||
func NewCSR(cfg CertConfig, key crypto.Signer) (*x509.CertificateRequest, error) {
|
||||
template := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
@ -538,12 +545,16 @@ func EncodePublicKeyPEM(key crypto.PublicKey) ([]byte, error) {
|
||||
}
|
||||
|
||||
// NewPrivateKey creates an RSA private key
|
||||
func NewPrivateKey() (crypto.Signer, error) {
|
||||
func NewPrivateKey(keyType x509.PublicKeyAlgorithm) (crypto.Signer, error) {
|
||||
if keyType == x509.ECDSA {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
|
||||
}
|
||||
|
||||
return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
|
||||
}
|
||||
|
||||
// NewSignedCert creates a signed certificate using the given CA certificate and key
|
||||
func NewSignedCert(cfg *certutil.Config, key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
|
||||
func NewSignedCert(cfg *CertConfig, key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
|
||||
serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -33,7 +33,9 @@ import (
|
||||
)
|
||||
|
||||
func TestNewCertificateAuthority(t *testing.T) {
|
||||
cert, key, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
cert, key, err := NewCertificateAuthority(&CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
})
|
||||
|
||||
if cert == nil {
|
||||
t.Error("failed NewCertificateAuthority, cert == nil")
|
||||
@ -86,10 +88,12 @@ func TestNewCertAndKey(t *testing.T) {
|
||||
t.Fatalf("Couldn't create Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
config := &certutil.Config{
|
||||
CommonName: "test",
|
||||
Organization: []string{"test"},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config := &CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Organization: []string{"test"},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
_, _, actual := NewCertAndKey(caCert, caKey, config)
|
||||
if (actual == nil) != rt.expected {
|
||||
@ -104,26 +108,41 @@ func TestNewCertAndKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHasServerAuth(t *testing.T) {
|
||||
caCert, caKey, _ := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
caCert, caKey, _ := NewCertificateAuthority(&CertConfig{Config: certutil.Config{CommonName: "kubernetes"}})
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
config certutil.Config
|
||||
config CertConfig
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "has ServerAuth",
|
||||
config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
config: CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "has ServerAuth ECDSA",
|
||||
config: CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
PublicKeyAlgorithm: x509.ECDSA,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "doesn't have ServerAuth",
|
||||
config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
config: CertConfig{
|
||||
Config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
@ -285,7 +304,9 @@ func TestTryLoadCertAndKeyFromDisk(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caCert, caKey, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
caCert, caKey, err := NewCertificateAuthority(&CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
@ -340,7 +361,9 @@ func TestTryLoadCertFromDisk(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caCert, _, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
caCert, _, err := NewCertificateAuthority(&CertConfig{
|
||||
Config: certutil.Config{CommonName: "kubernetes"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
|
@ -356,6 +356,10 @@ func TestCmdInitFeatureGates(t *testing.T) {
|
||||
name: "feature gate IPv6DualStack=true",
|
||||
args: "--feature-gates=IPv6DualStack=true",
|
||||
},
|
||||
{
|
||||
name: "feature gate PublicKeysECDSA=true",
|
||||
args: "--feature-gates=PublicKeysECDSA=true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range initTest {
|
||||
|
Loading…
Reference in New Issue
Block a user