diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index b3985ae5b24..8eefb2a421b 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -301,6 +301,7 @@ https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff] - Add TLS support to MongoDB module. {pull}7401[7401] - Added Traefik module with health metricset. {pull}7413[7413] - Add Elasticsearch ml_job metricsets. {pull}7196[7196] +- Add support for bearer token files to HTTP helper. {pull}7527[7527] *Packetbeat* diff --git a/metricbeat/autodiscover/appender/kubernetes/token/token.go b/metricbeat/autodiscover/appender/kubernetes/token/token.go index 2b6deb3bd93..5471f874ca9 100644 --- a/metricbeat/autodiscover/appender/kubernetes/token/token.go +++ b/metricbeat/autodiscover/appender/kubernetes/token/token.go @@ -41,7 +41,7 @@ type tokenAppender struct { // NewTokenAppender creates a token appender that can append a bearer token required to authenticate with // protected endpoints func NewTokenAppender(cfg *common.Config) (autodiscover.Appender, error) { - cfgwarn.Beta("The token appender is beta") + cfgwarn.Deprecate("7.0.0", "token appender is deprecated in favor of bearer_token_file config parameter") conf := defaultConfig() err := cfg.Unpack(&conf) diff --git a/metricbeat/docs/metricbeat-options.asciidoc b/metricbeat/docs/metricbeat-options.asciidoc index 426dccafd4f..c188df1405f 100644 --- a/metricbeat/docs/metricbeat-options.asciidoc +++ b/metricbeat/docs/metricbeat-options.asciidoc @@ -216,3 +216,9 @@ The username to use for basic authentication. ==== `password` The password to use for basic authentication. + +[float] +==== `bearer_token_file` + +If defined, Metricbeat will read the contents of the file once at initialization +and then use the value in an HTTP Authorization header. \ No newline at end of file diff --git a/metricbeat/docs/modules/kubernetes.asciidoc b/metricbeat/docs/modules/kubernetes.asciidoc index a3b8cc2fcc7..11cce59d264 100644 --- a/metricbeat/docs/modules/kubernetes.asciidoc +++ b/metricbeat/docs/modules/kubernetes.asciidoc @@ -35,7 +35,9 @@ metricbeat.modules: period: 10s hosts: ["localhost:10255"] enabled: true - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + #bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt #ssl.certificate: "/etc/pki/client/cert.pem" #ssl.key: "/etc/pki/client/cert.key" diff --git a/metricbeat/docs/modules/prometheus.asciidoc b/metricbeat/docs/modules/prometheus.asciidoc index d25d1618726..cada7468f0d 100644 --- a/metricbeat/docs/modules/prometheus.asciidoc +++ b/metricbeat/docs/modules/prometheus.asciidoc @@ -37,6 +37,11 @@ metricbeat.modules: hosts: ["localhost:9090"] #metrics_path: /metrics #namespace: example + + # This can be used for service account based authorization: + # bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt ---- This module supports TLS connection when using `ssl` config field, as described in <>. It also supports the options described in <>. diff --git a/metricbeat/helper/http.go b/metricbeat/helper/http.go index 495df91b1f5..b01fa781885 100644 --- a/metricbeat/helper/http.go +++ b/metricbeat/helper/http.go @@ -27,6 +27,8 @@ import ( "net/http" "time" + "github.com/pkg/errors" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/transport" "github.com/elastic/beats/metricbeat/mb" @@ -44,9 +46,10 @@ type HTTP struct { // NewHTTP creates new http helper func NewHTTP(base mb.BaseMetricSet) (*HTTP, error) { config := struct { - TLS *tlscommon.Config `config:"ssl"` - Timeout time.Duration `config:"timeout"` - Headers map[string]string `config:"headers"` + TLS *tlscommon.Config `config:"ssl"` + Timeout time.Duration `config:"timeout"` + Headers map[string]string `config:"headers"` + BearerTokenFile string `config:"bearer_token_file"` }{} if err := base.Module().UnpackConfig(&config); err != nil { return nil, err @@ -56,6 +59,14 @@ func NewHTTP(base mb.BaseMetricSet) (*HTTP, error) { config.Headers = map[string]string{} } + if config.BearerTokenFile != "" { + header, err := getAuthHeaderFromToken(config.BearerTokenFile) + if err != nil { + return nil, err + } + config.Headers["Authorization"] = header + } + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err @@ -179,3 +190,22 @@ func (h *HTTP) FetchJSON() (map[string]interface{}, error) { return data, nil } + +// getAuthHeaderFromToken reads a bearer authorizaiton token from the given file +func getAuthHeaderFromToken(path string) (string, error) { + var token string + + b, err := ioutil.ReadFile(path) + if err != nil { + return "", errors.Wrap(err, "reading bearer token file") + } + + if len(b) != 0 { + if b[len(b)-1] == '\n' { + b = b[0 : len(b)-1] + } + token = fmt.Sprintf("Bearer %s", string(b)) + } + + return token, nil +} diff --git a/metricbeat/helper/http_test.go b/metricbeat/helper/http_test.go new file mode 100644 index 00000000000..a3e5d615e4d --- /dev/null +++ b/metricbeat/helper/http_test.go @@ -0,0 +1,71 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package helper + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetAuthHeaderFromToken(t *testing.T) { + tests := []struct { + Name, Content, Expected string + }{ + { + "Test a token is read", + "testtoken", + "Bearer testtoken", + }, + { + "Test a token is trimmed", + "testtoken\n", + "Bearer testtoken", + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + content := []byte(test.Content) + tmpfile, err := ioutil.TempFile("", "token") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write(content); err != nil { + t.Fatal(err) + } + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } + + header, err := getAuthHeaderFromToken(tmpfile.Name()) + assert.NoError(t, err) + assert.Equal(t, test.Expected, header) + }) + } +} + +func TestGetAuthHeaderFromTokenNoFile(t *testing.T) { + header, err := getAuthHeaderFromToken("nonexistingfile") + assert.Equal(t, "", header) + assert.Error(t, err) +} diff --git a/metricbeat/metricbeat.reference.yml b/metricbeat/metricbeat.reference.yml index ed2f25bb766..750ebeb6e15 100644 --- a/metricbeat/metricbeat.reference.yml +++ b/metricbeat/metricbeat.reference.yml @@ -361,7 +361,9 @@ metricbeat.modules: period: 10s hosts: ["localhost:10255"] enabled: true - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + #bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt #ssl.certificate: "/etc/pki/client/cert.pem" #ssl.key: "/etc/pki/client/cert.key" @@ -542,6 +544,11 @@ metricbeat.modules: #metrics_path: /metrics #namespace: example + # This can be used for service account based authorization: + # bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + #------------------------------ RabbitMQ Module ------------------------------ - module: rabbitmq metricsets: ["node", "queue", "connection"] diff --git a/metricbeat/module/kubernetes/_meta/config.reference.yml b/metricbeat/module/kubernetes/_meta/config.reference.yml index b5ef0867653..5b87632596b 100644 --- a/metricbeat/module/kubernetes/_meta/config.reference.yml +++ b/metricbeat/module/kubernetes/_meta/config.reference.yml @@ -9,7 +9,9 @@ period: 10s hosts: ["localhost:10255"] enabled: true - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + #bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt #ssl.certificate: "/etc/pki/client/cert.pem" #ssl.key: "/etc/pki/client/cert.key" diff --git a/metricbeat/module/kubernetes/_meta/config.yml b/metricbeat/module/kubernetes/_meta/config.yml index 5492b0a3b99..896092f7b37 100644 --- a/metricbeat/module/kubernetes/_meta/config.yml +++ b/metricbeat/module/kubernetes/_meta/config.yml @@ -7,10 +7,10 @@ # - container # - volume period: 10s - hosts: ["localhost:10255"] - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - #ssl.certificate: "/etc/pki/client/cert.pem" - #ssl.key: "/etc/pki/client/cert.key" + hosts: ["localhost:10250"] + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.certificate_authorities: + - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt #username: "user" #password: "secret" diff --git a/metricbeat/module/prometheus/_meta/config.reference.yml b/metricbeat/module/prometheus/_meta/config.reference.yml index dda648a4243..59680f2a901 100644 --- a/metricbeat/module/prometheus/_meta/config.reference.yml +++ b/metricbeat/module/prometheus/_meta/config.reference.yml @@ -13,3 +13,8 @@ hosts: ["localhost:9090"] #metrics_path: /metrics #namespace: example + + # This can be used for service account based authorization: + # bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt diff --git a/metricbeat/module/prometheus/_meta/config.yml b/metricbeat/module/prometheus/_meta/config.yml index 176fd562f01..1ff113c2d0f 100644 --- a/metricbeat/module/prometheus/_meta/config.yml +++ b/metricbeat/module/prometheus/_meta/config.yml @@ -7,3 +7,8 @@ #namespace: example #username: "user" #password: "secret" + + # This can be used for service account based authorization: + # bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt diff --git a/metricbeat/modules.d/kubernetes.yml.disabled b/metricbeat/modules.d/kubernetes.yml.disabled index 5c569025d57..c78dfa15d47 100644 --- a/metricbeat/modules.d/kubernetes.yml.disabled +++ b/metricbeat/modules.d/kubernetes.yml.disabled @@ -10,10 +10,10 @@ # - container # - volume period: 10s - hosts: ["localhost:10255"] - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - #ssl.certificate: "/etc/pki/client/cert.pem" - #ssl.key: "/etc/pki/client/cert.key" + hosts: ["localhost:10250"] + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.certificate_authorities: + - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt #username: "user" #password: "secret" diff --git a/metricbeat/modules.d/prometheus.yml.disabled b/metricbeat/modules.d/prometheus.yml.disabled index 21684d3adf1..c13619278c2 100644 --- a/metricbeat/modules.d/prometheus.yml.disabled +++ b/metricbeat/modules.d/prometheus.yml.disabled @@ -10,3 +10,8 @@ #namespace: example #username: "user" #password: "secret" + + # This can be used for service account based authorization: + # bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + #ssl.certificate_authorities: + # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt