setting.go 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. // Copyright 2014 Unknwon
  2. // Copyright 2014 Torkel Ödegaard
  3. package setting
  4. import (
  5. "bytes"
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "regexp"
  14. "runtime"
  15. "strings"
  16. "time"
  17. "github.com/go-macaron/session"
  18. ini "gopkg.in/ini.v1"
  19. "github.com/grafana/grafana/pkg/infra/log"
  20. "github.com/grafana/grafana/pkg/util"
  21. )
  22. type Scheme string
  23. const (
  24. HTTP Scheme = "http"
  25. HTTPS Scheme = "https"
  26. HTTP2 Scheme = "h2"
  27. SOCKET Scheme = "socket"
  28. DEFAULT_HTTP_ADDR string = "0.0.0.0"
  29. )
  30. const (
  31. DEV = "development"
  32. PROD = "production"
  33. TEST = "test"
  34. APP_NAME = "Grafana"
  35. APP_NAME_ENTERPRISE = "Grafana Enterprise"
  36. )
  37. var (
  38. ERR_TEMPLATE_NAME = "error"
  39. )
  40. var (
  41. // App settings.
  42. Env = DEV
  43. AppUrl string
  44. AppSubUrl string
  45. ServeFromSubPath bool
  46. InstanceName string
  47. // build
  48. BuildVersion string
  49. BuildCommit string
  50. BuildBranch string
  51. BuildStamp int64
  52. IsEnterprise bool
  53. ApplicationName string
  54. // packaging
  55. Packaging = "unknown"
  56. // Paths
  57. HomePath string
  58. PluginsPath string
  59. CustomInitPath = "conf/custom.ini"
  60. // Log settings.
  61. LogConfigs []util.DynMap
  62. // Http server options
  63. Protocol Scheme
  64. Domain string
  65. HttpAddr, HttpPort string
  66. SshPort int
  67. CertFile, KeyFile string
  68. SocketPath string
  69. RouterLogging bool
  70. DataProxyLogging bool
  71. DataProxyTimeout int
  72. StaticRootPath string
  73. EnableGzip bool
  74. EnforceDomain bool
  75. // Security settings.
  76. SecretKey string
  77. DisableGravatar bool
  78. EmailCodeValidMinutes int
  79. DataProxyWhiteList map[string]bool
  80. DisableBruteForceLoginProtection bool
  81. CookieSecure bool
  82. CookieSameSite http.SameSite
  83. AllowEmbedding bool
  84. XSSProtectionHeader bool
  85. ContentTypeProtectionHeader bool
  86. StrictTransportSecurity bool
  87. StrictTransportSecurityMaxAge int
  88. StrictTransportSecurityPreload bool
  89. StrictTransportSecuritySubDomains bool
  90. // Snapshots
  91. ExternalSnapshotUrl string
  92. ExternalSnapshotName string
  93. ExternalEnabled bool
  94. SnapShotRemoveExpired bool
  95. SnapshotPublicMode bool
  96. // Dashboard history
  97. DashboardVersionsToKeep int
  98. // User settings
  99. AllowUserSignUp bool
  100. AllowUserOrgCreate bool
  101. AutoAssignOrg bool
  102. AutoAssignOrgId int
  103. AutoAssignOrgRole string
  104. VerifyEmailEnabled bool
  105. LoginHint string
  106. PasswordHint string
  107. DefaultTheme string
  108. DisableLoginForm bool
  109. DisableSignoutMenu bool
  110. SignoutRedirectUrl string
  111. ExternalUserMngLinkUrl string
  112. ExternalUserMngLinkName string
  113. ExternalUserMngInfo string
  114. OAuthAutoLogin bool
  115. ViewersCanEdit bool
  116. // Http auth
  117. AdminUser string
  118. AdminPassword string
  119. LoginCookieName string
  120. LoginMaxLifetimeDays int
  121. AnonymousEnabled bool
  122. AnonymousOrgName string
  123. AnonymousOrgRole string
  124. // Auth proxy settings
  125. AuthProxyEnabled bool
  126. AuthProxyHeaderName string
  127. AuthProxyHeaderProperty string
  128. AuthProxyAutoSignUp bool
  129. AuthProxyLDAPSyncTtl int
  130. AuthProxyWhitelist string
  131. AuthProxyHeaders map[string]string
  132. // Basic Auth
  133. BasicAuthEnabled bool
  134. // Session settings.
  135. SessionOptions session.Options
  136. SessionConnMaxLifetime int64
  137. // Global setting objects.
  138. Raw *ini.File
  139. ConfRootPath string
  140. IsWindows bool
  141. // for logging purposes
  142. configFiles []string
  143. appliedCommandLineProperties []string
  144. appliedEnvOverrides []string
  145. ReportingEnabled bool
  146. CheckForUpdates bool
  147. GoogleAnalyticsId string
  148. GoogleTagManagerId string
  149. // LDAP
  150. LDAPEnabled bool
  151. LDAPConfigFile string
  152. LDAPSyncCron string
  153. LDAPAllowSignup bool
  154. LDAPActiveSyncEnabled bool
  155. // QUOTA
  156. Quota QuotaSettings
  157. // Alerting
  158. AlertingEnabled bool
  159. ExecuteAlerts bool
  160. AlertingRenderLimit int
  161. AlertingErrorOrTimeout string
  162. AlertingNoDataOrNullValues string
  163. AlertingEvaluationTimeout time.Duration
  164. AlertingNotificationTimeout time.Duration
  165. AlertingMaxAttempts int
  166. // Explore UI
  167. ExploreEnabled bool
  168. // Grafana.NET URL
  169. GrafanaComUrl string
  170. // S3 temp image store
  171. S3TempImageStoreBucketUrl string
  172. S3TempImageStoreAccessKey string
  173. S3TempImageStoreSecretKey string
  174. ImageUploadProvider string
  175. )
  176. // TODO move all global vars to this struct
  177. type Cfg struct {
  178. Raw *ini.File
  179. Logger log.Logger
  180. // HTTP Server Settings
  181. AppUrl string
  182. AppSubUrl string
  183. ServeFromSubPath bool
  184. // Paths
  185. ProvisioningPath string
  186. DataPath string
  187. LogsPath string
  188. // SMTP email settings
  189. Smtp SmtpSettings
  190. // Rendering
  191. ImagesDir string
  192. PhantomDir string
  193. RendererUrl string
  194. RendererCallbackUrl string
  195. RendererLimit int
  196. RendererLimitAlerting int
  197. // Security
  198. DisableBruteForceLoginProtection bool
  199. CookieSecure bool
  200. CookieSameSite http.SameSite
  201. TempDataLifetime time.Duration
  202. MetricsEndpointEnabled bool
  203. MetricsEndpointBasicAuthUsername string
  204. MetricsEndpointBasicAuthPassword string
  205. MetricsEndpointDisableTotalStats bool
  206. PluginsEnableAlpha bool
  207. PluginsAppsSkipVerifyTLS bool
  208. DisableSanitizeHtml bool
  209. EnterpriseLicensePath string
  210. // Auth
  211. LoginCookieName string
  212. LoginMaxInactiveLifetimeDays int
  213. LoginMaxLifetimeDays int
  214. TokenRotationIntervalMinutes int
  215. // SAML Auth
  216. SAMLEnabled bool
  217. // Dataproxy
  218. SendUserHeader bool
  219. // DistributedCache
  220. RemoteCacheOptions *RemoteCacheOptions
  221. EditorsCanAdmin bool
  222. ApiKeyMaxSecondsToLive int64
  223. FeatureToggles map[string]bool
  224. }
  225. type CommandLineArgs struct {
  226. Config string
  227. HomePath string
  228. Args []string
  229. }
  230. func init() {
  231. IsWindows = runtime.GOOS == "windows"
  232. }
  233. func parseAppUrlAndSubUrl(section *ini.Section) (string, string, error) {
  234. appUrl, err := valueAsString(section, "root_url", "http://localhost:3000/")
  235. if err != nil {
  236. return "", "", err
  237. }
  238. if appUrl[len(appUrl)-1] != '/' {
  239. appUrl += "/"
  240. }
  241. // Check if has app suburl.
  242. url, err := url.Parse(appUrl)
  243. if err != nil {
  244. log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
  245. }
  246. appSubUrl := strings.TrimSuffix(url.Path, "/")
  247. return appUrl, appSubUrl, nil
  248. }
  249. func ToAbsUrl(relativeUrl string) string {
  250. return AppUrl + relativeUrl
  251. }
  252. func shouldRedactKey(s string) bool {
  253. uppercased := strings.ToUpper(s)
  254. return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
  255. }
  256. func shouldRedactURLKey(s string) bool {
  257. uppercased := strings.ToUpper(s)
  258. return strings.Contains(uppercased, "DATABASE_URL")
  259. }
  260. func applyEnvVariableOverrides(file *ini.File) error {
  261. appliedEnvOverrides = make([]string, 0)
  262. for _, section := range file.Sections() {
  263. for _, key := range section.Keys() {
  264. sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
  265. keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
  266. envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
  267. envValue := os.Getenv(envKey)
  268. if len(envValue) > 0 {
  269. key.SetValue(envValue)
  270. if shouldRedactKey(envKey) {
  271. envValue = "*********"
  272. }
  273. if shouldRedactURLKey(envKey) {
  274. u, err := url.Parse(envValue)
  275. if err != nil {
  276. return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
  277. }
  278. ui := u.User
  279. if ui != nil {
  280. _, exists := ui.Password()
  281. if exists {
  282. u.User = url.UserPassword(ui.Username(), "-redacted-")
  283. envValue = u.String()
  284. }
  285. }
  286. }
  287. appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
  288. }
  289. }
  290. }
  291. return nil
  292. }
  293. func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
  294. appliedCommandLineProperties = make([]string, 0)
  295. for _, section := range file.Sections() {
  296. for _, key := range section.Keys() {
  297. keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
  298. value, exists := props[keyString]
  299. if exists {
  300. key.SetValue(value)
  301. if shouldRedactKey(keyString) {
  302. value = "*********"
  303. }
  304. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  305. }
  306. }
  307. }
  308. }
  309. func applyCommandLineProperties(props map[string]string, file *ini.File) {
  310. for _, section := range file.Sections() {
  311. sectionName := section.Name() + "."
  312. if section.Name() == ini.DEFAULT_SECTION {
  313. sectionName = ""
  314. }
  315. for _, key := range section.Keys() {
  316. keyString := sectionName + key.Name()
  317. value, exists := props[keyString]
  318. if exists {
  319. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  320. key.SetValue(value)
  321. }
  322. }
  323. }
  324. }
  325. func getCommandLineProperties(args []string) map[string]string {
  326. props := make(map[string]string)
  327. for _, arg := range args {
  328. if !strings.HasPrefix(arg, "cfg:") {
  329. continue
  330. }
  331. trimmed := strings.TrimPrefix(arg, "cfg:")
  332. parts := strings.Split(trimmed, "=")
  333. if len(parts) != 2 {
  334. log.Fatal(3, "Invalid command line argument. argument: %v", arg)
  335. return nil
  336. }
  337. props[parts[0]] = parts[1]
  338. }
  339. return props
  340. }
  341. func makeAbsolute(path string, root string) string {
  342. if filepath.IsAbs(path) {
  343. return path
  344. }
  345. return filepath.Join(root, path)
  346. }
  347. func evalEnvVarExpression(value string) string {
  348. regex := regexp.MustCompile(`\${(\w+)}`)
  349. return regex.ReplaceAllStringFunc(value, func(envVar string) string {
  350. envVar = strings.TrimPrefix(envVar, "${")
  351. envVar = strings.TrimSuffix(envVar, "}")
  352. envValue := os.Getenv(envVar)
  353. // if env variable is hostname and it is empty use os.Hostname as default
  354. if envVar == "HOSTNAME" && envValue == "" {
  355. envValue, _ = os.Hostname()
  356. }
  357. return envValue
  358. })
  359. }
  360. func evalConfigValues(file *ini.File) {
  361. for _, section := range file.Sections() {
  362. for _, key := range section.Keys() {
  363. key.SetValue(evalEnvVarExpression(key.Value()))
  364. }
  365. }
  366. }
  367. func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
  368. if configFile == "" {
  369. configFile = filepath.Join(HomePath, CustomInitPath)
  370. // return without error if custom file does not exist
  371. if !pathExists(configFile) {
  372. return nil
  373. }
  374. }
  375. userConfig, err := ini.Load(configFile)
  376. if err != nil {
  377. return fmt.Errorf("Failed to parse %v, %v", configFile, err)
  378. }
  379. userConfig.BlockMode = false
  380. for _, section := range userConfig.Sections() {
  381. for _, key := range section.Keys() {
  382. if key.Value() == "" {
  383. continue
  384. }
  385. defaultSec, err := masterFile.GetSection(section.Name())
  386. if err != nil {
  387. defaultSec, _ = masterFile.NewSection(section.Name())
  388. }
  389. defaultKey, err := defaultSec.GetKey(key.Name())
  390. if err != nil {
  391. defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
  392. }
  393. defaultKey.SetValue(key.Value())
  394. }
  395. }
  396. configFiles = append(configFiles, configFile)
  397. return nil
  398. }
  399. func (cfg *Cfg) loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
  400. var err error
  401. // load config defaults
  402. defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
  403. configFiles = append(configFiles, defaultConfigFile)
  404. // check if config file exists
  405. if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
  406. fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
  407. os.Exit(1)
  408. }
  409. // load defaults
  410. parsedFile, err := ini.Load(defaultConfigFile)
  411. if err != nil {
  412. fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
  413. os.Exit(1)
  414. return nil, err
  415. }
  416. parsedFile.BlockMode = false
  417. // command line props
  418. commandLineProps := getCommandLineProperties(args.Args)
  419. // load default overrides
  420. applyCommandLineDefaultProperties(commandLineProps, parsedFile)
  421. // load specified config file
  422. err = loadSpecifedConfigFile(args.Config, parsedFile)
  423. if err != nil {
  424. err2 := cfg.initLogging(parsedFile)
  425. if err2 != nil {
  426. return nil, err2
  427. }
  428. log.Fatal(3, err.Error())
  429. }
  430. // apply environment overrides
  431. err = applyEnvVariableOverrides(parsedFile)
  432. if err != nil {
  433. return nil, err
  434. }
  435. // apply command line overrides
  436. applyCommandLineProperties(commandLineProps, parsedFile)
  437. // evaluate config values containing environment variables
  438. evalConfigValues(parsedFile)
  439. // update data path and logging config
  440. dataPath, err := valueAsString(parsedFile.Section("paths"), "data", "")
  441. if err != nil {
  442. return nil, err
  443. }
  444. cfg.DataPath = makeAbsolute(dataPath, HomePath)
  445. err = cfg.initLogging(parsedFile)
  446. if err != nil {
  447. return nil, err
  448. }
  449. return parsedFile, err
  450. }
  451. func pathExists(path string) bool {
  452. _, err := os.Stat(path)
  453. if err == nil {
  454. return true
  455. }
  456. if os.IsNotExist(err) {
  457. return false
  458. }
  459. return false
  460. }
  461. func setHomePath(args *CommandLineArgs) {
  462. if args.HomePath != "" {
  463. HomePath = args.HomePath
  464. return
  465. }
  466. HomePath, _ = filepath.Abs(".")
  467. // check if homepath is correct
  468. if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
  469. return
  470. }
  471. // try down one path
  472. if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
  473. HomePath = filepath.Join(HomePath, "../")
  474. }
  475. }
  476. var skipStaticRootValidation = false
  477. func NewCfg() *Cfg {
  478. return &Cfg{
  479. Logger: log.New("settings"),
  480. Raw: ini.Empty(),
  481. }
  482. }
  483. func (cfg *Cfg) validateStaticRootPath() error {
  484. if skipStaticRootValidation {
  485. return nil
  486. }
  487. if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
  488. cfg.Logger.Error("Failed to detect generated javascript files in public/build")
  489. }
  490. return nil
  491. }
  492. func (cfg *Cfg) Load(args *CommandLineArgs) error {
  493. setHomePath(args)
  494. iniFile, err := cfg.loadConfiguration(args)
  495. if err != nil {
  496. return err
  497. }
  498. cfg.Raw = iniFile
  499. // Temporary keep global, to make refactor in steps
  500. Raw = cfg.Raw
  501. ApplicationName = APP_NAME
  502. if IsEnterprise {
  503. ApplicationName = APP_NAME_ENTERPRISE
  504. }
  505. Env, err = valueAsString(iniFile.Section(""), "app_mode", "development")
  506. if err != nil {
  507. return err
  508. }
  509. InstanceName, err = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name")
  510. if err != nil {
  511. return err
  512. }
  513. plugins, err := valueAsString(iniFile.Section("paths"), "plugins", "")
  514. if err != nil {
  515. return err
  516. }
  517. PluginsPath = makeAbsolute(plugins, HomePath)
  518. Provisioning, err := valueAsString(iniFile.Section("paths"), "provisioning", "")
  519. if err != nil {
  520. return err
  521. }
  522. cfg.ProvisioningPath = makeAbsolute(Provisioning, HomePath)
  523. server := iniFile.Section("server")
  524. AppUrl, AppSubUrl, err = parseAppUrlAndSubUrl(server)
  525. if err != nil {
  526. return err
  527. }
  528. ServeFromSubPath = server.Key("serve_from_sub_path").MustBool(false)
  529. cfg.AppUrl = AppUrl
  530. cfg.AppSubUrl = AppSubUrl
  531. cfg.ServeFromSubPath = ServeFromSubPath
  532. Protocol = HTTP
  533. protocolStr, err := valueAsString(server, "protocol", "http")
  534. if err != nil {
  535. return err
  536. }
  537. if protocolStr == "https" {
  538. Protocol = HTTPS
  539. CertFile = server.Key("cert_file").String()
  540. KeyFile = server.Key("cert_key").String()
  541. }
  542. if protocolStr == "h2" {
  543. Protocol = HTTP2
  544. CertFile = server.Key("cert_file").String()
  545. KeyFile = server.Key("cert_key").String()
  546. }
  547. if protocolStr == "socket" {
  548. Protocol = SOCKET
  549. SocketPath = server.Key("socket").String()
  550. }
  551. Domain, err = valueAsString(server, "domain", "localhost")
  552. if err != nil {
  553. return err
  554. }
  555. HttpAddr, err = valueAsString(server, "http_addr", DEFAULT_HTTP_ADDR)
  556. if err != nil {
  557. return err
  558. }
  559. HttpPort, err = valueAsString(server, "http_port", "3000")
  560. if err != nil {
  561. return err
  562. }
  563. RouterLogging = server.Key("router_logging").MustBool(false)
  564. EnableGzip = server.Key("enable_gzip").MustBool(false)
  565. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  566. staticRoot, err := valueAsString(server, "static_root_path", "")
  567. if err != nil {
  568. return err
  569. }
  570. StaticRootPath = makeAbsolute(staticRoot, HomePath)
  571. if err := cfg.validateStaticRootPath(); err != nil {
  572. return err
  573. }
  574. // read data proxy settings
  575. dataproxy := iniFile.Section("dataproxy")
  576. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  577. DataProxyTimeout = dataproxy.Key("timeout").MustInt(30)
  578. cfg.SendUserHeader = dataproxy.Key("send_user_header").MustBool(false)
  579. // read security settings
  580. security := iniFile.Section("security")
  581. SecretKey, err = valueAsString(security, "secret_key", "")
  582. if err != nil {
  583. return err
  584. }
  585. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  586. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  587. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  588. CookieSecure = security.Key("cookie_secure").MustBool(false)
  589. cfg.CookieSecure = CookieSecure
  590. samesiteString, err := valueAsString(security, "cookie_samesite", "lax")
  591. if err != nil {
  592. return err
  593. }
  594. validSameSiteValues := map[string]http.SameSite{
  595. "lax": http.SameSiteLaxMode,
  596. "strict": http.SameSiteStrictMode,
  597. "none": http.SameSiteDefaultMode,
  598. }
  599. if samesite, ok := validSameSiteValues[samesiteString]; ok {
  600. CookieSameSite = samesite
  601. cfg.CookieSameSite = CookieSameSite
  602. } else {
  603. CookieSameSite = http.SameSiteLaxMode
  604. cfg.CookieSameSite = CookieSameSite
  605. }
  606. AllowEmbedding = security.Key("allow_embedding").MustBool(false)
  607. ContentTypeProtectionHeader = security.Key("x_content_type_options").MustBool(false)
  608. XSSProtectionHeader = security.Key("x_xss_protection").MustBool(false)
  609. StrictTransportSecurity = security.Key("strict_transport_security").MustBool(false)
  610. StrictTransportSecurityMaxAge = security.Key("strict_transport_security_max_age_seconds").MustInt(86400)
  611. StrictTransportSecurityPreload = security.Key("strict_transport_security_preload").MustBool(false)
  612. StrictTransportSecuritySubDomains = security.Key("strict_transport_security_subdomains").MustBool(false)
  613. // read snapshots settings
  614. snapshots := iniFile.Section("snapshots")
  615. ExternalSnapshotUrl, err = valueAsString(snapshots, "external_snapshot_url", "")
  616. if err != nil {
  617. return err
  618. }
  619. ExternalSnapshotName, err = valueAsString(snapshots, "external_snapshot_name", "")
  620. if err != nil {
  621. return err
  622. }
  623. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  624. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  625. SnapshotPublicMode = snapshots.Key("public_mode").MustBool(false)
  626. // read dashboard settings
  627. dashboards := iniFile.Section("dashboards")
  628. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  629. // read data source proxy white list
  630. DataProxyWhiteList = make(map[string]bool)
  631. securityStr, err := valueAsString(security, "data_source_proxy_whitelist", "")
  632. if err != nil {
  633. return err
  634. }
  635. for _, hostAndIp := range util.SplitString(securityStr) {
  636. DataProxyWhiteList[hostAndIp] = true
  637. }
  638. // admin
  639. AdminUser, err = valueAsString(security, "admin_user", "")
  640. if err != nil {
  641. return err
  642. }
  643. AdminPassword, err = valueAsString(security, "admin_password", "")
  644. if err != nil {
  645. return err
  646. }
  647. // users
  648. users := iniFile.Section("users")
  649. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  650. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  651. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  652. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  653. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  654. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  655. LoginHint, err = valueAsString(users, "login_hint", "")
  656. if err != nil {
  657. return err
  658. }
  659. PasswordHint, err = valueAsString(users, "password_hint", "")
  660. if err != nil {
  661. return err
  662. }
  663. DefaultTheme, err = valueAsString(users, "default_theme", "")
  664. if err != nil {
  665. return err
  666. }
  667. ExternalUserMngLinkUrl, err = valueAsString(users, "external_manage_link_url", "")
  668. if err != nil {
  669. return err
  670. }
  671. ExternalUserMngLinkName, err = valueAsString(users, "external_manage_link_name", "")
  672. if err != nil {
  673. return err
  674. }
  675. ExternalUserMngInfo, err = valueAsString(users, "external_manage_info", "")
  676. if err != nil {
  677. return err
  678. }
  679. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  680. cfg.EditorsCanAdmin = users.Key("editors_can_admin").MustBool(false)
  681. // auth
  682. auth := iniFile.Section("auth")
  683. LoginCookieName, err = valueAsString(auth, "login_cookie_name", "grafana_session")
  684. cfg.LoginCookieName = LoginCookieName
  685. if err != nil {
  686. return err
  687. }
  688. cfg.LoginMaxInactiveLifetimeDays = auth.Key("login_maximum_inactive_lifetime_days").MustInt(7)
  689. LoginMaxLifetimeDays = auth.Key("login_maximum_lifetime_days").MustInt(30)
  690. cfg.LoginMaxLifetimeDays = LoginMaxLifetimeDays
  691. cfg.ApiKeyMaxSecondsToLive = auth.Key("api_key_max_seconds_to_live").MustInt64(-1)
  692. cfg.TokenRotationIntervalMinutes = auth.Key("token_rotation_interval_minutes").MustInt(10)
  693. if cfg.TokenRotationIntervalMinutes < 2 {
  694. cfg.TokenRotationIntervalMinutes = 2
  695. }
  696. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  697. DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
  698. OAuthAutoLogin = auth.Key("oauth_auto_login").MustBool(false)
  699. SignoutRedirectUrl, err = valueAsString(auth, "signout_redirect_url", "")
  700. if err != nil {
  701. return err
  702. }
  703. // SAML auth
  704. cfg.SAMLEnabled = iniFile.Section("auth.saml").Key("enabled").MustBool(false)
  705. // anonymous access
  706. AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
  707. AnonymousOrgName, err = valueAsString(iniFile.Section("auth.anonymous"), "org_name", "")
  708. if err != nil {
  709. return err
  710. }
  711. AnonymousOrgRole, err = valueAsString(iniFile.Section("auth.anonymous"), "org_role", "")
  712. if err != nil {
  713. return err
  714. }
  715. // auth proxy
  716. authProxy := iniFile.Section("auth.proxy")
  717. AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
  718. AuthProxyHeaderName, err = valueAsString(authProxy, "header_name", "")
  719. if err != nil {
  720. return err
  721. }
  722. AuthProxyHeaderProperty, err = valueAsString(authProxy, "header_property", "")
  723. if err != nil {
  724. return err
  725. }
  726. AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
  727. AuthProxyLDAPSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
  728. AuthProxyWhitelist, err = valueAsString(authProxy, "whitelist", "")
  729. if err != nil {
  730. return err
  731. }
  732. AuthProxyHeaders = make(map[string]string)
  733. headers, err := valueAsString(authProxy, "headers", "")
  734. if err != nil {
  735. return err
  736. }
  737. for _, propertyAndHeader := range util.SplitString(headers) {
  738. split := strings.SplitN(propertyAndHeader, ":", 2)
  739. if len(split) == 2 {
  740. AuthProxyHeaders[split[0]] = split[1]
  741. }
  742. }
  743. // basic auth
  744. authBasic := iniFile.Section("auth.basic")
  745. BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
  746. // Rendering
  747. renderSec := iniFile.Section("rendering")
  748. cfg.RendererUrl, err = valueAsString(renderSec, "server_url", "")
  749. if err != nil {
  750. return err
  751. }
  752. cfg.RendererCallbackUrl, err = valueAsString(renderSec, "callback_url", "")
  753. if err != nil {
  754. return err
  755. }
  756. if cfg.RendererCallbackUrl == "" {
  757. cfg.RendererCallbackUrl = AppUrl
  758. } else {
  759. if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
  760. cfg.RendererCallbackUrl += "/"
  761. }
  762. _, err := url.Parse(cfg.RendererCallbackUrl)
  763. if err != nil {
  764. log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
  765. }
  766. }
  767. cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
  768. cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
  769. cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
  770. cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
  771. cfg.MetricsEndpointBasicAuthUsername, err = valueAsString(iniFile.Section("metrics"), "basic_auth_username", "")
  772. if err != nil {
  773. return err
  774. }
  775. cfg.MetricsEndpointBasicAuthPassword, err = valueAsString(iniFile.Section("metrics"), "basic_auth_password", "")
  776. if err != nil {
  777. return err
  778. }
  779. cfg.MetricsEndpointDisableTotalStats = iniFile.Section("metrics").Key("disable_total_stats").MustBool(false)
  780. analytics := iniFile.Section("analytics")
  781. ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
  782. CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
  783. GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
  784. GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
  785. alerting := iniFile.Section("alerting")
  786. AlertingEnabled = alerting.Key("enabled").MustBool(true)
  787. ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
  788. AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
  789. AlertingErrorOrTimeout, err = valueAsString(alerting, "error_or_timeout", "alerting")
  790. if err != nil {
  791. return err
  792. }
  793. AlertingNoDataOrNullValues, err = valueAsString(alerting, "nodata_or_nullvalues", "no_data")
  794. if err != nil {
  795. return err
  796. }
  797. evaluationTimeoutSeconds := alerting.Key("evaluation_timeout_seconds").MustInt64(30)
  798. AlertingEvaluationTimeout = time.Second * time.Duration(evaluationTimeoutSeconds)
  799. notificationTimeoutSeconds := alerting.Key("notification_timeout_seconds").MustInt64(30)
  800. AlertingNotificationTimeout = time.Second * time.Duration(notificationTimeoutSeconds)
  801. AlertingMaxAttempts = alerting.Key("max_attempts").MustInt(3)
  802. explore := iniFile.Section("explore")
  803. ExploreEnabled = explore.Key("enabled").MustBool(true)
  804. panelsSection := iniFile.Section("panels")
  805. cfg.DisableSanitizeHtml = panelsSection.Key("disable_sanitize_html").MustBool(false)
  806. pluginsSection := iniFile.Section("plugins")
  807. cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
  808. cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
  809. // Read and populate feature toggles list
  810. featureTogglesSection := iniFile.Section("feature_toggles")
  811. cfg.FeatureToggles = make(map[string]bool)
  812. featuresTogglesStr, err := valueAsString(featureTogglesSection, "enable", "")
  813. if err != nil {
  814. return err
  815. }
  816. for _, feature := range util.SplitString(featuresTogglesStr) {
  817. cfg.FeatureToggles[feature] = true
  818. }
  819. // check old location for this option
  820. if panelsSection.Key("enable_alpha").MustBool(false) {
  821. cfg.PluginsEnableAlpha = true
  822. }
  823. cfg.readLDAPConfig()
  824. cfg.readSessionConfig()
  825. cfg.readSmtpSettings()
  826. cfg.readQuotaSettings()
  827. if VerifyEmailEnabled && !cfg.Smtp.Enabled {
  828. log.Warn("require_email_validation is enabled but smtp is disabled")
  829. }
  830. // check old key name
  831. GrafanaComUrl, err = valueAsString(iniFile.Section("grafana_net"), "url", "")
  832. if err != nil {
  833. return err
  834. }
  835. if GrafanaComUrl == "" {
  836. GrafanaComUrl, err = valueAsString(iniFile.Section("grafana_com"), "url", "https://grafana.com")
  837. if err != nil {
  838. return err
  839. }
  840. }
  841. imageUploadingSection := iniFile.Section("external_image_storage")
  842. ImageUploadProvider, err = valueAsString(imageUploadingSection, "provider", "")
  843. if err != nil {
  844. return err
  845. }
  846. enterprise := iniFile.Section("enterprise")
  847. cfg.EnterpriseLicensePath, err = valueAsString(enterprise, "license_path", filepath.Join(cfg.DataPath, "license.jwt"))
  848. if err != nil {
  849. return err
  850. }
  851. cacheServer := iniFile.Section("remote_cache")
  852. dbName, err := valueAsString(cacheServer, "type", "database")
  853. if err != nil {
  854. return err
  855. }
  856. connStr, err := valueAsString(cacheServer, "connstr", "")
  857. if err != nil {
  858. return err
  859. }
  860. cfg.RemoteCacheOptions = &RemoteCacheOptions{
  861. Name: dbName,
  862. ConnStr: connStr,
  863. }
  864. return nil
  865. }
  866. func valueAsString(section *ini.Section, keyName string, defaultValue string) (value string, err error) {
  867. defer func() {
  868. if err_ := recover(); err_ != nil {
  869. err = errors.New("Invalid value for key '" + keyName + "' in configuration file")
  870. }
  871. }()
  872. return section.Key(keyName).MustString(defaultValue), nil
  873. }
  874. type RemoteCacheOptions struct {
  875. Name string
  876. ConnStr string
  877. }
  878. func (cfg *Cfg) readLDAPConfig() {
  879. ldapSec := cfg.Raw.Section("auth.ldap")
  880. LDAPConfigFile = ldapSec.Key("config_file").String()
  881. LDAPSyncCron = ldapSec.Key("sync_cron").String()
  882. LDAPEnabled = ldapSec.Key("enabled").MustBool(false)
  883. LDAPActiveSyncEnabled = ldapSec.Key("active_sync_enabled").MustBool(false)
  884. LDAPAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
  885. }
  886. func (cfg *Cfg) readSessionConfig() {
  887. sec, _ := cfg.Raw.GetSection("session")
  888. if sec != nil {
  889. cfg.Logger.Warn(
  890. "[Removed] Session setting was removed in v6.2, use remote_cache option instead",
  891. )
  892. }
  893. }
  894. func (cfg *Cfg) initLogging(file *ini.File) error {
  895. logModeStr, err := valueAsString(file.Section("log"), "mode", "console")
  896. if err != nil {
  897. return err
  898. }
  899. // split on comma
  900. logModes := strings.Split(logModeStr, ",")
  901. // also try space
  902. if len(logModes) == 1 {
  903. logModes = strings.Split(logModeStr, " ")
  904. }
  905. logsPath, err := valueAsString(file.Section("paths"), "logs", "")
  906. if err != nil {
  907. return err
  908. }
  909. cfg.LogsPath = makeAbsolute(logsPath, HomePath)
  910. log.ReadLoggingConfig(logModes, cfg.LogsPath, file)
  911. return nil
  912. }
  913. func (cfg *Cfg) LogConfigSources() {
  914. var text bytes.Buffer
  915. for _, file := range configFiles {
  916. cfg.Logger.Info("Config loaded from", "file", file)
  917. }
  918. if len(appliedCommandLineProperties) > 0 {
  919. for _, prop := range appliedCommandLineProperties {
  920. cfg.Logger.Info("Config overridden from command line", "arg", prop)
  921. }
  922. }
  923. if len(appliedEnvOverrides) > 0 {
  924. text.WriteString("\tEnvironment variables used:\n")
  925. for _, prop := range appliedEnvOverrides {
  926. cfg.Logger.Info("Config overridden from Environment variable", "var", prop)
  927. }
  928. }
  929. cfg.Logger.Info("Path Home", "path", HomePath)
  930. cfg.Logger.Info("Path Data", "path", cfg.DataPath)
  931. cfg.Logger.Info("Path Logs", "path", cfg.LogsPath)
  932. cfg.Logger.Info("Path Plugins", "path", PluginsPath)
  933. cfg.Logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
  934. cfg.Logger.Info("App mode " + Env)
  935. }