mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 05:37:32 +00:00
ipn/{ipnlocal,store},kube/kubeclient: store TLS cert and key pair to a Secret in a single operation. (#15147)
To avoid duplicate issuances/slowness while the state Secret contains a mismatched cert and key. Updates tailscale/tailscale#15134 Updates tailscale/corp#24795 Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
@@ -250,15 +250,13 @@ type certStore interface {
|
||||
// for now. If they're expired, it returns errCertExpired.
|
||||
// If they don't exist, it returns ipn.ErrStateNotExist.
|
||||
Read(domain string, now time.Time) (*TLSCertKeyPair, error)
|
||||
// WriteCert writes the cert for domain.
|
||||
WriteCert(domain string, cert []byte) error
|
||||
// WriteKey writes the key for domain.
|
||||
WriteKey(domain string, key []byte) error
|
||||
// ACMEKey returns the value previously stored via WriteACMEKey.
|
||||
// It is a PEM encoded ECDSA key.
|
||||
ACMEKey() ([]byte, error)
|
||||
// WriteACMEKey stores the provided PEM encoded ECDSA key.
|
||||
WriteACMEKey([]byte) error
|
||||
// WriteTLSCertAndKey writes the cert and key for domain.
|
||||
WriteTLSCertAndKey(domain string, cert, key []byte) error
|
||||
}
|
||||
|
||||
var errCertExpired = errors.New("cert expired")
|
||||
@@ -344,6 +342,13 @@ func (f certFileStore) WriteKey(domain string, key []byte) error {
|
||||
return atomicfile.WriteFile(keyFile(f.dir, domain), key, 0600)
|
||||
}
|
||||
|
||||
func (f certFileStore) WriteTLSCertAndKey(domain string, cert, key []byte) error {
|
||||
if err := f.WriteKey(domain, key); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.WriteCert(domain, cert)
|
||||
}
|
||||
|
||||
// certStateStore implements certStore by storing the cert & key files in an ipn.StateStore.
|
||||
type certStateStore struct {
|
||||
ipn.StateStore
|
||||
@@ -384,6 +389,27 @@ func (s certStateStore) WriteACMEKey(key []byte) error {
|
||||
return ipn.WriteState(s.StateStore, ipn.StateKey(acmePEMName), key)
|
||||
}
|
||||
|
||||
// TLSCertKeyWriter is an interface implemented by state stores that can write the TLS
|
||||
// cert and key in a single atomic operation. Currently this is only implemented
|
||||
// by the kubestore.StoreKube.
|
||||
type TLSCertKeyWriter interface {
|
||||
WriteTLSCertAndKey(domain string, cert, key []byte) error
|
||||
}
|
||||
|
||||
// WriteTLSCertAndKey writes the TLS cert and key for domain to the current
|
||||
// LocalBackend's StateStore.
|
||||
func (s certStateStore) WriteTLSCertAndKey(domain string, cert, key []byte) error {
|
||||
// If we're using a store that supports atomic writes, use that.
|
||||
if aw, ok := s.StateStore.(TLSCertKeyWriter); ok {
|
||||
return aw.WriteTLSCertAndKey(domain, cert, key)
|
||||
}
|
||||
// Otherwise fall back to separate writes for cert and key.
|
||||
if err := s.WriteKey(domain, key); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.WriteCert(domain, cert)
|
||||
}
|
||||
|
||||
// TLSCertKeyPair is a TLS public and private key, and whether they were obtained
|
||||
// from cache or freshly obtained.
|
||||
type TLSCertKeyPair struct {
|
||||
@@ -546,9 +572,6 @@ func (b *LocalBackend) getCertPEM(ctx context.Context, cs certStore, logf logger
|
||||
if err := encodeECDSAKey(&privPEM, certPrivKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cs.WriteKey(domain, privPEM.Bytes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
csr, err := certRequest(certPrivKey, domain, nil)
|
||||
if err != nil {
|
||||
@@ -570,7 +593,7 @@ func (b *LocalBackend) getCertPEM(ctx context.Context, cs certStore, logf logger
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := cs.WriteCert(domain, certPEM.Bytes()); err != nil {
|
||||
if err := cs.WriteTLSCertAndKey(domain, certPEM.Bytes(), privPEM.Bytes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.domainRenewed(domain)
|
||||
|
Reference in New Issue
Block a user