appsec.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Unless explicitly stated otherwise all files in this repository are licensed
  2. // under the Apache License Version 2.0.
  3. // This product includes software developed at Datadog (https://www.datadoghq.com/).
  4. // Copyright 2016 Datadog, Inc.
  5. //go:build appsec
  6. // +build appsec
  7. package appsec
  8. import (
  9. "sync"
  10. "gopkg.in/DataDog/dd-trace-go.v1/internal/appsec/dyngo"
  11. "gopkg.in/DataDog/dd-trace-go.v1/internal/log"
  12. "gopkg.in/DataDog/dd-trace-go.v1/internal/remoteconfig"
  13. )
  14. // Enabled returns true when AppSec is up and running. Meaning that the appsec build tag is enabled, the env var
  15. // DD_APPSEC_ENABLED is set to true, and the tracer is started.
  16. func Enabled() bool {
  17. mu.RLock()
  18. defer mu.RUnlock()
  19. return activeAppSec != nil && activeAppSec.started
  20. }
  21. // Start AppSec when enabled is enabled by both using the appsec build tag and
  22. // setting the environment variable DD_APPSEC_ENABLED to true.
  23. func Start(opts ...StartOption) {
  24. enabled, set, err := isEnabled()
  25. if err != nil {
  26. logUnexpectedStartError(err)
  27. return
  28. }
  29. // Check if AppSec is explicitly disabled
  30. if set && !enabled {
  31. log.Debug("appsec: disabled by the configuration: set the environment variable DD_APPSEC_ENABLED to true to enable it")
  32. return
  33. }
  34. // From this point we know that AppSec is either enabled or can be enabled through remote config
  35. cfg, err := newConfig()
  36. if err != nil {
  37. logUnexpectedStartError(err)
  38. return
  39. }
  40. for _, opt := range opts {
  41. opt(cfg)
  42. }
  43. appsec := newAppSec(cfg)
  44. appsec.startRC()
  45. // If the env var is not set ASM is disabled, but can be enabled through remote config
  46. if !set {
  47. log.Debug("appsec: %s is not set. AppSec won't start until activated through remote configuration", enabledEnvVar)
  48. if err := appsec.enableRemoteActivation(); err != nil {
  49. // ASM is not enabled and can't be enabled through remote configuration. Nothing more can be done.
  50. logUnexpectedStartError(err)
  51. appsec.stopRC()
  52. return
  53. }
  54. } else if err := appsec.start(); err != nil { // AppSec is specifically enabled
  55. logUnexpectedStartError(err)
  56. appsec.stopRC()
  57. return
  58. }
  59. setActiveAppSec(appsec)
  60. }
  61. // Implement the AppSec log message C1
  62. func logUnexpectedStartError(err error) {
  63. log.Error("appsec: could not start because of an unexpected error: %v\nNo security activities will be collected. Please contact support at https://docs.datadoghq.com/help/ for help.", err)
  64. }
  65. // Stop AppSec.
  66. func Stop() {
  67. setActiveAppSec(nil)
  68. }
  69. var (
  70. activeAppSec *appsec
  71. mu sync.RWMutex
  72. )
  73. func setActiveAppSec(a *appsec) {
  74. mu.Lock()
  75. defer mu.Unlock()
  76. if activeAppSec != nil {
  77. activeAppSec.stopRC()
  78. activeAppSec.stop()
  79. }
  80. activeAppSec = a
  81. }
  82. type appsec struct {
  83. cfg *Config
  84. unregisterWAF dyngo.UnregisterFunc
  85. limiter *TokenTicker
  86. rc *remoteconfig.Client
  87. started bool
  88. }
  89. func newAppSec(cfg *Config) *appsec {
  90. var client *remoteconfig.Client
  91. var err error
  92. if cfg.rc != nil {
  93. client, err = remoteconfig.NewClient(*cfg.rc)
  94. }
  95. if err != nil {
  96. log.Error("appsec: Remote config: disabled due to a client creation error: %v", err)
  97. }
  98. return &appsec{
  99. cfg: cfg,
  100. rc: client,
  101. }
  102. }
  103. // Start AppSec by registering its security protections according to the configured the security rules.
  104. func (a *appsec) start() error {
  105. a.limiter = NewTokenTicker(int64(a.cfg.traceRateLimit), int64(a.cfg.traceRateLimit))
  106. a.limiter.Start()
  107. // Register the WAF operation event listener
  108. unregisterWAF, err := a.registerWAF()
  109. if err != nil {
  110. return err
  111. }
  112. a.unregisterWAF = unregisterWAF
  113. a.started = true
  114. return nil
  115. }
  116. // Stop AppSec by unregistering the security protections.
  117. func (a *appsec) stop() {
  118. if a.started {
  119. a.started = false
  120. a.unregisterWAF()
  121. a.limiter.Stop()
  122. }
  123. }