dataproxy.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package api
  2. import (
  3. "crypto/tls"
  4. "crypto/x509"
  5. "net"
  6. "net/http"
  7. "net/http/httputil"
  8. "net/url"
  9. "sync"
  10. "time"
  11. "github.com/grafana/grafana/pkg/api/cloudwatch"
  12. "github.com/grafana/grafana/pkg/bus"
  13. "github.com/grafana/grafana/pkg/metrics"
  14. "github.com/grafana/grafana/pkg/middleware"
  15. m "github.com/grafana/grafana/pkg/models"
  16. "github.com/grafana/grafana/pkg/setting"
  17. "github.com/grafana/grafana/pkg/util"
  18. )
  19. type proxyTransportCache struct {
  20. cache map[int64]cachedTransport
  21. sync.Mutex
  22. }
  23. type cachedTransport struct {
  24. updated time.Time
  25. *http.Transport
  26. }
  27. var ptc = proxyTransportCache{
  28. cache: make(map[int64]cachedTransport),
  29. }
  30. func DataProxyTransport(ds *m.DataSource) (*http.Transport, error) {
  31. ptc.Lock()
  32. defer ptc.Unlock()
  33. if t, present := ptc.cache[ds.Id]; present && ds.Updated.Equal(t.updated) {
  34. return t.Transport, nil
  35. }
  36. transport := &http.Transport{
  37. TLSClientConfig: &tls.Config{
  38. InsecureSkipVerify: true,
  39. },
  40. Proxy: http.ProxyFromEnvironment,
  41. Dial: (&net.Dialer{
  42. Timeout: 30 * time.Second,
  43. KeepAlive: 30 * time.Second,
  44. }).Dial,
  45. TLSHandshakeTimeout: 10 * time.Second,
  46. }
  47. var tlsAuth, tlsAuthWithCACert bool
  48. if ds.JsonData != nil {
  49. tlsAuth = ds.JsonData.Get("tlsAuth").MustBool(false)
  50. tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
  51. }
  52. if tlsAuth {
  53. transport.TLSClientConfig.InsecureSkipVerify = false
  54. decrypted := ds.SecureJsonData.Decrypt()
  55. if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 {
  56. caPool := x509.NewCertPool()
  57. ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"]))
  58. if ok {
  59. transport.TLSClientConfig.RootCAs = caPool
  60. }
  61. }
  62. cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"]))
  63. if err != nil {
  64. return nil, err
  65. }
  66. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  67. }
  68. ptc.cache[ds.Id] = cachedTransport{
  69. Transport: transport,
  70. updated: ds.Updated,
  71. }
  72. return transport, nil
  73. }
  74. func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
  75. director := func(req *http.Request) {
  76. req.URL.Scheme = targetUrl.Scheme
  77. req.URL.Host = targetUrl.Host
  78. req.Host = targetUrl.Host
  79. reqQueryVals := req.URL.Query()
  80. if ds.Type == m.DS_INFLUXDB_08 {
  81. req.URL.Path = util.JoinUrlFragments(targetUrl.Path, "db/"+ds.Database+"/"+proxyPath)
  82. reqQueryVals.Add("u", ds.User)
  83. reqQueryVals.Add("p", ds.Password)
  84. req.URL.RawQuery = reqQueryVals.Encode()
  85. } else if ds.Type == m.DS_INFLUXDB {
  86. req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
  87. req.URL.RawQuery = reqQueryVals.Encode()
  88. if !ds.BasicAuth {
  89. req.Header.Del("Authorization")
  90. req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.User, ds.Password))
  91. }
  92. } else {
  93. req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
  94. }
  95. if ds.BasicAuth {
  96. req.Header.Del("Authorization")
  97. req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword))
  98. }
  99. dsAuth := req.Header.Get("X-DS-Authorization")
  100. if len(dsAuth) > 0 {
  101. req.Header.Del("X-DS-Authorization")
  102. req.Header.Del("Authorization")
  103. req.Header.Add("Authorization", dsAuth)
  104. }
  105. // clear cookie headers
  106. req.Header.Del("Cookie")
  107. req.Header.Del("Set-Cookie")
  108. }
  109. return &httputil.ReverseProxy{Director: director, FlushInterval: time.Millisecond * 200}
  110. }
  111. func getDatasource(id int64, orgId int64) (*m.DataSource, error) {
  112. query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgId}
  113. if err := bus.Dispatch(&query); err != nil {
  114. return nil, err
  115. }
  116. return query.Result, nil
  117. }
  118. func ProxyDataSourceRequest(c *middleware.Context) {
  119. c.TimeRequest(metrics.M_DataSource_ProxyReq_Timer)
  120. ds, err := getDatasource(c.ParamsInt64(":id"), c.OrgId)
  121. if err != nil {
  122. c.JsonApiErr(500, "Unable to load datasource meta data", err)
  123. return
  124. }
  125. if ds.Type == m.DS_CLOUDWATCH {
  126. cloudwatch.HandleRequest(c, ds)
  127. return
  128. }
  129. if ds.Type == m.DS_INFLUXDB {
  130. if c.Query("db") != ds.Database {
  131. c.JsonApiErr(403, "Datasource is not configured to allow this database", nil)
  132. return
  133. }
  134. }
  135. targetUrl, _ := url.Parse(ds.Url)
  136. if len(setting.DataProxyWhiteList) > 0 {
  137. if _, exists := setting.DataProxyWhiteList[targetUrl.Host]; !exists {
  138. c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil)
  139. return
  140. }
  141. }
  142. proxyPath := c.Params("*")
  143. if ds.Type == m.DS_ES {
  144. if c.Req.Request.Method == "DELETE" {
  145. c.JsonApiErr(403, "Deletes not allowed on proxied Elasticsearch datasource", nil)
  146. return
  147. }
  148. if c.Req.Request.Method == "PUT" {
  149. c.JsonApiErr(403, "Puts not allowed on proxied Elasticsearch datasource", nil)
  150. return
  151. }
  152. if c.Req.Request.Method == "POST" && proxyPath != "_msearch" {
  153. c.JsonApiErr(403, "Posts not allowed on proxied Elasticsearch datasource except on /_msearch", nil)
  154. return
  155. }
  156. }
  157. proxy := NewReverseProxy(ds, proxyPath, targetUrl)
  158. proxy.Transport, err = DataProxyTransport(ds)
  159. if err != nil {
  160. c.JsonApiErr(400, "Unable to load TLS certificate", err)
  161. return
  162. }
  163. proxy.ServeHTTP(c.Resp, c.Req.Request)
  164. c.Resp.Header().Del("Set-Cookie")
  165. }