-
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
Add mutual TLS support to prometheus_client output plugin #5473
Changes from 2 commits
c9fb1fc
05af32b
a85833a
b34ad9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ import ( | |
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/internal" | ||
"github.com/influxdata/telegraf/internal/tls" | ||
"github.com/influxdata/telegraf/plugins/outputs" | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/prometheus/client_golang/prometheus/promhttp" | ||
|
@@ -56,8 +57,6 @@ type MetricFamily struct { | |
|
||
type PrometheusClient struct { | ||
Listen string | ||
TLSCert string `toml:"tls_cert"` | ||
TLSKey string `toml:"tls_key"` | ||
BasicUsername string `toml:"basic_username"` | ||
BasicPassword string `toml:"basic_password"` | ||
IPRange []string `toml:"ip_range"` | ||
|
@@ -67,6 +66,8 @@ type PrometheusClient struct { | |
StringAsLabel bool `toml:"string_as_label"` | ||
ExportTimestamp bool `toml:"export_timestamp"` | ||
|
||
tls.ServerConfig | ||
|
||
server *http.Server | ||
|
||
sync.Mutex | ||
|
@@ -105,6 +106,12 @@ var sampleConfig = ` | |
## If set, enable TLS with the given certificate. | ||
# tls_cert = "/etc/ssl/telegraf.crt" | ||
# tls_key = "/etc/ssl/telegraf.key" | ||
|
||
## If set, enable TLS client authentication with the given CA. | ||
# tls_ca = "/etc/ssl/telegraf_ca.crt" | ||
|
||
## Boolean value indicating whether or not to skip SSL verification | ||
# insecure_skip_verify = false | ||
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. Remove this option, it's not available for the server configuration. Don't forget to update the README as well. 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. Done |
||
|
||
## Export metric collection time. | ||
# export_timestamp = false | ||
|
@@ -184,15 +191,20 @@ func (p *PrometheusClient) Connect() error { | |
mux.Handle(p.Path, p.auth(promhttp.HandlerFor( | ||
registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}))) | ||
|
||
tlsConfig, err := p.TLSConfig() | ||
if err != nil { | ||
return err | ||
} | ||
p.server = &http.Server{ | ||
Addr: p.Listen, | ||
Handler: mux, | ||
Addr: p.Listen, | ||
Handler: mux, | ||
TLSConfig: tlsConfig, | ||
} | ||
|
||
go func() { | ||
var err error | ||
if p.TLSCert != "" && p.TLSKey != "" { | ||
err = p.server.ListenAndServeTLS(p.TLSCert, p.TLSKey) | ||
err = p.server.ListenAndServeTLS("", "") | ||
} else { | ||
err = p.server.ListenAndServe() | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package prometheus_client_test | ||
|
||
import ( | ||
"crypto/tls" | ||
"fmt" | ||
"github.com/influxdata/telegraf/plugins/outputs/prometheus_client" | ||
"github.com/influxdata/telegraf/testutil" | ||
"github.com/influxdata/toml" | ||
. "github.com/onsi/gomega" | ||
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 will need to remove this dependency, I don't want to add it only for testing this one aspect. 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. Replaced with require |
||
"net/http" | ||
"testing" | ||
) | ||
|
||
var pki = testutil.NewPKI("../../../testutil/pki") | ||
|
||
var configWithTLS = fmt.Sprintf(` | ||
listen = "127.0.0.1:9090" | ||
tls_allowed_cacerts = ["%s"] | ||
tls_cert = "%s" | ||
tls_key = "%s" | ||
`, pki.TLSServerConfig().TLSAllowedCACerts[0], pki.TLSServerConfig().TLSCert, pki.TLSServerConfig().TLSKey) | ||
|
||
var configWithoutTLS = ` | ||
listen = "127.0.0.1:9090" | ||
` | ||
|
||
type PrometheusClientTestContext struct { | ||
Output *prometheus_client.PrometheusClient | ||
Accumulator *testutil.Accumulator | ||
Client *http.Client | ||
|
||
*GomegaWithT | ||
} | ||
|
||
func TestWorksWithoutTLS(t *testing.T) { | ||
tc := buildTestContext(t, []byte(configWithoutTLS)) | ||
err := tc.Output.Connect() | ||
defer tc.Output.Close() | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
var response *http.Response | ||
tc.Eventually(func() bool { | ||
response, err = tc.Client.Get("http://localhost:9090/metrics") | ||
return err == nil | ||
}, "5s").Should(BeTrue()) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
tc.Expect(response.StatusCode).To(Equal(http.StatusOK)) | ||
} | ||
|
||
func TestWorksWithTLS(t *testing.T) { | ||
tc := buildTestContext(t, []byte(configWithTLS)) | ||
err := tc.Output.Connect() | ||
defer tc.Output.Close() | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
var response *http.Response | ||
tc.Eventually(func() bool { | ||
response, err = tc.Client.Get("https://localhost:9090/metrics") | ||
return err == nil | ||
}, "5s").Should(BeTrue()) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
tc.Expect(response.StatusCode).To(Equal(http.StatusOK)) | ||
|
||
response, err = tc.Client.Get("http://localhost:9090/metrics") | ||
|
||
tc.Expect(err).To(HaveOccurred()) | ||
|
||
tr := &http.Transport{ | ||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | ||
} | ||
|
||
client := &http.Client{Transport: tr} | ||
response, err = client.Get("https://localhost:9090/metrics") | ||
|
||
tc.Expect(err).To(HaveOccurred()) | ||
} | ||
|
||
func buildTestContext(t *testing.T, config []byte) *PrometheusClientTestContext { | ||
output := prometheus_client.NewClient() | ||
err := toml.Unmarshal(config, output) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
var ( | ||
httpClient *http.Client | ||
) | ||
|
||
if len(output.TLSAllowedCACerts) != 0 { | ||
httpClient = buildClientWithTLS(output) | ||
} else { | ||
httpClient = buildClientWithoutTLS() | ||
} | ||
|
||
return &PrometheusClientTestContext{ | ||
Output: output, | ||
Accumulator: &testutil.Accumulator{}, | ||
Client: httpClient, | ||
GomegaWithT: NewGomegaWithT(t), | ||
} | ||
} | ||
|
||
func buildClientWithoutTLS() *http.Client { | ||
return &http.Client{} | ||
} | ||
|
||
func buildClientWithTLS(output *prometheus_client.PrometheusClient) *http.Client { | ||
tlsConfig, err := pki.TLSClientConfig().TLSConfig() | ||
if err != nil { | ||
panic(err) | ||
} | ||
transport := &http.Transport{TLSClientConfig: tlsConfig} | ||
return &http.Client{Transport: transport} | ||
} |
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.
Update this option:
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.
Done