@ -84,11 +84,9 @@ var acmeDebug = envknob.RegisterBool("TS_DEBUG_ACME")
// ACME process. ACME process is used for new domain certs, existing expired
// ACME process. ACME process is used for new domain certs, existing expired
// certs or existing certs that should get renewed due to upcoming expiry.
// certs or existing certs that should get renewed due to upcoming expiry.
//
//
// syncRenewal changes renewal behavior for existing certs that are still valid
// If a cert is expired, it will be renewed synchronously otherwise it will be
// but need renewal. When syncRenewal is set, the method blocks until a new
// renewed asynchronously.
// cert is issued. When syncRenewal is not set, existing cert is returned right
func ( b * LocalBackend ) GetCertPEM ( ctx context . Context , domain string ) ( * TLSCertKeyPair , error ) {
// away and renewal is kicked off in a background goroutine.
func ( b * LocalBackend ) GetCertPEM ( ctx context . Context , domain string , syncRenewal bool ) ( * TLSCertKeyPair , error ) {
if ! validLookingCertDomain ( domain ) {
if ! validLookingCertDomain ( domain ) {
return nil , errors . New ( "invalid domain" )
return nil , errors . New ( "invalid domain" )
}
}
@ -108,18 +106,16 @@ func (b *LocalBackend) GetCertPEM(ctx context.Context, domain string, syncRenewa
}
}
if pair , err := getCertPEMCached ( cs , domain , now ) ; err == nil {
if pair , err := getCertPEMCached ( cs , domain , now ) ; err == nil {
shouldRenew , err := b . shouldStartDomainRenewal ( cs , domain , now , pair )
// If we got here, we have a valid unexpired cert.
if err != nil {
// Check whether we should start an async renewal.
if shouldRenew , err := b . shouldStartDomainRenewal ( cs , domain , now , pair ) ; err != nil {
logf ( "error checking for certificate renewal: %v" , err )
logf ( "error checking for certificate renewal: %v" , err )
} else if ! shouldRenew {
} else if shouldRenew {
return pair , nil
}
if ! syncRenewal {
logf ( "starting async renewal" )
logf ( "starting async renewal" )
// Start renewal in the background.
// Start renewal in the background.
go b . getCertPEM ( context . Background ( ) , cs , logf , traceACME , domain , now )
go b . getCertPEM ( context . Background ( ) , cs , logf , traceACME , domain , now )
}
}
// Synchronous renewal happens below.
return pair , nil
}
}
pair , err := b . getCertPEM ( ctx , cs , logf , traceACME , domain , now )
pair , err := b . getCertPEM ( ctx , cs , logf , traceACME , domain , now )
@ -130,6 +126,8 @@ func (b *LocalBackend) GetCertPEM(ctx context.Context, domain string, syncRenewa
return pair , nil
return pair , nil
}
}
// shouldStartDomainRenewal reports whether the domain's cert should be renewed
// based on the current time, the cert's expiry, and the ARI check.
func ( b * LocalBackend ) shouldStartDomainRenewal ( cs certStore , domain string , now time . Time , pair * TLSCertKeyPair ) ( bool , error ) {
func ( b * LocalBackend ) shouldStartDomainRenewal ( cs certStore , domain string , now time . Time , pair * TLSCertKeyPair ) ( bool , error ) {
renewMu . Lock ( )
renewMu . Lock ( )
defer renewMu . Unlock ( )
defer renewMu . Unlock ( )
@ -365,8 +363,9 @@ type TLSCertKeyPair struct {
func keyFile ( dir , domain string ) string { return filepath . Join ( dir , domain + ".key" ) }
func keyFile ( dir , domain string ) string { return filepath . Join ( dir , domain + ".key" ) }
func certFile ( dir , domain string ) string { return filepath . Join ( dir , domain + ".crt" ) }
func certFile ( dir , domain string ) string { return filepath . Join ( dir , domain + ".crt" ) }
// getCertPEMCached returns a non-nil keyPair and true if a cached keypair for
// getCertPEMCached returns a non-nil keyPair if a cached keypair for domain
// domain exists on disk in dir that is valid at the provided now time.
// exists on disk in dir that is valid at the provided now time.
//
// If the keypair is expired, it returns errCertExpired.
// If the keypair is expired, it returns errCertExpired.
// If the keypair doesn't exist, it returns ipn.ErrStateNotExist.
// If the keypair doesn't exist, it returns ipn.ErrStateNotExist.
func getCertPEMCached ( cs certStore , domain string , now time . Time ) ( p * TLSCertKeyPair , err error ) {
func getCertPEMCached ( cs certStore , domain string , now time . Time ) ( p * TLSCertKeyPair , err error ) {