mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 05:04:05 -08:00
Configuration options for bearer tokens, client certs & CA certs
Fixes #918, fixes #917
This commit is contained in:
parent
c322422412
commit
52cf6b3e6e
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -17,6 +17,8 @@
|
|||
*~
|
||||
.*.swp
|
||||
.*.swo
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
.DS_Store
|
||||
._*
|
||||
|
|
|
@ -20,7 +20,7 @@ var (
|
|||
patJobName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`)
|
||||
patFileSDName = regexp.MustCompile(`^[^*]*(\*[^/]*)?\.(json|yml|yaml|JSON|YML|YAML)$`)
|
||||
patRulePath = regexp.MustCompile(`^[^*]*(\*[^/]*)?$`)
|
||||
patAuthLine = regexp.MustCompile(`((?:username|password):\s+)(".+"|'.+'|[^\s]+)`)
|
||||
patAuthLine = regexp.MustCompile(`((?:username|password|bearer_token):\s+)(".+"|'.+'|[^\s]+)`)
|
||||
)
|
||||
|
||||
// Load parses the YAML input s into a Config.
|
||||
|
@ -229,6 +229,14 @@ type ScrapeConfig struct {
|
|||
Scheme string `yaml:"scheme,omitempty"`
|
||||
// The HTTP basic authentication credentials for the targets.
|
||||
BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"`
|
||||
// The bearer token for the targets.
|
||||
BearerToken string `yaml:"bearer_token,omitempty"`
|
||||
// The bearer token file for the targets.
|
||||
BearerTokenFile string `yaml:"bearer_token_file,omitempty"`
|
||||
// The ca cert to use for the targets.
|
||||
CACert string `yaml:"ca_cert,omitempty"`
|
||||
// The client cert authentication credentials for the targets.
|
||||
ClientCert *ClientCert `yaml:"client_cert,omitempty"`
|
||||
|
||||
// List of labeled target groups for this job.
|
||||
TargetGroups []*TargetGroup `yaml:"target_groups,omitempty"`
|
||||
|
@ -261,6 +269,12 @@ func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
if !patJobName.MatchString(c.JobName) {
|
||||
return fmt.Errorf("%q is not a valid job name", c.JobName)
|
||||
}
|
||||
if len(c.BearerToken) > 0 && len(c.BearerTokenFile) > 0 {
|
||||
return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured")
|
||||
}
|
||||
if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) {
|
||||
return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured")
|
||||
}
|
||||
return checkOverflow(c.XXX, "scrape_config")
|
||||
}
|
||||
|
||||
|
@ -273,6 +287,15 @@ type BasicAuth struct {
|
|||
XXX map[string]interface{} `yaml:",inline"`
|
||||
}
|
||||
|
||||
// ClientCert contains client cert credentials.
|
||||
type ClientCert struct {
|
||||
Cert string `yaml:"cert"`
|
||||
Key string `yaml:"key"`
|
||||
|
||||
// Catches all undefined fields and must be empty after parsing.
|
||||
XXX map[string]interface{} `yaml:",inline"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
type plain BasicAuth
|
||||
|
|
|
@ -157,6 +157,21 @@ var expectedConf = &Config{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
JobName: "service-z",
|
||||
|
||||
ScrapeInterval: Duration(15 * time.Second),
|
||||
ScrapeTimeout: Duration(10 * time.Second),
|
||||
|
||||
MetricsPath: "/metrics",
|
||||
Scheme: "http",
|
||||
|
||||
ClientCert: &ClientCert{
|
||||
Cert: "valid_cert_file",
|
||||
Key: "valid_key_file",
|
||||
},
|
||||
BearerToken: "avalidtoken",
|
||||
},
|
||||
},
|
||||
original: "",
|
||||
}
|
||||
|
@ -224,6 +239,12 @@ var expectedErrors = []struct {
|
|||
}, {
|
||||
filename: "unknown_attr.bad.yml",
|
||||
errMsg: "unknown fields in scrape_config: consult_sd_configs",
|
||||
}, {
|
||||
filename: "bearertoken.bad.yml",
|
||||
errMsg: "at most one of bearer_token & bearer_token_file must be configured",
|
||||
}, {
|
||||
filename: "bearertoken_basicauth.bad.yml",
|
||||
errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
6
config/testdata/bearertoken.bad.yml
vendored
Normal file
6
config/testdata/bearertoken.bad.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
scrape_configs:
|
||||
- job_name: prometheus
|
||||
|
||||
bearer_token: 1234
|
||||
bearer_token_file: somefile
|
||||
|
8
config/testdata/bearertoken_basicauth.bad.yml
vendored
Normal file
8
config/testdata/bearertoken_basicauth.bad.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
scrape_configs:
|
||||
- job_name: prometheus
|
||||
|
||||
bearer_token: 1234
|
||||
basic_auth:
|
||||
username: user
|
||||
password: password
|
||||
|
8
config/testdata/conf.good.yml
vendored
8
config/testdata/conf.good.yml
vendored
|
@ -89,3 +89,11 @@ scrape_configs:
|
|||
consul_sd_configs:
|
||||
- server: 'localhost:1234'
|
||||
services: ['nginx', 'cache', 'mysql']
|
||||
|
||||
- job_name: service-z
|
||||
|
||||
client_cert:
|
||||
cert: valid_cert_file
|
||||
key: valid_key_file
|
||||
|
||||
bearer_token: avalidtoken
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
package retrieval
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -195,6 +198,13 @@ func (t *Target) Update(cfg *config.ScrapeConfig, baseLabels, metaLabels clientm
|
|||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
httpClient, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
log.Errorf("cannot create HTTP client: %v", err)
|
||||
return
|
||||
}
|
||||
t.httpClient = httpClient
|
||||
|
||||
t.url.Scheme = cfg.Scheme
|
||||
t.url.Path = string(baseLabels[clientmodel.MetricsPathLabel])
|
||||
params := url.Values{}
|
||||
|
@ -218,7 +228,6 @@ func (t *Target) Update(cfg *config.ScrapeConfig, baseLabels, metaLabels clientm
|
|||
|
||||
t.scrapeInterval = time.Duration(cfg.ScrapeInterval)
|
||||
t.deadline = time.Duration(cfg.ScrapeTimeout)
|
||||
t.httpClient = httputil.NewDeadlineClient(time.Duration(cfg.ScrapeTimeout))
|
||||
|
||||
t.honorLabels = cfg.HonorLabels
|
||||
t.metaLabels = metaLabels
|
||||
|
@ -235,6 +244,57 @@ func (t *Target) Update(cfg *config.ScrapeConfig, baseLabels, metaLabels clientm
|
|||
t.metricRelabelConfigs = cfg.MetricRelabelConfigs
|
||||
}
|
||||
|
||||
func newHTTPClient(cfg *config.ScrapeConfig) (*http.Client, error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
// If a CA cert is provided then let's read it in so we can validate the
|
||||
// scrape target's certificate properly.
|
||||
if len(cfg.CACert) > 0 {
|
||||
caCertPool := x509.NewCertPool()
|
||||
// Load CA cert.
|
||||
caCert, err := ioutil.ReadFile(cfg.CACert)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to use specified CA cert %s: %s", cfg.CACert, err)
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
tlsConfig.RootCAs = caCertPool
|
||||
}
|
||||
|
||||
// If a client cert & key is provided then configure TLS config accordingly.
|
||||
if cfg.ClientCert != nil && len(cfg.ClientCert.Cert) > 0 && len(cfg.ClientCert.Key) > 0 {
|
||||
cert, err := tls.LoadX509KeyPair(cfg.ClientCert.Cert, cfg.ClientCert.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to use specified client cert (%s) & key (%s): %s", cfg.ClientCert.Cert, cfg.ClientCert.Key, err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
// Get a default roundtripper with the scrape timeout.
|
||||
rt := httputil.NewDeadlineRoundTripper(time.Duration(cfg.ScrapeTimeout))
|
||||
tr := rt.(*http.Transport)
|
||||
// Set the TLS config from above
|
||||
tr.TLSClientConfig = tlsConfig
|
||||
rt = tr
|
||||
|
||||
// If a bearer token is provided, create a round tripper that will set the
|
||||
// Authorization header correctly on each request.
|
||||
bearerToken := cfg.BearerToken
|
||||
if len(bearerToken) == 0 && len(cfg.BearerTokenFile) > 0 {
|
||||
if b, err := ioutil.ReadFile(cfg.BearerTokenFile); err != nil {
|
||||
return nil, fmt.Errorf("Unable to read bearer token file %s: %s", cfg.BearerTokenFile, err)
|
||||
} else {
|
||||
bearerToken = string(b)
|
||||
}
|
||||
}
|
||||
if len(bearerToken) > 0 {
|
||||
rt = httputil.NewBearerAuthRoundTripper(bearerToken, rt)
|
||||
}
|
||||
|
||||
// Return a new client with the configured round tripper.
|
||||
return httputil.NewClient(rt), nil
|
||||
}
|
||||
|
||||
func (t *Target) String() string {
|
||||
return t.url.Host
|
||||
}
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
package retrieval
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -455,3 +458,140 @@ func newTestTarget(targetURL string, deadline time.Duration, baseLabels clientmo
|
|||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func TestNewHTTPBearerToken(t *testing.T) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
expected := "Bearer 1234"
|
||||
received := r.Header.Get("Authorization")
|
||||
if expected != received {
|
||||
t.Fatalf("Authorization header was not set correctly: expected '%v', got '%v'", expected, received)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
defer server.Close()
|
||||
|
||||
cfg := &config.ScrapeConfig{
|
||||
ScrapeTimeout: config.Duration(1 * time.Second),
|
||||
BearerToken: "1234",
|
||||
}
|
||||
c, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewHTTPBearerTokenFile(t *testing.T) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
expected := "Bearer 12345"
|
||||
received := r.Header.Get("Authorization")
|
||||
if expected != received {
|
||||
t.Fatalf("Authorization header was not set correctly: expected '%v', got '%v'", expected, received)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
defer server.Close()
|
||||
|
||||
cfg := &config.ScrapeConfig{
|
||||
ScrapeTimeout: config.Duration(1 * time.Second),
|
||||
BearerTokenFile: "testdata/bearertoken.txt",
|
||||
}
|
||||
c, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewHTTPCACert(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
|
||||
w.Write([]byte{})
|
||||
},
|
||||
),
|
||||
)
|
||||
server.TLS = newTLSConfig(t)
|
||||
server.StartTLS()
|
||||
defer server.Close()
|
||||
|
||||
cfg := &config.ScrapeConfig{
|
||||
ScrapeTimeout: config.Duration(1 * time.Second),
|
||||
CACert: "testdata/ca.cer",
|
||||
}
|
||||
c, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewHTTPClientCert(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
|
||||
w.Write([]byte{})
|
||||
},
|
||||
),
|
||||
)
|
||||
tlsConfig := newTLSConfig(t)
|
||||
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
tlsConfig.ClientCAs = tlsConfig.RootCAs
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
server.TLS = tlsConfig
|
||||
server.StartTLS()
|
||||
defer server.Close()
|
||||
|
||||
cfg := &config.ScrapeConfig{
|
||||
ScrapeTimeout: config.Duration(1 * time.Second),
|
||||
CACert: "testdata/ca.cer",
|
||||
ClientCert: &config.ClientCert{
|
||||
Cert: "testdata/client.cer",
|
||||
Key: "testdata/client.key",
|
||||
},
|
||||
}
|
||||
c, err := newHTTPClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newTLSConfig(t *testing.T) *tls.Config {
|
||||
tlsConfig := &tls.Config{}
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCert, err := ioutil.ReadFile("testdata/ca.cer")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't set up TLS server: %v", err)
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
tlsConfig.RootCAs = caCertPool
|
||||
tlsConfig.ServerName = "127.0.0.1"
|
||||
cert, err := tls.LoadX509KeyPair("testdata/server.cer", "testdata/server.key")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to use specified server cert (%s) & key (%v): %s", "testdata/server.cer", "testdata/server.key")
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
return tlsConfig
|
||||
}
|
||||
|
|
1
retrieval/testdata/bearertoken.txt
vendored
Normal file
1
retrieval/testdata/bearertoken.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
12345
|
22
retrieval/testdata/ca.cer
vendored
Normal file
22
retrieval/testdata/ca.cer
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIJAJNsnimNN3tmMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
|
||||
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
|
||||
Q29tcGFueSBMdGQxGzAZBgNVBAMMElByb21ldGhldXMgVGVzdCBDQTAeFw0xNTA4
|
||||
MDQxNDA5MjFaFw0yNTA4MDExNDA5MjFaMF8xCzAJBgNVBAYTAlhYMRUwEwYDVQQH
|
||||
DAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxGzAZ
|
||||
BgNVBAMMElByb21ldGhldXMgVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAOlSBU3yWpUELbhzizznR0hnAL7dbEHzfEtEc6N3PoSvMNcqrUVq
|
||||
t4kjBRWzqkZ5uJVkzBPERKEBoOI9pWcrqtMTBkMzHJY2Ep7GHTab10e9KC2IFQT6
|
||||
FKP/jCYixaIVx3azEfajRJooD8r79FGoagWUfHdHyCFWJb/iLt8z8+S91kelSRMS
|
||||
yB9M1ypWomzBz1UFXZp1oiNO5o7/dgXW4MgLUfC2obJ9j5xqpc6GkhWMW4ZFwEr/
|
||||
VLjuzxG9B8tLfQuhnXKGn1W8+WzZVWCWMD/sLfZfmjKaWlwcXzL51g8E+IEIBJqV
|
||||
w51aMI6lDkcvAM7gLq1auLZMVXyKWSKw7XMCAwEAAaNQME4wHQYDVR0OBBYEFMz1
|
||||
BZnlqxJp2HiJSjHK8IsLrWYbMB8GA1UdIwQYMBaAFMz1BZnlqxJp2HiJSjHK8IsL
|
||||
rWYbMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI2iA3w3TK5J15Pu
|
||||
e4fPFB4jxQqsbUwuyXbCCv/jKLeFNCD4BjM181WZEYjPMumeTBVzU3aF45LWQIG1
|
||||
0DJcrCL4mjMz9qgAoGqA7aDDXiJGbukMgYYsn7vrnVmrZH8T3E8ySlltr7+W578k
|
||||
pJ5FxnbCroQwn0zLyVB3sFbS8E3vpBr3L8oy8PwPHhIScexcNVc3V6/m4vTZsXTH
|
||||
U+vUm1XhDgpDcFMTg2QQiJbfpOYUkwIgnRDAT7t282t2KQWtnlqc3zwPQ1F/6Cpx
|
||||
j19JeNsaF1DArkD7YlyKj/GhZLtHwFHG5cxznH0mLDJTW7bQvqqh2iQTeXmBk1lU
|
||||
mM5lH/s=
|
||||
-----END CERTIFICATE-----
|
27
retrieval/testdata/ca.key
vendored
Normal file
27
retrieval/testdata/ca.key
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEA6VIFTfJalQQtuHOLPOdHSGcAvt1sQfN8S0Rzo3c+hK8w1yqt
|
||||
RWq3iSMFFbOqRnm4lWTME8REoQGg4j2lZyuq0xMGQzMcljYSnsYdNpvXR70oLYgV
|
||||
BPoUo/+MJiLFohXHdrMR9qNEmigPyvv0UahqBZR8d0fIIVYlv+Iu3zPz5L3WR6VJ
|
||||
ExLIH0zXKlaibMHPVQVdmnWiI07mjv92BdbgyAtR8Lahsn2PnGqlzoaSFYxbhkXA
|
||||
Sv9UuO7PEb0Hy0t9C6GdcoafVbz5bNlVYJYwP+wt9l+aMppaXBxfMvnWDwT4gQgE
|
||||
mpXDnVowjqUORy8AzuAurVq4tkxVfIpZIrDtcwIDAQABAoIBAQCcVDd3pYWpyLX1
|
||||
m31UnkX1rgYi3Gs3uTOznra4dSIvds6LrG2SUFGPEibLBql1NQNHHdVa/StakaPB
|
||||
UrqraOe5K0sL5Ygm4S4Ssf1K5JoW2Be+gipLPmBsDcJSnwO6eUs/LfZAQd6qR2Nl
|
||||
hvGJcQUwne/TYAYox/bdHWh4Zu/odz4NrZKZLbnXkdLLDEhZbjA0HpwJZ7NpMcB7
|
||||
Z6NayOm5dAZncfqBjY+3GNL0VjvDjwwYbESM8GkAbojMgcpODGk0h9arRWCP2RqT
|
||||
SVgmiFI2mVT7sW1XLdVXmyCL2jzak7sktpbLbVgngwOrBmLO/m4NBftzcZrgvxj3
|
||||
YakCPH/hAoGBAP1v85pIxqWr5dFdRlOW0MG35ifL+YXpavcs233jGDHYNZefrR5q
|
||||
Mw8eA20zwj41OdryqGh58nLYm3zYM0vPFrRJrzWYQfcWDmQELAylr9z9vsMj8gRq
|
||||
IZQD6wzFmLi1PN2QDmovF+2y/CLAq03XK6FQlNsVQxubfjh4hcX5+nXDAoGBAOut
|
||||
/pQaIBbIhaI8y3KjpizU24jxIkV8R/q1yE5V01YCl2OC5hEd4iZP14YLDRXLSHKT
|
||||
e/dyJ/OEyTIzUeDg0ZF3ao9ugbWuASgrnrrdPEooi7C9n9PeaLFTK5oVZoVP2A7E
|
||||
BwhSFW3VdEzQkdJczVE2jOY6JdBKMndjoDQnhT6RAoGBAL4WMO1gdnYeZ0JQJoZd
|
||||
kPgrOZpR2DaDa3I3F+3k3enM0+2EmzE70E4fYcyPTLqh62H4LS4ngRx4sK7D7j2G
|
||||
9u2EcsDNEXUE+wgzROK7hxtGysTMeiKrg8Hj6nFq53Bqp1s7SESGS/lCDPD398Rr
|
||||
hdL5gJyN5waW6uXqJ9Pk+eFHAoGBAKV/YGcV1XTKSPT9ZgxRmM6ghq0qT1umA1Gt
|
||||
t0QzBp2+Yhqx/+cDKhynMnxhZEXqoyw6HvJLSny5wSMsYJHeratNxRmFizZOQ2e3
|
||||
AdbMppqY0EdDUWnRI4lqExM3de+let4bj6irI3smSm3qhIvJOTCPcu/04zrZ74hh
|
||||
AE2/dtTRAoGBAO6bENEqLgxZOvX5NnbytTuuoEnbceUPiIvc6S/nWJPEoGXVN2EJ
|
||||
a3OaIOQmknE6bjXIWrHTaXJhwejvPUz9DVa4GxU5aJhs4gpocVGf+owQFvk4nJO8
|
||||
JL+QVVdXp3XdrXIGyvXJfy0fXXgJg5czrnDHjSTE8/2POtyuZ6VyBtQc
|
||||
-----END RSA PRIVATE KEY-----
|
25
retrieval/testdata/client.cer
vendored
Normal file
25
retrieval/testdata/client.cer
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIERjCCAy6gAwIBAgIBZDANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJYWDEV
|
||||
MBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkg
|
||||
THRkMRswGQYDVQQDDBJQcm9tZXRoZXVzIFRlc3QgQ0EwHhcNMTUwODA0MTQ0MTE2
|
||||
WhcNNDIxMjIwMTQ0MTE2WjBVMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs
|
||||
dCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMREwDwYDVQQDDAh0
|
||||
ZXN0dXNlcjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOKBBXx35X9+
|
||||
BLGqY/cC2+lQYZzn13Z8ZEDrUKpv5n91QA0B/YZE3gDSnk2yry8dxmp1NJtXm8Wr
|
||||
rIQSBnsTGOKwyIwR1gcggUYPD9fCyy7T7y7YbzBG8drEcxiK/YIWyio0fpRCfT9b
|
||||
2+fOEeY+0+tgFV++XjbXVzXRCBMmsZ22cOm4t2t7GHKBZhYoUoPgKjDn+4t/rr0r
|
||||
1od6yVOocYCo6RruQHsWPHj6QlU8VGutkD7PpvLS+w2l/6JqmZDHlY6o6pDidC8a
|
||||
kp8i/t3pNBlexk6st/8YZ5S9j6LjqC6bUnerUZB40b6L8OXXwWS3S5y6t07A1QIn
|
||||
Pv2DZKGbn8Uuj7RvS5OAZdDn1P+M5aVlRLoYbdTHJILrLg+bxyDIokqONbLgj78A
|
||||
FT6a013eJAZJBkeoaN7Djbf/d5FjRDadH2bX0Uur3APh4cbv+0Fo13CPPSckA9EU
|
||||
o42qBmKLWys858D8vRKyS/mq/IeRL0AIwKuaEIJtPtiwCTnk6PvFfQvO80z/Eyq+
|
||||
uvRBoZbrWHb+3GR8rNzu8Gc1UbTC+jnGYtbQhxx1/7nae52XGRpplnwPO9cb+px2
|
||||
Zf802h+lP3SMY/XS+nyTAp/jcy/jOAwrZKY4rgz+5ZmKCI61NZ0iovaK7Jqo9qTM
|
||||
iSjykZCamFhm4pg8itECD5FhnUetJ6axAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsG
|
||||
AQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQDEQyFfY9WAkdnzb+vIlICgfkydceYx
|
||||
KVJZ2WRMvrn2ZoRoSaK3CfGlz4nrCOgDjQxfX8OpKzudr/ghuBQCbDHHzxRrOen5
|
||||
0Zig9Q+pxTZNrtds/SwX2dHJ7PVEwGxXXaKl8S19bNEdO0syFrRJU6I50ZbeEkJe
|
||||
RI9IEFvBHcuG/GnEfqWj2ozI/+VhIOb4cTItg67ClmIPe8lteT2wj+/aydF9PKgF
|
||||
QhooCe/G1nok1uiaGjo1HzFEn4HzI3s4mrolc8PpBBVsS+HckCOrHpRPWnYuCFEm
|
||||
0yzS6tGaMrnITywwB2/uJ2aBAZIx2Go1zFhPf0YvFJc3e2x8cAuqBRLu
|
||||
-----END CERTIFICATE-----
|
51
retrieval/testdata/client.key
vendored
Normal file
51
retrieval/testdata/client.key
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
20
retrieval/testdata/server.cer
vendored
Normal file
20
retrieval/testdata/server.cer
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSzCCAjOgAwIBAgIJAPn0lI/95RQVMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
|
||||
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
|
||||
Q29tcGFueSBMdGQxGzAZBgNVBAMMElByb21ldGhldXMgVGVzdCBDQTAeFw0xNTA4
|
||||
MDQxNDE5MjRaFw00MjEyMjAxNDE5MjRaMFYxCzAJBgNVBAYTAlhYMRUwEwYDVQQH
|
||||
DAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEjAQ
|
||||
BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AMQhH0walZlA+Gy5ZB3YzzxZta7mhTX3P+yBeQ6G6yrei4H7gv+MTCJj5qUBc+BS
|
||||
cta8loKKUQWjoppjyh4tz8awkTD5sEyedE7/G3DS7mLgmx0PslwqrkXFBQhm/C2f
|
||||
aZfSO69TZ8uu1dgCmmGe9K2XqPnR6fu9egtLpK8RT0s/Cx04bFnaPS0ecyj+3q7A
|
||||
xzDsH84Z1KPo4LHgqNWlHqFsQPqH+7W9ajhF6lnO4ArEDJ3KuLDlgrENzCsDabls
|
||||
0U2XsccBJzP+Ls+iQwMfKpx2ISQDHqniopSICw+sPufiAv+OGnnG6rGGWQjUstqf
|
||||
w4DnU4DZvkrcEWoGa6fq26kCAwEAAaMTMBEwDwYDVR0RBAgwBocEfwAAATANBgkq
|
||||
hkiG9w0BAQUFAAOCAQEAVPs8IZffawWuRqbXJSvFz7a1q95febWQFjvvMe8ZJeCZ
|
||||
y1k9laQ5ZLHYuQ6NUWn09UbQNtK3fCLF4sJx5PCPCp1vZWx4nJs8N5mNyqdQ1Zfk
|
||||
oyoYTOR2izNcIj6ZUFRoOR/7B9hl2JouCXrbExr96oO13xIfsdslScINz1X68oyW
|
||||
KjU0yUrY+lWG1zEkUGXti9K6ujtXa7YY2n3nK/CvIqny5nVToYUgEMpjUR9S+KgN
|
||||
JUtawY3VQKyp6ZXlHqa0ihsuvY9Hrlh14h0AsZchPAHUtDFv2nEQob/Kf1XynKw6
|
||||
itVKcj/UFpkhsnc/19aP1gWje76fejXl0tzyPXDXFg==
|
||||
-----END CERTIFICATE-----
|
27
retrieval/testdata/server.key
vendored
Normal file
27
retrieval/testdata/server.key
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAxCEfTBqVmUD4bLlkHdjPPFm1ruaFNfc/7IF5DobrKt6LgfuC
|
||||
/4xMImPmpQFz4FJy1ryWgopRBaOimmPKHi3PxrCRMPmwTJ50Tv8bcNLuYuCbHQ+y
|
||||
XCquRcUFCGb8LZ9pl9I7r1Nny67V2AKaYZ70rZeo+dHp+716C0ukrxFPSz8LHThs
|
||||
Wdo9LR5zKP7ersDHMOwfzhnUo+jgseCo1aUeoWxA+of7tb1qOEXqWc7gCsQMncq4
|
||||
sOWCsQ3MKwNpuWzRTZexxwEnM/4uz6JDAx8qnHYhJAMeqeKilIgLD6w+5+IC/44a
|
||||
ecbqsYZZCNSy2p/DgOdTgNm+StwRagZrp+rbqQIDAQABAoIBACeOjqNo0TdhtTko
|
||||
gxrJ+bIwXcZy0/c4cPogeuwFJjU1QWnr8lXcVBazk3dAPcDGoEbTLoARqZm7kTYW
|
||||
XlOL5dYrEn2QPpCVfNvZ9AzjXhUvO9m2qsCQEyobPJKfQslo14E5c7Q+3DZmgtbY
|
||||
X47E4pCIgBoyzkBpzM2uaf6tPRLtv8QcLklcf7lP5rd0Zypc325RR6+J5nxfCoFp
|
||||
fD3sj7t/lJLS8Xb6m4/YFjsVJ2qEAelZ086v8unMBEj324Vv/VqrkPFtFNJKI+Az
|
||||
Pd9xFDBdsKijBn1Yam9/dj7CiyZYKaVZ9p/w7Oqkpbrt8J8S8OtNHZ4fz9FJgRu9
|
||||
uu+VTikCgYEA5ZkDmozDseA/c9JTUGAiPfAt5OrnqlKQNzp2m19GKh+Mlwg4k6O5
|
||||
uE+0vaQEfc0cX3o8qntWNsb63XC9h6oHewrdyVFMZNS4nzzmKEvGWt9ON6qfQDUs
|
||||
1cgZ0Y/uKydDX/3hk/hnJbeRW429rk0/GTuSHHilBzhE0uXJ11xPG48CgYEA2q7a
|
||||
yqTdqPmZFIAYT9ny099PhnGYE6cJljTUMX9Xhk4POqcigcq9kvNNsly2O1t0Eq0H
|
||||
2tYo91xTCZc3Cb0N+Vx3meLIljnzhEtwzU9w6W5VGJHWiqovjGwtCdm/W28OlMzY
|
||||
zM+0gVCJzZLhL0vOwBLwGUJvjgfpvgIb/W+C2UcCgYB5TJ3ayQOath7P0g6yKBfv
|
||||
ITUd+/zovzXx97Ex5OPs3T4pjO5XEejMt0+F4WF+FR8oUiw65W5nAjkHRMjdI7dQ
|
||||
Ci2ibpEttDTV7Bass1vYJqHsRvhbs7w8NbtuO9xYcCXoUPkcc+AKzTC+beQIckcj
|
||||
zZUj9Zk6dz/lLAG3Bc3FgQKBgQC+MmZI6auAU9Y4ZlC+4qi4bfkUzaefMCC+a6RC
|
||||
iKbvQOUt9j+k81h+fu6MuuYkKh6CP8wdITbwLXRrWwGbjrqgrzO2u/AJ+M07uwGZ
|
||||
EAb8f+GzROR8JhjE4TEq6B/uvmDIOoI1YFF2Rz4TdjQ0lpJzrAT3czjjJy68+8is
|
||||
XFhJ8QKBgQCMPpB7taMLQzuilEGabL6Xas9UxryiGoBHk4Umb107GVWgwXxWT6fk
|
||||
YSlvbMQHCgVeaJe374Bghyw33Z3WilWM1fCWya/CxXlw9wakjQHiqFCIOCxdgosX
|
||||
Sr35bRFWJMnHXD+jD0Vr8WrtbGzFSZb3ZrjT6WhWRIGCHcaMANN9ew==
|
||||
-----END RSA PRIVATE KEY-----
|
86
util/httputil/client.go
Normal file
86
util/httputil/client.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2013 The Prometheus Authors
|
||||
// Licensed 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 httputil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewClient returns a http.Client using the specified http.RoundTripper.
|
||||
func NewClient(rt http.RoundTripper) *http.Client {
|
||||
return &http.Client{Transport: rt}
|
||||
}
|
||||
|
||||
// NewDeadlineClient returns a new http.Client which will time out long running
|
||||
// requests.
|
||||
func NewDeadlineClient(timeout time.Duration) *http.Client {
|
||||
return NewClient(NewDeadlineRoundTripper(timeout))
|
||||
}
|
||||
|
||||
// NewDeadlineRoundTripper returns a new http.RoundTripper which will time out
|
||||
// long running requests.
|
||||
func NewDeadlineRoundTripper(timeout time.Duration) http.RoundTripper {
|
||||
return &http.Transport{
|
||||
// We need to disable keepalive, because we set a deadline on the
|
||||
// underlying connection.
|
||||
DisableKeepAlives: true,
|
||||
Dial: func(netw, addr string) (c net.Conn, err error) {
|
||||
start := time.Now()
|
||||
|
||||
c, err = net.DialTimeout(netw, addr, timeout)
|
||||
|
||||
if err == nil {
|
||||
c.SetDeadline(start.Add(timeout))
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type bearerAuthRoundTripper struct {
|
||||
bearerToken string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization
|
||||
// header has already been set.
|
||||
func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &bearerAuthRoundTripper{bearer, rt}
|
||||
}
|
||||
|
||||
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("Authorization")) == 0 {
|
||||
req = cloneRequest(req)
|
||||
req.Header.Set("Authorization", "Bearer "+rt.bearerToken)
|
||||
}
|
||||
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// Shallow copy of the struct.
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// Deep copy of the Header.
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return r2
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2013 The Prometheus Authors
|
||||
// Licensed 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 httputil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewDeadlineClient returns a new http.Client which will time out long running
|
||||
// requests.
|
||||
func NewDeadlineClient(timeout time.Duration) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
// We need to disable keepalive, because we set a deadline on the
|
||||
// underlying connection.
|
||||
DisableKeepAlives: true,
|
||||
Dial: func(netw, addr string) (c net.Conn, err error) {
|
||||
start := time.Now()
|
||||
|
||||
c, err = net.DialTimeout(netw, addr, timeout)
|
||||
|
||||
if err == nil {
|
||||
c.SetDeadline(start.Add(timeout))
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue