Skip to content

Commit

Permalink
feat: Change renew rc when cert is still valid
Browse files Browse the repository at this point in the history
Sometimes the lego Client may fail to contact the CA due to some
temporary networking issue on the host. The certificate may otherwise
still be valid, and a user may want to ignore this issue.

This change modifies the renew service so that if the lego client
is nil, but the certificate is not expired, the exit code of the
program will be 2 instead of 1.

In order to implement this, I had to change the setup function to remove
a usage of log.Fatalf which in turn required me to introduce explicit
os.Exit calls in some commands. Although this was the lowest patch delta
solution, I also considered refactoring the setup entirely to remove
log.Fatalf, and return setup errors instead.
  • Loading branch information
m1cr0man committed Dec 1, 2024
1 parent c2f179f commit a0d8e4f
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
36 changes: 33 additions & 3 deletions cmd/cmd_renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ func createRenew() *cli.Command {

func renew(ctx *cli.Context) error {
account, client := setup(ctx, NewAccountsStorage(ctx))
setupChallenges(ctx, client)
if client != nil {
setupChallenges(ctx, client)
}

if account.Registration == nil {
log.Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", account.Email)
Expand Down Expand Up @@ -162,7 +164,7 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif
var ariRenewalTime *time.Time
var replacesCertID string

if !ctx.Bool(flgARIDisable) {
if !ctx.Bool(flgARIDisable) && client != nil {
ariRenewalTime = getARIRenewalTime(ctx, cert, domain, client)
if ariRenewalTime != nil {
now := time.Now().UTC()
Expand All @@ -186,9 +188,23 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif

if ariRenewalTime == nil && !needRenewal(cert, domain, ctx.Int(flgDays)) &&
(!forceDomains || slices.Equal(certDomains, domains)) {
// Warn the user that renewal check occurred offline, but the cert is not expired yet.
if client == nil {
log.Warnf(
"[%s] Failed to check ARI as there is no client."+
" Check previous error messages for possible initialization issues.",
domain,
)
os.Exit(2)
}
return nil
}

if client == nil {
// Abort renewal if we don't have a lego client
os.Exit(1)
}

// This is just meant to be informal for the user.
timeLeft := cert.NotAfter.Sub(time.Now().UTC())
log.Infof("[%s] acme: Trying renewal with %d hours remaining", domain, int(timeLeft.Hours()))
Expand Down Expand Up @@ -274,7 +290,7 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
var ariRenewalTime *time.Time
var replacesCertID string

if !ctx.Bool(flgARIDisable) {
if !ctx.Bool(flgARIDisable) && client != nil {
ariRenewalTime = getARIRenewalTime(ctx, cert, domain, client)
if ariRenewalTime != nil {
now := time.Now().UTC()
Expand All @@ -293,9 +309,23 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
}

if ariRenewalTime == nil && !needRenewal(cert, domain, ctx.Int(flgDays)) {
// Warn the user that renewal check occurred offline, but the cert is not expired yet.
if client == nil {
log.Warnf(
"[%s] Failed to check ARI as there is no client."+
" Check previous error messages for an indicator of initialization issues.",
domain,
)
os.Exit(2)
}
return nil
}

if client == nil {
// Abort renewal if we don't have a lego client
os.Exit(1)
}

// This is just meant to be informal for the user.
timeLeft := cert.NotAfter.Sub(time.Now().UTC())
log.Infof("[%s] acme: Trying renewal with %d hours remaining", domain, int(timeLeft.Hours()))
Expand Down
5 changes: 5 additions & 0 deletions cmd/cmd_revoke.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd

import (
"os"

"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/log"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -39,6 +41,9 @@ func createRevoke() *cli.Command {

func revoke(ctx *cli.Context) error {
acc, client := setup(ctx, NewAccountsStorage(ctx))
if client == nil {
os.Exit(1)
}

if acc.Registration == nil {
log.Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", acc.Email)
Expand Down
3 changes: 3 additions & 0 deletions cmd/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ func run(ctx *cli.Context) error {
accountsStorage := NewAccountsStorage(ctx)

account, client := setup(ctx, accountsStorage)
if client == nil {
os.Exit(1)
}
setupChallenges(ctx, client)

if account.Registration == nil {
Expand Down
3 changes: 2 additions & 1 deletion cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func newClient(ctx *cli.Context, acc registration.User, keyType certcrypto.KeyTy

client, err := lego.NewClient(config)
if err != nil {
log.Fatalf("Could not create client: %v", err)
log.Warnf("Could not create client: %v", err)
return nil
}

if client.GetExternalAccountRequired() && !ctx.IsSet(flgEAB) {
Expand Down

0 comments on commit a0d8e4f

Please sign in to comment.