From 7a61e681b0a20c0e65dd0a4ec9148975fdca1b08 Mon Sep 17 00:00:00 2001 From: sdlspr <39553693+sdlspr@users.noreply.github.com> Date: Sat, 11 Apr 2020 14:57:06 +0200 Subject: [PATCH] Informations about renewed certificates are now passed to the renew hook (#1108) --- cmd/certs_storage.go | 11 ++++--- cmd/cmd_renew.go | 51 ++++++++++++++++++++++++------ docs/content/usage/cli/examples.md | 7 ++++ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/cmd/certs_storage.go b/cmd/certs_storage.go index c00d83ff..4a69125f 100644 --- a/cmd/certs_storage.go +++ b/cmd/certs_storage.go @@ -133,8 +133,7 @@ func (s *CertificatesStorage) ReadResource(domain string) certificate.Resource { } func (s *CertificatesStorage) ExistsFile(domain, extension string) bool { - filename := sanitizedDomain(domain) + extension - filePath := filepath.Join(s.rootPath, filename) + filePath := s.GetFileName(domain, extension) if _, err := os.Stat(filePath); os.IsNotExist(err) { return false @@ -145,10 +144,12 @@ func (s *CertificatesStorage) ExistsFile(domain, extension string) bool { } func (s *CertificatesStorage) ReadFile(domain, extension string) ([]byte, error) { - filename := sanitizedDomain(domain) + extension - filePath := filepath.Join(s.rootPath, filename) + return ioutil.ReadFile(s.GetFileName(domain, extension)) +} - return ioutil.ReadFile(filePath) +func (s *CertificatesStorage) GetFileName(domain, extension string) string { + filename := sanitizedDomain(domain) + extension + return filepath.Join(s.rootPath, filename) } func (s *CertificatesStorage) ReadCertificate(domain, extension string) ([]*x509.Certificate, error) { diff --git a/cmd/cmd_renew.go b/cmd/cmd_renew.go index 7e6a09a7..6d086da8 100644 --- a/cmd/cmd_renew.go +++ b/cmd/cmd_renew.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "errors" "fmt" + "os" "os/exec" "strings" "time" @@ -17,6 +18,13 @@ import ( "github.com/urfave/cli" ) +const ( + renewEnvAccountEmail = "LEGO_ACCOUNT_EMAIL" + renewEnvCertDomain = "LEGO_CERT_DOMAIN" + renewEnvCertPath = "LEGO_CERT_PATH" + renewEnvCertKeyPath = "LEGO_CERT_KEY_PATH" +) + func createRenew() cli.Command { return cli.Command{ Name: "renew", @@ -72,16 +80,18 @@ func renew(ctx *cli.Context) error { bundle := !ctx.Bool("no-bundle") + meta := map[string]string{renewEnvAccountEmail: account.Email} + // CSR if ctx.GlobalIsSet("csr") { - return renewForCSR(ctx, client, certsStorage, bundle) + return renewForCSR(ctx, client, certsStorage, bundle, meta) } // Domains - return renewForDomains(ctx, client, certsStorage, bundle) + return renewForDomains(ctx, client, certsStorage, bundle, meta) } -func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *CertificatesStorage, bundle bool) error { +func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *CertificatesStorage, bundle bool, meta map[string]string) error { domains := ctx.GlobalStringSlice("domains") domain := domains[0] @@ -131,10 +141,14 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif certsStorage.SaveResource(certRes) - return renewHook(ctx) + meta[renewEnvCertDomain] = domain + meta[renewEnvCertPath] = certsStorage.GetFileName(domain, "crt") + meta[renewEnvCertKeyPath] = certsStorage.GetFileName(domain, "key") + + return renewHook(ctx, meta) } -func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *CertificatesStorage, bundle bool) error { +func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *CertificatesStorage, bundle bool, meta map[string]string) error { csr, err := readCSRFile(ctx.GlobalString("csr")) if err != nil { log.Fatal(err) @@ -167,7 +181,11 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat certsStorage.SaveResource(certRes) - return renewHook(ctx) + meta[renewEnvCertDomain] = domain + meta[renewEnvCertPath] = certsStorage.GetFileName(domain, "crt") + meta[renewEnvCertKeyPath] = certsStorage.GetFileName(domain, "key") + + return renewHook(ctx, meta) } func needRenewal(x509Cert *x509.Certificate, domain string, days int) bool { @@ -203,17 +221,22 @@ func merge(prevDomains []string, nextDomains []string) []string { return prevDomains } -func renewHook(ctx *cli.Context) error { +func renewHook(ctx *cli.Context, meta map[string]string) error { hook := ctx.String("renew-hook") if hook == "" { return nil } - ctxCmd, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctxCmd, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() parts := strings.Fields(hook) - output, err := exec.CommandContext(ctxCmd, parts[0], parts[1:]...).CombinedOutput() + + cmdCtx := exec.CommandContext(ctxCmd, parts[0], parts[1:]...) + cmdCtx.Env = append(os.Environ(), metaToEnv(meta)...) + + output, err := cmdCtx.CombinedOutput() + if len(output) > 0 { fmt.Println(string(output)) } @@ -224,3 +247,13 @@ func renewHook(ctx *cli.Context) error { return err } + +func metaToEnv(meta map[string]string) []string { + var envs []string + + for k, v := range meta { + envs = append(envs, k+"="+v) + } + + return envs +} diff --git a/docs/content/usage/cli/examples.md b/docs/content/usage/cli/examples.md index e6f3059e..eb77fe8f 100644 --- a/docs/content/usage/cli/examples.md +++ b/docs/content/usage/cli/examples.md @@ -38,6 +38,13 @@ The hook is executed only when the certificates are effectively renewed. lego --email="foo@bar.com" --domains="example.com" --http renew --renew-hook="./myscript.sh" ``` +Some information are added to the environment variables when the hook is used: + +- `LEGO_ACCOUNT_EMAIL`: the email of the account. +- `LEGO_CERT_DOMAIN`: the main domain of the certificate. +- `LEGO_CERT_PATH`: the path of the certificate. +- `LEGO_CERT_KEY_PATH`: the path of the certificate key. + ### Obtain a certificate using the DNS challenge ```bash