Files
talos/pkg/grpc/tls/provider.go
Andrew Rynhard d430a37e46 refactor: use go 1.13 error wrapping
This removes the github.com/pkg/errors package in favor of the official
error wrapping in go 1.13.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
2019-10-15 22:20:50 -07:00

132 lines
2.9 KiB
Go

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package tls
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"log"
"net"
"sync"
"time"
"github.com/talos-systems/talos/pkg/constants"
)
// CertificateProvider describes an interface by which TLS certificates may be managed.
type CertificateProvider interface {
// GetCA returns the active root CA.
GetCA() ([]byte, error)
// GetCertificate returns the current certificate matching the given client request.
GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error)
// UpdateCertificate updates the stored certificate for the given client request.
UpdateCertificates([]byte, *tls.Certificate) error
}
type embeddableCertificateProvider struct {
sync.RWMutex
ca []byte
crt *tls.Certificate
hostname string
ips []net.IP
updateFunc func() ([]byte, tls.Certificate, error)
updateHooks []func(newCert *tls.Certificate)
}
func (p *embeddableCertificateProvider) GetCA() ([]byte, error) {
if p == nil {
return nil, errors.New("no provider")
}
p.RLock()
defer p.RUnlock()
return p.ca, nil
}
func (p *embeddableCertificateProvider) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) {
if p == nil {
return nil, errors.New("no provider")
}
p.RLock()
defer p.RUnlock()
return p.crt, nil
}
func (p *embeddableCertificateProvider) UpdateCertificates(ca []byte, cert *tls.Certificate) error {
p.Lock()
p.ca = ca
p.crt = cert
p.Unlock()
for _, f := range p.updateHooks {
f(cert)
}
return nil
}
func (p *embeddableCertificateProvider) manageUpdates(ctx context.Context) (err error) {
nextRenewal := constants.DefaultCertificateValidityDuration
for ctx.Err() == nil {
// nolint: errcheck
if c, _ := p.GetCertificate(nil); c != nil {
if len(c.Certificate) > 0 {
var crt *x509.Certificate
crt, err = x509.ParseCertificate(c.Certificate[0])
if err == nil {
nextRenewal = time.Until(crt.NotAfter) / 2
} else {
log.Println("failed to parse current leaf certificate")
}
} else {
log.Println("current leaf certificate not found")
}
} else {
log.Println("certificate not found")
}
log.Println("next renewal in", nextRenewal)
if nextRenewal > constants.DefaultCertificateValidityDuration {
nextRenewal = constants.DefaultCertificateValidityDuration
}
select {
case <-time.After(nextRenewal):
case <-ctx.Done():
return nil
}
var (
ca []byte
cert tls.Certificate
)
if ca, cert, err = p.updateFunc(); err != nil {
log.Println("failed to renew certificate:", err)
continue
}
if err = p.UpdateCertificates(ca, &cert); err != nil {
log.Println("failed to renew certificate:", err)
continue
}
}
return errors.New("certificate update manager exited unexpectedly")
}