setting.go 29 KB

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