Module: Datadog::AppSec::Remote

Defined in:
lib/datadog/appsec/remote.rb

Overview

Remote

Defined Under Namespace

Classes: NoRulesError, ReadError

Constant Summary collapse

CAP_ASM_RESERVED_1 =

RESERVED

1 << 0
CAP_ASM_ACTIVATION =

Remote activation via ASM_FEATURES product

1 << 1
CAP_ASM_IP_BLOCKING =

accept IP blocking data from ASM_DATA product

1 << 2
CAP_ASM_DD_RULES =

read ASM rules from ASM_DD product

1 << 3
CAP_ASM_EXCLUSIONS =

exclusion filters (passlist) via ASM product

1 << 4
CAP_ASM_REQUEST_BLOCKING =

can block on request info

1 << 5
CAP_ASM_RESPONSE_BLOCKING =

can block on response info

1 << 6
CAP_ASM_USER_BLOCKING =

accept user blocking data from ASM_DATA product

1 << 7
CAP_ASM_CUSTOM_RULES =

accept custom rules

1 << 8
CAP_ASM_CUSTOM_BLOCKING_RESPONSE =

supports custom http code or redirect sa blocking response

1 << 9
CAP_ASM_TRUSTED_IPS =

supports trusted ip

1 << 10
ASM_CAPABILITIES =

TODO: we need to dynamically add CAP_ASM_ACTIVATION once we support it

[
  CAP_ASM_IP_BLOCKING,
  CAP_ASM_USER_BLOCKING,
  CAP_ASM_EXCLUSIONS,
  CAP_ASM_REQUEST_BLOCKING,
  CAP_ASM_RESPONSE_BLOCKING,
  CAP_ASM_DD_RULES,
  CAP_ASM_CUSTOM_RULES,
  CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
  CAP_ASM_TRUSTED_IPS,
].freeze
ASM_PRODUCTS =
[
  'ASM_DD',       # Datadog employee issued configuration
  'ASM',          # customer issued configuration (rulesets, passlist...)
  'ASM_FEATURES', # capabilities
  'ASM_DATA',     # config files (IP addresses or users for blocking)
].freeze

Class Method Summary collapse

Class Method Details

.capabilitiesObject



47
48
49
# File 'lib/datadog/appsec/remote.rb', line 47

def capabilities
  remote_features_enabled? ? ASM_CAPABILITIES : []
end

.productsObject



51
52
53
# File 'lib/datadog/appsec/remote.rb', line 51

def products
  remote_features_enabled? ? ASM_PRODUCTS : []
end

.receiversObject

rubocop:disable Metrics/MethodLength



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/datadog/appsec/remote.rb', line 56

def receivers
  return [] unless remote_features_enabled?

  matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
  receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
    changes.each do |change|
      Datadog.logger.debug { "remote config change: '#{change.path}'" }
    end

    rules = []
    custom_rules = []
    data = []
    overrides = []
    exclusions = []
    actions = []

    repository.contents.each do |content|
      parsed_content = parse_content(content)

      case content.path.product
      when 'ASM_DD'
        rules << parsed_content
      when 'ASM_DATA'
        data << parsed_content['rules_data'] if parsed_content['rules_data']
      when 'ASM'
        overrides << parsed_content['rules_override'] if parsed_content['rules_override']
        exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
        custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
        actions.concat(parsed_content['actions']) if parsed_content['actions']
      end
    end

    if rules.empty?
      settings_rules = AppSec::Processor::RuleLoader.load_rules(ruleset: Datadog.configuration.appsec.ruleset)

      raise NoRulesError, 'no default rules available' unless settings_rules

      rules = [settings_rules]
    end

    ruleset = AppSec::Processor::RuleMerger.merge(
      rules: rules,
      data: data,
      overrides: overrides,
      exclusions: exclusions,
      custom_rules: custom_rules,
    )

    Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions)
  end

  [receiver]
end