2018-07-31 03:12:45 +08:00
|
|
|
// Package x509_cert reports metrics from an SSL certificate.
|
2022-08-06 02:54:23 +08:00
|
|
|
//
|
|
|
|
|
//go:generate ../../../tools/readme_config_includer/generator
|
2018-07-31 03:12:45 +08:00
|
|
|
package x509_cert
|
|
|
|
|
|
|
|
|
|
import (
|
2019-11-26 07:38:57 +08:00
|
|
|
"bytes"
|
2018-07-31 03:12:45 +08:00
|
|
|
"crypto/tls"
|
|
|
|
|
"crypto/x509"
|
2022-05-24 21:49:47 +08:00
|
|
|
_ "embed"
|
2018-07-31 03:12:45 +08:00
|
|
|
"encoding/pem"
|
2022-11-18 23:23:07 +08:00
|
|
|
"errors"
|
2018-07-31 03:12:45 +08:00
|
|
|
"fmt"
|
|
|
|
|
"net"
|
2022-06-16 00:46:26 +08:00
|
|
|
"net/smtp"
|
2018-07-31 03:12:45 +08:00
|
|
|
"net/url"
|
2021-09-29 05:16:32 +08:00
|
|
|
"os"
|
2020-11-23 23:40:32 +08:00
|
|
|
"path/filepath"
|
2018-07-31 03:12:45 +08:00
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
2021-09-29 05:16:32 +08:00
|
|
|
"github.com/pion/dtls/v2"
|
|
|
|
|
|
2018-07-31 03:12:45 +08:00
|
|
|
"github.com/influxdata/telegraf"
|
2021-04-10 01:15:04 +08:00
|
|
|
"github.com/influxdata/telegraf/config"
|
2021-03-24 05:31:15 +08:00
|
|
|
"github.com/influxdata/telegraf/internal/globpath"
|
2022-06-22 04:50:06 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/common/proxy"
|
2022-11-18 23:23:07 +08:00
|
|
|
commontls "github.com/influxdata/telegraf/plugins/common/tls"
|
2018-07-31 03:12:45 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
|
|
|
)
|
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
//go:embed sample.conf
|
|
|
|
|
var sampleConfig string
|
|
|
|
|
|
2018-07-31 03:12:45 +08:00
|
|
|
// X509Cert holds the configuration of the plugin.
|
|
|
|
|
type X509Cert struct {
|
2021-12-23 04:39:36 +08:00
|
|
|
Sources []string `toml:"sources"`
|
|
|
|
|
Timeout config.Duration `toml:"timeout"`
|
|
|
|
|
ServerName string `toml:"server_name"`
|
|
|
|
|
ExcludeRootCerts bool `toml:"exclude_root_certs"`
|
2022-11-18 23:23:07 +08:00
|
|
|
Log telegraf.Logger `toml:"-"`
|
|
|
|
|
commontls.ClientConfig
|
2022-06-22 04:50:06 +08:00
|
|
|
proxy.TCPProxy
|
2022-11-18 23:23:07 +08:00
|
|
|
|
|
|
|
|
tlsCfg *tls.Config
|
2021-03-24 05:31:15 +08:00
|
|
|
locations []*url.URL
|
|
|
|
|
globpaths []*globpath.GlobPath
|
2022-11-18 23:23:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (*X509Cert) SampleConfig() string {
|
|
|
|
|
return sampleConfig
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *X509Cert) Init() error {
|
|
|
|
|
// Check if we do have at least one source
|
|
|
|
|
if len(c.Sources) == 0 {
|
|
|
|
|
return errors.New("no source configured")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the server name and transfer it if necessary
|
|
|
|
|
if c.ClientConfig.ServerName != "" && c.ServerName != "" {
|
|
|
|
|
return fmt.Errorf("both server_name (%q) and tls_server_name (%q) are set, but they are mutually exclusive", c.ServerName, c.ClientConfig.ServerName)
|
|
|
|
|
} else if c.ServerName != "" {
|
|
|
|
|
// Store the user-provided server-name in the TLS configuration
|
|
|
|
|
c.ClientConfig.ServerName = c.ServerName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normalize the sources, handle files and file-globbing
|
|
|
|
|
if err := c.sourcesToURLs(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the TLS configuration
|
|
|
|
|
tlsCfg, err := c.ClientConfig.TLSConfig()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if tlsCfg == nil {
|
|
|
|
|
tlsCfg = &tls.Config{}
|
|
|
|
|
}
|
|
|
|
|
c.tlsCfg = tlsCfg
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gather adds metrics into the accumulator.
|
|
|
|
|
func (c *X509Cert) Gather(acc telegraf.Accumulator) error {
|
|
|
|
|
now := time.Now()
|
|
|
|
|
collectedUrls, err := c.collectCertURLs()
|
|
|
|
|
if err != nil {
|
|
|
|
|
acc.AddError(fmt.Errorf("getting some certificates failed: %w", err))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, location := range append(c.locations, collectedUrls...) {
|
|
|
|
|
certs, err := c.getCert(location, time.Duration(c.Timeout))
|
|
|
|
|
if err != nil {
|
|
|
|
|
acc.AddError(fmt.Errorf("cannot get SSL cert '%s': %s", location, err.Error()))
|
|
|
|
|
}
|
2023-02-01 03:05:05 +08:00
|
|
|
|
|
|
|
|
dnsName := c.serverName(location)
|
2022-11-18 23:23:07 +08:00
|
|
|
for i, cert := range certs {
|
|
|
|
|
fields := getFields(cert, now)
|
|
|
|
|
tags := getTags(cert, location.String())
|
|
|
|
|
|
|
|
|
|
// The first certificate is the leaf/end-entity certificate which
|
|
|
|
|
// needs DNS name validation against the URL hostname.
|
|
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
|
|
|
Roots: c.tlsCfg.RootCAs,
|
|
|
|
|
DNSName: dnsName,
|
|
|
|
|
}
|
|
|
|
|
// Reset DNS name to only use it for the leaf node
|
|
|
|
|
dnsName = ""
|
|
|
|
|
|
|
|
|
|
// Add all returned certs to the pool if intermediates except for
|
|
|
|
|
// the leaf node and ourself
|
|
|
|
|
for j, c := range certs[1:] {
|
2022-12-15 22:52:36 +08:00
|
|
|
if i+1 != j {
|
2022-11-18 23:23:07 +08:00
|
|
|
opts.Intermediates.AddCert(c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := cert.Verify(opts); err == nil {
|
|
|
|
|
tags["verification"] = "valid"
|
|
|
|
|
fields["verification_code"] = 0
|
|
|
|
|
} else {
|
|
|
|
|
c.Log.Debugf("Invalid certificate at index %2d!", i)
|
|
|
|
|
c.Log.Debugf(" cert DNS names: %v", cert.DNSNames)
|
|
|
|
|
c.Log.Debugf(" cert IP addresses: %v", cert.IPAddresses)
|
2022-12-15 22:52:36 +08:00
|
|
|
c.Log.Debugf(" cert subject: %v", cert.Subject)
|
|
|
|
|
c.Log.Debugf(" cert issuer: %v", cert.Issuer)
|
2022-11-18 23:23:07 +08:00
|
|
|
c.Log.Debugf(" opts.DNSName: %v", opts.DNSName)
|
|
|
|
|
c.Log.Debugf(" verify options: %v", opts)
|
|
|
|
|
c.Log.Debugf(" verify error: %v", err)
|
|
|
|
|
c.Log.Debugf(" location: %v", location)
|
|
|
|
|
c.Log.Debugf(" tlsCfg.ServerName: %v", c.tlsCfg.ServerName)
|
|
|
|
|
c.Log.Debugf(" ServerName: %v", c.ServerName)
|
|
|
|
|
tags["verification"] = "invalid"
|
|
|
|
|
fields["verification_code"] = 1
|
|
|
|
|
fields["verification_error"] = err.Error()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc.AddFields("x509_cert", fields, tags)
|
|
|
|
|
if c.ExcludeRootCerts {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2018-07-31 03:12:45 +08:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 05:31:15 +08:00
|
|
|
func (c *X509Cert) sourcesToURLs() error {
|
|
|
|
|
for _, source := range c.Sources {
|
|
|
|
|
if strings.HasPrefix(source, "file://") ||
|
2021-06-23 00:41:45 +08:00
|
|
|
strings.HasPrefix(source, "/") {
|
2021-03-24 05:31:15 +08:00
|
|
|
source = filepath.ToSlash(strings.TrimPrefix(source, "file://"))
|
|
|
|
|
g, err := globpath.Compile(source)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("could not compile glob %v: %v", source, err)
|
|
|
|
|
}
|
|
|
|
|
c.globpaths = append(c.globpaths, g)
|
|
|
|
|
} else {
|
|
|
|
|
if strings.Index(source, ":\\") == 1 {
|
|
|
|
|
source = "file://" + filepath.ToSlash(source)
|
|
|
|
|
}
|
|
|
|
|
u, err := url.Parse(source)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to parse cert location - %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
c.locations = append(c.locations, u)
|
|
|
|
|
}
|
2018-07-31 03:12:45 +08:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 05:31:15 +08:00
|
|
|
return nil
|
2019-07-23 07:10:40 +08:00
|
|
|
}
|
|
|
|
|
|
2023-02-01 03:05:05 +08:00
|
|
|
func (c *X509Cert) serverName(u *url.URL) string {
|
2020-12-24 03:39:43 +08:00
|
|
|
if c.tlsCfg.ServerName != "" {
|
2023-02-01 03:05:05 +08:00
|
|
|
return c.tlsCfg.ServerName
|
2020-12-24 03:39:43 +08:00
|
|
|
}
|
2023-02-01 03:05:05 +08:00
|
|
|
return u.Hostname()
|
2020-12-24 03:39:43 +08:00
|
|
|
}
|
|
|
|
|
|
2019-07-23 07:10:40 +08:00
|
|
|
func (c *X509Cert) getCert(u *url.URL, timeout time.Duration) ([]*x509.Certificate, error) {
|
2021-06-23 02:45:03 +08:00
|
|
|
protocol := u.Scheme
|
2018-07-31 03:12:45 +08:00
|
|
|
switch u.Scheme {
|
2021-07-23 08:44:36 +08:00
|
|
|
case "udp", "udp4", "udp6":
|
|
|
|
|
ipConn, err := net.DialTimeout(u.Scheme, u.Host, timeout)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer ipConn.Close()
|
|
|
|
|
|
|
|
|
|
dtlsCfg := &dtls.Config{
|
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
|
Certificates: c.tlsCfg.Certificates,
|
|
|
|
|
RootCAs: c.tlsCfg.RootCAs,
|
2023-02-01 03:05:05 +08:00
|
|
|
ServerName: c.serverName(u),
|
2021-07-23 08:44:36 +08:00
|
|
|
}
|
|
|
|
|
conn, err := dtls.Client(ipConn, dtlsCfg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
|
|
rawCerts := conn.ConnectionState().PeerCertificates
|
|
|
|
|
var certs []*x509.Certificate
|
|
|
|
|
for _, rawCert := range rawCerts {
|
|
|
|
|
parsed, err := x509.ParseCertificate(rawCert)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if parsed != nil {
|
|
|
|
|
certs = append(certs, parsed)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return certs, nil
|
2018-07-31 03:12:45 +08:00
|
|
|
case "https":
|
2021-06-23 02:45:03 +08:00
|
|
|
protocol = "tcp"
|
2022-11-18 23:23:07 +08:00
|
|
|
if u.Port() == "" {
|
|
|
|
|
u.Host += ":443"
|
|
|
|
|
}
|
2018-07-31 03:12:45 +08:00
|
|
|
fallthrough
|
|
|
|
|
case "tcp", "tcp4", "tcp6":
|
2022-06-22 04:50:06 +08:00
|
|
|
dialer, err := c.Proxy()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
ipConn, err := dialer.DialTimeout(protocol, u.Host, timeout)
|
2018-07-31 03:12:45 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer ipConn.Close()
|
|
|
|
|
|
2022-08-06 02:54:23 +08:00
|
|
|
downloadTLSCfg := c.tlsCfg.Clone()
|
2023-02-01 03:05:05 +08:00
|
|
|
downloadTLSCfg.ServerName = c.serverName(u)
|
2022-08-06 02:54:23 +08:00
|
|
|
downloadTLSCfg.InsecureSkipVerify = true
|
2018-07-31 03:12:45 +08:00
|
|
|
|
2022-08-06 02:54:23 +08:00
|
|
|
conn := tls.Client(ipConn, downloadTLSCfg)
|
|
|
|
|
defer conn.Close()
|
2021-06-23 00:41:45 +08:00
|
|
|
|
2018-07-31 03:12:45 +08:00
|
|
|
hsErr := conn.Handshake()
|
|
|
|
|
if hsErr != nil {
|
|
|
|
|
return nil, hsErr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certs := conn.ConnectionState().PeerCertificates
|
|
|
|
|
|
|
|
|
|
return certs, nil
|
|
|
|
|
case "file":
|
2021-09-29 05:16:32 +08:00
|
|
|
content, err := os.ReadFile(u.Path)
|
2018-07-31 03:12:45 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-11-26 07:38:57 +08:00
|
|
|
var certs []*x509.Certificate
|
|
|
|
|
for {
|
|
|
|
|
block, rest := pem.Decode(bytes.TrimSpace(content))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to parse certificate PEM")
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 02:49:14 +08:00
|
|
|
if block.Type == "CERTIFICATE" {
|
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
certs = append(certs, cert)
|
2019-11-26 07:38:57 +08:00
|
|
|
}
|
2021-03-26 01:57:01 +08:00
|
|
|
if len(rest) == 0 {
|
2019-11-26 07:38:57 +08:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
content = rest
|
2018-07-31 03:12:45 +08:00
|
|
|
}
|
2022-06-16 00:46:26 +08:00
|
|
|
return certs, nil
|
|
|
|
|
case "smtp":
|
|
|
|
|
ipConn, err := net.DialTimeout("tcp", u.Host, timeout)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer ipConn.Close()
|
|
|
|
|
|
2022-08-06 02:54:23 +08:00
|
|
|
downloadTLSCfg := c.tlsCfg.Clone()
|
2023-02-01 03:05:05 +08:00
|
|
|
downloadTLSCfg.ServerName = c.serverName(u)
|
2022-08-06 02:54:23 +08:00
|
|
|
downloadTLSCfg.InsecureSkipVerify = true
|
2022-06-16 00:46:26 +08:00
|
|
|
|
|
|
|
|
smtpConn, err := smtp.NewClient(ipConn, u.Host)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-06 02:54:23 +08:00
|
|
|
err = smtpConn.Hello(downloadTLSCfg.ServerName)
|
2022-06-16 00:46:26 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id, err := smtpConn.Text.Cmd("STARTTLS")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smtpConn.Text.StartResponse(id)
|
|
|
|
|
defer smtpConn.Text.EndResponse(id)
|
|
|
|
|
_, _, err = smtpConn.Text.ReadResponse(220)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("did not get 220 after STARTTLS: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-06 02:54:23 +08:00
|
|
|
tlsConn := tls.Client(ipConn, downloadTLSCfg)
|
2022-06-16 00:46:26 +08:00
|
|
|
defer tlsConn.Close()
|
|
|
|
|
|
|
|
|
|
hsErr := tlsConn.Handshake()
|
|
|
|
|
if hsErr != nil {
|
|
|
|
|
return nil, hsErr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certs := tlsConn.ConnectionState().PeerCertificates
|
|
|
|
|
|
2019-11-26 07:38:57 +08:00
|
|
|
return certs, nil
|
2018-07-31 03:12:45 +08:00
|
|
|
default:
|
2020-05-16 06:43:32 +08:00
|
|
|
return nil, fmt.Errorf("unsupported scheme '%s' in location %s", u.Scheme, u.String())
|
2018-07-31 03:12:45 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getFields(cert *x509.Certificate, now time.Time) map[string]interface{} {
|
|
|
|
|
age := int(now.Sub(cert.NotBefore).Seconds())
|
|
|
|
|
expiry := int(cert.NotAfter.Sub(now).Seconds())
|
|
|
|
|
startdate := cert.NotBefore.Unix()
|
|
|
|
|
enddate := cert.NotAfter.Unix()
|
|
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
|
|
|
|
"age": age,
|
|
|
|
|
"expiry": expiry,
|
|
|
|
|
"startdate": startdate,
|
|
|
|
|
"enddate": enddate,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fields
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 02:04:55 +08:00
|
|
|
func getTags(cert *x509.Certificate, location string) map[string]string {
|
2018-10-19 14:32:43 +08:00
|
|
|
tags := map[string]string{
|
2019-11-27 02:04:55 +08:00
|
|
|
"source": location,
|
|
|
|
|
"common_name": cert.Subject.CommonName,
|
|
|
|
|
"serial_number": cert.SerialNumber.Text(16),
|
|
|
|
|
"signature_algorithm": cert.SignatureAlgorithm.String(),
|
|
|
|
|
"public_key_algorithm": cert.PublicKeyAlgorithm.String(),
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
2019-11-27 02:04:55 +08:00
|
|
|
if len(cert.Subject.Organization) > 0 {
|
|
|
|
|
tags["organization"] = cert.Subject.Organization[0]
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
2019-11-27 02:04:55 +08:00
|
|
|
if len(cert.Subject.OrganizationalUnit) > 0 {
|
|
|
|
|
tags["organizational_unit"] = cert.Subject.OrganizationalUnit[0]
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
2019-11-27 02:04:55 +08:00
|
|
|
if len(cert.Subject.Country) > 0 {
|
|
|
|
|
tags["country"] = cert.Subject.Country[0]
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
2019-11-27 02:04:55 +08:00
|
|
|
if len(cert.Subject.Province) > 0 {
|
|
|
|
|
tags["province"] = cert.Subject.Province[0]
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
2019-11-27 02:04:55 +08:00
|
|
|
if len(cert.Subject.Locality) > 0 {
|
|
|
|
|
tags["locality"] = cert.Subject.Locality[0]
|
2018-10-19 14:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
2019-11-27 02:04:55 +08:00
|
|
|
tags["issuer_common_name"] = cert.Issuer.CommonName
|
|
|
|
|
tags["issuer_serial_number"] = cert.Issuer.SerialNumber
|
|
|
|
|
|
|
|
|
|
san := append(cert.DNSNames, cert.EmailAddresses...)
|
|
|
|
|
for _, ip := range cert.IPAddresses {
|
|
|
|
|
san = append(san, ip.String())
|
|
|
|
|
}
|
|
|
|
|
for _, uri := range cert.URIs {
|
|
|
|
|
san = append(san, uri.String())
|
|
|
|
|
}
|
|
|
|
|
tags["san"] = strings.Join(san, ",")
|
|
|
|
|
|
2018-10-19 14:32:43 +08:00
|
|
|
return tags
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 05:31:15 +08:00
|
|
|
func (c *X509Cert) collectCertURLs() ([]*url.URL, error) {
|
|
|
|
|
var urls []*url.URL
|
|
|
|
|
|
|
|
|
|
for _, path := range c.globpaths {
|
|
|
|
|
files := path.Match()
|
|
|
|
|
if len(files) <= 0 {
|
|
|
|
|
c.Log.Errorf("could not find file: %v", path)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, file := range files {
|
|
|
|
|
file = "file://" + file
|
|
|
|
|
u, err := url.Parse(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return urls, fmt.Errorf("failed to parse cert location - %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
urls = append(urls, u)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return urls, nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-31 03:12:45 +08:00
|
|
|
func init() {
|
|
|
|
|
inputs.Add("x509_cert", func() telegraf.Input {
|
|
|
|
|
return &X509Cert{
|
2022-11-18 23:23:07 +08:00
|
|
|
Timeout: config.Duration(5 * time.Second),
|
2018-07-31 03:12:45 +08:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|