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

Allow certificate manager to be initialized with client. #45553

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
17 changes: 17 additions & 0 deletions pkg/kubelet/certificate/certificate_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const (
// manager. In the background it communicates with the API server to get new
// certificates for certificates about to expire.
type Manager interface {
// CertificateSigningRequestClient sets the client interface that is used for
// signing new certificates generated as part of rotation.
SetCertificateSigningRequestClient(certificatesclient.CertificateSigningRequestInterface) error
// Start the API server status sync loop.
Start()
// Current returns the currently selected certificate from the
Expand Down Expand Up @@ -156,6 +159,20 @@ func (m *manager) Current() *tls.Certificate {
return m.cert
}

// SetCertificateSigningRequestClient sets the client interface that is used
// for signing new certificates generated as part of rotation. It must be
// called before Start() and can not be used to change the
// CertificateSigningRequestClient that has already been set. This method is to
// support the one specific scenario where the CertificateSigningRequestClient
// uses the CertificateManager.
func (m *manager) SetCertificateSigningRequestClient(certSigningRequestClient certificatesclient.CertificateSigningRequestInterface) error {
if m.certSigningRequestClient == nil {
m.certSigningRequestClient = certSigningRequestClient
return nil
}
return fmt.Errorf("CertificateSigningRequestClient is already set.")
}

// Start will start the background work of rotating the certificates.
func (m *manager) Start() {
// Certificate rotation depends on access to the API server certificate
Expand Down
98 changes: 96 additions & 2 deletions pkg/kubelet/certificate/certificate_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,14 @@ func TestRotateCertWaitingForResultError(t *testing.T) {
func TestNewManagerBootstrap(t *testing.T) {
store := &fakeStore{}

var cm Manager
cm, err := NewManager(&Config{
Template: &x509.CertificateRequest{},
Usages: []certificates.KeyUsage{},
CertificateStore: store,
BootstrapCertificatePEM: bootstrapCertData.certificatePEM,
BootstrapKeyPEM: bootstrapCertData.keyPEM,
})

if err != nil {
t.Fatalf("Failed to initialize the certificate manager: %v", err)
}
Expand Down Expand Up @@ -356,6 +356,98 @@ func TestGetCurrentCertificateOrBootstrap(t *testing.T) {
}
}

func TestInitializeCertificateSigningRequestClient(t *testing.T) {
var nilCertificate = &certificateData{}
testCases := []struct {
description string
storeCert *certificateData
bootstrapCert *certificateData
apiCert *certificateData
expectedCertBeforeStart *certificateData
expectedCertAfterStart *certificateData
}{
{
description: "No current certificate, no bootstrap certificate",
storeCert: nilCertificate,
bootstrapCert: nilCertificate,
apiCert: apiServerCertData,
expectedCertBeforeStart: nilCertificate,
expectedCertAfterStart: apiServerCertData,
},
{
description: "No current certificate, bootstrap certificate",
storeCert: nilCertificate,
bootstrapCert: bootstrapCertData,
apiCert: apiServerCertData,
expectedCertBeforeStart: bootstrapCertData,
expectedCertAfterStart: apiServerCertData,
},
{
description: "Current certificate, no bootstrap certificate",
storeCert: storeCertData,
bootstrapCert: nilCertificate,
apiCert: apiServerCertData,
expectedCertBeforeStart: storeCertData,
expectedCertAfterStart: storeCertData,
},
{
description: "Current certificate, bootstrap certificate",
storeCert: storeCertData,
bootstrapCert: bootstrapCertData,
apiCert: apiServerCertData,
expectedCertBeforeStart: storeCertData,
expectedCertAfterStart: storeCertData,
},
}

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
certificateStore := &fakeStore{
cert: tc.storeCert.certificate,
}

certificateManager, err := NewManager(&Config{
Template: &x509.CertificateRequest{
Subject: pkix.Name{
Organization: []string{"system:nodes"},
CommonName: "system:node:fake-node-name",
},
},
Usages: []certificates.KeyUsage{
certificates.UsageDigitalSignature,
certificates.UsageKeyEncipherment,
certificates.UsageClientAuth,
},
CertificateStore: certificateStore,
BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
})
if err != nil {
t.Errorf("Got %v, wanted no error.", err)
}

certificate := certificateManager.Current()
if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
}
if err := certificateManager.SetCertificateSigningRequestClient(&fakeClient{
certificatePEM: tc.apiCert.certificatePEM,
}); err != nil {
t.Errorf("Got error %v, expected none.", err)
}

if err := certificateManager.(*manager).rotateCerts(); err != nil {
t.Errorf("Got error %v, expected none.", err)
}

certificate = certificateManager.Current()
if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
}
})
}
}

func TestInitializeOtherRESTClients(t *testing.T) {
var nilCertificate = &certificateData{}
testCases := []struct {
Expand Down Expand Up @@ -434,7 +526,9 @@ func TestInitializeOtherRESTClients(t *testing.T) {
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
}

certificateManager.Start()
if err := certificateManager.(*manager).rotateCerts(); err != nil {
t.Errorf("Got error %v, expected none.", err)
}

certificate = certificateManager.Current()
if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
Expand Down