Wildcard support for x509_cert files (#6952)
* Accept standard unix glob matching rules * comply with indentation * update readme * move globing expand and url parsing into Init() * chore: rebase branch on upstream master * rename refreshFilePaths to expandFilePaths * expandFilePaths handles '/path/to/*.pem' and 'files:///path/to/*.pem' * update sample config * fix: recompile files globing pattern at every gather tic * add var globFilePathsToUrls to stack files path * add var globpaths to stack compiled globpath * rework sourcesToURLs to compile files path and stack them * rename expandFilePaths to expandFilePathsToUrls * rework expandFilePathsToUrls to only match compiled globpath * rework the `Gather` ticker to match globpath at each call * fix: comply with requested changes * add specifics regarding relative paths in sample config * add logger and use it in expandFilePathsToUrls() * precompile glob for `files://`, `/` and `://` * fix: update README to match last changes * fix: comply with last requested changes * rename expandFilePathsToUrls() to collectCertURLs() * collectCertURLs() now returns []*url.URL to avoid extra field globFilePathsToUrls in structure * update the Gather() ticker accordingly * fix(windows): do not try to compile glopath for windows path as it's not supposed to be supported by the OS * fix(ci): apply go fmt * fix(ci): empty-lines/import-shadowing Co-authored-by: Anthony LE BERRE <aleberre@vente-privee.com>
This commit is contained in:
parent
f267f342ae
commit
b2b361356e
|
|
@ -9,8 +9,10 @@ file or network connection.
|
||||||
```toml
|
```toml
|
||||||
# Reads metrics from a SSL certificate
|
# Reads metrics from a SSL certificate
|
||||||
[[inputs.x509_cert]]
|
[[inputs.x509_cert]]
|
||||||
## List certificate sources
|
## List certificate sources, support wildcard expands for files
|
||||||
sources = ["/etc/ssl/certs/ssl-cert-snakeoil.pem", "https://example.org:443"]
|
## Prefix your entry with 'file://' if you intend to use relative paths
|
||||||
|
sources = ["/etc/ssl/certs/ssl-cert-snakeoil.pem", "tcp://example.org:443",
|
||||||
|
"/etc/mycerts/*.mydomain.org.pem", "file:///path/to/*.pem"]
|
||||||
|
|
||||||
## Timeout for SSL connection
|
## Timeout for SSL connection
|
||||||
# timeout = "5s"
|
# timeout = "5s"
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,16 @@ import (
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/internal"
|
"github.com/influxdata/telegraf/internal"
|
||||||
|
"github.com/influxdata/telegraf/internal/globpath"
|
||||||
_tls "github.com/influxdata/telegraf/plugins/common/tls"
|
_tls "github.com/influxdata/telegraf/plugins/common/tls"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sampleConfig = `
|
const sampleConfig = `
|
||||||
## List certificate sources
|
## List certificate sources
|
||||||
sources = ["/etc/ssl/certs/ssl-cert-snakeoil.pem", "tcp://example.org:443"]
|
## Prefix your entry with 'file://' if you intend to use relative paths
|
||||||
|
sources = ["/etc/ssl/certs/ssl-cert-snakeoil.pem", "tcp://example.org:443",
|
||||||
|
"/etc/mycerts/*.mydomain.org.pem", "file:///path/to/*.pem"]
|
||||||
|
|
||||||
## Timeout for SSL connection
|
## Timeout for SSL connection
|
||||||
# timeout = "5s"
|
# timeout = "5s"
|
||||||
|
|
@ -45,6 +48,9 @@ type X509Cert struct {
|
||||||
ServerName string `toml:"server_name"`
|
ServerName string `toml:"server_name"`
|
||||||
tlsCfg *tls.Config
|
tlsCfg *tls.Config
|
||||||
_tls.ClientConfig
|
_tls.ClientConfig
|
||||||
|
locations []*url.URL
|
||||||
|
globpaths []*globpath.GlobPath
|
||||||
|
Log telegraf.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description returns description of the plugin.
|
// Description returns description of the plugin.
|
||||||
|
|
@ -57,20 +63,31 @@ func (c *X509Cert) SampleConfig() string {
|
||||||
return sampleConfig
|
return sampleConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *X509Cert) locationToURL(location string) (*url.URL, error) {
|
func (c *X509Cert) sourcesToURLs() error {
|
||||||
if strings.HasPrefix(location, "/") {
|
for _, source := range c.Sources {
|
||||||
location = "file://" + location
|
if strings.HasPrefix(source, "file://") ||
|
||||||
}
|
strings.HasPrefix(source, "/") ||
|
||||||
if strings.Index(location, ":\\") == 1 {
|
strings.Index(source, ":\\") != 1 {
|
||||||
location = "file://" + filepath.ToSlash(location)
|
source = filepath.ToSlash(strings.TrimPrefix(source, "file://"))
|
||||||
}
|
g, err := globpath.Compile(source)
|
||||||
|
|
||||||
u, err := url.Parse(location)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse cert location - %s", err.Error())
|
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
return u, nil
|
c.locations = append(c.locations, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *X509Cert) serverName(u *url.URL) (string, error) {
|
func (c *X509Cert) serverName(u *url.URL) (string, error) {
|
||||||
|
|
@ -204,25 +221,45 @@ func getTags(cert *x509.Certificate, location string) map[string]string {
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// Gather adds metrics into the accumulator.
|
// Gather adds metrics into the accumulator.
|
||||||
func (c *X509Cert) Gather(acc telegraf.Accumulator) error {
|
func (c *X509Cert) Gather(acc telegraf.Accumulator) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
collectedUrls, err := c.collectCertURLs()
|
||||||
for _, location := range c.Sources {
|
|
||||||
u, err := c.locationToURL(location)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acc.AddError(err)
|
acc.AddError(fmt.Errorf("cannot get file: %s", err.Error()))
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
certs, err := c.getCert(u, c.Timeout.Duration)
|
for _, location := range append(c.locations, collectedUrls...) {
|
||||||
|
certs, err := c.getCert(location, c.Timeout.Duration*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acc.AddError(fmt.Errorf("cannot get SSL cert '%s': %s", location, err.Error()))
|
acc.AddError(fmt.Errorf("cannot get SSL cert '%s': %s", location, err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, cert := range certs {
|
for i, cert := range certs {
|
||||||
fields := getFields(cert, now)
|
fields := getFields(cert, now)
|
||||||
tags := getTags(cert, location)
|
tags := getTags(cert, location.String())
|
||||||
|
|
||||||
// The first certificate is the leaf/end-entity certificate which needs DNS
|
// The first certificate is the leaf/end-entity certificate which needs DNS
|
||||||
// name validation against the URL hostname.
|
// name validation against the URL hostname.
|
||||||
|
|
@ -231,7 +268,7 @@ func (c *X509Cert) Gather(acc telegraf.Accumulator) error {
|
||||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||||
}
|
}
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
opts.DNSName, err = c.serverName(u)
|
opts.DNSName, err = c.serverName(location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -263,6 +300,11 @@ func (c *X509Cert) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *X509Cert) Init() error {
|
func (c *X509Cert) Init() error {
|
||||||
|
err := c.sourcesToURLs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
tlsCfg, err := c.ClientConfig.TLSConfig()
|
tlsCfg, err := c.ClientConfig.TLSConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue