From 8bc0447d8c40213462a0260ce1e871842d3a8a9c Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 8 Nov 2018 01:16:33 +0200 Subject: [PATCH 1/2] kubeadm: use client-go's MakeCSRFromTemplate() in 'renew' Create CSR using the mentioned function which also encodes the type CertificateRequestBlockType. Without that 'certs renew' is failing with: 'PEM block type must be CERTIFICATE REQUEST' --- cmd/kubeadm/app/phases/certs/renewal/certsapi.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/kubeadm/app/phases/certs/renewal/certsapi.go b/cmd/kubeadm/app/phases/certs/renewal/certsapi.go index 949e17f3175..8303d91f37b 100644 --- a/cmd/kubeadm/app/phases/certs/renewal/certsapi.go +++ b/cmd/kubeadm/app/phases/certs/renewal/certsapi.go @@ -17,7 +17,6 @@ limitations under the License. package renewal import ( - "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" @@ -70,7 +69,7 @@ func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.P return nil, nil, errors.Wrap(err, "couldn't create new private key") } - csr, err := x509.CreateCertificateRequest(rand.Reader, reqTmp, key) + csr, err := certutil.MakeCSRFromTemplate(key, reqTmp) if err != nil { return nil, nil, errors.Wrap(err, "couldn't create certificate signing request") } From 6afb9a117b0ac5dd3e3bc1249cd499d9af2faebd Mon Sep 17 00:00:00 2001 From: liz Date: Wed, 14 Nov 2018 14:10:34 -0800 Subject: [PATCH 2/2] Fix renewing certificates via the API Poll for events, print CSR name, and parse PEM instead of CSR --- cmd/kubeadm/app/phases/certs/renewal/BUILD | 3 +- .../app/phases/certs/renewal/certsapi.go | 54 ++++++------------- .../app/phases/certs/renewal/renewal_test.go | 8 ++- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/cmd/kubeadm/app/phases/certs/renewal/BUILD b/cmd/kubeadm/app/phases/certs/renewal/BUILD index 623ad5aa52e..6172ca48370 100644 --- a/cmd/kubeadm/app/phases/certs/renewal/BUILD +++ b/cmd/kubeadm/app/phases/certs/renewal/BUILD @@ -14,11 +14,10 @@ go_library( "//cmd/kubeadm/app/util/pkiutil:go_default_library", "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library", "//staging/src/k8s.io/client-go/util/cert:go_default_library", + "//staging/src/k8s.io/client-go/util/certificate/csr:go_default_library", "//vendor/github.com/pkg/errors:go_default_library", ], ) diff --git a/cmd/kubeadm/app/phases/certs/renewal/certsapi.go b/cmd/kubeadm/app/phases/certs/renewal/certsapi.go index 8303d91f37b..6326ac5f0a9 100644 --- a/cmd/kubeadm/app/phases/certs/renewal/certsapi.go +++ b/cmd/kubeadm/app/phases/certs/renewal/certsapi.go @@ -20,26 +20,22 @@ import ( "crypto/rsa" "crypto/x509" "crypto/x509/pkix" + "fmt" "time" "github.com/pkg/errors" certsapi "k8s.io/api/certificates/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" certstype "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" certutil "k8s.io/client-go/util/cert" + csrutil "k8s.io/client-go/util/certificate/csr" ) -const ( - certAPIPrefixName = "kubeadm-cert" -) +const certAPIPrefixName = "kubeadm-cert" -var ( - watchTimeout = 5 * time.Minute -) +var watchTimeout = 5 * time.Minute // CertsAPIRenewal creates new certificates using the certs API type CertsAPIRenewal struct { @@ -85,7 +81,7 @@ func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.P k8sCSR := &certsapi.CertificateSigningRequest{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: certAPIPrefixName, + GenerateName: fmt.Sprintf("%s-%s-", certAPIPrefixName, cfg.CommonName), }, Spec: certsapi.CertificateSigningRequestSpec{ Request: csr, @@ -98,43 +94,23 @@ func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.P return nil, nil, errors.Wrap(err, "couldn't create certificate signing request") } - watcher, err := r.client.CertificateSigningRequests().Watch(metav1.ListOptions{ - Watch: true, - FieldSelector: fields.Set{"metadata.name": req.Name}.String(), - }) + fmt.Printf("[certs] certificate request %q created\n", req.Name) + + certData, err := csrutil.WaitForCertificate(r.client.CertificateSigningRequests(), req, watchTimeout) if err != nil { - return nil, nil, errors.Wrap(err, "couldn't watch for certificate creation") - } - defer watcher.Stop() - - select { - case ev := <-watcher.ResultChan(): - if ev.Type != watch.Modified { - return nil, nil, errors.Errorf("unexpected event received: %q", ev.Type) - } - case <-time.After(watchTimeout): - return nil, nil, errors.New("timeout trying to sign certificate") + return nil, nil, errors.Wrap(err, "certificate failed to appear") } - req, err = r.client.CertificateSigningRequests().Get(req.Name, metav1.GetOptions{}) - if err != nil { - return nil, nil, errors.Wrap(err, "couldn't get certificate signing request") - } - if len(req.Status.Conditions) < 1 { - return nil, nil, errors.New("certificate signing request has no statuses") - } - - // TODO: under what circumstances are there more than one? - if status := req.Status.Conditions[0].Type; status != certsapi.CertificateApproved { - return nil, nil, errors.Errorf("unexpected certificate status: %v", status) - } - - cert, err := x509.ParseCertificate(req.Status.Certificate) + cert, err := certutil.ParseCertsPEM(certData) if err != nil { return nil, nil, errors.Wrap(err, "couldn't parse issued certificate") } - return cert, key, nil + if len(cert) != 1 { + return nil, nil, errors.Errorf("certificate request %q has %d certificates, wanted exactly 1", req.Name, len(cert)) + } + + return cert[0], key, nil } var usageMap = map[x509.ExtKeyUsage]certsapi.KeyUsage{ diff --git a/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go b/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go index 327542a4ab9..6b24c6f0606 100644 --- a/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go +++ b/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go @@ -49,8 +49,12 @@ func TestRenewImplementations(t *testing.T) { Fake: &k8stesting.Fake{}, } certReq := getCertReq(t, caCert, caKey) + certReqNoCert := certReq.DeepCopy() + certReqNoCert.Status.Certificate = nil client.AddReactor("get", "certificatesigningrequests", defaultReactionFunc(certReq)) - watcher := watch.NewFakeWithChanSize(1, false) + watcher := watch.NewFakeWithChanSize(3, false) + watcher.Add(certReqNoCert) + watcher.Modify(certReqNoCert) watcher.Modify(certReq) client.AddWatchReactor("certificatesigningrequests", k8stesting.DefaultWatchReactor(watcher, nil)) @@ -132,7 +136,7 @@ func getCertReq(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) * Type: certsapi.CertificateApproved, }, }, - Certificate: cert.Raw, + Certificate: certutil.EncodeCertPEM(cert), }, } }