Add bootstrap support to certificate manager.
This commit is contained in:
parent
db53e80445
commit
e992eaec8f
@ -48,19 +48,56 @@ const (
|
|||||||
type Manager interface {
|
type Manager interface {
|
||||||
// Start the API server status sync loop.
|
// Start the API server status sync loop.
|
||||||
Start()
|
Start()
|
||||||
// GetCertificate gets the current certificate from the certificate
|
// Current returns the currently selected certificate from the
|
||||||
// manager. This function matches the signature required by
|
// certificate manager.
|
||||||
// tls.Config.GetCertificate so it can be passed as TLS configuration. A
|
Current() *tls.Certificate
|
||||||
// TLS server will automatically call back here to get the correct
|
}
|
||||||
// certificate when establishing each new connection.
|
|
||||||
GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
|
// Config is the set of configuration parameters available for a new Manager.
|
||||||
|
type Config struct {
|
||||||
|
// CertificateSigningRequestClient will be used for signing new certificate
|
||||||
|
// requests generated when a key rotation occurs.
|
||||||
|
CertificateSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
||||||
|
// Template is the CertificateRequest that will be used as a template for
|
||||||
|
// generating certificate signing requests for all new keys generated as
|
||||||
|
// part of rotation. It follows the same rules as the template parameter of
|
||||||
|
// crypto.x509.CreateCertificateRequest in the Go standard libraries.
|
||||||
|
Template *x509.CertificateRequest
|
||||||
|
// Usages is the types of usages that certificates generated by the manager
|
||||||
|
// can be used for.
|
||||||
|
Usages []certificates.KeyUsage
|
||||||
|
// CertificateStore is a persistent store where the current cert/key is
|
||||||
|
// kept and future cert/key pairs will be persisted after they are
|
||||||
|
// generated.
|
||||||
|
CertificateStore Store
|
||||||
|
// BootstrapCertificatePEM is the certificate data that will be returned
|
||||||
|
// from the Manager if the CertificateStore doesn't have any cert/key pairs
|
||||||
|
// currently available. If the CertificateStore does have a cert/key pair,
|
||||||
|
// this will be ignored. If the bootstrap cert/key pair are used, they will
|
||||||
|
// be rotated at the first opportunity, possibly well in advance of
|
||||||
|
// expiring. This is intended to allow the first boot of a component to be
|
||||||
|
// initialized using a generic, multi-use cert/key pair which will be
|
||||||
|
// quickly replaced with a unique cert/key pair.
|
||||||
|
BootstrapCertificatePEM []byte
|
||||||
|
// BootstrapKeyPEM is the key data that will be returned from the Manager
|
||||||
|
// if the CertificateStore doesn't have any cert/key pairs currently
|
||||||
|
// available. If the CertificateStore does have a cert/key pair, this will
|
||||||
|
// be ignored. If the bootstrap cert/key pair are used, they will be
|
||||||
|
// rotated at the first opportunity, possibly well in advance of expiring.
|
||||||
|
// This is intended to allow the first boot of a component to be
|
||||||
|
// initialized using a generic, multi-use cert/key pair which will be
|
||||||
|
// quickly replaced with a unique cert/key pair.
|
||||||
|
BootstrapKeyPEM []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store is responsible for getting and updating the current certificate.
|
// Store is responsible for getting and updating the current certificate.
|
||||||
// Depending on the concrete implementation, the backing store for this
|
// Depending on the concrete implementation, the backing store for this
|
||||||
// behavior may vary.
|
// behavior may vary.
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Current returns the currently selected certificate.
|
// Current returns the currently selected certificate. If the Store doesn't
|
||||||
|
// have a cert/key pair currently, it should return a NoCertKeyError so
|
||||||
|
// that the Manager can recover by using bootstrap certificates to request
|
||||||
|
// a new cert/key pair.
|
||||||
Current() (*tls.Certificate, error)
|
Current() (*tls.Certificate, error)
|
||||||
// Update accepts the PEM data for the cert/key pair and makes the new
|
// Update accepts the PEM data for the cert/key pair and makes the new
|
||||||
// cert/key pair the 'current' pair, that will be returned by future calls
|
// cert/key pair the 'current' pair, that will be returned by future calls
|
||||||
@ -68,6 +105,11 @@ type Store interface {
|
|||||||
Update(cert, key []byte) (*tls.Certificate, error)
|
Update(cert, key []byte) (*tls.Certificate, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoCertKeyError indicates there is no cert/key currently available.
|
||||||
|
type NoCertKeyError string
|
||||||
|
|
||||||
|
func (e *NoCertKeyError) Error() string { return string(*e) }
|
||||||
|
|
||||||
type manager struct {
|
type manager struct {
|
||||||
certSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
certSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
||||||
template *x509.CertificateRequest
|
template *x509.CertificateRequest
|
||||||
@ -75,49 +117,39 @@ type manager struct {
|
|||||||
certStore Store
|
certStore Store
|
||||||
certAccessLock sync.RWMutex
|
certAccessLock sync.RWMutex
|
||||||
cert *tls.Certificate
|
cert *tls.Certificate
|
||||||
|
forceRotation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager returns a new certificate manager. A certificate manager is
|
// NewManager returns a new certificate manager. A certificate manager is
|
||||||
// responsible for being the authoritative source of certificates in the
|
// responsible for being the authoritative source of certificates in the
|
||||||
// Kubelet and handling updates due to rotation.
|
// Kubelet and handling updates due to rotation.
|
||||||
func NewManager(
|
func NewManager(config *Config) (Manager, error) {
|
||||||
certSigningRequestClient certificatesclient.CertificateSigningRequestInterface,
|
cert, forceRotation, err := getCurrentCertificateOrBootstrap(
|
||||||
template *x509.CertificateRequest,
|
config.CertificateStore,
|
||||||
usages []certificates.KeyUsage,
|
config.BootstrapCertificatePEM,
|
||||||
certificateStore Store) (Manager, error) {
|
config.BootstrapKeyPEM)
|
||||||
|
|
||||||
cert, err := certificateStore.Current()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m := manager{
|
m := manager{
|
||||||
certSigningRequestClient: certSigningRequestClient,
|
certSigningRequestClient: config.CertificateSigningRequestClient,
|
||||||
template: template,
|
template: config.Template,
|
||||||
usages: usages,
|
usages: config.Usages,
|
||||||
certStore: certificateStore,
|
certStore: config.CertificateStore,
|
||||||
cert: cert,
|
cert: cert,
|
||||||
|
forceRotation: forceRotation,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &m, nil
|
return &m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCertificate returns the certificate that should be used with TLS
|
// Current returns the currently selected certificate from the
|
||||||
// connections. The value returned by this function will change over time as
|
// certificate manager.
|
||||||
// the certificate is rotated. If a reference to this method is passed directly
|
func (m *manager) Current() *tls.Certificate {
|
||||||
// into the TLS options for a connection, certificate rotation will be handled
|
|
||||||
// correctly by the underlying go libraries.
|
|
||||||
//
|
|
||||||
// tlsOptions := &server.TLSOptions{
|
|
||||||
// ...
|
|
||||||
// GetCertificate: certificateManager.GetCertificate
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
func (m *manager) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
||||||
m.certAccessLock.RLock()
|
m.certAccessLock.RLock()
|
||||||
defer m.certAccessLock.RUnlock()
|
defer m.certAccessLock.RUnlock()
|
||||||
return m.cert, nil
|
return m.cert
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start will start the background work of rotating the certificates.
|
// Start will start the background work of rotating the certificates.
|
||||||
@ -142,6 +174,40 @@ func (m *manager) Start() {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCurrentCertificateOrBootstrap(
|
||||||
|
store Store,
|
||||||
|
bootstrapCertificatePEM []byte,
|
||||||
|
bootstrapKeyPEM []byte) (cert *tls.Certificate, shouldRotate bool, errResult error) {
|
||||||
|
|
||||||
|
currentCert, err := store.Current()
|
||||||
|
if err == nil {
|
||||||
|
return currentCert, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := err.(*NoCertKeyError); !ok {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bootstrapCertificatePEM == nil || bootstrapKeyPEM == nil {
|
||||||
|
return nil, false, fmt.Errorf("no cert/key available and no bootstrap cert/key to fall back to")
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrapCert, err := tls.X509KeyPair(bootstrapCertificatePEM, bootstrapKeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if len(bootstrapCert.Certificate) < 1 {
|
||||||
|
return nil, false, fmt.Errorf("no cert/key data found")
|
||||||
|
}
|
||||||
|
|
||||||
|
certs, err := x509.ParseCertificates(bootstrapCert.Certificate[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("unable to parse certificate data: %v", err)
|
||||||
|
}
|
||||||
|
bootstrapCert.Leaf = certs[0]
|
||||||
|
return &bootstrapCert, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// shouldRotate looks at how close the current certificate is to expiring and
|
// shouldRotate looks at how close the current certificate is to expiring and
|
||||||
// decides if it is time to rotate or not.
|
// decides if it is time to rotate or not.
|
||||||
func (m *manager) shouldRotate() bool {
|
func (m *manager) shouldRotate() bool {
|
||||||
@ -158,7 +224,8 @@ func (m *manager) shouldRotate() bool {
|
|||||||
jitteryDuration := wait.Jitter(time.Duration(totalDuration), 0.2) - time.Duration(totalDuration*0.3)
|
jitteryDuration := wait.Jitter(time.Duration(totalDuration), 0.2) - time.Duration(totalDuration*0.3)
|
||||||
|
|
||||||
rotationThreshold := m.cert.Leaf.NotBefore.Add(jitteryDuration)
|
rotationThreshold := m.cert.Leaf.NotBefore.Add(jitteryDuration)
|
||||||
return time.Now().After(rotationThreshold)
|
passedThreshold := time.Now().After(rotationThreshold)
|
||||||
|
return m.forceRotation || passedThreshold
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) rotateCerts() error {
|
func (m *manager) rotateCerts() error {
|
||||||
@ -183,10 +250,15 @@ func (m *manager) rotateCerts() error {
|
|||||||
return fmt.Errorf("unable to store the new cert/key pair: %v", err)
|
return fmt.Errorf("unable to store the new cert/key pair: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.updateCached(cert)
|
||||||
|
m.forceRotation = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *manager) updateCached(cert *tls.Certificate) {
|
||||||
m.certAccessLock.Lock()
|
m.certAccessLock.Lock()
|
||||||
defer m.certAccessLock.Unlock()
|
defer m.certAccessLock.Unlock()
|
||||||
m.cert = cert
|
m.cert = cert
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) generateCSR() (csrPEM []byte, keyPEM []byte, err error) {
|
func (m *manager) generateCSR() (csrPEM []byte, keyPEM []byte, err error) {
|
||||||
|
@ -17,9 +17,11 @@ limitations under the License.
|
|||||||
package certificate
|
package certificate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -78,6 +80,24 @@ O1eRCsCGPAnUCviFgNeH15ug+6N54DTTR6ZV/TTV64FDOcsox9nrhYcmH9sYuITi
|
|||||||
-----END CERTIFICATE-----`
|
-----END CERTIFICATE-----`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestNewManagerNoRotation(t *testing.T) {
|
||||||
|
cert, err := tls.X509KeyPair([]byte(certificateData), []byte(privateKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to initialize a certificate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
store := &fakeStore{
|
||||||
|
cert: &cert,
|
||||||
|
}
|
||||||
|
if _, err := NewManager(&Config{
|
||||||
|
Template: &x509.CertificateRequest{},
|
||||||
|
Usages: []certificates.KeyUsage{},
|
||||||
|
CertificateStore: store,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestShouldRotate(t *testing.T) {
|
func TestShouldRotate(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -122,8 +142,8 @@ func TestRotateCertCreateCSRError(t *testing.T) {
|
|||||||
m := manager{
|
m := manager{
|
||||||
cert: &tls.Certificate{
|
cert: &tls.Certificate{
|
||||||
Leaf: &x509.Certificate{
|
Leaf: &x509.Certificate{
|
||||||
NotAfter: now.Add(-1 * time.Hour),
|
|
||||||
NotBefore: now.Add(-2 * time.Hour),
|
NotBefore: now.Add(-2 * time.Hour),
|
||||||
|
NotAfter: now.Add(-1 * time.Hour),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: &x509.CertificateRequest{},
|
template: &x509.CertificateRequest{},
|
||||||
@ -143,8 +163,8 @@ func TestRotateCertWaitingForResultError(t *testing.T) {
|
|||||||
m := manager{
|
m := manager{
|
||||||
cert: &tls.Certificate{
|
cert: &tls.Certificate{
|
||||||
Leaf: &x509.Certificate{
|
Leaf: &x509.Certificate{
|
||||||
NotAfter: now.Add(-1 * time.Hour),
|
|
||||||
NotBefore: now.Add(-2 * time.Hour),
|
NotBefore: now.Add(-2 * time.Hour),
|
||||||
|
NotAfter: now.Add(-1 * time.Hour),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: &x509.CertificateRequest{},
|
template: &x509.CertificateRequest{},
|
||||||
@ -159,6 +179,146 @@ func TestRotateCertWaitingForResultError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewManagerBootstrap(t *testing.T) {
|
||||||
|
store := &fakeStore{}
|
||||||
|
|
||||||
|
cm, err := NewManager(&Config{
|
||||||
|
Template: &x509.CertificateRequest{},
|
||||||
|
Usages: []certificates.KeyUsage{},
|
||||||
|
CertificateStore: store,
|
||||||
|
BootstrapCertificatePEM: []byte(certificateData),
|
||||||
|
BootstrapKeyPEM: []byte(privateKeyData),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cert := cm.Current()
|
||||||
|
|
||||||
|
if cert == nil {
|
||||||
|
t.Errorf("Certificate was nil, expected something.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := cm.(*manager); !ok {
|
||||||
|
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||||
|
} else if !m.shouldRotate() {
|
||||||
|
t.Errorf("Expected rotation should happen during bootstrap, but it won't.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewManagerNoBootstrap(t *testing.T) {
|
||||||
|
now := time.Now()
|
||||||
|
cert, err := tls.X509KeyPair([]byte(certificateData), []byte(privateKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to initialize a certificate: %v", err)
|
||||||
|
}
|
||||||
|
cert.Leaf = &x509.Certificate{
|
||||||
|
NotBefore: now.Add(-24 * time.Hour),
|
||||||
|
NotAfter: now.Add(24 * time.Hour),
|
||||||
|
}
|
||||||
|
store := &fakeStore{
|
||||||
|
cert: &cert,
|
||||||
|
}
|
||||||
|
|
||||||
|
cm, err := NewManager(&Config{
|
||||||
|
Template: &x509.CertificateRequest{},
|
||||||
|
Usages: []certificates.KeyUsage{},
|
||||||
|
CertificateStore: store,
|
||||||
|
BootstrapCertificatePEM: []byte(certificateData),
|
||||||
|
BootstrapKeyPEM: []byte(privateKeyData),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCert := cm.Current()
|
||||||
|
|
||||||
|
if currentCert == nil {
|
||||||
|
t.Errorf("Certificate was nil, expected something.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := cm.(*manager); !ok {
|
||||||
|
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||||
|
} else if m.shouldRotate() {
|
||||||
|
t.Errorf("Expected rotation should happen during bootstrap, but it won't.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCurrentCertificateOrBootstrap(t *testing.T) {
|
||||||
|
cert, err := tls.X509KeyPair([]byte(certificateData), []byte(privateKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to initialize a certificate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
storeCert *tls.Certificate
|
||||||
|
bootstrapCertData []byte
|
||||||
|
bootstrapKeyData []byte
|
||||||
|
expectedCert *tls.Certificate
|
||||||
|
expectedShouldRotate bool
|
||||||
|
expectedErrMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"return cert from store",
|
||||||
|
&cert,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
&cert,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no cert in store and no bootstrap cert",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
"no cert/key available and no bootstrap cert/key to fall back to",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
store := &fakeStore{
|
||||||
|
cert: tc.storeCert,
|
||||||
|
}
|
||||||
|
|
||||||
|
certResult, shouldRotate, err := getCurrentCertificateOrBootstrap(
|
||||||
|
store,
|
||||||
|
tc.bootstrapCertData,
|
||||||
|
tc.bootstrapKeyData)
|
||||||
|
if certResult == nil || tc.expectedCert == nil {
|
||||||
|
if certResult != tc.expectedCert {
|
||||||
|
t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(certResult.Certificate) != len(tc.expectedCert.Certificate) {
|
||||||
|
t.Errorf("Got %d certificates, wanted %d", len(certResult.Certificate), len(tc.expectedCert.Certificate))
|
||||||
|
}
|
||||||
|
if !bytes.Equal(certResult.Certificate[0], tc.expectedCert.Certificate[0]) {
|
||||||
|
t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shouldRotate != tc.expectedShouldRotate {
|
||||||
|
t.Errorf("Got shouldRotate %t, wanted %t", shouldRotate, tc.expectedShouldRotate)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if tc.expectedErrMsg != "" {
|
||||||
|
t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if tc.expectedErrMsg == "" || !strings.Contains(err.Error(), tc.expectedErrMsg) {
|
||||||
|
t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakeClientFailureType int
|
type fakeClientFailureType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -233,6 +393,10 @@ type fakeStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *fakeStore) Current() (*tls.Certificate, error) {
|
func (s *fakeStore) Current() (*tls.Certificate, error) {
|
||||||
|
if s.cert == nil {
|
||||||
|
noKeyErr := NoCertKeyError("")
|
||||||
|
return nil, &noKeyErr
|
||||||
|
}
|
||||||
return s.cert, nil
|
return s.cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +408,11 @@ func (s *fakeStore) Update(certPEM, keyPEM []byte) (*tls.Certificate, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
now := time.Now()
|
||||||
s.cert = &cert
|
s.cert = &cert
|
||||||
|
s.cert.Leaf = &x509.Certificate{
|
||||||
|
NotBefore: now.Add(-24 * time.Hour),
|
||||||
|
NotAfter: now.Add(24 * time.Hour),
|
||||||
|
}
|
||||||
return s.cert, nil
|
return s.cert, nil
|
||||||
}
|
}
|
||||||
|
@ -148,12 +148,14 @@ func (s *fileStore) Current() (*tls.Certificate, error) {
|
|||||||
return loadX509KeyPair(c, k)
|
return loadX509KeyPair(c, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("no cert/key files read at %q, (%q, %q) or (%q, %q)",
|
noKeyErr := NoCertKeyError(
|
||||||
pairFile,
|
fmt.Sprintf("no cert/key files read at %q, (%q, %q) or (%q, %q)",
|
||||||
s.certFile,
|
pairFile,
|
||||||
s.keyFile,
|
s.certFile,
|
||||||
s.certDirectory,
|
s.keyFile,
|
||||||
s.keyDirectory)
|
s.certDirectory,
|
||||||
|
s.keyDirectory))
|
||||||
|
return nil, &noKeyErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFile(pairFile string) (*tls.Certificate, error) {
|
func loadFile(pairFile string) (*tls.Certificate, error) {
|
||||||
|
@ -181,7 +181,7 @@ func TestUpdateSymlinkReplaceExistingSymlink(t *testing.T) {
|
|||||||
func TestLoadCertKeyBlocksNoFile(t *testing.T) {
|
func TestLoadCertKeyBlocksNoFile(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -199,7 +199,7 @@ func TestLoadCertKeyBlocksNoFile(t *testing.T) {
|
|||||||
func TestLoadCertKeyBlocksEmptyFile(t *testing.T) {
|
func TestLoadCertKeyBlocksEmptyFile(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -220,7 +220,7 @@ func TestLoadCertKeyBlocksEmptyFile(t *testing.T) {
|
|||||||
func TestLoadCertKeyBlocksPartialFile(t *testing.T) {
|
func TestLoadCertKeyBlocksPartialFile(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -241,7 +241,7 @@ func TestLoadCertKeyBlocksPartialFile(t *testing.T) {
|
|||||||
func TestLoadCertKeyBlocks(t *testing.T) {
|
func TestLoadCertKeyBlocks(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -269,7 +269,7 @@ func TestLoadCertKeyBlocks(t *testing.T) {
|
|||||||
func TestLoadFile(t *testing.T) {
|
func TestLoadFile(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -298,7 +298,7 @@ func TestUpdateNoRotation(t *testing.T) {
|
|||||||
prefix := "kubelet-server"
|
prefix := "kubelet-server"
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -332,7 +332,7 @@ func TestUpdateRotation(t *testing.T) {
|
|||||||
prefix := "kubelet-server"
|
prefix := "kubelet-server"
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -366,7 +366,7 @@ func TestUpdateWithBadCertKeyData(t *testing.T) {
|
|||||||
prefix := "kubelet-server"
|
prefix := "kubelet-server"
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -400,7 +400,7 @@ func TestCurrentPairFile(t *testing.T) {
|
|||||||
prefix := "kubelet-server"
|
prefix := "kubelet-server"
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -437,7 +437,7 @@ func TestCurrentCertKeyFiles(t *testing.T) {
|
|||||||
prefix := "kubelet-server"
|
prefix := "kubelet-server"
|
||||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to created the test directory %q: %v", dir, err)
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
@ -469,3 +469,31 @@ func TestCurrentCertKeyFiles(t *testing.T) {
|
|||||||
t.Fatalf("Got an empty leaf, expected private data.")
|
t.Fatalf("Got an empty leaf, expected private data.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCurrentNoFiles(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
|
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
store, err := NewFileStore("kubelet-server", dir, dir, "", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize certificate store: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := store.Current()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Got no error, expected an error because the cert/key files don't exist.")
|
||||||
|
}
|
||||||
|
if _, ok := err.(*NoCertKeyError); !ok {
|
||||||
|
t.Fatalf("Got error %v, expected NoCertKeyError.", err)
|
||||||
|
}
|
||||||
|
if cert != nil {
|
||||||
|
t.Fatalf("Got certificate, expected no certificate because the cert/key files don't exist.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user