heimdall_tools 1.3.35 → 1.3.39

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30a8aa48d76c322433d3b7233585d2f7265c5d9906147f904a56d7c37468943d
4
- data.tar.gz: de9c85b3ec842451ba8ccd52ef66b516390677c1d9971e602c434cc21725d619
3
+ metadata.gz: f629e9d519b119329b6bfd8a8eeb7826420262f654cbe127e6efe05b88fc9ac3
4
+ data.tar.gz: 1d66b4d6505221cbd2fbb06dc4d856c179d8db11566148386b2f67bd0110e851
5
5
  SHA512:
6
- metadata.gz: 735203a3dedc20625a366530d50c5f0e11a5a654a13f1264b53dd239b6902a851b35ea49ae1b783714399d6c2215ebf137a2c54e4edb6a2c7e40e3a17ef1d8db
7
- data.tar.gz: 19b63fc27d52ede491025d7880771e31ffeaf090707b73885970b9455e4c81bda1c15b428621436e8086f9e6d5521d6810fd1000df4f2900fe8b57911fc44488
6
+ metadata.gz: 6f7898ac0e5b94f3efaeda24117c4f8ff6dc06bf1140786d6c99eccffbdc1fa9792c93eda05847c7e6a9a1d2e5d70596a486ba4fe53bc931eace7bb6dff45146
7
+ data.tar.gz: 34b4302cae0fad8bcec837e2b81df578aade9e3850a1040a0cadf1510e57078a7f110bdae8c74fd4974bec079b7c9115f1ff573536a32221936ba93e4eaf9280
data/README.md CHANGED
@@ -13,6 +13,8 @@ HeimdallTools supplies several methods to convert output from various tools to "
13
13
  - **snyk_mapper** - commercial package vulnerability scanner
14
14
  - **nikto_mapper** - open-source web server scanner
15
15
  - **jfrog_xray_mapper** - package vulnerability scanner
16
+ - **dbprotect_mapper** - database vulnerability scanner
17
+ - **aws_config_mapper** - assess, audit, and evaluate AWS resources
16
18
 
17
19
  Ruby 2.4 or higher (check using "ruby -v")
18
20
 
@@ -197,6 +199,41 @@ FLAGS:
197
199
  example: heimdall_tools jfrog_xray_mapper -j xray_results.json -o xray_results_hdf.json
198
200
  ```
199
201
 
202
+ ## dbprotect_mapper
203
+
204
+ dbprotect_mapper translates DBProtect report in `Check Results Details` format XML to HDF format JSON be viewed on Heimdall.
205
+
206
+ ```
207
+ USAGE: heimdall_tools dbprotect_mapper [OPTIONS] -x <check_results_details_report_xml> -o <db_protect_hdf.json>
208
+
209
+ FLAGS:
210
+ -x <check_results_details_report_xml> : path to DBProtect report XML file.
211
+ -o --output <scan-results> : path to output scan-results json.
212
+ -V --verbose : verbose run [optional].
213
+
214
+ example: heimdall_tools dbprotect_mapper -x check_results_details_report.xml -o db_protect_hdf.json
215
+ ```
216
+
217
+ ## aws_config_mapper
218
+
219
+ aws_config_mapper pulls Ruby AWS SDK data to translate AWS Config Rule results into HDF format json to be viewable in Heimdall
220
+
221
+ ### AWS Config Rule Mapping:
222
+ The mapping of AWS Config Rules to 800-53 Controls was sourced from [this link](https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-nist-800-53_rev_4.html).
223
+
224
+ ### Authentication with AWS:
225
+ [Developer Guide for configuring Ruby AWS SDK for authentication](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html)
226
+
227
+ ```
228
+ USAGE: heimdall_tools aws_config_mapper [OPTIONS] -o <hdf-scan-results.json>
229
+
230
+ FLAGS:
231
+ -o --output <scan-results> : path to output scan-results json.
232
+ -V --verbose : verbose run [optional].
233
+
234
+ example: heimdall_tools aws_config_mapper -o aws_config_results_hdf.json
235
+ ```
236
+
200
237
  ## version
201
238
 
202
239
  Prints out the gem version
@@ -0,0 +1,107 @@
1
+ AwsConfigRuleName,NIST-ID,Rev
2
+ secretsmanager-scheduled-rotation-success-check,AC-2(1)|AC-2(j),4
3
+ iam-user-group-membership-check,AC-2(1)|AC-2(j)|AC-3|AC-6,4
4
+ iam-password-policy,AC-2(1)|AC-2(f)|AC-2(j)|IA-2|IA-5(1)(a)(d)(e)|IA-5(4),4
5
+ access-keys-rotated,AC-2(1)|AC-2(j),4
6
+ iam-user-unused-credentials-check,AC-2(1)|AC-2(3)|AC-2(f)|AC-3|AC-6,4
7
+ securityhub-enabled,AC-2(1)|AC-2(4)|AC-2(12)(a)|AC-2(g)|AC-17(1)|AU-6(1)(3)|CA-7(a)(b)|SA-10|SI-4(2)|SI-4(4)|SI-4(5)|SI-4(16)|SI-4(a)(b)(c),4
8
+ guardduty-enabled-centralized,AC-2(1)|AC-2(4)|AC-2(12)(a)|AC-2(g)|AC-17(1)|AU-6(1)(3)|CA-7(a)(b)|RA-5|SA-10|SI-4(1)|SI-4(2)|SI-4(4)|SI-4(5)|SI-4(16)|SI-4(a)(b)(c),4
9
+ cloud-trail-cloud-watch-logs-enabled,AC-2(4)|AC-2(g)|AU-2(a)(d)|AU-3|AU-6(1)(3)|AU-7(1)|AU-12(a)(c)|CA-7(a)(b)|SI-4(2)|SI-4(4)|SI-4(5)|SI-4(a)(b)(c),4
10
+ cloudtrail-enabled,AC-2(4)|AC-2(g)|AU-2(a)(d)|AU-3|AU-12(a)(c),4
11
+ multi-region-cloudtrail-enabled,AC-2(4)|AU-2(a)(d)|AU-3|AU-12(a)(c),4
12
+ rds-logging-enabled,AC-2(4)|AC-2(g)|AU-2(a)(d)|AU-3|AU-12(a)(c),4
13
+ cloudwatch-alarm-action-check,AC-2(4)|AU-6(1)(3)|AU-7(1)|CA-7(a)(b)|IR-4(1)|SI-4(2)|SI-4(4)|SI-4(5)|SI-4(a)(b)(c),4
14
+ redshift-cluster-configuration-check,AC-2(4)|AC-2(g)|AU-2(a)(d)|AU-3|AU-12(a)(c)|SC-13|SC-28,4
15
+ iam-root-access-key-check,AC-2(f)|AC-2(j)|AC-3|AC-6|AC-6(10),4
16
+ s3-bucket-logging-enabled,AC-2(g)|AU-2(a)(d)|AU-3|AU-12(a)(c),4
17
+ cloudtrail-s3-dataevents-enabled,AC-2(g)|AU-2(a)(d)|AU-3|AU-12(a)(c),4
18
+ root-account-mfa-enabled,AC-2(j)|IA-2(1)(11),4
19
+ emr-kerberos-enabled,AC-2(j)|AC-3|AC-5(c)|AC-6,4
20
+ iam-group-has-users-check,AC-2(j)|AC-3|AC-5(c)|AC-6|SC-2,4
21
+ iam-policy-no-statements-with-admin-access,AC-2(j)|AC-3|AC-5(c)|AC-6|SC-2,4
22
+ iam-user-no-policies-check,AC-2(j)|AC-3|AC-5(c)|AC-6,4
23
+ s3-bucket-public-write-prohibited,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
24
+ lambda-function-public-access-prohibited,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
25
+ rds-snapshots-public-prohibited,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
26
+ redshift-cluster-public-access-check,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
27
+ s3-bucket-policy-grantee-check,AC-3|AC-6|SC-7|SC-7(3),4
28
+ s3-bucket-public-read-prohibited,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
29
+ s3-account-level-public-access-blocks,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
30
+ dms-replication-not-public,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
31
+ ebs-snapshot-public-restorable-check,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
32
+ sagemaker-notebook-no-direct-internet-access,AC-3|AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
33
+ rds-instance-public-access-check,AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
34
+ lambda-inside-vpc,AC-4|SC-7|SC-7(3),4
35
+ ec2-instances-in-vpc,AC-4|SC-7|SC-7(3),4
36
+ restricted-common-ports,AC-4|CM-2|SC-7|SC-7(3),4
37
+ restricted-ssh,AC-4|SC-7|SC-7(3),4
38
+ vpc-default-security-group-closed,AC-4|SC-7|SC-7(3),4
39
+ vpc-sg-open-only-to-authorized-ports,AC-4|SC-7|SC-7(3),4
40
+ acm-certificate-expiration-check,AC-4|AC-17(2)|SC-12,4
41
+ ec2-instance-no-public-ip,AC-4|AC-6|AC-21(b)|SC-7|SC-7(3),4
42
+ elasticsearch-in-vpc-only,AC-4|SC-7|SC-7(3),4
43
+ emr-master-no-public-ip,AC-4|AC-21(b)|SC-7|SC-7(3),4
44
+ internet-gateway-authorized-vpc-only,AC-4|AC-17(3)|SC-7|SC-7(3),4
45
+ codebuild-project-envvar-awscred-check,AC-6|IA-5(7)|SA-3(a),4
46
+ ec2-imdsv2-check,AC-6,4
47
+ iam-no-inline-policy-check,AC-6,4
48
+ alb-http-to-https-redirection-check,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-13|SC-23,4
49
+ redshift-require-tls-ssl,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-13,4
50
+ s3-bucket-ssl-requests-only,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-13,4
51
+ elb-acm-certificate-required,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-13,4
52
+ alb-http-drop-invalid-header-enabled,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-23,4
53
+ elb-tls-https-listeners-only,AC-17(2)|SC-7|SC-8|SC-8(1)|SC-23,4
54
+ api-gw-execution-logging-enabled,AU-2(a)(d)|AU-3|AU-12(a)(c),4
55
+ elb-logging-enabled,AU-2(a)(d)|AU-3|AU-12(a)(c),4
56
+ vpc-flow-logs-enabled,AU-2(a)(d)|AU-3|AU-12(a)(c),4
57
+ wafv2-logging-enabled,AU-2(a)(d)|AU-3|AU-12(a)(c)|SC-7|SI-4(a)(b)(c),4
58
+ cloud-trail-encryption-enabled,AU-9|SC-13|SC-28,4
59
+ cloudwatch-log-group-encrypted,AU-9|SC-13|SC-28,4
60
+ s3-bucket-replication-enabled,AU-9(2)|CP-9(b)|CP-10|SC-5|SC-36,4
61
+ cw-loggroup-retention-period-check,AU-11|SI-12,4
62
+ ec2-instance-detailed-monitoring-enabled,CA-7(a)(b)|SI-4(2)|SI-4(a)(b)(c),4
63
+ rds-enhanced-monitoring-enabled,CA-7(a)(b),4
64
+ ec2-instance-managed-by-systems-manager,CM-2|CM-7(a)|CM-8(1)|CM-8(3)(a)|SA-3(a)|SA-10|SI-2(2)|SI-7(1),4
65
+ ec2-managedinstance-association-compliance-status-check,CM-2|CM-7(a)|CM-8(3)(a)|SI-2(2),4
66
+ ec2-stopped-instance,CM-2,4
67
+ ec2-volume-inuse-check,CM-2|SC-4,4
68
+ elb-deletion-protection-enabled,CM-2|CP-10,4
69
+ cloudtrail-security-trail-enabled,CM-2,4
70
+ ec2-managedinstance-patch-compliance-status-check,CM-8(3)(a)|SI-2(2)|SI-7(1),4
71
+ db-instance-backup-enabled,CP-9(b)|CP-10|SI-12,4
72
+ dynamodb-pitr-enabled,CP-9(b)|CP-10|SI-12,4
73
+ elasticache-redis-cluster-automatic-backup-check,CP-9(b)|CP-10|SI-12,4
74
+ dynamodb-in-backup-plan,CP-9(b)|CP-10|SI-12,4
75
+ ebs-in-backup-plan,CP-9(b)|CP-10|SI-12,4
76
+ efs-in-backup-plan,CP-9(b)|CP-10|SI-12,4
77
+ rds-in-backup-plan,CP-9(b)|CP-10|SI-12,4
78
+ dynamodb-autoscaling-enabled,CP-10|SC-5,4
79
+ rds-multi-az-support,CP-10|SC-5|SC-36,4
80
+ s3-bucket-versioning-enabled,CP-10|SI-12,4
81
+ vpc-vpn-2-tunnels-up,CP-10,4
82
+ elb-cross-zone-load-balancing-enabled,CP-10|SC-5,4
83
+ root-account-hardware-mfa-enabled,IA-2(1)(11),4
84
+ mfa-enabled-for-iam-console-access,IA-2(1)(2)(11),4
85
+ iam-user-mfa-enabled,IA-2(1)(2)(11),4
86
+ guardduty-non-archived-findings,IR-4(1)|IR-6(1)|IR-7(1)|RA-5|SA-10|SI-4(a)(b)(c),4
87
+ codebuild-project-source-repo-url-check,SA-3(a),4
88
+ autoscaling-group-elb-healthcheck-required,SC-5,4
89
+ rds-instance-deletion-protection-enabled,SC-5,4
90
+ alb-waf-enabled,SC-7|SI-4(a)(b)(c),4
91
+ elasticsearch-node-to-node-encryption-check,SC-7|SC-8|SC-8(1),4
92
+ cmk-backing-key-rotation-enabled,SC-12,4
93
+ kms-cmk-not-scheduled-for-deletion,SC-12|SC-28,4
94
+ api-gw-cache-enabled-and-encrypted,SC-13|SC-28,4
95
+ efs-encrypted-check,SC-13|SC-28,4
96
+ elasticsearch-encrypted-at-rest,SC-13|SC-28,4
97
+ encrypted-volumes,SC-13|SC-28,4
98
+ rds-storage-encrypted,SC-13|SC-28,4
99
+ s3-bucket-server-side-encryption-enabled,SC-13|SC-28,4
100
+ sagemaker-endpoint-configuration-kms-key-configured,SC-13|SC-28,4
101
+ sagemaker-notebook-instance-kms-key-configured,SC-13|SC-28,4
102
+ sns-encrypted-kms,SC-13|SC-28,4
103
+ dynamodb-table-encrypted-kms,SC-13,4
104
+ s3-bucket-default-lock-enabled,SC-28,4
105
+ ec2-ebs-encryption-by-default,SC-28,4
106
+ rds-snapshot-encrypted,SC-28,4
107
+ cloud-trail-log-file-validation-enabled,SI-7|SI-7(1),4
@@ -13,4 +13,6 @@ module HeimdallTools
13
13
  autoload :SnykMapper, 'heimdall_tools/snyk_mapper'
14
14
  autoload :NiktoMapper, 'heimdall_tools/nikto_mapper'
15
15
  autoload :JfrogXrayMapper, 'heimdall_tools/jfrog_xray_mapper'
16
+ autoload :DBProtectMapper, 'heimdall_tools/dbprotect_mapper'
17
+ autoload :AwsConfigMapper, 'heimdall_tools/aws_config_mapper'
16
18
  end
@@ -0,0 +1,284 @@
1
+ require 'aws-sdk-configservice'
2
+ require 'heimdall_tools/hdf'
3
+ require 'csv'
4
+ require 'json'
5
+
6
+ RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
7
+
8
+ AWS_CONFIG_MAPPING_FILE = File.join(RESOURCE_DIR, 'aws-config-mapping.csv')
9
+
10
+ NOT_APPLICABLE_MSG = 'No AWS resources found to evaluate complaince for this rule'.freeze
11
+ INSUFFICIENT_DATA_MSG = 'Not enough data has been collectd to determine compliance yet.'.freeze
12
+
13
+ ##
14
+ # HDF mapper for use with AWS Config rules.
15
+ #
16
+ # Ruby AWS Ruby SDK for ConfigService:
17
+ # - https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/ConfigService/Client.html
18
+ #
19
+ # rubocop:disable Metrics/AbcSize, Metrics/ClassLength
20
+ module HeimdallTools
21
+ class AwsConfigMapper
22
+ def initialize(custom_mapping, verbose = false)
23
+ @verbose = verbose
24
+ @default_mapping = get_rule_mapping(AWS_CONFIG_MAPPING_FILE)
25
+ @custom_mapping = custom_mapping.nil? ? {} : get_rule_mapping(custom_mapping)
26
+ @client = Aws::ConfigService::Client.new
27
+ @issues = get_all_config_rules
28
+ end
29
+
30
+ ##
31
+ # Convert to HDF
32
+ #
33
+ # If there is overlap in rule names from @default_mapping and @custom_mapping,
34
+ # then the tags from both will be added to the rule.
35
+ def to_hdf
36
+ controls = @issues.map do |issue|
37
+ @item = {}
38
+ @item['id'] = issue[:config_rule_name]
39
+ @item['title'] = issue[:config_rule_name]
40
+ @item['desc'] = issue[:description]
41
+ @item['impact'] = 0.5
42
+ @item['tags'] = hdf_tags(issue)
43
+ @item['descriptions'] = hdf_descriptions(issue)
44
+ @item['refs'] = NA_ARRAY
45
+ @item['source_location'] = { ref: issue[:config_rule_arn], line: 1 }
46
+ @item['code'] = ''
47
+ @item['results'] = issue[:results]
48
+ # Avoid duplicating rules that exist in the custom mapping as 'unmapped' in this loop
49
+ if @custom_mapping.include?(issue[:config_rule_name]) && !@default_mapping.include?(issue[:config_rule_name])
50
+ nil
51
+ else
52
+ @item
53
+ end
54
+ end
55
+ results = HeimdallDataFormat.new(
56
+ profile_name: 'AWS Config',
57
+ title: 'AWS Config',
58
+ summary: 'AWS Config',
59
+ controls: controls,
60
+ statistics: { aws_config_sdk_version: Aws::ConfigService::GEM_VERSION }
61
+ )
62
+ results.to_hdf
63
+ end
64
+
65
+ private
66
+
67
+ ##
68
+ # Read in a config rule -> 800-53 control mapping CSV.
69
+ #
70
+ # Params:
71
+ # - path: The file path to the CSV file
72
+ #
73
+ # Returns: A mapped version of the csv in the format { rule_name: row, ... }
74
+ def get_rule_mapping(path)
75
+ Hash[CSV.read(path, headers: true).map { |row| [row[0], row] }]
76
+ end
77
+
78
+ ##
79
+ # Fetches information on all of the config rules available to the
80
+ # AWS account.
81
+ #
82
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/ConfigService/Client.html#describe_config_rules-instance_method
83
+ #
84
+ # Returns: list of hash for all config rules available
85
+ def get_all_config_rules
86
+ config_rules = []
87
+
88
+ # Fetch all rules with pagination
89
+ response = @client.describe_config_rules
90
+ config_rules += response.config_rules
91
+ while response.next_token
92
+ response = @client.describe_config_rules(next_token: response.next_token)
93
+ config_rules += response.config_rules
94
+ end
95
+ config_rules = config_rules.map(&:to_h)
96
+
97
+ # Add necessary data to rules using helpers
98
+ add_compliance_to_config_rules(config_rules)
99
+ add_results_to_config_rules(config_rules)
100
+ end
101
+
102
+ ##
103
+ # Adds compliance information for config rules to the config rule hash
104
+ # from AwsConfigMapper::get_all_config_rules.
105
+ #
106
+ # `complaince_type` may be any of the following:
107
+ # ["COMPLIANT", "NON_COMPLIANT", "NOT_APPLICABLE", "INSUFFICIENT_DATA"]
108
+ #
109
+ # Params:
110
+ # - config_rules: The list of hash from AwsConfigMapper::get_all_config_rules
111
+ #
112
+ # Returns: The same config_rules array with `compliance` key added to each rule
113
+ def add_compliance_to_config_rules(config_rules)
114
+ mapped_compliance_results = fetch_all_compliance_info(config_rules)
115
+
116
+ # Add compliance to config_rules
117
+ config_rules.each do |rule|
118
+ rule[:compliance] = mapped_compliance_results[rule[:config_rule_name]]&.dig(:compliance, :compliance_type)
119
+ end
120
+
121
+ config_rules
122
+ end
123
+
124
+ ##
125
+ # Fetch and combine all compliance information for the config rules.
126
+ #
127
+ # AWS allows passing up to 25 rules at a time to this endpoint.
128
+ #
129
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/ConfigService/Client.html#describe_compliance_by_config_rule-instance_method
130
+ #
131
+ # Params:
132
+ # - config_rules: The list of hash from AwsConfigMapper::get_all_config_rules
133
+ #
134
+ # Returns: Results mapped by config rule in the format { name: {<response>}, ... }
135
+ def fetch_all_compliance_info(config_rules)
136
+ compliance_results = []
137
+
138
+ config_rules.each_slice(25).each do |slice|
139
+ config_rule_names = slice.map { |r| r[:config_rule_name] }
140
+ response = @client.describe_compliance_by_config_rule(config_rule_names: config_rule_names)
141
+ compliance_results += response.compliance_by_config_rules
142
+ end
143
+
144
+ # Map based on name for easy lookup
145
+ Hash[compliance_results.collect { |r| [r.config_rule_name, r.to_h] }]
146
+ end
147
+
148
+ ##
149
+ # Takes in config rules and formats the results for hdf format.
150
+ #
151
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/ConfigService/Client.html#get_compliance_details_by_config_rule-instance_method
152
+ #
153
+ # Example hdf results:
154
+ # [
155
+ # {
156
+ # "code_desc": "This rule...",
157
+ # "run_time": 0.314016,
158
+ # "start_time": "2018-11-18T20:21:40-05:00",
159
+ # "status": "passed"
160
+ # },
161
+ # ...
162
+ # ]
163
+ #
164
+ # Status may be any of the following: ['passed', 'failed', 'skipped', 'loaded']
165
+ #
166
+ # Params:
167
+ # - rule: Rules from AwsConfigMapper::get_all_config_rules
168
+ #
169
+ # Returns: The same config_rules array with `results` key added to each rule.
170
+ def add_results_to_config_rules(config_rules)
171
+ config_rules.each do |rule|
172
+ response = @client.get_compliance_details_by_config_rule(config_rule_name: rule[:config_rule_name], limit: 100)
173
+ rule_results = response.to_h[:evaluation_results]
174
+ while response.next_token
175
+ response = @client.get_compliance_details_by_config_rule(next_token: response.next_token, limit: 100)
176
+ rule_results += response.to_h[:evaluation_results]
177
+ end
178
+
179
+ rule[:results] = []
180
+ rule_results.each do |result|
181
+ hdf_result = {}
182
+ # code_desc
183
+ hdf_result['code_desc'] = result.dig(:evaluation_result_identifier, :evaluation_result_qualifier)&.map do |k, v|
184
+ "#{k}: #{v}"
185
+ end&.join(', ')
186
+ # start_time
187
+ hdf_result['start_time'] = if result.key?(:config_rule_invoked_time)
188
+ DateTime.parse(result[:config_rule_invoked_time].to_s).strftime('%Y-%m-%dT%H:%M:%S%:z')
189
+ end
190
+ # run_time
191
+ hdf_result['run_time'] = if result.key?(:result_recorded_time) && result.key?(:config_rule_invoked_time)
192
+ (result[:result_recorded_time] - result[:config_rule_invoked_time]).round(6)
193
+ end
194
+ # status
195
+ hdf_result['status'] = case result.dig(:compliance_type)
196
+ when 'COMPLIANT'
197
+ 'passed'
198
+ when 'NON_COMPLIANT'
199
+ 'failed'
200
+ else
201
+ 'skipped'
202
+ end
203
+ hdf_result['message'] = "(#{hdf_result['code_desc']}): #{result[:annotation] || 'Rule does not pass rule compliance'}" if hdf_result['status'] == 'failed'
204
+ rule[:results] << hdf_result
205
+ end
206
+ next unless rule[:results].empty?
207
+
208
+ case rule[:compliance]
209
+ when 'NOT_APPLICABLE'
210
+ rule[:impact] = 0
211
+ rule[:results] << {
212
+ 'run_time': 0,
213
+ 'code_desc': NOT_APPLICABLE_MSG,
214
+ 'skip_message': NOT_APPLICABLE_MSG,
215
+ 'start_time': DateTime.now.strftime('%Y-%m-%dT%H:%M:%S%:z'),
216
+ 'status': 'skipped'
217
+ }
218
+ when 'INSUFFICIENT_DATA'
219
+ rule[:results] << {
220
+ 'run_time': 0,
221
+ 'code_desc': INSUFFICIENT_DATA_MSG,
222
+ 'skip_message': INSUFFICIENT_DATA_MSG,
223
+ 'start_time': DateTime.now.strftime('%Y-%m-%dT%H:%M:%S%:z'),
224
+ 'status': 'skipped'
225
+ }
226
+ end
227
+ end
228
+
229
+ config_rules
230
+ end
231
+
232
+ ##
233
+ # Takes in a config rule and pulls out tags that are useful for HDF.
234
+ #
235
+ # Params:
236
+ # - config_rule: A single config rule from AwsConfigMapper::get_all_config_rules
237
+ #
238
+ # Returns: Hash containing all relevant HDF tags
239
+ def hdf_tags(config_rule)
240
+ result = {}
241
+
242
+ @default_mapping
243
+ @custom_mapping
244
+
245
+ # NIST tag
246
+ result['nist'] = []
247
+ default_mapping_match = @default_mapping[config_rule[:config_rule_name]]
248
+
249
+ result['nist'] += default_mapping_match[1].split('|') unless default_mapping_match.nil?
250
+
251
+ custom_mapping_match = @custom_mapping[config_rule[:config_rule_name]]
252
+
253
+ result['nist'] += custom_mapping_match[1].split('|').map { |name| "#{name} (user provided)" } unless custom_mapping_match.nil?
254
+
255
+ result['nist'] = ['unmapped'] if result['nist'].empty?
256
+
257
+ result
258
+ end
259
+
260
+ def check_text(config_rule)
261
+ params = (JSON.parse(config_rule[:input_parameters]).map { |key, value| "#{key}: #{value}" }).join('<br/>')
262
+ check_text = config_rule[:config_rule_arn]
263
+ check_text += "<br/>#{params}" unless params.empty?
264
+ check_text
265
+ end
266
+
267
+ ##
268
+ # Takes in a config rule and pulls out information for the descriptions array
269
+ #
270
+ # Params:
271
+ # - config_rule: A single config rule from AwsConfigMapper::get_all_config_rules
272
+ #
273
+ # Returns: Array containing all relevant descriptions information
274
+ def hdf_descriptions(config_rule)
275
+ [
276
+ {
277
+ 'label': 'check',
278
+ 'data': check_text(config_rule)
279
+ }
280
+ ]
281
+ end
282
+ end
283
+ end
284
+ # rubocop:enable Metrics/AbcSize, Metrics/ClassLength
@@ -63,7 +63,7 @@ module HeimdallTools
63
63
  end
64
64
 
65
65
  def nist_tag(cweid)
66
- entries = @cwe_nist_mapping.select { |x| cweid.include? x[:cweid].to_s }
66
+ entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
67
67
  tags = entries.map { |x| [x[:nistid], "Rev_#{x[:rev]}"] }
68
68
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
69
69
  end
@@ -98,6 +98,30 @@ module HeimdallTools
98
98
  puts "\r\HDF Generated:\n"
99
99
  puts "#{options[:output]}"
100
100
  end
101
+
102
+ desc 'dbprotect_mapper', 'dbprotect_mapper translates dbprotect results xml to HDF format Json be viewed on Heimdall'
103
+ long_desc Help.text(:dbprotect_mapper)
104
+ option :xml, required: true, aliases: '-x'
105
+ option :output, required: true, aliases: '-o'
106
+ option :verbose, type: :boolean, aliases: '-V'
107
+ def dbprotect_mapper
108
+ hdf = HeimdallTools::DBProtectMapper.new(File.read(options[:xml])).to_hdf
109
+ File.write(options[:output], hdf)
110
+ puts "\r\HDF Generated:\n"
111
+ puts "#{options[:output]}"
112
+ end
113
+
114
+ desc 'aws_config_mapper', 'aws_config_mapper pulls Ruby AWS SDK data to translate AWS Config Rule results into HDF format Json to be viewable in Heimdall'
115
+ long_desc Help.text(:aws_config_mapper)
116
+ # option :custom_mapping, required: false, aliases: '-m'
117
+ option :output, required: true, aliases: '-o'
118
+ option :verbose, type: :boolean, aliases: '-V'
119
+ def aws_config_mapper
120
+ hdf = HeimdallTools::AwsConfigMapper.new(options[:custom_mapping]).to_hdf
121
+ File.write(options[:output], hdf)
122
+ puts "\r\HDF Generated:\n"
123
+ puts "#{options[:output]}"
124
+ end
101
125
 
102
126
  desc 'version', 'prints version'
103
127
  def version
@@ -0,0 +1,127 @@
1
+ require 'json'
2
+ require 'csv'
3
+ require 'heimdall_tools/hdf'
4
+ require 'utilities/xml_to_hash'
5
+
6
+ IMPACT_MAPPING = {
7
+ High: 0.7,
8
+ Medium: 0.5,
9
+ Low: 0.3,
10
+ Informational: 0.0
11
+ }.freeze
12
+
13
+ # rubocop:disable Metrics/AbcSize
14
+
15
+ module HeimdallTools
16
+ class DBProtectMapper
17
+ def initialize(xml, name=nil, verbose = false)
18
+ @verbose = verbose
19
+
20
+ begin
21
+ dataset = xml_to_hash(xml)
22
+ @entries = compile_findings(dataset['dataset'])
23
+
24
+ rescue StandardError => e
25
+ raise "Invalid DBProtect XML file provided Exception: #{e};\nNote that XML must be of kind `Check Results Details`."
26
+ end
27
+
28
+ end
29
+
30
+ def to_hdf
31
+ controls = []
32
+ @entries.each do |entry|
33
+ @item = {}
34
+ @item['id'] = entry['Check ID']
35
+ @item['title'] = entry['Check']
36
+ @item['desc'] = format_desc(entry)
37
+ @item['impact'] = impact(entry['Risk DV'])
38
+ @item['tags'] = {}
39
+ @item['descriptions'] = []
40
+ @item['refs'] = NA_ARRAY
41
+ @item['source_location'] = NA_HASH
42
+ @item['code'] = ''
43
+ @item['results'] = finding(entry)
44
+
45
+ controls << @item
46
+ end
47
+ controls = collapse_duplicates(controls)
48
+ results = HeimdallDataFormat.new(profile_name: @entries.first['Policy'],
49
+ version: "",
50
+ title: @entries.first['Job Name'],
51
+ summary: format_summary(@entries.first),
52
+ controls: controls)
53
+ results.to_hdf
54
+ end
55
+
56
+ private
57
+
58
+ def compile_findings(dataset)
59
+ keys = dataset['metadata']['item'].map{ |e| e['name']}
60
+ findings = dataset['data']['row'].map { |e| Hash[keys.zip(e['value'])] }
61
+ findings
62
+ end
63
+
64
+ def format_desc(entry)
65
+ text = []
66
+ text << "Task : #{entry['Task']}"
67
+ text << "Check Category : #{entry['Check Category']}"
68
+ text.join("; ")
69
+ end
70
+
71
+ def format_summary(entry)
72
+ text = []
73
+ text << "Organization : #{entry['Organization']}"
74
+ text << "Asset : #{entry['Check Asset']}"
75
+ text << "Asset Type : #{entry['Asset Type']}"
76
+ text << "IP Address, Port, Instance : #{entry['Asset Type']}"
77
+ text << "IP Address, Port, Instance : #{entry['IP Address, Port, Instance']}"
78
+ text.join("\n")
79
+ end
80
+
81
+ def finding(entry)
82
+ finding = {}
83
+
84
+ finding['code_desc'] = entry['Details']
85
+ finding['run_time'] = 0.0
86
+ finding['start_time'] = entry['Date']
87
+
88
+ case entry['Result Status']
89
+ when 'Fact'
90
+ finding['status'] = 'skipped'
91
+ when 'Failed'
92
+ finding['status'] = 'failed'
93
+ finding['backtrace'] = ["DB Protect Failed Check"]
94
+ when 'Finding'
95
+ finding['status'] = 'failed'
96
+ when 'Not A Finding'
97
+ finding['status'] = 'passed'
98
+ when 'Skipped'
99
+ finding['status'] = 'skipped'
100
+ else
101
+ finding['status'] = 'skipped'
102
+ end
103
+ [finding]
104
+ end
105
+
106
+ def impact(severity)
107
+ IMPACT_MAPPING[severity.to_sym]
108
+ end
109
+
110
+ # DBProtect report could have multiple issue entries for multiple findings of same issue type.
111
+ # The meta data is identical across entries
112
+ # method collapse_duplicates return unique controls with applicable findings collapsed into it.
113
+ def collapse_duplicates(controls)
114
+ unique_controls = []
115
+
116
+ controls.map { |x| x['id'] }.uniq.each do |id|
117
+ collapsed_results = controls.select { |x| x['id'].eql?(id) }.map {|x| x['results']}
118
+ unique_control = controls.find { |x| x['id'].eql?(id) }
119
+ unique_control['results'] = collapsed_results.flatten
120
+ unique_controls << unique_control
121
+ end
122
+ unique_controls
123
+ end
124
+
125
+
126
+ end
127
+ end
@@ -29,7 +29,8 @@ module HeimdallTools
29
29
  groups: NA_ARRAY,
30
30
  status: 'loaded',
31
31
  controls: NA_TAG,
32
- target_id: NA_TAG)
32
+ target_id: NA_TAG,
33
+ statistics: NA_HASH)
33
34
 
34
35
  @results_json = {}
35
36
  @results_json['platform'] = {}
@@ -40,6 +41,7 @@ module HeimdallTools
40
41
 
41
42
  @results_json['statistics'] = {}
42
43
  @results_json['statistics']['duration'] = duration || NA_TAG
44
+ @results_json['statistics'].merge! statistics
43
45
 
44
46
  @results_json['profiles'] = []
45
47
 
@@ -0,0 +1,30 @@
1
+ aws_config_mapper pulls Ruby AWS SDK data to translate AWS Config Rule results into HDF format json to be viewable in Heimdall
2
+
3
+ AWS Config Rule Mapping:
4
+ The mapping of AWS Config Rules to 800-53 Controls was sourced from [this link](https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-nist-800-53_rev_4.html).
5
+
6
+ Authentication with AWS:
7
+ [Developer Guide for configuring Ruby AWS SDK for authentication](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html)
8
+
9
+ Authentication Example:
10
+
11
+ - Create `~/.aws/credentials`
12
+ - Add contents to file, replacing with your access ID and key
13
+
14
+ ```
15
+ [default]
16
+ aws_access_key_id = your_access_key_id
17
+ aws_secret_access_key = your_secret_access_key
18
+ ```
19
+
20
+ - (optional) set AWS region through `~/.aws/config` file with contents
21
+
22
+ ```
23
+ [default]
24
+ output = json
25
+ region = us-gov-west-1
26
+ ```
27
+
28
+ Examples:
29
+
30
+ heimdall_tools aws_config_mapper -o aws_config_results.json
@@ -0,0 +1,5 @@
1
+ dbprotect_mapper translates DBProtect report in `Check Results Details` format XML to HDF format JSON be viewed on Heimdall.
2
+
3
+ Examples:
4
+
5
+ heimdall_tools dbprotect_mapper -x check_results_details_report.xml -o db_protect_hdf.json
@@ -58,7 +58,7 @@ module HeimdallTools
58
58
  end
59
59
 
60
60
  def nist_tag(cweid)
61
- entries = @cwe_nist_mapping.select { |x| cweid.include? x[:cweid].to_s }
61
+ entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
62
62
  tags = entries.map { |x| x[:nistid] }
63
63
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
64
64
  end
@@ -140,7 +140,7 @@ module HeimdallTools
140
140
  end
141
141
 
142
142
  def plugin_nist_tag(pluginfamily, pluginid)
143
- entries = @cwe_nist_mapping.select { |x| (x[:pluginfamily].eql?(pluginfamily) && (x[:pluginid].eql?('*') || x[:pluginid].eql?(pluginid.to_i)) ) }
143
+ entries = @cwe_nist_mapping.select { |x| (x[:pluginfamily].eql?(pluginfamily) && (x[:pluginid].eql?('*') || x[:pluginid].eql?(pluginid.to_i)) ) && !x[:nistid].nil? }
144
144
  tags = entries.map { |x| [x[:nistid].split('|'), "Rev_#{x[:rev]}"] }
145
145
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
146
146
  end
@@ -71,7 +71,7 @@ module HeimdallTools
71
71
  end
72
72
 
73
73
  def nist_tag(niktoid)
74
- entries = @nikto_nist_mapping.select { |x| niktoid.eql?(x[:niktoid].to_s) }
74
+ entries = @nikto_nist_mapping.select { |x| niktoid.eql?(x[:niktoid].to_s) && !x[:nistid].nil? }
75
75
  tags = entries.map { |x| x[:nistid] }
76
76
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
77
77
  end
@@ -74,7 +74,7 @@ module HeimdallTools
74
74
  end
75
75
 
76
76
  def nist_tag(cweid)
77
- entries = @cwe_nist_mapping.select { |x| cweid.include? x[:cweid].to_s }
77
+ entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
78
78
  tags = entries.map { |x| x[:nistid] }
79
79
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
80
80
  end
@@ -65,7 +65,7 @@ module HeimdallTools
65
65
  end
66
66
 
67
67
  def nist_tag(cweid)
68
- entries = @cwe_nist_mapping.select { |x| x[:cweid].to_s.eql?(cweid.to_s) }
68
+ entries = @cwe_nist_mapping.select { |x| x[:cweid].to_s.eql?(cweid.to_s) && !x[:nistid].nil? }
69
69
  tags = entries.map { |x| [x[:nistid], "Rev_#{x[:rev]}"] }
70
70
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
71
71
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heimdall_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.35
4
+ version: 1.3.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Thew
@@ -10,8 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-02-17 00:00:00.000000000 Z
13
+ date: 2021-03-11 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: aws-sdk-configservice
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1'
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: nokogiri
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -181,18 +195,23 @@ files:
181
195
  - Rakefile
182
196
  - exe/heimdall_tools
183
197
  - lib/data/U_CCI_List.xml
198
+ - lib/data/aws-config-mapping.csv
184
199
  - lib/data/cwe-nist-mapping.csv
185
200
  - lib/data/nessus-plugins-nist-mapping.csv
186
201
  - lib/data/nikto-nist-mapping.csv
187
202
  - lib/data/owasp-nist-mapping.csv
188
203
  - lib/heimdall_tools.rb
204
+ - lib/heimdall_tools/aws_config_mapper.rb
189
205
  - lib/heimdall_tools/burpsuite_mapper.rb
190
206
  - lib/heimdall_tools/cli.rb
191
207
  - lib/heimdall_tools/command.rb
208
+ - lib/heimdall_tools/dbprotect_mapper.rb
192
209
  - lib/heimdall_tools/fortify_mapper.rb
193
210
  - lib/heimdall_tools/hdf.rb
194
211
  - lib/heimdall_tools/help.rb
212
+ - lib/heimdall_tools/help/aws_config_mapper.md
195
213
  - lib/heimdall_tools/help/burpsuite_mapper.md
214
+ - lib/heimdall_tools/help/dbprotect_mapper.md
196
215
  - lib/heimdall_tools/help/fortify_mapper.md
197
216
  - lib/heimdall_tools/help/jfrog_xray_mapper.md
198
217
  - lib/heimdall_tools/help/nessus_mapper.md