feat(outputs.influxdb_v2): Support secrets in http_headers values (#16746)

This commit is contained in:
Lars Stegman 2025-04-10 19:36:30 +02:00 committed by GitHub
parent 8c5114b067
commit 73d092a566
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 58 additions and 42 deletions

View File

@ -19,9 +19,9 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Secret-store support
This plugin supports secrets from secret-stores for the `token` option.
See the [secret-store documentation][SECRETSTORE] for more details on how
to use them.
This plugin supports secrets from secret-stores for the `token` and
`http_headers` option. See the [secret-store documentation][SECRETSTORE] for
more details on how to use them.
[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets

View File

@ -53,7 +53,7 @@ type httpClient struct {
bucketTag string
excludeBucketTag bool
timeout time.Duration
headers map[string]string
headers map[string]*config.Secret
proxy *url.URL
userAgent string
contentEncoding string
@ -72,11 +72,12 @@ type httpClient struct {
func (c *httpClient) Init() error {
if c.headers == nil {
c.headers = make(map[string]string, 1)
c.headers = make(map[string]*config.Secret, 1)
}
if _, ok := c.headers["User-Agent"]; !ok {
c.headers["User-Agent"] = c.userAgent
sec := config.NewSecret([]byte(c.userAgent))
c.headers["User-Agent"] = &sec
}
var proxy func(*http.Request) (*url.URL, error)
@ -279,7 +280,9 @@ func (c *httpClient) writeBatch(ctx context.Context, bucket string, metrics []te
req.Header.Set("Authorization", "Token "+token.String())
token.Destroy()
c.addHeaders(req)
if err := c.addHeaders(req); err != nil {
return fmt.Errorf("adding headers failed: %w", err)
}
// Execute the request
c.rateLimiter.Accept(ratets, used)
@ -395,14 +398,23 @@ func (c *httpClient) getRetryDuration(headers http.Header) time.Duration {
return time.Duration(retry*1000) * time.Millisecond
}
func (c *httpClient) addHeaders(req *http.Request) {
func (c *httpClient) addHeaders(req *http.Request) error {
for header, value := range c.headers {
secret, err := value.Get()
if err != nil {
return err
}
headerVal := secret.String()
secret.Destroy()
if strings.EqualFold(header, "host") {
req.Host = value
req.Host = headerVal
} else {
req.Header.Set(header, value)
req.Header.Set(header, headerVal)
}
}
return nil
}
func makeWriteURL(loc url.URL, params url.Values, bucket string) string {

View File

@ -190,17 +190,19 @@ func TestExponentialBackoffCalculationWithRetryAfter(t *testing.T) {
func TestHeadersDoNotOverrideConfig(t *testing.T) {
testURL, err := url.Parse("https://localhost:8181")
require.NoError(t, err)
authHeader := config.NewSecret([]byte("Bearer foo"))
userAgentHeader := config.NewSecret([]byte("foo"))
c := &httpClient{
headers: map[string]string{
"Authorization": "Bearer foo",
"User-Agent": "foo",
headers: map[string]*config.Secret{
"Authorization": &authHeader,
"User-Agent": &userAgentHeader,
},
// URL to make Init() happy
url: testURL,
}
require.NoError(t, c.Init())
require.Equal(t, "Bearer foo", c.headers["Authorization"])
require.Equal(t, "foo", c.headers["User-Agent"])
require.Equal(t, &authHeader, c.headers["Authorization"])
require.Equal(t, &userAgentHeader, c.headers["User-Agent"])
}
// goos: linux

View File

@ -27,23 +27,23 @@ import (
var sampleConfig string
type InfluxDB struct {
URLs []string `toml:"urls"`
LocalAddr string `toml:"local_address"`
Token config.Secret `toml:"token"`
Organization string `toml:"organization"`
Bucket string `toml:"bucket"`
BucketTag string `toml:"bucket_tag"`
ExcludeBucketTag bool `toml:"exclude_bucket_tag"`
Timeout config.Duration `toml:"timeout"`
HTTPHeaders map[string]string `toml:"http_headers"`
HTTPProxy string `toml:"http_proxy"`
UserAgent string `toml:"user_agent"`
ContentEncoding string `toml:"content_encoding"`
UintSupport bool `toml:"influx_uint_support"`
OmitTimestamp bool `toml:"influx_omit_timestamp"`
PingTimeout config.Duration `toml:"ping_timeout"`
ReadIdleTimeout config.Duration `toml:"read_idle_timeout"`
Log telegraf.Logger `toml:"-"`
URLs []string `toml:"urls"`
LocalAddr string `toml:"local_address"`
Token config.Secret `toml:"token"`
Organization string `toml:"organization"`
Bucket string `toml:"bucket"`
BucketTag string `toml:"bucket_tag"`
ExcludeBucketTag bool `toml:"exclude_bucket_tag"`
Timeout config.Duration `toml:"timeout"`
HTTPHeaders map[string]*config.Secret `toml:"http_headers"`
HTTPProxy string `toml:"http_proxy"`
UserAgent string `toml:"user_agent"`
ContentEncoding string `toml:"content_encoding"`
UintSupport bool `toml:"influx_uint_support"`
OmitTimestamp bool `toml:"influx_omit_timestamp"`
PingTimeout config.Duration `toml:"ping_timeout"`
ReadIdleTimeout config.Duration `toml:"read_idle_timeout"`
Log telegraf.Logger `toml:"-"`
commontls.ClientConfig
ratelimiter.RateLimitConfig

View File

@ -64,13 +64,15 @@ func TestInit(t *testing.T) {
}
}
var headerSecret = config.NewSecret([]byte("y"))
func TestConnectFail(t *testing.T) {
tests := []*influxdb.InfluxDB{
{
URLs: []string{"!@#$qwert"},
HTTPProxy: "http://localhost:8086",
HTTPHeaders: map[string]string{
"x": "y",
HTTPHeaders: map[string]*config.Secret{
"x": &headerSecret,
},
},
@ -78,8 +80,8 @@ func TestConnectFail(t *testing.T) {
URLs: []string{"http://localhost:1234"},
HTTPProxy: "!@#$%^&*()_+",
HTTPHeaders: map[string]string{
"x": "y",
HTTPHeaders: map[string]*config.Secret{
"x": &headerSecret,
},
},
@ -87,8 +89,8 @@ func TestConnectFail(t *testing.T) {
URLs: []string{"!@#$%^&*()_+"},
HTTPProxy: "http://localhost:8086",
HTTPHeaders: map[string]string{
"x": "y",
HTTPHeaders: map[string]*config.Secret{
"x": &headerSecret,
},
},
@ -96,8 +98,8 @@ func TestConnectFail(t *testing.T) {
URLs: []string{":::@#$qwert"},
HTTPProxy: "http://localhost:8086",
HTTPHeaders: map[string]string{
"x": "y",
HTTPHeaders: map[string]*config.Secret{
"x": &headerSecret,
},
},
}
@ -115,8 +117,8 @@ func TestConnect(t *testing.T) {
{
URLs: []string{"http://localhost:1234"},
HTTPProxy: "http://localhost:8086",
HTTPHeaders: map[string]string{
"x": "y",
HTTPHeaders: map[string]*config.Secret{
"x": &headerSecret,
},
},
}