From 7997c14b0d1477943f86471ce81e01624854b036 Mon Sep 17 00:00:00 2001 From: "Gregory G. Tseng" Date: Thu, 26 May 2016 14:24:49 -0700 Subject: [PATCH] Add ServerName into TLS Config --- config/config.go | 2 + retrieval/target.go | 3 ++ retrieval/target_test.go | 82 ++++++++++++++++++++++++++++--- retrieval/testdata/servername.cer | 20 ++++++++ retrieval/testdata/servername.key | 27 ++++++++++ util/httputil/client.go | 4 ++ 6 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 retrieval/testdata/servername.cer create mode 100644 retrieval/testdata/servername.key diff --git a/config/config.go b/config/config.go index 0c9537f22..3190291ba 100644 --- a/config/config.go +++ b/config/config.go @@ -354,6 +354,8 @@ type TLSConfig struct { CertFile string `yaml:"cert_file,omitempty"` // The client key file for the targets. KeyFile string `yaml:"key_file,omitempty"` + // Used to verify the hostname for the targets. + ServerName string `yaml:"server_name,omitempty"` // Disable target certificate validation. InsecureSkipVerify bool `yaml:"insecure_skip_verify"` diff --git a/retrieval/target.go b/retrieval/target.go index 65d5ba123..7ce3390d3 100644 --- a/retrieval/target.go +++ b/retrieval/target.go @@ -74,6 +74,9 @@ func newHTTPClient(cfg *config.ScrapeConfig) (*http.Client, error) { tlsOpts.CertFile = cfg.TLSConfig.CertFile tlsOpts.KeyFile = cfg.TLSConfig.KeyFile } + if len(cfg.TLSConfig.ServerName) > 0 { + tlsOpts.ServerName = cfg.TLSConfig.ServerName + } tlsConfig, err := httputil.NewTLSConfig(tlsOpts) if err != nil { return nil, err diff --git a/retrieval/target_test.go b/retrieval/target_test.go index 851dc5403..dbbb8f02b 100644 --- a/retrieval/target_test.go +++ b/retrieval/target_test.go @@ -31,6 +31,10 @@ import ( "github.com/prometheus/prometheus/config" ) +const ( + CAFilePath = "testdata/ca.cer" +) + func TestTargetLabels(t *testing.T) { target := newTestTarget("example.com:80", 0, model.LabelSet{"job": "some_job", "foo": "bar"}) want := model.LabelSet{ @@ -228,14 +232,14 @@ func TestNewHTTPCACert(t *testing.T) { }, ), ) - server.TLS = newTLSConfig(t) + server.TLS = newTLSConfig("server", t) server.StartTLS() defer server.Close() cfg := &config.ScrapeConfig{ ScrapeTimeout: model.Duration(1 * time.Second), TLSConfig: config.TLSConfig{ - CAFile: "testdata/ca.cer", + CAFile: CAFilePath, }, } c, err := newHTTPClient(cfg) @@ -257,7 +261,7 @@ func TestNewHTTPClientCert(t *testing.T) { }, ), ) - tlsConfig := newTLSConfig(t) + tlsConfig := newTLSConfig("server", t) tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert tlsConfig.ClientCAs = tlsConfig.RootCAs tlsConfig.BuildNameToCertificate() @@ -268,7 +272,7 @@ func TestNewHTTPClientCert(t *testing.T) { cfg := &config.ScrapeConfig{ ScrapeTimeout: model.Duration(1 * time.Second), TLSConfig: config.TLSConfig{ - CAFile: "testdata/ca.cer", + CAFile: CAFilePath, CertFile: "testdata/client.cer", KeyFile: "testdata/client.key", }, @@ -283,19 +287,81 @@ func TestNewHTTPClientCert(t *testing.T) { } } -func newTLSConfig(t *testing.T) *tls.Config { +func TestNewHTTPWithServerName(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("servername", t) + server.StartTLS() + defer server.Close() + + cfg := &config.ScrapeConfig{ + ScrapeTimeout: model.Duration(1 * time.Second), + TLSConfig: config.TLSConfig{ + CAFile: CAFilePath, + ServerName: "prometheus.rocks", + }, + } + c, err := newHTTPClient(cfg) + if err != nil { + t.Fatal(err) + } + _, err = c.Get(server.URL) + if err != nil { + t.Fatal(err) + } +} + +func TestNewHTTPWithBadServerName(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("servername", t) + server.StartTLS() + defer server.Close() + + cfg := &config.ScrapeConfig{ + ScrapeTimeout: model.Duration(1 * time.Second), + TLSConfig: config.TLSConfig{ + CAFile: CAFilePath, + ServerName: "badname", + }, + } + c, err := newHTTPClient(cfg) + if err != nil { + t.Fatal(err) + } + _, err = c.Get(server.URL) + if err == nil { + t.Fatal("Expected error, got nil.") + } +} + +func newTLSConfig(certName string, t *testing.T) *tls.Config { tlsConfig := &tls.Config{} caCertPool := x509.NewCertPool() - caCert, err := ioutil.ReadFile("testdata/ca.cer") + caCert, err := ioutil.ReadFile(CAFilePath) 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") + certPath := fmt.Sprintf("testdata/%s.cer", certName) + keyPath := fmt.Sprintf("testdata/%s.key", certName) + cert, err := tls.LoadX509KeyPair(certPath, keyPath) if err != nil { - t.Errorf("Unable to use specified server cert (%s) & key (%v): %s", "testdata/server.cer", "testdata/server.key", err) + t.Errorf("Unable to use specified server cert (%s) & key (%v): %s", certPath, keyPath, err) } tlsConfig.Certificates = []tls.Certificate{cert} tlsConfig.BuildNameToCertificate() diff --git a/retrieval/testdata/servername.cer b/retrieval/testdata/servername.cer new file mode 100644 index 000000000..d9c8a9e39 --- /dev/null +++ b/retrieval/testdata/servername.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOzCCAiMCCQDU4khDjkOJSTANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJY +WDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh +bnkgTHRkMRswGQYDVQQDDBJQcm9tZXRoZXVzIFRlc3QgQ0EwHhcNMTYwNTI2MjEx +MjU5WhcNNDMxMDEyMjExMjU5WjBgMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29t +ZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRkwFwYD +VQQDExBwcm9tZXRoZXVzLnJvY2tzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAylgjuph/zgi1A2KS0Iw/73zdom449Gw+DATApL1sKYUTAVBk0uDpEZIw +fuYEAz6RbzBgzdYw10cmDCDDb0lNTBF4V08bGAXcYeJkKnIHRZprTPs7PWAai1jE +0H6ph+ThuHghPku7OAeyTvYyt5i0jkU2vgLSPa9wLciCfvwtd6S1gsthfEl8YsKH +iEVE+5h4nLjzp8MIgGBNPhzQvwW8x6bp0whuVzOFRHR1VBeK5rxG0LbCVU3Q5oPV +SLuRTkjQ6vNtm/qZPTw2mALjpRUrNxbA453aE33foJHb3gF85bSt67F7glFww5sq +GtxTiju8t8gNy7UV0ROlkoC7o1pMswIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCr +Fp+7FSOrgZO9BdBwmsnpNiymaOdf4ydOAXt5fdqkmgAyoRY5hPhFGduAfgKxESTf +tf8dKPV82j0EQR8EOu4qqDhXaKeZ69ZWMEkmpafO0MMixZ2/CeTV+z9DydLOZ2cC +IFJihSiLNGh8E4AUFdujbWBcTdv4FafRAiEhQ98iMyYiKXC/wcFLkL/u5Lvhr8yw +LGuaKwheDy41Q9Vdb2xlPbgDdibMlvOGxP1AWbE+/0fmmncwr7oeF6b4+mpMEDJS +XCoX6MSBdDmo9Gw1yH6l4KrvAI+StLWWxK2qs8lkWzZjiNS+JPWDeNqJBRmG6Yxc +Fl2KpVLCjhcNehUvg23x +-----END CERTIFICATE----- diff --git a/retrieval/testdata/servername.key b/retrieval/testdata/servername.key new file mode 100644 index 000000000..95d6aca52 --- /dev/null +++ b/retrieval/testdata/servername.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAylgjuph/zgi1A2KS0Iw/73zdom449Gw+DATApL1sKYUTAVBk +0uDpEZIwfuYEAz6RbzBgzdYw10cmDCDDb0lNTBF4V08bGAXcYeJkKnIHRZprTPs7 +PWAai1jE0H6ph+ThuHghPku7OAeyTvYyt5i0jkU2vgLSPa9wLciCfvwtd6S1gsth +fEl8YsKHiEVE+5h4nLjzp8MIgGBNPhzQvwW8x6bp0whuVzOFRHR1VBeK5rxG0LbC +VU3Q5oPVSLuRTkjQ6vNtm/qZPTw2mALjpRUrNxbA453aE33foJHb3gF85bSt67F7 +glFww5sqGtxTiju8t8gNy7UV0ROlkoC7o1pMswIDAQABAoIBADZ5vETEQcRKe9FJ +fJVA7QWg7FqKqjLD4YCC1wqDJNeYyCEWb86GVrkwTnYbnwDwm17/+0/vVn7e3NNv +Dq6rYXAVU/zNg1HYYhjIRodW47ZNeI3lJXHEqeDSKUqojyPS7yIm1WxcHy9agxrX +FZhwOEwFPlOxlsCcturcjKV7ZxJKftiWoyPodQLjlEmNoD/MQ6Obuge1dQZRLwCk +/R+EcTWHN4A+rpnZLoKFEaw5p7DTjdKSGOu+EFB+lrEg5kTOCN/kR0PYGnDH1Ygd +6/DmP0xiPpT2pKudTtI7f+QoPtff+GJ47Xy1oYks/cXUJiJbtCT9wyKQtR5mZRUc +ruNWBCECgYEA9e87HbUaMA4tAqaur684RTFAqpDjDBB8tDAxbnuQrv6947odgQHu +YcBAneL2HIvUMuusI0X52nGRwt+qOSXiS1WQwA1P44qR28VYxLIkgK1xMEpezClU +xIavMzwZtmjCZ84Q6H/qvVuqa5MuE4pe6O9vnb4cUWF280ngmf+zViUCgYEA0qAx +qzh6cUBSF6PAV+7QKXB4YLfvLloX3qwC+qkdaGjacREb7URxTKs1lHLhpmHwoPN+ +aXccxNs443Z67AK68N2RAOVw3z1IPTmSUzL7HCKqzZtRXsj+Lm8bj9sRzvWuE7RU +X2QW+9ppAvjwwrhG0vXCs3yua2usMyHjr6ekw/cCgYBSut0qCyf6Dmq5v5R36PuG +2yCjwAWAo3Mvsh6OyeZL18nM92jBYwLrwx55fkXIKImDb6ACZaG9CAM+iLrcapAL +Q4dj85ZyNsUGJwbLdBmvZ6jx07K7/xNS4PPCym7j2625+anabF1swY88jNAtJpjy +xsjHSZKBFcZL5Qg3BbswOQKBgHigD/IMRWtot9scCAMUHRkudXKGxK9aH4OCJa6i +fdoW+st4TfMjmHOdNfFPndWpD6NN8B68fbhsCHeUmi9iHOfnLK1DudHQCfguaZPG +hbOGUyWvhvluyMuVDEbl4pwRbeGRDCUZcGRKoIt4QIJ0APO+lgQvKsEQiC08gmZN +73nfAoGAKXVVV7dN59gohMTRWsOSGP+YLEj8+rGZZYNKCLVTol0VQ7T30tA0P4Cf +Dw9oLKGnDdgTtJA6Fsms858B6ANC+6Hxd9LG0ecOevKMBFHuWPm56Z0ofDzoPVBW +eDuHeR5xF0xq5PIFl/mIJJ1NK0p1Do9gwqEEIftdNyrcGefGdXk= +-----END RSA PRIVATE KEY----- diff --git a/util/httputil/client.go b/util/httputil/client.go index d7526cc6e..47a9876c7 100644 --- a/util/httputil/client.go +++ b/util/httputil/client.go @@ -122,6 +122,7 @@ type TLSOptions struct { CAFile string CertFile string KeyFile string + ServerName string } func NewTLSConfig(opts TLSOptions) (*tls.Config, error) { @@ -140,6 +141,9 @@ func NewTLSConfig(opts TLSOptions) (*tls.Config, error) { tlsConfig.RootCAs = caCertPool } + if len(opts.ServerName) > 0 { + tlsConfig.ServerName = opts.ServerName + } // If a client cert & key is provided then configure TLS config accordingly. if len(opts.CertFile) > 0 && len(opts.KeyFile) > 0 { cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)