From f60b682535c96dd90a6b2cfa45236b939f9650c9 Mon Sep 17 00:00:00 2001 From: Rob de Heer Date: Sun, 17 Sep 2023 11:09:45 -0700 Subject: [PATCH 1/2] Added support for aws waf v2 --- libraries/aws_backend.rb | 5 ++ libraries/aws_wafv2_byte_match_set.rb | 66 +++++++++++++++ libraries/aws_wafv2_byte_match_sets.rb | 37 +++++++++ libraries/aws_wafv2_ip_set.rb | 50 ++++++++++++ libraries/aws_wafv2_ip_sets.rb | 37 +++++++++ libraries/aws_wafv2_rule.rb | 54 +++++++++++++ libraries/aws_wafv2_rules.rb | 37 +++++++++ libraries/aws_wafv2_size_constraint_set.rb | 62 ++++++++++++++ libraries/aws_wafv2_size_constraint_sets.rb | 37 +++++++++ .../aws_wafv2_sql_injection_match_set.rb | 54 +++++++++++++ .../aws_wafv2_sql_injection_match_sets.rb | 37 +++++++++ libraries/aws_wafv2_web_acl.rb | 80 +++++++++++++++++++ libraries/aws_wafv2_web_acls.rb | 37 +++++++++ libraries/aws_wafv2_xss_match_set.rb | 54 +++++++++++++ libraries/aws_wafv2_xss_match_sets.rb | 37 +++++++++ 15 files changed, 684 insertions(+) create mode 100644 libraries/aws_wafv2_byte_match_set.rb create mode 100644 libraries/aws_wafv2_byte_match_sets.rb create mode 100644 libraries/aws_wafv2_ip_set.rb create mode 100644 libraries/aws_wafv2_ip_sets.rb create mode 100644 libraries/aws_wafv2_rule.rb create mode 100644 libraries/aws_wafv2_rules.rb create mode 100644 libraries/aws_wafv2_size_constraint_set.rb create mode 100644 libraries/aws_wafv2_size_constraint_sets.rb create mode 100644 libraries/aws_wafv2_sql_injection_match_set.rb create mode 100644 libraries/aws_wafv2_sql_injection_match_sets.rb create mode 100644 libraries/aws_wafv2_web_acl.rb create mode 100644 libraries/aws_wafv2_web_acls.rb create mode 100644 libraries/aws_wafv2_xss_match_set.rb create mode 100644 libraries/aws_wafv2_xss_match_sets.rb diff --git a/libraries/aws_backend.rb b/libraries/aws_backend.rb index fb31dd227..010449760 100644 --- a/libraries/aws_backend.rb +++ b/libraries/aws_backend.rb @@ -59,6 +59,7 @@ require "aws-sdk-securityhub" require "aws-sdk-ses" require "aws-sdk-waf" +require "aws-sdk-wafv2" require "aws-sdk-synthetics" require "aws-sdk-apigatewayv2" @@ -330,6 +331,10 @@ def waf_client aws_client(Aws::WAF::Client) end + def waf_client_v2 + aws_client(Aws::WAFWAFV2::Client) + end + def synthetics_client aws_client(Aws::Synthetics::Client) end diff --git a/libraries/aws_wafv2_byte_match_set.rb b/libraries/aws_wafv2_byte_match_set.rb new file mode 100644 index 000000000..08067a4e1 --- /dev/null +++ b/libraries/aws_wafv2_byte_match_set.rb @@ -0,0 +1,66 @@ +require "aws_backend" + +class AWSWAFV2ByteMatchSet < AwsResourceBase + name "aws_wafv2_byte_match_set" + desc "Describes one WAF byte set." + + example " + describe aws_wafv2_byte_match_set(byte_match_set_id: 'BYTE_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { byte_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(byte_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: byte_match_set_id must be provided" unless opts[:byte_match_set_id] && !opts[:byte_match_set_id].empty? + @display_name = opts[:byte_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_byte_match_set({ byte_match_set_id: opts[:byte_match_set_id] }) + @resp = resp.byte_match_set.to_h + create_resource_methods(@resp) + end + end + + def byte_match_set_id + return nil unless exists? + @resp[:byte_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Byte Match Set ID: #{@display_name}" + end + + def byte_match_tuples_field_to_matches + byte_match_tuples.map(&:field_to_match) + end + + def byte_match_tuples_field_to_match_types + byte_match_tuples.map(&:field_to_match).map(&:type) + end + + def byte_match_tuples_field_to_match_data + byte_match_tuples.map(&:field_to_match).map(&:data) + end + + def byte_match_tuples_target_strings + byte_match_tuples.map(&:target_string) + end + + def byte_match_tuples_text_transformations + byte_match_tuples.map(&:text_transformation) + end + + def byte_match_tuples_positional_constraints + byte_match_tuples.map(&:positional_constraint) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_byte_match_sets.rb b/libraries/aws_wafv2_byte_match_sets.rb new file mode 100644 index 000000000..0550eb6ae --- /dev/null +++ b/libraries/aws_wafv2_byte_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2ByteMatchSets < AwsResourceBase + name "aws_wafv2_byte_match_sets" + desc "Verifies settings for all the WAF rules." + + example " + describe aws_wafv2_byte_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:byte_match_set_ids, field: :byte_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_byte_match_sets.map do |table| + table.map { |table_name| { + byte_match_set_id: table_name.byte_match_sets.map(&:byte_match_set_id), + name: table_name.byte_match_sets.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_ip_set.rb b/libraries/aws_wafv2_ip_set.rb new file mode 100644 index 000000000..b0461538c --- /dev/null +++ b/libraries/aws_wafv2_ip_set.rb @@ -0,0 +1,50 @@ +require "aws_backend" + +class AWSWAFV2IPSet < AwsResourceBase + name "aws_wafv2_ip_set" + desc "Describes one WAF IP set." + + example " + describe aws_wafv2_ip_set(ip_set_id: 'IP_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { ip_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(ip_set_id)) + raise ArgumentError, "#{@__resource_name__}: ip_set_id must be provided" unless opts[:ip_set_id] && !opts[:ip_set_id].empty? + @display_name = opts[:ip_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_ip_set({ ip_set_id: opts[:ip_set_id] }) + @resp = resp.ip_set.to_h + create_resource_methods(@resp) + end + end + + def ip_set_id + return nil unless exists? + @resp[:ip_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "IP Set ID: #{@display_name}" + end + + def ip_set_descriptors_types + ip_set_descriptors.map(&:type) + end + + def ip_set_descriptors_values + ip_set_descriptors.map(&:value) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_ip_sets.rb b/libraries/aws_wafv2_ip_sets.rb new file mode 100644 index 000000000..289810ffd --- /dev/null +++ b/libraries/aws_wafv2_ip_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2IPSets < AwsResourceBase + name "aws_wafv2_ip_sets" + desc "Verifies settings for all the IP sets." + + example " + describe aws_wafv2_ip_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:ip_set_ids, field: :ip_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_ip_sets.map do |table| + table.map { |table_name| { + name: table_name.ip_sets.map(&:name), + ip_set_id: table_name.ip_sets.map(&:ip_set_id), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_rule.rb b/libraries/aws_wafv2_rule.rb new file mode 100644 index 000000000..adcd6bf20 --- /dev/null +++ b/libraries/aws_wafv2_rule.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2Rule < AwsResourceBase + name "aws_wafv2_rule" + desc "Describes one WAF rule." + + example " + describe aws_wafv2_rule(rule_id: 'RULE_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { rule_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(rule_id)) + raise ArgumentError, "#{@__resource_name__}: rule_id must be provided" unless opts[:rule_id] && !opts[:rule_id].empty? + @display_name = opts[:rule_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_rule({ rule_id: opts[:rule_id] }) + @resp = resp.rule.to_h + create_resource_methods(@resp) + end + end + + def rule_id + return nil unless exists? + @resp[:rule_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Rule ID: #{@display_name}" + end + + def predicates_negated + predicates.map(&:negated) + end + + def predicates_type + predicates.map(&:type) + end + + def predicates_data_id + predicates.map(&:data_id) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_rules.rb b/libraries/aws_wafv2_rules.rb new file mode 100644 index 000000000..45c9fdf39 --- /dev/null +++ b/libraries/aws_wafv2_rules.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2Rules < AwsResourceBase + name "aws_wafv2_rules" + desc "Verifies settings for all the WAF rules." + + example " + describe aws_wafv2_rules do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:rule_ids, field: :rule_id) + .register_column(:names, field: :name) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_rules.map do |table| + table.rules.map { |table_name| { + rule_id: table_name[:rule_id], + name: table_name[:name], + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_size_constraint_set.rb b/libraries/aws_wafv2_size_constraint_set.rb new file mode 100644 index 000000000..b3b023f18 --- /dev/null +++ b/libraries/aws_wafv2_size_constraint_set.rb @@ -0,0 +1,62 @@ +require "aws_backend" + +class AWSWAFV2SizeConstraintSet < AwsResourceBase + name "aws_wafv2_size_constraint_set" + desc "Describes one WAF size constraint set." + + example " + describe aws_wafv2_size_constraint_set(size_constraint_set_id: 'SIZE_CONSTRAINT_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { size_constraint_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(size_constraint_set_id)) + raise ArgumentError, "#{@__resource_name__}: size_constraint_set_id must be provided" unless opts[:size_constraint_set_id] && !opts[:size_constraint_set_id].empty? + @display_name = opts[:size_constraint_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_size_constraint_set({ size_constraint_set_id: opts[:size_constraint_set_id] }) + @resp = resp.size_constraint_set.to_h + create_resource_methods(@resp) + end + end + + def size_constraint_set_id + return nil unless exists? + @resp[:size_constraint_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Size Constraint Set ID: #{@display_name}" + end + + def size_constraints_field_to_match_types + size_constraints.map(&:field_to_match).map(&:type) + end + + def size_constraints_field_to_match_data + size_constraints.map(&:field_to_match).map(&:data) + end + + def size_constraints_text_transformations + size_constraints.map(&:text_transformation) + end + + def size_constraints_comparison_operators + size_constraints.map(&:comparison_operator) + end + + def size_constraints_sizes + size_constraints.map(&:size) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_size_constraint_sets.rb b/libraries/aws_wafv2_size_constraint_sets.rb new file mode 100644 index 000000000..0b03d2ef8 --- /dev/null +++ b/libraries/aws_wafv2_size_constraint_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2SizeConstraintSets < AwsResourceBase + name "aws_wafv2_size_constraint_sets" + desc "Describes all the WAF size constraint sets." + + example " + describe aws_wafv2_size_constraint_set do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:size_constraint_set_ids, field: :size_constraint_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_size_constraint_sets.map do |table| + table.map { |table_name| { + name: table_name.size_constraint_sets.map(&:name), + size_constraint_set_id: table_name.size_constraint_sets.map(&:size_constraint_set_id), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_sql_injection_match_set.rb b/libraries/aws_wafv2_sql_injection_match_set.rb new file mode 100644 index 000000000..16055f1ba --- /dev/null +++ b/libraries/aws_wafv2_sql_injection_match_set.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2SQLInjectionMatchSet < AwsResourceBase + name "aws_wafv2_sql_injection_match_set" + desc "Describes one WAF SQL Injection match set." + + example " + describe aws_wafv2_sql_injection_match_set(sql_injection_match_set_id: 'SQL_INJECTION_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { sql_injection_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(sql_injection_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: sql_injection_match_set_id must be provided" unless opts[:sql_injection_match_set_id] && !opts[:sql_injection_match_set_id].empty? + @display_name = opts[:sql_injection_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_sql_injection_match_set({ sql_injection_match_set_id: opts[:sql_injection_match_set_id] }) + @resp = resp.sql_injection_match_set.to_h + create_resource_methods(@resp) + end + end + + def sql_injection_match_set_id + return nil unless exists? + @resp[:sql_injection_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "SQL Injection Match Set ID: #{@display_name}" + end + + def sql_injection_match_tuples_field_to_match_types + sql_injection_match_tuples.map(&:field_to_match).map(&:type) + end + + def sql_injection_match_tuples_field_to_match_data + sql_injection_match_tuples.map(&:field_to_match).map(&:data) + end + + def sql_injection_match_tuples_text_transformations + sql_injection_match_tuples.map(&:text_transformation) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_sql_injection_match_sets.rb b/libraries/aws_wafv2_sql_injection_match_sets.rb new file mode 100644 index 000000000..6da51a708 --- /dev/null +++ b/libraries/aws_wafv2_sql_injection_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2SQLInjectionMatchSets < AwsResourceBase + name "aws_wafv2_sql_injection_match_sets" + desc "Verifies settings for all the WAF SQL Injection match set." + + example " + describe aws_wafv2_sql_injection_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:sql_injection_match_set_ids, field: :sql_injection_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_sql_injection_match_sets.map do |table| + table.map { |table_name| { + sql_injection_match_set_id: table_name.sql_injection_match_sets.map(&:sql_injection_match_set_id), + name: table_name.sql_injection_match_sets.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_web_acl.rb b/libraries/aws_wafv2_web_acl.rb new file mode 100644 index 000000000..f3f283488 --- /dev/null +++ b/libraries/aws_wafv2_web_acl.rb @@ -0,0 +1,80 @@ +require "aws_backend" + +class AWSWAFV2WebACL < AwsResourceBase + name "aws_wafv2_web_acl" + desc "Describes one WAF Web ACL." + + example " + describe aws_wafv2_web_acl(name: 'NAME', web_acl_id: 'WEB_ACL_ID', scope 'SCOPE') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { name: opts } if opts.is_a?(String) + opts = { web_acl_id: opts } if opts.is_a?(String) + opts = { scope: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(name web_acl_id scope)) + raise ArgumentError, "#{@__resource_name__}: name, web_acl_id and scope must be provided" unless opts[:name] && !opts[:name].empty? && opts[:web_acl_id] && !opts[:web_acl_id].empty? && opts[:scope] && !opts[:scope].empty? + @display_name = opts[:name] + catch_aws_errors do + resp = @aws.waf_client_v2.get_web_acl({ name: opts[:name], web_acl_id: opts[:web_acl_id], scope: opts[:scope] }) + @resp = resp.web_acl.to_h + create_resource_methods(@resp) + end + end + + def web_acl_id + return nil unless exists? + @resp[:web_acl_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Web ACL ID: #{@display_name}" + end + + def rules_priorities + rules.map(&:priority) + end + + def rules_rule_ids + rules.map(&:rule_id) + end + + def rules_actions + rules.map(&:action) + end + + def rules_action_types + rules.map(&:action).map(&:type) + end + + def rules_override_actions + rules.map(&:override_action) + end + + def rules_override_action_types + rules.map(&:override_action).map(&:type) + end + + def rules_types + rules.map(&:type) + end + + def rules_excluded_rules + rules.map(&:excluded_rules) + end + + def rules_excluded_rules_rule_ids + rules.map(&:excluded_rules).map(&:rule_id) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_web_acls.rb b/libraries/aws_wafv2_web_acls.rb new file mode 100644 index 000000000..3043f0520 --- /dev/null +++ b/libraries/aws_wafv2_web_acls.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2WebACLS < AwsResourceBase + name "aws_wafv2_web_acls" + desc "Verifies settings for all the Web ACLs." + + example " + describe aws_wafv2_web_acls do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:web_acl_ids, field: :web_acl_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_web_acls.map do |table| + table.map { |table_name| { + web_acl_id: table_name.web_acls.map(&:web_acl_id), + name: table_name.web_acls.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_xss_match_set.rb b/libraries/aws_wafv2_xss_match_set.rb new file mode 100644 index 000000000..076675b5a --- /dev/null +++ b/libraries/aws_wafv2_xss_match_set.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2XSSMatchSet < AwsResourceBase + name "aws_wafv2_xss_match_set" + desc "Describes one WAF XSS match set." + + example " + describe aws_wafv2_xss_match_set(xss_match_set_id: 'XSS_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { xss_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(xss_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: xss_match_set_id must be provided" unless opts[:xss_match_set_id] && !opts[:xss_match_set_id].empty? + @display_name = opts[:xss_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_xss_match_set({ xss_match_set_id: opts[:xss_match_set_id] }) + @resp = resp.xss_match_set.to_h + create_resource_methods(@resp) + end + end + + def xss_match_set_id + return nil unless exists? + @resp[:xss_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "XSS Match Set ID: #{@display_name}" + end + + def xss_match_tuples_field_to_match_types + xss_match_tuples.map(&:field_to_match).map(&:type) + end + + def xss_match_tuples_field_to_match_data + xss_match_tuples.map(&:field_to_match).map(&:data) + end + + def xss_match_tuples_text_transformations + xss_match_tuples.map(&:text_transformation) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_xss_match_sets.rb b/libraries/aws_wafv2_xss_match_sets.rb new file mode 100644 index 000000000..ec24d5806 --- /dev/null +++ b/libraries/aws_wafv2_xss_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2XSSMatchSets < AwsResourceBase + name "aws_wafv2_xss_match_sets" + desc "Verifies settings for all the WAF XSS Match Set." + + example " + describe aws_wafv2_xss_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:xss_match_set_ids, field: :xss_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_xss_match_sets.map do |table| + table.map { |table_name| { + xss_match_set_id: table_name.xss_match_sets.map(&:xss_match_set_id), + name: table_name.xss_match_sets.map(&:name), + } + } + end.flatten + end + end +end From 37d45df4163997c8466502d4d4bc13144b39b2c9 Mon Sep 17 00:00:00 2001 From: Rob de Heer Date: Sun, 17 Sep 2023 11:09:45 -0700 Subject: [PATCH 2/2] Added support for aws waf v2 Signed-off-by: Rob de Heer robertsdeheer@gmail.com --- libraries/aws_backend.rb | 5 ++ libraries/aws_wafv2_byte_match_set.rb | 66 +++++++++++++++ libraries/aws_wafv2_byte_match_sets.rb | 37 +++++++++ libraries/aws_wafv2_ip_set.rb | 50 ++++++++++++ libraries/aws_wafv2_ip_sets.rb | 37 +++++++++ libraries/aws_wafv2_rule.rb | 54 +++++++++++++ libraries/aws_wafv2_rules.rb | 37 +++++++++ libraries/aws_wafv2_size_constraint_set.rb | 62 ++++++++++++++ libraries/aws_wafv2_size_constraint_sets.rb | 37 +++++++++ .../aws_wafv2_sql_injection_match_set.rb | 54 +++++++++++++ .../aws_wafv2_sql_injection_match_sets.rb | 37 +++++++++ libraries/aws_wafv2_web_acl.rb | 80 +++++++++++++++++++ libraries/aws_wafv2_web_acls.rb | 37 +++++++++ libraries/aws_wafv2_xss_match_set.rb | 54 +++++++++++++ libraries/aws_wafv2_xss_match_sets.rb | 37 +++++++++ 15 files changed, 684 insertions(+) create mode 100644 libraries/aws_wafv2_byte_match_set.rb create mode 100644 libraries/aws_wafv2_byte_match_sets.rb create mode 100644 libraries/aws_wafv2_ip_set.rb create mode 100644 libraries/aws_wafv2_ip_sets.rb create mode 100644 libraries/aws_wafv2_rule.rb create mode 100644 libraries/aws_wafv2_rules.rb create mode 100644 libraries/aws_wafv2_size_constraint_set.rb create mode 100644 libraries/aws_wafv2_size_constraint_sets.rb create mode 100644 libraries/aws_wafv2_sql_injection_match_set.rb create mode 100644 libraries/aws_wafv2_sql_injection_match_sets.rb create mode 100644 libraries/aws_wafv2_web_acl.rb create mode 100644 libraries/aws_wafv2_web_acls.rb create mode 100644 libraries/aws_wafv2_xss_match_set.rb create mode 100644 libraries/aws_wafv2_xss_match_sets.rb diff --git a/libraries/aws_backend.rb b/libraries/aws_backend.rb index fb31dd227..010449760 100644 --- a/libraries/aws_backend.rb +++ b/libraries/aws_backend.rb @@ -59,6 +59,7 @@ require "aws-sdk-securityhub" require "aws-sdk-ses" require "aws-sdk-waf" +require "aws-sdk-wafv2" require "aws-sdk-synthetics" require "aws-sdk-apigatewayv2" @@ -330,6 +331,10 @@ def waf_client aws_client(Aws::WAF::Client) end + def waf_client_v2 + aws_client(Aws::WAFWAFV2::Client) + end + def synthetics_client aws_client(Aws::Synthetics::Client) end diff --git a/libraries/aws_wafv2_byte_match_set.rb b/libraries/aws_wafv2_byte_match_set.rb new file mode 100644 index 000000000..08067a4e1 --- /dev/null +++ b/libraries/aws_wafv2_byte_match_set.rb @@ -0,0 +1,66 @@ +require "aws_backend" + +class AWSWAFV2ByteMatchSet < AwsResourceBase + name "aws_wafv2_byte_match_set" + desc "Describes one WAF byte set." + + example " + describe aws_wafv2_byte_match_set(byte_match_set_id: 'BYTE_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { byte_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(byte_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: byte_match_set_id must be provided" unless opts[:byte_match_set_id] && !opts[:byte_match_set_id].empty? + @display_name = opts[:byte_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_byte_match_set({ byte_match_set_id: opts[:byte_match_set_id] }) + @resp = resp.byte_match_set.to_h + create_resource_methods(@resp) + end + end + + def byte_match_set_id + return nil unless exists? + @resp[:byte_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Byte Match Set ID: #{@display_name}" + end + + def byte_match_tuples_field_to_matches + byte_match_tuples.map(&:field_to_match) + end + + def byte_match_tuples_field_to_match_types + byte_match_tuples.map(&:field_to_match).map(&:type) + end + + def byte_match_tuples_field_to_match_data + byte_match_tuples.map(&:field_to_match).map(&:data) + end + + def byte_match_tuples_target_strings + byte_match_tuples.map(&:target_string) + end + + def byte_match_tuples_text_transformations + byte_match_tuples.map(&:text_transformation) + end + + def byte_match_tuples_positional_constraints + byte_match_tuples.map(&:positional_constraint) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_byte_match_sets.rb b/libraries/aws_wafv2_byte_match_sets.rb new file mode 100644 index 000000000..0550eb6ae --- /dev/null +++ b/libraries/aws_wafv2_byte_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2ByteMatchSets < AwsResourceBase + name "aws_wafv2_byte_match_sets" + desc "Verifies settings for all the WAF rules." + + example " + describe aws_wafv2_byte_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:byte_match_set_ids, field: :byte_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_byte_match_sets.map do |table| + table.map { |table_name| { + byte_match_set_id: table_name.byte_match_sets.map(&:byte_match_set_id), + name: table_name.byte_match_sets.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_ip_set.rb b/libraries/aws_wafv2_ip_set.rb new file mode 100644 index 000000000..b0461538c --- /dev/null +++ b/libraries/aws_wafv2_ip_set.rb @@ -0,0 +1,50 @@ +require "aws_backend" + +class AWSWAFV2IPSet < AwsResourceBase + name "aws_wafv2_ip_set" + desc "Describes one WAF IP set." + + example " + describe aws_wafv2_ip_set(ip_set_id: 'IP_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { ip_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(ip_set_id)) + raise ArgumentError, "#{@__resource_name__}: ip_set_id must be provided" unless opts[:ip_set_id] && !opts[:ip_set_id].empty? + @display_name = opts[:ip_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_ip_set({ ip_set_id: opts[:ip_set_id] }) + @resp = resp.ip_set.to_h + create_resource_methods(@resp) + end + end + + def ip_set_id + return nil unless exists? + @resp[:ip_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "IP Set ID: #{@display_name}" + end + + def ip_set_descriptors_types + ip_set_descriptors.map(&:type) + end + + def ip_set_descriptors_values + ip_set_descriptors.map(&:value) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_ip_sets.rb b/libraries/aws_wafv2_ip_sets.rb new file mode 100644 index 000000000..289810ffd --- /dev/null +++ b/libraries/aws_wafv2_ip_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2IPSets < AwsResourceBase + name "aws_wafv2_ip_sets" + desc "Verifies settings for all the IP sets." + + example " + describe aws_wafv2_ip_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:ip_set_ids, field: :ip_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_ip_sets.map do |table| + table.map { |table_name| { + name: table_name.ip_sets.map(&:name), + ip_set_id: table_name.ip_sets.map(&:ip_set_id), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_rule.rb b/libraries/aws_wafv2_rule.rb new file mode 100644 index 000000000..adcd6bf20 --- /dev/null +++ b/libraries/aws_wafv2_rule.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2Rule < AwsResourceBase + name "aws_wafv2_rule" + desc "Describes one WAF rule." + + example " + describe aws_wafv2_rule(rule_id: 'RULE_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { rule_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(rule_id)) + raise ArgumentError, "#{@__resource_name__}: rule_id must be provided" unless opts[:rule_id] && !opts[:rule_id].empty? + @display_name = opts[:rule_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_rule({ rule_id: opts[:rule_id] }) + @resp = resp.rule.to_h + create_resource_methods(@resp) + end + end + + def rule_id + return nil unless exists? + @resp[:rule_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Rule ID: #{@display_name}" + end + + def predicates_negated + predicates.map(&:negated) + end + + def predicates_type + predicates.map(&:type) + end + + def predicates_data_id + predicates.map(&:data_id) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_rules.rb b/libraries/aws_wafv2_rules.rb new file mode 100644 index 000000000..45c9fdf39 --- /dev/null +++ b/libraries/aws_wafv2_rules.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2Rules < AwsResourceBase + name "aws_wafv2_rules" + desc "Verifies settings for all the WAF rules." + + example " + describe aws_wafv2_rules do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:rule_ids, field: :rule_id) + .register_column(:names, field: :name) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_rules.map do |table| + table.rules.map { |table_name| { + rule_id: table_name[:rule_id], + name: table_name[:name], + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_size_constraint_set.rb b/libraries/aws_wafv2_size_constraint_set.rb new file mode 100644 index 000000000..b3b023f18 --- /dev/null +++ b/libraries/aws_wafv2_size_constraint_set.rb @@ -0,0 +1,62 @@ +require "aws_backend" + +class AWSWAFV2SizeConstraintSet < AwsResourceBase + name "aws_wafv2_size_constraint_set" + desc "Describes one WAF size constraint set." + + example " + describe aws_wafv2_size_constraint_set(size_constraint_set_id: 'SIZE_CONSTRAINT_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { size_constraint_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(size_constraint_set_id)) + raise ArgumentError, "#{@__resource_name__}: size_constraint_set_id must be provided" unless opts[:size_constraint_set_id] && !opts[:size_constraint_set_id].empty? + @display_name = opts[:size_constraint_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_size_constraint_set({ size_constraint_set_id: opts[:size_constraint_set_id] }) + @resp = resp.size_constraint_set.to_h + create_resource_methods(@resp) + end + end + + def size_constraint_set_id + return nil unless exists? + @resp[:size_constraint_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Size Constraint Set ID: #{@display_name}" + end + + def size_constraints_field_to_match_types + size_constraints.map(&:field_to_match).map(&:type) + end + + def size_constraints_field_to_match_data + size_constraints.map(&:field_to_match).map(&:data) + end + + def size_constraints_text_transformations + size_constraints.map(&:text_transformation) + end + + def size_constraints_comparison_operators + size_constraints.map(&:comparison_operator) + end + + def size_constraints_sizes + size_constraints.map(&:size) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_size_constraint_sets.rb b/libraries/aws_wafv2_size_constraint_sets.rb new file mode 100644 index 000000000..0b03d2ef8 --- /dev/null +++ b/libraries/aws_wafv2_size_constraint_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2SizeConstraintSets < AwsResourceBase + name "aws_wafv2_size_constraint_sets" + desc "Describes all the WAF size constraint sets." + + example " + describe aws_wafv2_size_constraint_set do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:size_constraint_set_ids, field: :size_constraint_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_size_constraint_sets.map do |table| + table.map { |table_name| { + name: table_name.size_constraint_sets.map(&:name), + size_constraint_set_id: table_name.size_constraint_sets.map(&:size_constraint_set_id), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_sql_injection_match_set.rb b/libraries/aws_wafv2_sql_injection_match_set.rb new file mode 100644 index 000000000..16055f1ba --- /dev/null +++ b/libraries/aws_wafv2_sql_injection_match_set.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2SQLInjectionMatchSet < AwsResourceBase + name "aws_wafv2_sql_injection_match_set" + desc "Describes one WAF SQL Injection match set." + + example " + describe aws_wafv2_sql_injection_match_set(sql_injection_match_set_id: 'SQL_INJECTION_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { sql_injection_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(sql_injection_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: sql_injection_match_set_id must be provided" unless opts[:sql_injection_match_set_id] && !opts[:sql_injection_match_set_id].empty? + @display_name = opts[:sql_injection_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_sql_injection_match_set({ sql_injection_match_set_id: opts[:sql_injection_match_set_id] }) + @resp = resp.sql_injection_match_set.to_h + create_resource_methods(@resp) + end + end + + def sql_injection_match_set_id + return nil unless exists? + @resp[:sql_injection_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "SQL Injection Match Set ID: #{@display_name}" + end + + def sql_injection_match_tuples_field_to_match_types + sql_injection_match_tuples.map(&:field_to_match).map(&:type) + end + + def sql_injection_match_tuples_field_to_match_data + sql_injection_match_tuples.map(&:field_to_match).map(&:data) + end + + def sql_injection_match_tuples_text_transformations + sql_injection_match_tuples.map(&:text_transformation) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_sql_injection_match_sets.rb b/libraries/aws_wafv2_sql_injection_match_sets.rb new file mode 100644 index 000000000..6da51a708 --- /dev/null +++ b/libraries/aws_wafv2_sql_injection_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2SQLInjectionMatchSets < AwsResourceBase + name "aws_wafv2_sql_injection_match_sets" + desc "Verifies settings for all the WAF SQL Injection match set." + + example " + describe aws_wafv2_sql_injection_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:sql_injection_match_set_ids, field: :sql_injection_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_sql_injection_match_sets.map do |table| + table.map { |table_name| { + sql_injection_match_set_id: table_name.sql_injection_match_sets.map(&:sql_injection_match_set_id), + name: table_name.sql_injection_match_sets.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_web_acl.rb b/libraries/aws_wafv2_web_acl.rb new file mode 100644 index 000000000..f3f283488 --- /dev/null +++ b/libraries/aws_wafv2_web_acl.rb @@ -0,0 +1,80 @@ +require "aws_backend" + +class AWSWAFV2WebACL < AwsResourceBase + name "aws_wafv2_web_acl" + desc "Describes one WAF Web ACL." + + example " + describe aws_wafv2_web_acl(name: 'NAME', web_acl_id: 'WEB_ACL_ID', scope 'SCOPE') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { name: opts } if opts.is_a?(String) + opts = { web_acl_id: opts } if opts.is_a?(String) + opts = { scope: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(name web_acl_id scope)) + raise ArgumentError, "#{@__resource_name__}: name, web_acl_id and scope must be provided" unless opts[:name] && !opts[:name].empty? && opts[:web_acl_id] && !opts[:web_acl_id].empty? && opts[:scope] && !opts[:scope].empty? + @display_name = opts[:name] + catch_aws_errors do + resp = @aws.waf_client_v2.get_web_acl({ name: opts[:name], web_acl_id: opts[:web_acl_id], scope: opts[:scope] }) + @resp = resp.web_acl.to_h + create_resource_methods(@resp) + end + end + + def web_acl_id + return nil unless exists? + @resp[:web_acl_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "Web ACL ID: #{@display_name}" + end + + def rules_priorities + rules.map(&:priority) + end + + def rules_rule_ids + rules.map(&:rule_id) + end + + def rules_actions + rules.map(&:action) + end + + def rules_action_types + rules.map(&:action).map(&:type) + end + + def rules_override_actions + rules.map(&:override_action) + end + + def rules_override_action_types + rules.map(&:override_action).map(&:type) + end + + def rules_types + rules.map(&:type) + end + + def rules_excluded_rules + rules.map(&:excluded_rules) + end + + def rules_excluded_rules_rule_ids + rules.map(&:excluded_rules).map(&:rule_id) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_web_acls.rb b/libraries/aws_wafv2_web_acls.rb new file mode 100644 index 000000000..3043f0520 --- /dev/null +++ b/libraries/aws_wafv2_web_acls.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2WebACLS < AwsResourceBase + name "aws_wafv2_web_acls" + desc "Verifies settings for all the Web ACLs." + + example " + describe aws_wafv2_web_acls do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:web_acl_ids, field: :web_acl_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_web_acls.map do |table| + table.map { |table_name| { + web_acl_id: table_name.web_acls.map(&:web_acl_id), + name: table_name.web_acls.map(&:name), + } + } + end.flatten + end + end +end diff --git a/libraries/aws_wafv2_xss_match_set.rb b/libraries/aws_wafv2_xss_match_set.rb new file mode 100644 index 000000000..076675b5a --- /dev/null +++ b/libraries/aws_wafv2_xss_match_set.rb @@ -0,0 +1,54 @@ +require "aws_backend" + +class AWSWAFV2XSSMatchSet < AwsResourceBase + name "aws_wafv2_xss_match_set" + desc "Describes one WAF XSS match set." + + example " + describe aws_wafv2_xss_match_set(xss_match_set_id: 'XSS_MATCH_SET_ID') do + it { should exits } + end + " + + def initialize(opts = {}) + opts = { xss_match_set_id: opts } if opts.is_a?(String) + super(opts) + validate_parameters(required: %i(xss_match_set_id)) + raise ArgumentError, "#{@__resource_name__}: xss_match_set_id must be provided" unless opts[:xss_match_set_id] && !opts[:xss_match_set_id].empty? + @display_name = opts[:xss_match_set_id] + catch_aws_errors do + resp = @aws.waf_client_v2.get_xss_match_set({ xss_match_set_id: opts[:xss_match_set_id] }) + @resp = resp.xss_match_set.to_h + create_resource_methods(@resp) + end + end + + def xss_match_set_id + return nil unless exists? + @resp[:xss_match_set_id] + end + + def exists? + !@resp.nil? && !@resp.empty? + end + + def to_s + "XSS Match Set ID: #{@display_name}" + end + + def xss_match_tuples_field_to_match_types + xss_match_tuples.map(&:field_to_match).map(&:type) + end + + def xss_match_tuples_field_to_match_data + xss_match_tuples.map(&:field_to_match).map(&:data) + end + + def xss_match_tuples_text_transformations + xss_match_tuples.map(&:text_transformation) + end + + def resource_id + @display_name + end +end diff --git a/libraries/aws_wafv2_xss_match_sets.rb b/libraries/aws_wafv2_xss_match_sets.rb new file mode 100644 index 000000000..ec24d5806 --- /dev/null +++ b/libraries/aws_wafv2_xss_match_sets.rb @@ -0,0 +1,37 @@ +require "aws_backend" + +class AWSWAFV2XSSMatchSets < AwsResourceBase + name "aws_wafv2_xss_match_sets" + desc "Verifies settings for all the WAF XSS Match Set." + + example " + describe aws_wafv2_xss_match_sets do + it { should exist } + end + " + + attr_reader :table + + def initialize(opts = {}) + super(opts) + validate_parameters + @table = fetch_data + end + + FilterTable.create + .register_column(:xss_match_set_ids, field: :xss_match_set_id, style: :simple) + .register_column(:names, field: :name, style: :simple) + .install_filter_methods_on_resource(self, :table) + + def fetch_data + catch_aws_errors do + @resp = @aws.waf_client_v2.list_xss_match_sets.map do |table| + table.map { |table_name| { + xss_match_set_id: table_name.xss_match_sets.map(&:xss_match_set_id), + name: table_name.xss_match_sets.map(&:name), + } + } + end.flatten + end + end +end