mirror of
https://github.com/lingble/talos.git
synced 2025-11-30 21:03:41 +00:00
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>
132 lines
2.9 KiB
Go
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")
|
|
}
|