feat(http): Allow secrets in headers (#14743)

This commit is contained in:
Lars Stegman 2024-02-12 23:04:49 +01:00 committed by GitHub
parent 616ad305fe
commit 4f0ac6e155
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 46 additions and 26 deletions

View File

@ -17,8 +17,8 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Secret-store support
This plugin supports secrets from secret-stores for the `username`, `password`
and `token` option.
This plugin supports secrets from secret-stores for the `username`, `password`,
`token` and `headers` option.
See the [secret-store documentation][SECRETSTORE] for more details on how
to use them.

View File

@ -38,9 +38,9 @@ type HTTP struct {
Token config.Secret `toml:"token"`
TokenFile string `toml:"token_file"`
Headers map[string]string `toml:"headers"`
SuccessStatusCodes []int `toml:"success_status_codes"`
Log telegraf.Logger `toml:"-"`
Headers map[string]*config.Secret `toml:"headers"`
SuccessStatusCodes []int `toml:"success_status_codes"`
Log telegraf.Logger `toml:"-"`
httpconfig.HTTPClientConfig
@ -142,11 +142,19 @@ func (h *HTTP) gatherURL(acc telegraf.Accumulator, url string) error {
}
for k, v := range h.Headers {
if strings.EqualFold(k, "host") {
request.Host = v
} else {
request.Header.Add(k, v)
secret, err := v.Get()
if err != nil {
return err
}
headerVal := secret.String()
if strings.EqualFold(k, "host") {
request.Host = headerVal
} else {
request.Header.Add(k, headerVal)
}
secret.Destroy()
}
if err := h.setRequestAuth(request); err != nil {

View File

@ -3,6 +3,7 @@ package http_test
import (
"compress/gzip"
"fmt"
"github.com/influxdata/telegraf/config"
"io"
"math/rand"
"net"
@ -82,9 +83,10 @@ func TestHTTPHeaders(t *testing.T) {
defer fakeServer.Close()
address := fakeServer.URL + "/endpoint"
headerSecret := config.NewSecret([]byte(headerValue))
plugin := &httpplugin.HTTP{
URLs: []string{address},
Headers: map[string]string{header: headerValue},
Headers: map[string]*config.Secret{header: &headerSecret},
Log: testutil.Logger{},
}
@ -116,7 +118,7 @@ func TestHTTPContentLengthHeader(t *testing.T) {
address := fakeServer.URL + "/endpoint"
plugin := &httpplugin.HTTP{
URLs: []string{address},
Headers: map[string]string{},
Headers: map[string]*config.Secret{},
Body: "{}",
Log: testutil.Logger{},
}

View File

@ -15,8 +15,8 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Secret-store support
This plugin supports secrets from secret-stores for the `username` and
`password` option.
This plugin supports secrets from secret-stores for the `username`, `password`
and `headers` option.
See the [secret-store documentation][SECRETSTORE] for more details on how
to use them.

View File

@ -43,15 +43,15 @@ const (
)
type HTTP struct {
URL string `toml:"url"`
Method string `toml:"method"`
Username config.Secret `toml:"username"`
Password config.Secret `toml:"password"`
Headers map[string]string `toml:"headers"`
ContentEncoding string `toml:"content_encoding"`
UseBatchFormat bool `toml:"use_batch_format"`
AwsService string `toml:"aws_service"`
NonRetryableStatusCodes []int `toml:"non_retryable_statuscodes"`
URL string `toml:"url"`
Method string `toml:"method"`
Username config.Secret `toml:"username"`
Password config.Secret `toml:"password"`
Headers map[string]*config.Secret `toml:"headers"`
ContentEncoding string `toml:"content_encoding"`
UseBatchFormat bool `toml:"use_batch_format"`
AwsService string `toml:"aws_service"`
NonRetryableStatusCodes []int `toml:"non_retryable_statuscodes"`
httpconfig.HTTPClientConfig
Log telegraf.Logger `toml:"-"`
@ -204,11 +204,20 @@ func (h *HTTP) writeMetric(reqBody []byte) error {
if h.ContentEncoding == "gzip" {
req.Header.Set("Content-Encoding", "gzip")
}
for k, v := range h.Headers {
if strings.EqualFold(k, "host") {
req.Host = v
secret, err := v.Get()
if err != nil {
return err
}
req.Header.Set(k, v)
headerVal := secret.String()
if strings.EqualFold(k, "host") {
req.Host = headerVal
}
req.Header.Set(k, headerVal)
secret.Destroy()
}
resp, err := h.client.Do(req)

View File

@ -290,6 +290,7 @@ func TestContentType(t *testing.T) {
u, err := url.Parse("http://" + ts.Listener.Addr().String())
require.NoError(t, err)
headerSecret := config.NewSecret([]byte("application/json"))
tests := []struct {
name string
plugin *HTTP
@ -306,7 +307,7 @@ func TestContentType(t *testing.T) {
name: "overwrite content_type",
plugin: &HTTP{
URL: u.String(),
Headers: map[string]string{"Content-Type": "application/json"},
Headers: map[string]*config.Secret{"Content-Type": &headerSecret},
},
expected: "application/json",
},