/
apigateway.sp
438 lines (399 loc) · 16.3 KB
/
apigateway.sp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
locals {
conformance_pack_apigateway_common_tags = merge(local.aws_compliance_common_tags, {
service = "AWS/APIGateway"
})
}
control "api_gatewayv2_route_authorization_type_configured" {
title = "API Gateway routes should specify an authorization type"
description = "This control checks if AWS API Gateway routes have an authorization type. The control fails if the API Gateway route does not specify an authorization type."
query = query.api_gatewayv2_route_authorization_type_configured
tags = local.conformance_pack_apigateway_common_tags
}
control "gatewayv2_stage_access_logging_enabled" {
title = "Access logging should be configured for API Gateway V2 Stages"
description = "This control checks if AWS API Gateway V2 stages have access logging configured. This control fails if access log settings aren't defined."
query = query.gatewayv2_stage_access_logging_enabled
tags = local.conformance_pack_apigateway_common_tags
}
control "apigateway_stage_cache_encryption_at_rest_enabled" {
title = "API Gateway stage cache encryption at rest should be enabled"
description = "To help protect data at rest, ensure encryption is enabled for your API Gateway stage's cache."
query = query.apigateway_stage_cache_encryption_at_rest_enabled
tags = merge(local.conformance_pack_apigateway_common_tags, {
cisa_cyber_essentials = "true"
fedramp_moderate_rev_4 = "true"
gdpr = "true"
gxp_21_cfr_part_11 = "true"
gxp_eu_annex_11 = "true"
hipaa_final_omnibus_security_rule_2013 = "true"
hipaa_security_rule_2003 = "true"
nist_800_171_rev_2 = "true"
nist_800_53_rev_4 = "true"
nist_800_53_rev_5 = "true"
nist_csf = "true"
pci_dss_v321 = "true"
rbi_cyber_security = "true"
soc_2 = "true"
})
}
control "apigateway_stage_logging_enabled" {
title = "API Gateway stage logging should be enabled"
description = "API Gateway logging displays detailed views of users who accessed the API and the way they accessed the API."
query = query.apigateway_stage_logging_enabled
tags = merge(local.conformance_pack_apigateway_common_tags, {
cis_controls_v8_ig1 = "true"
cisa_cyber_essentials = "true"
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "true"
ffiec = "true"
gxp_21_cfr_part_11 = "true"
hipaa_final_omnibus_security_rule_2013 = "true"
hipaa_security_rule_2003 = "true"
nist_800_171_rev_2 = "true"
nist_800_53_rev_4 = "true"
nist_800_53_rev_5 = "true"
nist_csf = "true"
pci_dss_v321 = "true"
rbi_cyber_security = "true"
soc_2 = "true"
})
}
control "apigateway_rest_api_stage_use_ssl_certificate" {
title = "API Gateway stage should uses SSL certificate"
description = "Ensure that a REST API stage uses a Secure Sockets Layer (SSL) certificate. This rule is compliant if the REST API stage does not have an associated SSL certificate."
query = query.apigateway_rest_api_stage_use_ssl_certificate
tags = merge(local.conformance_pack_apigateway_common_tags, {
cisa_cyber_essentials = "true"
fedramp_moderate_rev_4 = "true"
ffiec = "true"
gxp_21_cfr_part_11 = "true"
hipaa_final_omnibus_security_rule_2013 = "true"
nist_800_171_rev_2 = "true"
nist_800_53_rev_5 = "true"
nist_csf = "true"
rbi_cyber_security = "true"
})
}
control "apigateway_rest_api_stage_xray_tracing_enabled" {
title = "API Gateway REST API stages should have AWS X-Ray tracing enabled"
description = "This control checks whether AWS X-Ray active tracing is enabled for your AWS API Gateway REST API stages."
query = query.apigateway_rest_api_stage_xray_tracing_enabled
tags = merge(local.conformance_pack_apigateway_common_tags, {
hipaa_final_omnibus_security_rule_2013 = "true"
nist_csf = "true"
})
}
control "apigateway_stage_use_waf_web_acl" {
title = "API Gateway stage should be associated with waf"
description = "Ensure that an AWS API Gateway API stage is using a WAF Web ACL. This rule is non-compliant if an AWS WAF Web ACL is not used."
query = query.apigateway_stage_use_waf_web_acl
tags = merge(local.conformance_pack_apigateway_common_tags, {
cisa_cyber_essentials = "true"
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "true"
ffiec = "true"
nist_800_171_rev_2 = "true"
nist_800_53_rev_5 = "true"
nist_csf = "true"
pci_dss_v321 = "true"
rbi_cyber_security = "true"
})
}
control "apigateway_rest_api_authorizers_configured" {
title = "API Gateway stages should have authorizers configured"
description = "Ensure API Gateway stages have authorizers configured."
query = query.apigateway_rest_api_authorizers_configured
tags = local.conformance_pack_apigateway_common_tags
}
control "apigateway_rest_api_endpoint_restrict_public_access" {
title = "API Gateway REST API endpoint type should be configured to private"
description = "This control checks whether API Gateway endpoint is public or private. This rule is non-compliant if API Gateway endpoint is public."
query = query.apigateway_rest_api_endpoint_restrict_public_access
tags = local.conformance_pack_apigateway_common_tags
}
control "api_gatewayv2_route_authorizer_configured" {
title = "API Gateway V2 authorizer should be configured"
description = "This control checks whether API Gateway V2 has an authorizer configured. This rule is non-compliant if API Gateway V2 has no authorizers configured."
query = query.api_gatewayv2_route_authorizer_configured
tags = local.conformance_pack_apigateway_common_tags
}
control "api_gateway_rest_api_public_endpoint_with_authorizer" {
title = "API Gateway REST API public endpoints should be configured with authorizer"
description = "Ensure API Gateway REST API public endpoint is configured with authorizer. This rule is non-compliant if API Gateway REST API public endpoint has no authorizer configured."
query = query.api_gateway_rest_api_public_endpoint_with_authorizer
tags = local.conformance_pack_apigateway_common_tags
}
control "api_gateway_method_authorization_type_configured" {
title = "API Gateway methods authorizer should be configured"
description = "This control checks whether API Gateway method has an authorizer configured. This rule is non-compliant if API Gateway method has no authorizers configured."
query = query.api_gateway_method_authorization_type_configured
tags = local.conformance_pack_apigateway_common_tags
}
control "api_gateway_method_request_parameter_validated" {
title = "API Gateway methods request parameter should be validated"
description = "This control checks whether API Gateway method request parameter is validated. This rule is non-compliant if API Gateway method request parameter is not validated."
query = query.api_gateway_method_request_parameter_validated
tags = local.conformance_pack_apigateway_common_tags
}
query "apigateway_stage_cache_encryption_at_rest_enabled" {
sql = <<-EOQ
select
'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as resource,
case
when method_settings -> '*/*' ->> 'CachingEnabled' = 'true'
and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' then 'ok'
else 'alarm'
end as status,
case
when method_settings -> '*/*' ->> 'CachingEnabled' = 'true'
and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true'
then title || ' API cache and encryption enabled.'
else title || ' API cache and encryption not enabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gateway_stage;
EOQ
}
query "apigateway_stage_logging_enabled" {
sql = <<-EOQ
with all_stages as (
select
name as stage_name,
'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as arn,
method_settings -> '*/*' ->> 'LoggingLevel' as log_level,
title,
region,
account_id,
tags,
_ctx
from
aws_api_gateway_stage
union
select
stage_name,
'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as arn,
default_route_logging_level as log_level,
title,
region,
account_id,
tags,
_ctx
from
aws_api_gatewayv2_stage
)
select
arn as resource,
case
when log_level is null or log_level = '' or log_level = 'OFF' then 'alarm'
else 'ok'
end as status,
case
when log_level is null or log_level = '' or log_level = 'OFF' then title || ' logging not enabled.'
else title || ' logging enabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
all_stages;
EOQ
}
query "apigateway_rest_api_stage_use_ssl_certificate" {
sql = <<-EOQ
select
arn as resource,
case
when client_certificate_id is null then 'alarm'
else 'ok'
end as status,
case
when client_certificate_id is null then title || ' does not use SSL certificate.'
else title || ' uses SSL certificate.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gateway_stage;
EOQ
}
query "apigateway_rest_api_stage_xray_tracing_enabled" {
sql = <<-EOQ
select
arn as resource,
case
when tracing_enabled then 'ok'
else 'alarm'
end as status,
case
when tracing_enabled then title || ' X-Ray tracing enabled.'
else title || ' X-Ray tracing disabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gateway_stage;
EOQ
}
query "apigateway_stage_use_waf_web_acl" {
sql = <<-EOQ
select
arn as resource,
case
when web_acl_arn is not null then 'ok'
else 'alarm'
end as status,
case
when web_acl_arn is not null then title || ' associated with WAF web ACL.'
else title || ' not associated with WAF web ACL.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gateway_stage;
EOQ
}
query "apigateway_rest_api_authorizers_configured" {
sql = <<-EOQ
select
p.name as resource,
case
when jsonb_array_length(a.provider_arns) > 0 then 'ok'
else 'alarm'
end as status,
case
when jsonb_array_length(a.provider_arns) > 0 then p.name || ' authorizers configured.'
else p.name || ' authorizers not configured.'
end as reason
${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "p.")}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "p.")}
from
aws_api_gateway_rest_api as p
left join aws_api_gateway_authorizer as a on p.api_id = a.rest_api_id;
EOQ
}
query "apigateway_rest_api_endpoint_restrict_public_access" {
sql = <<-EOQ
select
'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id as resource,
case
when endpoint_configuration_types ? 'PRIVATE' then 'ok'
else 'alarm'
end as status,
case
when endpoint_configuration_types ? 'PRIVATE' then name || ' not publicly accessible.'
else name || ' publicly accessible.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gateway_rest_api;
EOQ
}
query "api_gatewayv2_route_authorizer_configured" {
sql = <<-EOQ
select
'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id as resource,
case
when authorizer_id is null then 'alarm'
else 'ok'
end as status,
case
when authorizer_id is null then route_id || ' authorizer not configured.'
else route_id || ' authorizer ' || authorizer_id || ' configured.'
end as reason
${local.common_dimensions_sql}
from
aws_api_gatewayv2_route;
EOQ
}
query "api_gatewayv2_route_authorization_type_configured" {
sql = <<-EOQ
select
'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id as resource,
case
when authorization_type is null then 'alarm'
else 'ok'
end as status,
case
when authorization_type is null then route_id || ' authorization type not configured.'
else route_id || ' authorization type ' || authorization_type || ' configured.'
end as reason
${local.common_dimensions_sql}
from
aws_api_gatewayv2_route;
EOQ
}
query "gatewayv2_stage_access_logging_enabled" {
sql = <<-EOQ
select
'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as resource,
case
when access_log_settings is null then 'alarm'
else 'ok'
end as status,
case
when access_log_settings is null then title || ' access logging disabled.'
else title || ' access logging enabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_api_gatewayv2_stage;
EOQ
}
query "api_gateway_rest_api_public_endpoint_with_authorizer" {
sql = <<-EOQ
select
'arn:' || p.partition || ':apigateway:' || p.region || '::/apis/' || p.api_id as resource,
case
when not (endpoint_configuration_types ? 'PRIVATE') and (a.provider_arns is not null and jsonb_array_length(a.provider_arns) > 0 ) then 'ok'
when not (endpoint_configuration_types ? 'PRIVATE') and ( a.provider_arns is null or jsonb_array_length(a.provider_arns) = 0 ) then 'alarm'
else 'ok'
end as status,
case
when not (endpoint_configuration_types ? 'PRIVATE') and (a.provider_arns is not null and jsonb_array_length(a.provider_arns) > 0 ) then p.name || ' has public endpoint with authorizer.'
when not (endpoint_configuration_types ? 'PRIVATE') and ( a.provider_arns is null or jsonb_array_length(a.provider_arns) = 0 ) then p.name || ' has public endpoint without authorizer.'
else p.name || ' has private endpoint.'
end as reason
${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "p.")}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "p.")}
from
aws_api_gateway_rest_api as p
left join aws_api_gateway_authorizer as a on p.api_id = a.rest_api_id;
EOQ
}
query "api_gateway_method_authorization_type_configured" {
sql = <<-EOQ
select
resource_id as resource,
case
when authorization_type = 'NONE' then 'alarm'
else 'ok'
end as status,
case
when authorization_type = 'NONE' then title || ' authorization type not configured.'
else title || ' authorization type ' || authorization_type || ' configured.'
end as reason
${local.common_dimensions_sql}
from
aws_api_gateway_method;
EOQ
}
query "api_gateway_method_request_parameter_validated" {
sql = <<-EOQ
select
resource_id as resource,
case
when request_validator_id is null then 'alarm'
else 'ok'
end as status,
case
when request_validator_id is null then title || ' request parameter not validated.'
else title || ' request parameter validated.'
end as reason
${local.common_dimensions_sql}
from
aws_api_gateway_method;
EOQ
}