telemetry.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (C) 2019 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. // Package telemetry provides telemetry information for SFTPGo, such as:
  15. // - health information (for health checks)
  16. // - metrics
  17. // - profiling information
  18. package telemetry
  19. import (
  20. "crypto/tls"
  21. "log"
  22. "net/http"
  23. "path/filepath"
  24. "runtime"
  25. "time"
  26. "github.com/go-chi/chi/v5"
  27. "github.com/drakkan/sftpgo/v2/internal/common"
  28. "github.com/drakkan/sftpgo/v2/internal/logger"
  29. "github.com/drakkan/sftpgo/v2/internal/util"
  30. )
  31. const (
  32. logSender = "telemetry"
  33. metricsPath = "/metrics"
  34. pprofBasePath = "/debug"
  35. )
  36. var (
  37. router *chi.Mux
  38. httpAuth common.HTTPAuthProvider
  39. certMgr *common.CertManager
  40. )
  41. // Conf telemetry server configuration.
  42. type Conf struct {
  43. // The port used for serving HTTP requests. 0 disable the HTTP server. Default: 0
  44. BindPort int `json:"bind_port" mapstructure:"bind_port"`
  45. // The address to listen on. A blank value means listen on all available network interfaces. Default: "127.0.0.1"
  46. BindAddress string `json:"bind_address" mapstructure:"bind_address"`
  47. // Enable the built-in profiler.
  48. // The profiler will be accessible via HTTP/HTTPS using the base URL "/debug/pprof/"
  49. EnableProfiler bool `json:"enable_profiler" mapstructure:"enable_profiler"`
  50. // Path to a file used to store usernames and password for basic authentication.
  51. // This can be an absolute path or a path relative to the config dir.
  52. // We support HTTP basic authentication and the file format must conform to the one generated using the Apache
  53. // htpasswd tool. The supported password formats are bcrypt ($2y$ prefix) and md5 crypt ($apr1$ prefix).
  54. // If empty HTTP authentication is disabled
  55. AuthUserFile string `json:"auth_user_file" mapstructure:"auth_user_file"`
  56. // If files containing a certificate and matching private key for the server are provided the server will expect
  57. // HTTPS connections.
  58. // Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
  59. // "paramchange" request to the running service on Windows.
  60. CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
  61. CertificateKeyFile string `json:"certificate_key_file" mapstructure:"certificate_key_file"`
  62. // TLSCipherSuites is a list of supported cipher suites for TLS version 1.2.
  63. // If CipherSuites is nil/empty, a default list of secure cipher suites
  64. // is used, with a preference order based on hardware performance.
  65. // Note that TLS 1.3 ciphersuites are not configurable.
  66. // The supported ciphersuites names are defined here:
  67. //
  68. // https://github.com/golang/go/blob/master/src/crypto/tls/cipher_suites.go#L53
  69. //
  70. // any invalid name will be silently ignored.
  71. // The order matters, the ciphers listed first will be the preferred ones.
  72. TLSCipherSuites []string `json:"tls_cipher_suites" mapstructure:"tls_cipher_suites"`
  73. // Defines the minimum TLS version. 13 means TLS 1.3, default is TLS 1.2
  74. MinTLSVersion int `json:"min_tls_version" mapstructure:"min_tls_version"`
  75. // HTTP protocols to enable in preference order. Supported values: http/1.1, h2
  76. Protocols []string `json:"tls_protocols" mapstructure:"tls_protocols"`
  77. }
  78. // ShouldBind returns true if there service must be started
  79. func (c Conf) ShouldBind() bool {
  80. if c.BindPort > 0 {
  81. return true
  82. }
  83. if filepath.IsAbs(c.BindAddress) && runtime.GOOS != "windows" {
  84. return true
  85. }
  86. return false
  87. }
  88. // Initialize configures and starts the telemetry server.
  89. func (c Conf) Initialize(configDir string) error {
  90. var err error
  91. logger.Info(logSender, "", "initializing telemetry server with config %+v", c)
  92. authUserFile := getConfigPath(c.AuthUserFile, configDir)
  93. httpAuth, err = common.NewBasicAuthProvider(authUserFile)
  94. if err != nil {
  95. return err
  96. }
  97. certificateFile := getConfigPath(c.CertificateFile, configDir)
  98. certificateKeyFile := getConfigPath(c.CertificateKeyFile, configDir)
  99. initializeRouter(c.EnableProfiler)
  100. httpServer := &http.Server{
  101. Handler: router,
  102. ReadHeaderTimeout: 30 * time.Second,
  103. ReadTimeout: 60 * time.Second,
  104. WriteTimeout: 60 * time.Second,
  105. IdleTimeout: 60 * time.Second,
  106. MaxHeaderBytes: 1 << 14, // 16KB
  107. ErrorLog: log.New(&logger.StdLoggerWrapper{Sender: logSender}, "", 0),
  108. }
  109. if certificateFile != "" && certificateKeyFile != "" {
  110. keyPairs := []common.TLSKeyPair{
  111. {
  112. Cert: certificateFile,
  113. Key: certificateKeyFile,
  114. ID: common.DefaultTLSKeyPaidID,
  115. },
  116. }
  117. certMgr, err = common.NewCertManager(keyPairs, configDir, logSender)
  118. if err != nil {
  119. return err
  120. }
  121. config := &tls.Config{
  122. GetCertificate: certMgr.GetCertificateFunc(common.DefaultTLSKeyPaidID),
  123. MinVersion: util.GetTLSVersion(c.MinTLSVersion),
  124. NextProtos: util.GetALPNProtocols(c.Protocols),
  125. CipherSuites: util.GetTLSCiphersFromNames(c.TLSCipherSuites),
  126. }
  127. logger.Debug(logSender, "", "configured TLS cipher suites: %v", config.CipherSuites)
  128. httpServer.TLSConfig = config
  129. return util.HTTPListenAndServe(httpServer, c.BindAddress, c.BindPort, true, logSender)
  130. }
  131. return util.HTTPListenAndServe(httpServer, c.BindAddress, c.BindPort, false, logSender)
  132. }
  133. // ReloadCertificateMgr reloads the certificate manager
  134. func ReloadCertificateMgr() error {
  135. if certMgr != nil {
  136. return certMgr.Reload()
  137. }
  138. return nil
  139. }
  140. func getConfigPath(name, configDir string) string {
  141. if !util.IsFileInputValid(name) {
  142. return ""
  143. }
  144. if name != "" && !filepath.IsAbs(name) {
  145. return filepath.Join(configDir, name)
  146. }
  147. return name
  148. }