/
ec2.sp
1838 lines (1715 loc) · 73.8 KB
/
ec2.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
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
locals {
conformance_pack_ec2_common_tags = merge(local.aws_compliance_common_tags, {
service = "AWS/EC2"
})
}
control "ec2_instance_termination_protection_enabled" {
title = "AWS EC2 instances should have termination protection enabled"
description = "This control checks whether termination protection is enabled for EC2 instances. The control fails if termination protection is not enabled for an EC2 instance."
query = query.ec2_instance_termination_protection_enabled
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_launch_template_not_publicly_accessible" {
title = "AWS EC2 launch templates should not assign public IPs to network interfaces"
description = "This control checks if AWS EC2 launch templates are configured to assign public IP addresses to network interfaces upon launch. The control fails if an EC2 launch template is configured to assign a public IP address to network interfaces or if there is at least one network interface that has a public IP address."
query = query.ec2_launch_template_not_publicly_accessible
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_ebs_default_encryption_enabled" {
title = "EBS default encryption should be enabled"
description = "To help protect data at rest, ensure that encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes."
query = query.ec2_ebs_default_encryption_enabled
tags = merge(local.conformance_pack_ec2_common_tags, {
cis_controls_v8_ig1 = "true"
cisa_cyber_essentials = "true"
ffiec = "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"
soc_2 = "true"
})
}
control "ec2_instance_detailed_monitoring_enabled" {
title = "EC2 instance detailed monitoring should be enabled"
description = "Enable this rule to help improve AWS Elastic Compute Cloud (AWS EC2) instance monitoring on the AWS EC2 console, which displays monitoring graphs with a 1-minute period for the instance."
query = query.ec2_instance_detailed_monitoring_enabled
tags = merge(local.conformance_pack_ec2_common_tags, {
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "true"
hipaa_final_omnibus_security_rule_2013 = "true"
nist_800_171_rev_2 = "true"
nist_800_53_rev_4 = "true"
nist_csf = "true"
soc_2 = "true"
})
}
control "ec2_instance_not_use_multiple_enis" {
title = "EC2 instances should not use multiple ENIs"
description = "This control checks whether an EC2 instance uses multiple Elastic Network Interfaces (ENIs) or Elastic Fabric Adapters (EFAs). This control passes if a single network adapter is used. The control includes an optional parameter list to identify the allowed ENIs."
query = query.ec2_instance_not_use_multiple_enis
tags = merge(local.conformance_pack_ec2_common_tags, {
nist_csf = "true"
})
}
control "ec2_instance_no_amazon_key_pair" {
title = "EC2 instances should not use key pairs in running state"
description = "This control checks whether running EC2 instances are using key pairs. The control fails if a running EC2 instance uses a key pair."
query = query.ec2_instance_no_amazon_key_pair
tags = merge(local.conformance_pack_ec2_common_tags, {
nist_csf = "true"
})
}
control "ec2_instance_in_vpc" {
title = "EC2 instances should be in a VPC"
description = "Deploy AWS Elastic Compute Cloud (AWS EC2) instances within an AWS Virtual Private Cloud (AWS VPC) to enable secure communication between an instance and other services within the amazon VPC, without requiring an internet gateway, NAT device, or VPN connection."
query = query.ec2_instance_in_vpc
tags = merge(local.conformance_pack_ec2_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 "ec2_instance_not_publicly_accessible" {
title = "EC2 instances should not have a public IP address"
description = "Manage access to the AWS Cloud by ensuring AWS Elastic Compute Cloud (AWS EC2) instances cannot be publicly accessed."
query = query.ec2_instance_not_publicly_accessible
tags = merge(local.conformance_pack_ec2_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 "ec2_instance_no_high_level_finding_in_inspector_scan" {
title = "EC2 instances high level findings should not be there in inspector scans"
description = "AWS Inspector scans operating system packages installed on your AWS EC2 instances for vulnerabilities and network reachability issues. Each finding has the name of the detected vulnerability and provides a severity rating, information about the affected resource, and details such as how to remediate the reported vulnerability."
query = query.ec2_instance_no_high_level_finding_in_inspector_scan
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_stopped_instance_30_days" {
title = "EC2 stopped instances should be removed in 30 days"
description = "Enable this rule to help with the baseline configuration of AWS Elastic Compute Cloud (AWS EC2) instances by checking whether AWS EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards."
query = query.ec2_stopped_instance_30_days
tags = merge(local.conformance_pack_ec2_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"
})
}
control "ec2_instance_ebs_optimized" {
title = "EC2 instance should have EBS optimization enabled"
description = "An optimized instance in AWS Elastic Block Store (AWS EBS) provides additional, dedicated capacity for AWS EBS I/O operations."
query = query.ec2_instance_ebs_optimized
tags = merge(local.conformance_pack_ec2_common_tags, {
audit_manager_control_tower = "true"
cis_controls_v8_ig1 = "true"
cisa_cyber_essentials = "true"
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "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_5 = "true"
nist_csf = "true"
pci_dss_v321 = "true"
soc_2 = "true"
})
}
control "ec2_instance_uses_imdsv2" {
title = "EC2 instances should use IMDSv2"
description = "Ensure the Instance Metadata Service Version 2 (IMDSv2) method is enabled to help protect access and control of AWS Elastic Compute Cloud (AWS EC2) instance metadata."
query = query.ec2_instance_uses_imdsv2
tags = merge(local.conformance_pack_ec2_common_tags, {
cis_controls_v8_ig1 = "true"
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "true"
gxp_21_cfr_part_11 = "true"
hipaa_final_omnibus_security_rule_2013 = "true"
nist_800_53_rev_4 = "true"
nist_800_53_rev_5 = "true"
nist_csf = "true"
})
}
control "ec2_instance_protected_by_backup_plan" {
title = "EC2 instances should be protected by backup plan"
description = "Ensure that AWS Elastic Compute Cloud (AWS EC2) instances are protected by a backup plan. The rule is non-compliant if the AWS EC2 instance is not covered by a backup plan."
query = query.ec2_instance_protected_by_backup_plan
tags = merge(local.conformance_pack_ec2_common_tags, {
cisa_cyber_essentials = "true"
fedramp_low_rev_4 = "true"
fedramp_moderate_rev_4 = "true"
ffiec = "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_csf = "true"
pci_dss_v321 = "true"
soc_2 = "true"
})
}
control "ec2_instance_iam_profile_attached" {
title = "EC2 instances should have IAM profile attached"
description = "Ensure that an AWS Elastic Compute Cloud (AWS EC2) instance has an Identity and Access Management (IAM) profile attached to it. This rule is non-compliant if no IAM profile is attached to the AWS EC2 instance."
query = query.ec2_instance_iam_profile_attached
tags = merge(local.conformance_pack_ec2_common_tags, {
cis_controls_v8_ig1 = "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"
})
}
control "ec2_instance_publicly_accessible_iam_profile_attached" {
title = "Public EC2 instances should have IAM profile attached"
description = "Ensure AWS Elastic Compute Cloud (AWS EC2) public instances have an Identity and Access Management (IAM) profile attached to them. This rule is non-compliant if no IAM profile is attached to a public AWS EC2 instance."
query = query.ec2_instance_publicly_accessible_iam_profile_attached
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_user_data_no_secrets" {
title = "EC2 instances user data should not have secrets"
description = "User data is a metadata field of an EC2 instance that allows custom code to run after the instance is launched. It contains code which is exposed to any entity which has the most basic access to EC2, even read-only configurations. It is recommended to not use secrets in user data."
query = query.ec2_instance_user_data_no_secrets
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_transit_gateway_auto_cross_account_attachment_disabled" {
title = "EC2 transit gateways should have auto accept shared attachments disabled"
description = "Ensure transit gateways have auto accept shared attachments feature disabled. If this setting is disabled, then any VPC that attempts to attach to a transit gateway will need to request authorization, and the account that owns the transit gateway will need to accept the authorization."
query = query.ec2_transit_gateway_auto_cross_account_attachment_disabled
tags = merge(local.conformance_pack_ec2_common_tags, {
nist_csf = "true"
})
}
control "ec2_instance_no_launch_wizard_security_group" {
title = "EC2 instances should not be attached to 'launch wizard' security groups"
description = "Ensure EC2 instances provisioned in your AWS account are not associated with security groups that have their name prefixed with 'launch-wizard', in order to enforce using secure and custom security groups that exercise the principle of least privilege."
query = query.ec2_instance_no_launch_wizard_security_group
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_virtualization_type_no_paravirtual" {
title = "Paravirtual EC2 instance types should not be used"
description = "This control checks whether the virtualization type of an EC2 instance is paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual."
query = query.ec2_instance_virtualization_type_no_paravirtual
tags = merge(local.conformance_pack_ec2_common_tags, {
nist_csf = "true"
})
}
control "ec2_ami_restrict_public_access" {
title = "EC2 AMIs should restrict public access"
description = "This control checks whether EC2 AMIs are set as private or not. The control fails if the EC2 AMIs are set as public."
query = query.ec2_ami_restrict_public_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_management_level_access" {
title = "EC2 instance IAM role should not allow management level access"
description = "This control ensures that EC2 instance IAM role does not allow management level access."
query = query.ec2_instance_no_iam_role_with_management_level_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_data_destruction_access" {
title = "EC2 instance IAM role should not allow data destruction access"
description = "This control ensures that EC2 instance IAM role does not allow data destruction access."
query = query.ec2_instance_no_iam_role_with_data_destruction_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_with_write_level_access" {
title = "EC2 instance IAM role should not allow write level access"
description = "This control ensures that EC2 instance IAM role does not allow write level access."
query = query.ec2_instance_no_iam_with_write_level_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_database_management_write_access" {
title = "EC2 instance IAM role should not allow database management write access"
description = "This control ensures that EC2 instance IAM role does not allow database management write access."
query = query.ec2_instance_no_iam_role_with_database_management_write_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_org_write_access" {
title = "EC2 instance IAM role should not allow oraganization write access"
description = "This control ensures that EC2 instance IAM role does not allow oraganization write access."
query = query.ec2_instance_no_iam_role_with_org_write_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_privilege_escalation_risk_access" {
title = "EC2 instance IAM role should not allow privilege escalation risk access"
description = "This control ensures that EC2 instance IAM role does not allow privilege escalation risk access."
query = query.ec2_instance_no_iam_role_with_privilege_escalation_risk_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access" {
title = "EC2 instance IAM role should not allow new group creation with attached policy access"
description = "This control ensures that EC2 instance IAM role does not allow new group creation with attached policy access."
query = query.ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access" {
title = "EC2 instance IAM role should not allow new role creation with attached policy access"
description = "This control ensures that EC2 instance IAM role does not allow new role creation with attached policy access."
query = query.ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access" {
title = "EC2 instance IAM role should not allow new user creation with attached policy access"
description = "This control ensures that EC2 instance IAM role does not allow new user creation with attached policy access."
query = query.ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_write_access_to_resource_based_policies" {
title = "EC2 instance IAM role should not allow write access to resource based policies"
description = "This control ensures that EC2 instance IAM role does not allow write access to resource based policies."
query = query.ec2_instance_no_iam_role_with_write_access_to_resource_based_policies
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_attached_with_credentials_exposure_access" {
title = "EC2 instance IAM role should not be attached with credentials exposure access"
description = "This control ensures that EC2 instance IAM role should not be attached with credentials exposure access."
query = query.ec2_instance_no_iam_role_attached_with_credentials_exposure_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration" {
title = "EC2 instance IAM role should not allow to alter critical s3 permissions configuration"
description = "This control ensures that EC2 instance IAM role does not allow to alter critical s3 permissions configuration."
query = query.ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_destruction_kms_access" {
title = "EC2 instance IAM role should not allow destruction KMS access"
description = "This control ensures that EC2 instance IAM roles do not allow destruction KMS access."
query = query.ec2_instance_no_iam_role_with_destruction_kms_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_destruction_rds_access" {
title = "EC2 instance IAM role should not allow destruction RDS access"
description = "This control ensures that EC2 instance IAM roles do not allow destruction RDS access."
query = query.ec2_instance_no_iam_role_with_destruction_rds_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_cloud_log_tampering_access" {
title = "EC2 instance IAM role should not allow cloud log tampering access"
description = "This control ensures that EC2 instance IAM roles do not allow cloud log tampering access."
query = query.ec2_instance_no_iam_role_with_cloud_log_tampering_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration" {
title = "EC2 instance IAM role should not allow write permission on critical s3 configuration"
description = "This control ensures that EC2 instance IAM roles do not allow write permission on critical s3 configuration."
query = query.ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_security_group_write_access" {
title = "EC2 instance IAM role should not allow security group write access"
description = "This control ensures that EC2 instance IAM roles do not allow security group write access."
query = query.ec2_instance_no_iam_role_with_security_group_write_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access" {
title = "EC2 instance IAM role should not allow defense evasion impact of AWS security services access"
description = "This control ensures that EC2 instance IAM role does not allow defense evasion impact of AWS security services access."
query = query.ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_role_with_elastic_ip_hijacking_access" {
title = "EC2 instance IAM role should not allow elastic IP hijacking access."
description = "This control ensures that EC2 instance IAM role does not allow elastic IP hijacking access."
query = query.ec2_instance_no_iam_role_with_elastic_ip_hijacking_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_instance_no_iam_passrole_and_lambda_invoke_function_access" {
title = "EC2 instance IAM should not allow pass role and lambda invoke function access."
description = "This control ensures that EC2 instance IAM role does not allow pass role and lambda invoke function access."
query = query.ec2_instance_no_iam_passrole_and_lambda_invoke_function_access
tags = local.conformance_pack_ec2_common_tags
}
control "ec2_client_vpn_endpoint_client_connection_logging_enabled" {
title = "EC2 Client VPN endpoints should have client connection logging enabled"
description = "This control checks whether an AWS Client VPN endpoint has client connection logging enabled. The control fails if the endpoint doesn't have client connection logging enabled."
query = query.ec2_client_vpn_endpoint_client_connection_logging_enabled
tags = local.conformance_pack_ec2_common_tags
}
query "ec2_ebs_default_encryption_enabled" {
sql = <<-EOQ
select
'arn:' || partition || '::' || region || ':' || account_id as resource,
case
when not default_ebs_encryption_enabled then 'alarm'
else 'ok'
end as status,
case
when not default_ebs_encryption_enabled then region || ' default EBS encryption disabled.'
else region || ' default EBS encryption enabled.'
end as reason
${local.common_dimensions_sql}
from
aws_ec2_regional_settings;
EOQ
}
query "ec2_instance_detailed_monitoring_enabled" {
sql = <<-EOQ
select
arn as resource,
case
when monitoring_state = 'enabled' then 'ok'
else 'alarm'
end as status,
case
when monitoring_state = 'enabled' then instance_id || ' detailed monitoring enabled.'
else instance_id || ' detailed monitoring disabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_not_use_multiple_enis" {
sql = <<-EOQ
select
arn as resource,
case
when jsonb_array_length(network_interfaces) = 1 then 'ok'
else 'alarm'
end status,
title || ' has ' || jsonb_array_length(network_interfaces) || ' ENI(s) attached.'
as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_no_amazon_key_pair" {
sql = <<-EOQ
select
arn as resource,
case
when instance_state <> 'running' then 'skip'
when key_name is null then 'ok'
else 'alarm'
end as status,
case
when instance_state <> 'running' then title || ' is in ' || instance_state || ' state.'
when key_name is null then title || ' not launched using amazon key pairs.'
else title || ' launched using amazon key pairs.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_in_vpc" {
sql = <<-EOQ
select
arn as resource,
case
when vpc_id is null then 'alarm'
else 'ok'
end as status,
case
when vpc_id is null then title || ' not in VPC.'
else title || ' in VPC.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_not_publicly_accessible" {
sql = <<-EOQ
select
arn as resource,
case
when public_ip_address is null then 'ok'
else 'alarm'
end as status,
case
when public_ip_address is null then instance_id || ' not publicly accessible.'
else instance_id || ' publicly accessible.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_no_high_level_finding_in_inspector_scan" {
sql = <<-EOQ
with severity_list as (
select
distinct title ,
a ->> 'Value' as instance_id
from
aws_inspector_finding,
jsonb_array_elements(attributes) as a
where
severity = 'High'
and asset_type = 'ec2-instance'
and a ->> 'Key' = 'INSTANCE_ID'
group by
a ->> 'Value',
title
), ec2_istance_list as (
select
distinct instance_id
from
severity_list
)
select
arn as resource,
case
when l.instance_id is null then 'ok'
else 'alarm'
end as status,
case
when l.instance_id is null then i.title || ' has no high level finding in inspector scans.'
else i.title || ' has ' || (select count(*) from severity_list where instance_id = i.instance_id) || ' high level findings in inspector scans.'
end as reason
${local.tag_dimensions_sql}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "i.")}
from
aws_ec2_instance as i
left join ec2_istance_list as l on i.instance_id = l.instance_id;
EOQ
}
query "ec2_stopped_instance_30_days" {
sql = <<-EOQ
select
arn as resource,
case
when instance_state not in ('stopped', 'stopping') then 'skip'
when state_transition_time <= (current_date - interval '30' day) then 'alarm'
else 'ok'
end as status,
case
when instance_state not in ('stopped', 'stopping') then title || ' is in ' || instance_state || ' state.'
else title || ' stopped since ' || to_char(state_transition_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - state_transition_time) || ' days).'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_ebs_optimized" {
sql = <<-EOQ
select
arn as resource,
case
when ebs_optimized then 'ok'
else 'alarm'
end as status,
case
when ebs_optimized then title || ' EBS optimization enabled.'
else title || ' EBS optimization disabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_uses_imdsv2" {
sql = <<-EOQ
select
arn as resource,
case
when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm'
else 'ok'
end as status,
case
when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).'
else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_protected_by_backup_plan" {
sql = <<-EOQ
with backup_protected_instance as (
select
resource_arn as arn
from
aws_backup_protected_resource as b
where
resource_type = 'EC2'
)
select
i.arn as resource,
case
when b.arn is not null then 'ok'
else 'alarm'
end as status,
case
when b.arn is not null then i.title || ' is protected by backup plan.'
else i.title || ' is not protected by backup plan.'
end as reason
${local.tag_dimensions_sql}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "i.")}
from
aws_ec2_instance as i
left join backup_protected_instance as b on i.arn = b.arn;
EOQ
}
query "ec2_instance_iam_profile_attached" {
sql = <<-EOQ
select
arn as resource,
case
when iam_instance_profile_id is not null then 'ok'
else 'alarm'
end as status,
case
when iam_instance_profile_id is not null then title || ' IAM profile attached.'
else title || ' IAM profile not attached.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_instance_publicly_accessible_iam_profile_attached" {
sql = <<-EOQ
select
arn as resource,
case
when iam_instance_profile_id is not null then 'ok'
else 'alarm'
end as status,
case
when iam_instance_profile_id is not null then title || ' IAM profile attached.'
else title || ' IAM profile not attached.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance
where
public_ip_address is not null;
EOQ
}
query "ec2_instance_user_data_no_secrets" {
sql = <<-EOQ
select
arn as resource,
case
when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])
or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' then 'alarm'
else 'ok'
end as status,
case
when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])
or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' then instance_id ||' potential secret found in user data.'
else instance_id || ' no secrets found in user data.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_transit_gateway_auto_cross_account_attachment_disabled" {
sql = <<-EOQ
select
transit_gateway_arn as resource,
case
when auto_accept_shared_attachments = 'enable' then 'alarm'
else 'ok'
end as status,
case
when auto_accept_shared_attachments = 'enable' then title || ' automatic shared account attachment enabled.'
else title || ' automatic shared account attachment disabled.'
end as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_transit_gateway;
EOQ
}
query "ec2_instance_no_launch_wizard_security_group" {
sql = <<-EOQ
with launch_wizard_sg_attached_instance as (
select
distinct arn as arn
from
aws_ec2_instance,
jsonb_array_elements(security_groups) as sg
where
sg ->> 'GroupName' like 'launch-wizard%'
)
select
i.arn as resource,
case
when sg.arn is null then 'ok'
else 'alarm'
end as status,
case
when sg.arn is null then i.title || ' not associated with launch-wizard security group.'
else i.title || ' associated with launch-wizard security group.'
end as reason
${local.tag_dimensions_sql}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "i.")}
from
aws_ec2_instance as i
left join launch_wizard_sg_attached_instance as sg on i.arn = sg.arn;
EOQ
}
query "ec2_instance_virtualization_type_no_paravirtual" {
sql = <<-EOQ
select
arn as resource,
case
when virtualization_type = 'paravirtual' then 'alarm'
else 'ok'
end as status,
title || ' virtualization type is ' || virtualization_type || '.' as reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_ami_restrict_public_access" {
sql = <<-EOQ
select
'arn:' || partition || ':ec2:' || region || ':' || account_id || ':image/' || image_id as resource,
case
when public then 'alarm'
else 'ok'
end status,
case
when public then title || ' publicly accessible.'
else title || ' not publicly accessible.'
end reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_ami;
EOQ
}
query "ec2_instance_termination_protection_enabled" {
sql = <<-EOQ
select
arn as resource,
case
when disable_api_termination then 'ok'
else 'alarm'
end status,
case
when disable_api_termination then instance_id || ' termination protection enabled.'
else instance_id || ' termination protection disabled.'
end reason
${local.tag_dimensions_sql}
${local.common_dimensions_sql}
from
aws_ec2_instance;
EOQ
}
query "ec2_launch_template_not_publicly_accessible" {
sql = <<-EOQ
with public_launch_templates as (
select
i.tags ->> 'aws:ec2launchtemplate:id' as public_launch_template_id
from
aws_ec2_instance as i,
jsonb_array_elements(launch_template_data -> 'NetworkInterfaces') as nic
where
(nic -> 'AssociatePublicIpAddress')::bool
),
launch_templates_associated_instance as (
select
distinct tags ->> 'aws:ec2launchtemplate:id' as launch_template_id
from
aws_ec2_instance
)
select
t.launch_template_id as resource,
case
when i.launch_template_id is null then 'skip'
when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then 'alarm'
else 'ok'
end as status,
case
when i.launch_template_id is null then t.title || ' does not launch any instance.'
when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then t.title || ' publicly accessible.'
else t.title || ' not publicly accessible.'
end as reason
${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "t.")}
${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "t.")}
from
aws_ec2_launch_template as t
left join launch_templates_associated_instance as i on i.launch_template_id = t.launch_template_id;
EOQ
}
query "ec2_instance_no_iam_role_with_management_level_access" {
sql = <<-EOQ
with iam_roles as (
select
r.arn as role_arn,
i.arn as intance_arn
from
aws_iam_role as r,
jsonb_array_elements_text(instance_profile_arns) as p
left join aws_ec2_instance as i on p = i.iam_instance_profile_arn
where
i.arn is not null
), iam_role_with_permission as (
select
arn
from
aws_iam_role,
jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,
jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,
jsonb_array_elements_text(s -> 'Action') as action
where
arn in (select role_arn from iam_roles)
and s ->> 'Effect' = 'Allow'
and service = 'ec2.amazonaws.com'
and (
(action in ('iam:attachgrouppolicy', 'iam:attachrolepolicy', 'iam:attachuserpolicy', 'iam:createpolicy', 'iam:createpolicyversion', 'iam:deleteaccountpasswordpolicy', 'iam:deletegrouppolicy', 'iam:deletepolicy', 'iam:deletepolicyversion', 'iam:deleterolepermissionsboundary', 'iam:deleterolepolicy', 'iam:deleteuserpermissionsboundary', 'iam:deleteuserpolicy', 'iam:detachgrouppolicy', 'iam:detachrolepolicy', 'iam:detachuserpolicy', 'iam:putgrouppolicy', 'iam:putrolepermissionsboundary', 'iam:putrolepolicy', 'iam:putuserpermissionsboundary', 'iam:putuserpolicy','iam:setdefaultpolicyversion','iam:updateassumerolerolicy', '*:*')
)
)
)
select
i.arn as resource,
case
when p.arn is null then 'ok'
else 'alarm'
end status,
case
when p.arn is null then title || ' has no management level access.'
else title || ' has management level access.'
end as reason
${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "i.")}
${replace(local.common_dimensions_qualifier_global_sql, "__QUALIFIER__", "i.")}
from
aws_ec2_instance as i
left join iam_roles as r on r.intance_arn = i.arn
left join iam_role_with_permission as p on p.arn = r.role_arn;
EOQ
}
query "ec2_instance_no_iam_role_with_data_destruction_access" {
sql = <<-EOQ
with iam_roles as (
select
r.arn as role_arn,
i.arn as intance_arn
from
aws_iam_role as r,
jsonb_array_elements_text(instance_profile_arns) as p
left join aws_ec2_instance as i on p = i.iam_instance_profile_arn
where
i.arn is not null
), iam_role_with_permission as (
select
arn
from
aws_iam_role,
jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,
jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,
jsonb_array_elements_text(s -> 'Action') as action
where
arn in (select role_arn from iam_roles)
and s ->> 'Effect' = 'Allow'
and service = 'ec2.amazonaws.com'
and (
(action in ('s3:deletebucket', 'rds:deletedbcluster', 'rds:deletedbinstance', 'rds:deleteDBSnapshot', 'rds:deletedbclustersnapshot', 'rds:deleteglobalcluster', 'ec2:deletesnapshot', 'ec2:deletevolume', '*:*')
)
)
)
select
i.arn as resource,
case
when p.arn is null then 'ok'
else 'alarm'
end status,
case
when p.arn is null then title || ' has no data destruction access.'
else title || ' has data destruction access.'
end as reason
${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "i.")}
${replace(local.common_dimensions_qualifier_global_sql, "__QUALIFIER__", "i.")}
from
aws_ec2_instance as i
left join iam_roles as r on r.intance_arn = i.arn
left join iam_role_with_permission as p on p.arn = r.role_arn;
EOQ
}
query "ec2_instance_no_iam_with_write_level_access" {
sql = <<-EOQ
with iam_roles as (
select
r.arn as role_arn,
i.arn as intance_arn
from
aws_iam_role as r,
jsonb_array_elements_text(instance_profile_arns) as p
left join aws_ec2_instance as i on p = i.iam_instance_profile_arn
where