From 988d8dd3f47ba07f6e09683b757ce61a8642643b Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Fri, 15 Nov 2019 23:13:24 +0000 Subject: [PATCH 1/3] Add info logging when certs change --- storage/kubernetes/controller.go | 4 ++-- storage/memory/memory.go | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/storage/kubernetes/controller.go b/storage/kubernetes/controller.go index f903662..c08f2e0 100644 --- a/storage/kubernetes/controller.go +++ b/storage/kubernetes/controller.go @@ -132,10 +132,10 @@ func (s *storage) saveInK8s(secret *v1.Secret) (*v1.Secret, error) { targetSecret.Data = secret.Data if targetSecret.UID == "" { - logrus.Infof("Creating new TLS secret for %v (count: %d)", targetSecret.Name, len(targetSecret.Data)-1) + logrus.Infof("Creating new TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations) return s.secrets.Create(targetSecret) } else { - logrus.Infof("Updating TLS secret for %v (count: %d)", targetSecret.Name, len(targetSecret.Data)-1) + logrus.Infof("Updating TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations) return s.secrets.Update(targetSecret) } } diff --git a/storage/memory/memory.go b/storage/memory/memory.go index 079f180..c417e30 100644 --- a/storage/memory/memory.go +++ b/storage/memory/memory.go @@ -2,6 +2,7 @@ package memory import ( "github.com/rancher/dynamiclistener" + "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" ) @@ -15,7 +16,7 @@ func NewBacked(storage dynamiclistener.TLSStorage) dynamiclistener.TLSStorage { type memory struct { storage dynamiclistener.TLSStorage - secret *v1.Secret + secret *v1.Secret } func (m *memory) Get() (*v1.Secret, error) { @@ -37,6 +38,7 @@ func (m *memory) Update(secret *v1.Secret) error { } } + logrus.Infof("Active TLS secret %s (ver=%s) (count %d): %v", secret.Name, secret.ResourceVersion, len(secret.Annotations)-1, secret.Annotations) m.secret = secret return nil } From ccf76b35ea31d5a0fdd1427e123c65c7b74d3e96 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Fri, 15 Nov 2019 23:13:38 +0000 Subject: [PATCH 2/3] Don't clobber secret key On the start of a new server we do not want to blindly save the cert because that will change the TLS key. Instead only write to k8s on start if there is no secret in k8s. On start of the controller it will sync up if the local file and k8s secret aren't the same --- storage/kubernetes/controller.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/storage/kubernetes/controller.go b/storage/kubernetes/controller.go index c08f2e0..0c91e75 100644 --- a/storage/kubernetes/controller.go +++ b/storage/kubernetes/controller.go @@ -80,9 +80,19 @@ func (s *storage) init(secrets v1controller.SecretController) { }) s.secrets = secrets - secret, err := s.storage.Get() - if err == nil && secret != nil { - s.saveInK8s(secret) + if secret, err := s.storage.Get(); err == nil && secret != nil && len(secret.Data) > 0 { + // just ensure there is a secret in k3s + if _, err := s.secrets.Get(s.namespace, s.name, metav1.GetOptions{}); errors.IsNotFound(err) { + _, _ = s.secrets.Create(&v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: s.name, + Namespace: s.namespace, + Annotations: secret.Annotations, + }, + Type: v1.SecretTypeTLS, + Data: secret.Data, + }) + } } } From 3c2990b7c5230268d4eb689ad164db7d0f88f671 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Fri, 15 Nov 2019 23:43:02 +0000 Subject: [PATCH 3/3] Support old or imported RSA keys --- factory/ca.go | 21 ++++++++++++++------- factory/cert_utils.go | 20 +------------------- factory/gen.go | 24 ++++++++++-------------- 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/factory/ca.go b/factory/ca.go index a35738c..cc3380f 100644 --- a/factory/ca.go +++ b/factory/ca.go @@ -1,13 +1,16 @@ package factory import ( - "crypto/ecdsa" + "crypto" "crypto/x509" + "fmt" "io/ioutil" "os" + + "github.com/rancher/dynamiclistener/cert" ) -func GenCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { +func GenCA() (*x509.Certificate, crypto.Signer, error) { caKey, err := NewPrivateKey() if err != nil { return nil, nil, err @@ -21,7 +24,7 @@ func GenCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { return caCert, caKey, nil } -func LoadOrGenCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { +func LoadOrGenCA() (*x509.Certificate, crypto.Signer, error) { cert, key, err := loadCA() if err == nil { return cert, key, nil @@ -52,11 +55,11 @@ func LoadOrGenCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { return cert, key, nil } -func loadCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { +func loadCA() (*x509.Certificate, crypto.Signer, error) { return LoadCerts("./certs/ca.pem", "./certs/ca.key") } -func LoadCerts(certFile, keyFile string) (*x509.Certificate, *ecdsa.PrivateKey, error) { +func LoadCerts(certFile, keyFile string) (*x509.Certificate, crypto.Signer, error) { caPem, err := ioutil.ReadFile(certFile) if err != nil { return nil, nil, err @@ -66,15 +69,19 @@ func LoadCerts(certFile, keyFile string) (*x509.Certificate, *ecdsa.PrivateKey, return nil, nil, err } - key, err := ParseECPrivateKeyPEM(caKey) + key, err := cert.ParsePrivateKeyPEM(caKey) if err != nil { return nil, nil, err } + signer, ok := key.(crypto.Signer) + if !ok { + return nil, nil, fmt.Errorf("key is not a crypto.Signer") + } cert, err := ParseCertPEM(caPem) if err != nil { return nil, nil, err } - return cert, key, nil + return cert, signer, nil } diff --git a/factory/cert_utils.go b/factory/cert_utils.go index 459bd2e..cb62678 100644 --- a/factory/cert_utils.go +++ b/factory/cert_utils.go @@ -2,7 +2,6 @@ package factory import ( "crypto" - "crypto/ecdsa" "crypto/rand" "crypto/x509" "crypto/x509/pkix" @@ -15,8 +14,7 @@ import ( ) const ( - ECPrivateKeyBlockType = "EC PRIVATE KEY" - CertificateBlockType = "CERTIFICATE" + CertificateBlockType = "CERTIFICATE" ) func NewSelfSignedCACert(key crypto.Signer, cn string, org ...string) (*x509.Certificate, error) { @@ -72,22 +70,6 @@ func NewSignedCert(signer crypto.Signer, caCert *x509.Certificate, caKey crypto. return x509.ParseCertificate(cert) } -func ParseECPrivateKeyPEM(keyData []byte) (*ecdsa.PrivateKey, error) { - var privateKeyPemBlock *pem.Block - for { - privateKeyPemBlock, keyData = pem.Decode(keyData) - if privateKeyPemBlock == nil { - break - } - - if privateKeyPemBlock.Type == ECPrivateKeyBlockType { - return x509.ParseECPrivateKey(privateKeyPemBlock.Bytes) - } - } - - return nil, fmt.Errorf("pem does not include a valid EC private key") -} - func ParseCertPEM(pemCerts []byte) (*x509.Certificate, error) { var pemBlock *pem.Block for { diff --git a/factory/gen.go b/factory/gen.go index b54e9a0..cbe34fe 100644 --- a/factory/gen.go +++ b/factory/gen.go @@ -13,6 +13,7 @@ import ( "sort" "strings" + "github.com/rancher/dynamiclistener/cert" v1 "k8s.io/api/core/v1" ) @@ -105,7 +106,7 @@ func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) { return secret, true, nil } -func (t *TLS) newCert(domains []string, ips []net.IP, privateKey *ecdsa.PrivateKey) (*x509.Certificate, error) { +func (t *TLS) newCert(domains []string, ips []net.IP, privateKey crypto.Signer) (*x509.Certificate, error) { return NewSignedCert(privateKey, t.CACert, t.CAKey, t.CN, t.Organization, domains, ips) } @@ -134,39 +135,34 @@ func NeedsUpdate(secret *v1.Secret, cn ...string) bool { return false } -func getPrivateKey(secret *v1.Secret) (*ecdsa.PrivateKey, error) { +func getPrivateKey(secret *v1.Secret) (crypto.Signer, error) { keyBytes := secret.Data[v1.TLSPrivateKeyKey] if len(keyBytes) == 0 { return NewPrivateKey() } - privateKey, err := ParseECPrivateKeyPEM(keyBytes) - if err == nil { - return privateKey, nil + privateKey, err := cert.ParsePrivateKeyPEM(keyBytes) + if signer, ok := privateKey.(crypto.Signer); ok && err == nil { + return signer, nil } return NewPrivateKey() } -func Marshal(x509Cert *x509.Certificate, privateKey *ecdsa.PrivateKey) ([]byte, []byte, error) { +func Marshal(x509Cert *x509.Certificate, privateKey crypto.Signer) ([]byte, []byte, error) { certBlock := pem.Block{ Type: CertificateBlockType, Bytes: x509Cert.Raw, } - keyBytes, err := x509.MarshalECPrivateKey(privateKey) + keyBytes, err := cert.MarshalPrivateKeyToPEM(privateKey) if err != nil { return nil, nil, err } - keyBlock := pem.Block{ - Type: ECPrivateKeyBlockType, - Bytes: keyBytes, - } - - return pem.EncodeToMemory(&certBlock), pem.EncodeToMemory(&keyBlock), nil + return pem.EncodeToMemory(&certBlock), keyBytes, nil } -func NewPrivateKey() (*ecdsa.PrivateKey, error) { +func NewPrivateKey() (crypto.Signer, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) }