main: adding too-soon remote
to check a remote hosts cert
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
01e8a6e859
commit
be72e38bfc
2 changed files with 90 additions and 4 deletions
16
README.md
16
README.md
|
@ -41,6 +41,22 @@ DEBU[0000] "letsencrypt/live/example.com-0007/fullchain.pem" : [example.com]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Likewise, you can check the expiration of a remote host with the `remote` command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
vbatts@jungle:~$ too-soon -D remote example.com
|
||||||
|
DEBU[0000] server: example.com
|
||||||
|
DEBU[0000] version: 772
|
||||||
|
DEBU[0000] -- cert serial: 498c7524e0cbd9f3fba887d6b7bba9dacac
|
||||||
|
DEBU[0000] "example.com:443"(498c7524e0cbd9f3fba887d6b7bba9dacac) : 2025-04-06 18:47:55 +0000 UTC
|
||||||
|
DEBU[0000] "example.com:443"(498c7524e0cbd9f3fba887d6b7bba9dacac) : [example.com]
|
||||||
|
DEBU[0000] -- cert serial: 838f6c63ceb1398c6206628315c9fdde
|
||||||
|
DEBU[0000] -- cert: skipping as there are no DNS names
|
||||||
|
DEBU[0000] -- cert serial: 498c7524e0cbd9f3fba887d6b7bba9dacac
|
||||||
|
DEBU[0000] "example.com:443"(498c7524e0cbd9f3fba887d6b7bba9dacac) : 2025-04-06 18:47:55 +0000 UTC
|
||||||
|
DEBU[0000] "example.com:443"(498c7524e0cbd9f3fba887d6b7bba9dacac) : [example.com]
|
||||||
|
```
|
||||||
|
|
||||||
## Combo
|
## Combo
|
||||||
|
|
||||||
Whether you use a cronjob or a systemd timer, you can chain this command to a daily/weekly job to check an email yourself:
|
Whether you use a cronjob or a systemd timer, you can chain this command to a daily/weekly job to check an email yourself:
|
||||||
|
|
78
main.go
78
main.go
|
@ -2,10 +2,13 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -46,6 +49,12 @@ func main() {
|
||||||
Action: fPEMCheck,
|
Action: fPEMCheck,
|
||||||
ArgsUsage: "[PEM files...]",
|
ArgsUsage: "[PEM files...]",
|
||||||
},
|
},
|
||||||
|
&cli.Command{
|
||||||
|
Name: "remote",
|
||||||
|
Usage: "check if certificate on a remote host expires too soon",
|
||||||
|
Action: fHostCheck,
|
||||||
|
ArgsUsage: "[host/host:port...]",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||||
cli.ShowAppHelpAndExit(cmd, 1)
|
cli.ShowAppHelpAndExit(cmd, 1)
|
||||||
|
@ -58,8 +67,69 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fHostCheck(ctx context.Context, cmd *cli.Command) error {
|
||||||
|
numAlert := 0
|
||||||
|
numHostErr := 0
|
||||||
|
for i := 0; i <= cmd.Args().Len(); i++ {
|
||||||
|
host := cmd.Args().Get(i)
|
||||||
|
if host == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO use the url.Parse package to do this, incase there is a protocol and path on there as well
|
||||||
|
port := "443"
|
||||||
|
if strings.Contains(host, ":") {
|
||||||
|
chunks := strings.Split(host, ":")
|
||||||
|
host = chunks[0]
|
||||||
|
port = chunks[1]
|
||||||
|
}
|
||||||
|
// connect to the domain:port/tcp
|
||||||
|
dest := fmt.Sprintf("%s:%s", host, port)
|
||||||
|
conn, err := tls.Dial("tcp", dest, &tls.Config{
|
||||||
|
InsecureSkipVerify: true, // TODO add a flag to force this
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
numHostErr++
|
||||||
|
log.Errorf("%q connection failed: %s", dest, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
log.Debugf("server: %s", conn.ConnectionState().ServerName)
|
||||||
|
log.Debugf("version: %d", conn.ConnectionState().Version)
|
||||||
|
for _, cert := range conn.ConnectionState().PeerCertificates {
|
||||||
|
log.Debugf(" -- cert serial: %x", cert.SerialNumber)
|
||||||
|
if len(cert.DNSNames) == 0 {
|
||||||
|
log.Debugf(" -- cert: skipping as there are no DNS names")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hours := time.Duration(cmd.Int("days") * -24)
|
||||||
|
alertTime := cert.NotAfter.Add(hours * time.Hour)
|
||||||
|
today := time.Now()
|
||||||
|
if today.After(alertTime) {
|
||||||
|
if today.After(cert.NotAfter) {
|
||||||
|
log.Warnf("%q(%x) : TIME TO RENEW CERTIFICATE (already expired!)", dest, cert.SerialNumber)
|
||||||
|
} else {
|
||||||
|
log.Warnf("%q(%x) : TIME TO RENEW CERTIFICATE (expires in less than %d days)", dest, cert.SerialNumber, cmd.Int("days"))
|
||||||
|
}
|
||||||
|
log.Warnf("%q(%x) : %v", dest, cert.SerialNumber, cert.NotAfter)
|
||||||
|
log.Warnf("%q(%x) : %v", dest, cert.SerialNumber, cert.DNSNames)
|
||||||
|
numAlert++
|
||||||
|
} else {
|
||||||
|
log.Debugf("%q(%x) : %v", dest, cert.SerialNumber, cert.NotAfter)
|
||||||
|
log.Debugf("%q(%x) : %v", dest, cert.SerialNumber, cert.DNSNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if numAlert != 0 {
|
||||||
|
return cli.Exit("domain certificates need to be renewed", numAlert)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func fPEMCheck(ctx context.Context, cmd *cli.Command) error {
|
func fPEMCheck(ctx context.Context, cmd *cli.Command) error {
|
||||||
retCode := 0
|
numAlert := 0
|
||||||
for i := 0; i <= cmd.Args().Len(); i++ {
|
for i := 0; i <= cmd.Args().Len(); i++ {
|
||||||
file := cmd.Args().Get(i)
|
file := cmd.Args().Get(i)
|
||||||
if file == "" {
|
if file == "" {
|
||||||
|
@ -107,15 +177,15 @@ func fPEMCheck(ctx context.Context, cmd *cli.Command) error {
|
||||||
}
|
}
|
||||||
log.Warnf("%q : %v", file, cert.NotAfter)
|
log.Warnf("%q : %v", file, cert.NotAfter)
|
||||||
log.Warnf("%q : %v", file, cert.DNSNames)
|
log.Warnf("%q : %v", file, cert.DNSNames)
|
||||||
retCode++
|
numAlert++
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("%q : %v", file, cert.NotAfter)
|
log.Debugf("%q : %v", file, cert.NotAfter)
|
||||||
log.Debugf("%q : %v", file, cert.DNSNames)
|
log.Debugf("%q : %v", file, cert.DNSNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if retCode != 0 {
|
if numAlert != 0 {
|
||||||
return cli.Exit("certificates need to be renewed", retCode)
|
return cli.Exit("certificates need to be renewed", numAlert)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue