-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added a new input plugin to check SSL certs #1762
Changes from all commits
3162925
0b588b5
2e74ebc
d72d81f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Check SSL Input Plugin | ||
|
||
This input plugin will return how much time (in seconds) left for a SSL cert to expire. | ||
Warning, this check doesnt verify if SSL is valid/secure or not. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should recommend that the user use a increased interval, since 10s default would be too small. |
||
|
||
### Configuration: | ||
|
||
``` | ||
# SSL request given a list of servers (server:port) and a timeout | ||
[[inputs.check_ssl]] | ||
## Servers ( Default [] ) | ||
servers = ["github.com:443"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't use a real site as an example, since I'm sure they wouldn't appreciate being polled by Telegraf, you can use example.org instead. Please do this throughout the pull request. What about other protocols, should this start with |
||
## Set timeout (default 5 seconds) | ||
timeout = "5s" | ||
``` | ||
|
||
### Measurements & Fields: | ||
|
||
- ssl_cert | ||
- time_to_expire (int) # seconds left for the SSL cert to expire | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Appears to be a float, you can format this like What do you think about naming this |
||
|
||
### Tags: | ||
|
||
- All measurements have the following tags: | ||
- server | ||
|
||
### Example Output: | ||
|
||
``` | ||
$ ./telegraf -config telegraf.conf -input-filter check_ssl -test | ||
> ssl_cert,server=www.google.com:443 time_to_expire=6185474.476944118 1468864305580596685 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package ssl | ||
|
||
import ( | ||
"crypto/tls" | ||
"crypto/x509" | ||
"errors" | ||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
"net" | ||
"time" | ||
) | ||
|
||
type CheckExpire struct { | ||
// Server to check | ||
Servers []string | ||
|
||
// Timeout in seconds. 0 means no timeout | ||
Timeout string | ||
} | ||
|
||
// Description returns the plugin Description | ||
func (c *CheckExpire) Description() string { | ||
return "time left until SSL cert is expired" | ||
} | ||
|
||
var sampleConfig = ` | ||
## server name list default [] ) | ||
servers = ["github.com:443"] | ||
## Set timeout (default 5 seconds) | ||
timeout = "5s" | ||
` | ||
|
||
// SampleConfig returns the plugin SampleConfig | ||
func (c *CheckExpire) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
// Connect to server and retrieve chain certificates | ||
func (c *CheckExpire) checkHost(server string) ([]*x509.Certificate, error) { | ||
|
||
tout, err := time.ParseDuration(c.Timeout) | ||
if err != nil { | ||
return nil, err | ||
} | ||
//Connect network | ||
ipConn, err := net.DialTimeout("tcp", server, tout) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer ipConn.Close() | ||
|
||
// Configure tls to not verify if site is secure | ||
config := tls.Config{ServerName: server, InsecureSkipVerify: true} | ||
|
||
// Connect to tls | ||
conn := tls.Client(ipConn, &config) | ||
defer conn.Close() | ||
|
||
// Handshake with TLS to get certs | ||
hsErr := conn.Handshake() | ||
if hsErr != nil { | ||
return nil, hsErr | ||
} | ||
|
||
certs := conn.ConnectionState().PeerCertificates | ||
|
||
if certs == nil || len(certs) < 1 { | ||
return nil, errors.New("Could not get server's certificate from the TLS connection.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Include the name of the server that caused this. |
||
} | ||
return certs, nil | ||
|
||
} | ||
|
||
// Gather gets all metric fields and tags and returns any errors it encounters | ||
func (c *CheckExpire) Gather(acc telegraf.Accumulator) error { | ||
for _, server := range c.Servers { | ||
// Prepare data | ||
tags := map[string]string{"server": server} | ||
// Gather data | ||
var timeToExpire time.Duration | ||
timeNow := time.Now() | ||
certs, err := c.checkHost(server) | ||
acc.AddError(err) | ||
if err != nil { | ||
timeToExpire = 0 | ||
} else { | ||
timeToExpire = certs[0].NotAfter.Sub(timeNow) | ||
} | ||
fields := map[string]interface{}{"time_to_expire": timeToExpire.Seconds()} | ||
// Add metrics | ||
acc.AddFields("ssl_cert", fields, tags) | ||
} | ||
return nil | ||
} | ||
|
||
func init() { | ||
inputs.Add("check_ssl", func() telegraf.Input { | ||
return &CheckExpire{Timeout: "5s"} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ssl | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/influxdata/telegraf/testutil" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var servers = []string{"github.com:443"} | ||
var server_of_timeout = []string{"8.8.8.8:443"} | ||
var tout = "1s" | ||
|
||
func TestGathering(t *testing.T) { | ||
if testing.Short() { | ||
t.Skip("Skipping network-dependent test in short mode.") | ||
} | ||
var sslConfig = CheckExpire{ | ||
Servers: servers, | ||
Timeout: tout, | ||
} | ||
var acc testutil.Accumulator | ||
tags := map[string]string{ | ||
"server": "github.com:443", | ||
} | ||
fields := map[string]interface{}{} | ||
|
||
err := sslConfig.Gather(&acc) | ||
assert.NoError(t, err) | ||
metric, ok := acc.Get("ssl_cert") | ||
require.True(t, ok) | ||
expireTime, _ := metric.Fields["time_to_expire"] | ||
|
||
assert.NotEqual(t, 0, expireTime) | ||
fields["time_to_expire"] = expireTime | ||
acc.AssertContainsTaggedFields(t, "ssl_cert", fields, tags) | ||
} | ||
|
||
func TestGatheringTimeout(t *testing.T) { | ||
if testing.Short() { | ||
t.Skip("Skipping network-dependent test in short mode.") | ||
} | ||
var sslConfig = CheckExpire{ | ||
Servers: server_of_timeout, | ||
Timeout: tout, | ||
} | ||
var acc testutil.Accumulator | ||
var err error | ||
|
||
channel := make(chan error, 1) | ||
go func() { | ||
channel <- sslConfig.Gather(&acc) | ||
}() | ||
select { | ||
case res := <-channel: | ||
err = res | ||
case <-time.After(time.Second * 5): | ||
err = nil | ||
} | ||
|
||
assert.Error(t, err) | ||
assert.Contains(t, err.Error(), "i/o timeout") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that ssl is the right name for this, maybe it should be x509 or cert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danielnelson So, what exactly should I change? Everything? the directory, file names and the references to them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think we need to change all of this.