Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kubeadm: add support for ECDSA keys #76390

Merged
merged 1 commit into from Apr 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 6 additions & 4 deletions cmd/kubeadm/app/cmd/alpha/certs_test.go
Expand Up @@ -209,11 +209,13 @@ func TestRunRenewCommands(t *testing.T) {
t.Errorf("couldn't verify renewed cert: %v", err)
}

pubKey, ok := newCert.PublicKey.(*rsa.PublicKey)
if !ok {
switch pubKey := newCert.PublicKey.(type) {
case *rsa.PublicKey:
if pubKey.N.Cmp(newKey.(*rsa.PrivateKey).N) != 0 {
t.Error("private key does not match public key")
}
default:
t.Errorf("unknown public key type %T", newCert.PublicKey)
} else if pubKey.N.Cmp(newKey.N) != 0 {
t.Error("private key does not match public key")
}
}

Expand Down
1 change: 1 addition & 0 deletions cmd/kubeadm/app/phases/certs/BUILD
Expand Up @@ -20,6 +20,7 @@ go_test(
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
"//cmd/kubeadm/test:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
Expand Down
8 changes: 4 additions & 4 deletions cmd/kubeadm/app/phases/certs/certlist.go
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package certs

import (
"crypto/rsa"
"crypto"
"crypto/x509"

"github.com/pkg/errors"
Expand Down Expand Up @@ -54,7 +54,7 @@ func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*certutil.Con
}

// CreateFromCA makes and writes a certificate using the given CA cert and key.
func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey crypto.Signer) error {
cfg, err := k.GetConfig(ic)
if err != nil {
return errors.Wrapf(err, "couldn't create %q certificate", k.Name)
Expand All @@ -80,7 +80,7 @@ func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x50
}

// CreateAsCA creates a certificate authority, writing the files to disk and also returning the created CA so it can be used to sign child certs.
func (k *KubeadmCert) CreateAsCA(ic *kubeadmapi.InitConfiguration) (*x509.Certificate, *rsa.PrivateKey, error) {
func (k *KubeadmCert) CreateAsCA(ic *kubeadmapi.InitConfiguration) (*x509.Certificate, crypto.Signer, error) {
cfg, err := k.GetConfig(ic)
if err != nil {
return nil, nil, errors.Wrapf(err, "couldn't get configuration for %q CA certificate", k.Name)
Expand Down Expand Up @@ -114,7 +114,7 @@ func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
return err
}

var caKey *rsa.PrivateKey
var caKey crypto.Signer

caCert, err := pkiutil.TryLoadCertFromDisk(ic.CertificatesDir, ca.BaseName)
if err == nil {
Expand Down
18 changes: 9 additions & 9 deletions cmd/kubeadm/app/phases/certs/certs.go
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package certs

import (
"crypto/rsa"
"crypto"
"crypto/x509"
"fmt"
"os"
Expand Down Expand Up @@ -80,7 +80,7 @@ func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
}

// NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens.
func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
func NewServiceAccountSigningKey() (crypto.Signer, error) {
// The key does NOT exist, let's generate it now
saSigningKey, err := pkiutil.NewPrivateKey()
if err != nil {
Expand Down Expand Up @@ -117,7 +117,7 @@ func CreateCACertAndKeyFiles(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfigur
}

// NewCSR will generate a new CSR and accompanying key
func NewCSR(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
func NewCSR(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) (*x509.CertificateRequest, crypto.Signer, error) {
certConfig, err := certSpec.GetConfig(cfg)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to retrieve cert configuration")
Expand Down Expand Up @@ -151,7 +151,7 @@ func CreateCertAndKeyFilesWithCA(certSpec *KubeadmCert, caCertSpec *KubeadmCert,
}

// LoadCertificateAuthority tries to load a CA in the given directory with the given name.
func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, crypto.Signer, error) {
// Checks if certificate authority exists in the PKI directory
if !pkiutil.CertOrKeyExist(pkiDir, baseName) {
return nil, nil, errors.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
Expand All @@ -175,7 +175,7 @@ func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate
// 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 writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey crypto.Signer) error {

// If cert or key exists, we should try to load them
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
Expand Down Expand Up @@ -210,7 +210,7 @@ func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, c
// 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 *rsa.PrivateKey, cfg *certutil.Config) error {
func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *certutil.Config) error {

// Checks if the signed certificate exists in the PKI directory
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
Expand Down Expand Up @@ -250,7 +250,7 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
// If there already is a key file at the given path; kubeadm tries to load it and check if the values in the
// existing and the expected key equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
// otherwise this function returns an error.
func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey) error {
func writeKeyFilesIfNotExist(pkiDir string, baseName string, key crypto.Signer) error {

// Checks if the key exists in the PKI directory
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
Expand All @@ -274,7 +274,7 @@ func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey
return errors.Wrapf(err, "failure while saving %s key", baseName)
}

if err := pkiutil.WritePublicKey(pkiDir, baseName, &key.PublicKey); err != nil {
if err := pkiutil.WritePublicKey(pkiDir, baseName, key.Public()); err != nil {
return errors.Wrapf(err, "failure while saving %s public key", baseName)
}
}
Expand All @@ -285,7 +285,7 @@ func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey
// writeCSRFilesIfNotExist writes a new CSR to the given path.
// If there already is a CSR file at the given path; kubeadm tries to load it and check if it's a valid certificate.
// otherwise this function returns an error.
func writeCSRFilesIfNotExist(csrDir string, baseName string, csr *x509.CertificateRequest, key *rsa.PrivateKey) error {
func writeCSRFilesIfNotExist(csrDir string, baseName string, csr *x509.CertificateRequest, key crypto.Signer) error {
if pkiutil.CSROrKeyExist(csrDir, baseName) {
_, _, err := pkiutil.TryLoadCSRAndKeyFromDisk(csrDir, baseName)
if err != nil {
Expand Down
28 changes: 20 additions & 8 deletions cmd/kubeadm/app/phases/certs/certs_test.go
Expand Up @@ -17,7 +17,8 @@ limitations under the License.
package certs

import (
"crypto/rsa"
"bytes"
"crypto"
"crypto/sha256"
"crypto/x509"
"io/ioutil"
Expand All @@ -31,14 +32,15 @@ import (
"github.com/stretchr/testify/assert"

certutil "k8s.io/client-go/util/cert"
"k8s.io/client-go/util/keyutil"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
certstestutil "k8s.io/kubernetes/cmd/kubeadm/app/util/certs"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
)

func createTestCSR(t *testing.T) (*x509.CertificateRequest, *rsa.PrivateKey) {
func createTestCSR(t *testing.T) (*x509.CertificateRequest, crypto.Signer) {
csr, key, err := pkiutil.NewCSRAndKey(
&certutil.Config{
CommonName: "testCert",
Expand Down Expand Up @@ -307,7 +309,7 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
var tests = []struct {
setupFunc func(pkiDir string) error
expectedError bool
expectedKey *rsa.PrivateKey
expectedKey crypto.Signer
}{
{ // key does not exists > key written
expectedKey: key,
Expand Down Expand Up @@ -349,7 +351,7 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
} else if test.expectedError && err == nil {
t.Error("error writeKeyFilesIfNotExist didn't failed when expected")
continue
} else if test.expectedError {
} else if test.expectedError || test.expectedKey == nil {
continue
}

Expand All @@ -363,8 +365,18 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
continue
}

//TODO: check if there is a better method to compare keys
if resultingKey.D == test.expectedKey.D {
resultingKeyPEM, err := keyutil.MarshalPrivateKeyToPEM(resultingKey)
if err != nil {
t.Errorf("failure marshaling created key: %v", err)
continue
}

expectedKeyPEM, err := keyutil.MarshalPrivateKeyToPEM(test.expectedKey)
if err != nil {
t.Fatalf("Failed to marshal expected private key: %v", err)
}

if bytes.Compare(resultingKeyPEM, expectedKeyPEM) != 0 {
t.Error("created key does not match expected key")
}
}
Expand All @@ -373,7 +385,7 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
func TestSharedCertificateExists(t *testing.T) {
caCert, caKey := certstestutil.CreateCACert(t)
_, key, _ := certstestutil.CreateTestCert(t, caCert, caKey, certutil.AltNames{})
publicKey := &key.PublicKey
publicKey := key.Public()

var tests = []struct {
name string
Expand Down Expand Up @@ -664,7 +676,7 @@ func TestValidateMethods(t *testing.T) {
{
name: "validatePrivatePublicKey",
files: certstestutil.PKIFiles{
"sa.pub": &key.PublicKey,
"sa.pub": key.Public(),
"sa.key": key,
},
validateFunc: validatePrivatePublicKey,
Expand Down
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/phases/certs/renewal/certsapi.go
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package renewal

import (
"crypto/rsa"
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
Expand Down Expand Up @@ -51,7 +51,7 @@ func NewCertsAPIRenawal(client kubernetes.Interface) Interface {
}

// Renew takes a certificate using the cert and key.
func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
reqTmp := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: cfg.CommonName,
Expand Down
8 changes: 4 additions & 4 deletions cmd/kubeadm/app/phases/certs/renewal/filerenewal.go
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package renewal

import (
"crypto/rsa"
"crypto"
"crypto/x509"

certutil "k8s.io/client-go/util/cert"
Expand All @@ -27,18 +27,18 @@ import (
// FileRenewal renews a certificate using local certs
type FileRenewal struct {
caCert *x509.Certificate
caKey *rsa.PrivateKey
caKey crypto.Signer
}

// NewFileRenewal takes a certificate pair to construct the Interface.
func NewFileRenewal(caCert *x509.Certificate, caKey *rsa.PrivateKey) Interface {
func NewFileRenewal(caCert *x509.Certificate, caKey crypto.Signer) Interface {
return &FileRenewal{
caCert: caCert,
caKey: caKey,
}
}

// Renew takes a certificate using the cert and key
func (r *FileRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
func (r *FileRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
return pkiutil.NewCertAndKey(r.caCert, r.caKey, cfg)
}
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/phases/certs/renewal/interface.go
Expand Up @@ -17,13 +17,13 @@ limitations under the License.
package renewal

import (
"crypto/rsa"
"crypto"
"crypto/x509"

certutil "k8s.io/client-go/util/cert"
)

// Interface represents a standard way to renew a certificate.
type Interface interface {
Renew(*certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error)
Renew(*certutil.Config) (*x509.Certificate, crypto.Signer, error)
}
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/phases/certs/renewal/renewal_test.go
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package renewal

import (
"crypto/rsa"
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"net"
Expand Down Expand Up @@ -113,7 +113,7 @@ func defaultReactionFunc(obj runtime.Object) k8stesting.ReactionFunc {
}
}

func getCertReq(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) *certsapi.CertificateSigningRequest {
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{
Expand Down
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
Expand Up @@ -18,7 +18,7 @@ package kubeconfig

import (
"bytes"
"crypto/rsa"
"crypto"
"crypto/x509"
"fmt"
"io"
Expand All @@ -41,7 +41,7 @@ import (

// clientCertAuth struct holds info required to build a client certificate to provide authentication info in a kubeconfig object
type clientCertAuth struct {
CAKey *rsa.PrivateKey
CAKey crypto.Signer
Organizations []string
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go
Expand Up @@ -18,7 +18,7 @@ package kubeconfig

import (
"bytes"
"crypto/rsa"
"crypto"
"crypto/x509"
"fmt"
"io"
Expand Down Expand Up @@ -621,7 +621,7 @@ func TestValidateKubeconfigsForExternalCA(t *testing.T) {
}

// setupdKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With ClientAuth
func setupdKubeConfigWithClientAuth(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, APIServer, clientName, clustername string, organizations ...string) *clientcmdapi.Config {
func setupdKubeConfigWithClientAuth(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer, APIServer, clientName, clustername string, organizations ...string) *clientcmdapi.Config {
spec := &kubeConfigSpec{
CACert: caCert,
APIServer: APIServer,
Expand Down
7 changes: 4 additions & 3 deletions cmd/kubeadm/app/util/certs/util.go
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package certs

import (
"crypto"
"crypto/rsa"
"crypto/x509"
"net"
Expand All @@ -30,7 +31,7 @@ import (

// SetupCertificateAuthorithy is a utility function for kubeadm testing that creates a
// CertificateAuthorithy cert/key pair
func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, crypto.Signer) {
caCert, caKey, err := pkiutil.NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if err != nil {
t.Fatalf("failure while generating CA certificate and key: %v", err)
Expand Down Expand Up @@ -130,7 +131,7 @@ func AssertCertificateHasIPAddresses(t *testing.T, cert *x509.Certificate, IPAdd
}

// CreateCACert creates a generic CA cert.
func CreateCACert(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
func CreateCACert(t *testing.T) (*x509.Certificate, crypto.Signer) {
certCfg := &certutil.Config{CommonName: "kubernetes"}
cert, key, err := pkiutil.NewCertificateAuthority(certCfg)
if err != nil {
Expand All @@ -140,7 +141,7 @@ func CreateCACert(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
}

// CreateTestCert makes a generic certificate with the given CA and alternative names.
func CreateTestCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*x509.Certificate, *rsa.PrivateKey, *certutil.Config) {
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},
Expand Down