-
Notifications
You must be signed in to change notification settings - Fork 17
/
mondoo-aws-security.mql.yaml
2430 lines (2112 loc) · 101 KB
/
mondoo-aws-security.mql.yaml
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
# Copyright (c) Mondoo, Inc.
# SPDX-License-Identifier: BUSL-1.1
policies:
- uid: mondoo-aws-security
name: Mondoo AWS Security
version: 3.0.1
license: BUSL-1.1
tags:
mondoo.com/category: security
mondoo.com/platform: aws,cloud
authors:
- name: Mondoo, Inc
email: hello@mondoo.com
docs:
desc: |
The Mondoo AWS Security policy provides guidance for establishing minimum recommended security and operational best practices for Amazon Web Services (AWS). The checks in this policy bundle are based on AWS's Operational Best Practices recommendations as part of the [AWS Config conformance packs](https://docs.aws.amazon.com/config/latest/developerguide/conformance-packs.html).
## Remote scan
Remote scans use cnspec providers to retrieve on-demand scan results without having to install any agents.
For a complete list of providers, run:
```bash
cnspec scan --help
```
### Prerequisites
Remote scanning of AWS accounts with cnspec relies on the access key ID and secret access key configured for the AWS CLI. To learn how to configure these keys in the AWS CLI, read [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html).
### Scan an AWS account
This command scans all enabled regions in an AWS account:
```bash
cnspec scan aws
```
### Scan a single AWS region
To specify a single region to scan with cnspec, use the `--region` flag with the AWS region code:
```bash
cnspec scan aws --region us-west-2
```
For a complete list of AWS region codes, read [Regions and Zones](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html).
### Scan an AWS account using a specific profile
If multiple AWS profiles are configured for the AWS CLI, you can target a specific profile by setting the `AWS_PROFILE` environment variable or the `--profile` command line flag.
```bash
export AWS_PROFILE=my-profile
cnspec scan aws
```
```bash
cnspec scan aws --profile my-profile
```
## Join the community!
Our goal is to build policies that are simple to deploy, accurate, and actionable.
If you have any suggestions for how to improve this policy or need support, [join the community](https://github.com/orgs/mondoohq/discussions) in GitHub Discussions.
groups:
- title: AWS IAM
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-access-keys-rotated
- uid: mondoo-aws-security-mfa-enabled-for-iam-console-access
- uid: mondoo-aws-security-root-account-mfa-enabled
- uid: mondoo-aws-security-iam-password-policy
- uid: mondoo-aws-security-iam-root-access-key-check
- uid: mondoo-aws-security-iam-users-only-one-access-key
- uid: mondoo-aws-security-iam-group-has-users-check
- uid: mondoo-aws-security-iam-user-no-inline-policies-check
- title: AWS Lambda Function
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-lambda-concurrency-check
- title: AWS S3 Bucket
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-s3-bucket-level-public-access-prohibited
- uid: mondoo-aws-security-s3-buckets-account-level-block-public-access
- title: AWS Security Group
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-secgroup-restricted-ssh
- title: AWS VPC
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-vpc-default-security-group-closed
- uid: mondoo-aws-security-vpc-flow-logs-enabled
- title: AWS DynamoDB Table
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-dynamodb-table-encrypted-kms
- title: AWS RDS DBInstance
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-rds-instance-public-access-check
- title: AWS Redshift Cluster
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-redshift-cluster-public-access-check
- title: AWS EC2
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-ec2-ebs-encryption-by-default
- uid: mondoo-aws-security-ec2-imdsv2-check
- uid: mondoo-aws-security-ec2-instance-no-public-ip
- uid: mondoo-aws-security-ec2-volume-inuse-check
- uid: mondoo-aws-security-ebs-snapshot-public-restorable-check
- title: AWS EFS Filesystem
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-efs-encrypted-check
- title: AWS CloudWatch LogGroup
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-cloudwatch-log-group-encrypted
- title: AWS ELB LoadBalancer
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-elb-deletion-protection-enabled
- title: AWS ES Domain
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-elasticsearch-encrypted-at-rest
- title: AWS KMS Key
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-rotation-customer-created-cmks-enabled
- title: AWS SageMaker NotebookInstance
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-sagemaker-notebook-instance-kms-key-configured
- title: AWS CloudTrail Trail
filters: asset.platform == "aws"
checks:
- uid: mondoo-aws-security-cloud-trail-encryption-enabled
scoring_system: highest impact
queries:
- uid: mondoo-aws-security-iam-root-access-key-check
title: Ensure no root user account access key exists
impact: 85
mql: |
aws.iam.credentialReport.where(properties.user == "<root_account>").all(accessKey1Active == false)
aws.iam.credentialReport.where(properties.user == "<root_account>").all(accessKey2Active == false)
docs:
desc: |
AWS strongly recommends that you not use the root user for your everyday tasks, even administrative ones. Instead, adhere to the best practice of using the root user only to create your first IAM user. Then securely lock away the root user credentials and use them to perform only a few account and service management tasks. Anyone with root user credentials for your AWS account has unrestricted access to all the resources in your account, including billing information.
audit: |
__cnspec shell__
1. Open a terminal
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.credentialReport.where( properties[\"user\"] == \"<root_account>\") { accessKey1Active accessKey2Active }
```
Example output:
```mql
aws.iam.credentialReport.where: [
0: {
accessKey1Active: false
accessKey2Active: false
}
]
```
remediation: |
If any access keys exist for the root user, read [Deleting access keys for the root user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_delete-key) in the AWS documentation.
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html
title: AWS Documentation - AWS account root user
- uid: mondoo-aws-security-root-account-mfa-enabled
title: Ensure MFA is enabled for the "root user" account
impact: 95
mql: aws.iam.credentialReport.where(properties.user == "<root_account>").all(mfaActive == true)
docs:
desc: |
AWS highly recommends that you follow the security best practice to enable multi-factor authentication (MFA) for your root account. Because your root user can perform sensitive operations in your account, adding an additional layer of authentication helps you to better secure your account. Multiple types of MFA are available.
audit: |
__cnspec shell__
1. Open a terminal
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.credentialReport.where( properties["user"] == "<root_account>") { mfaActive passwordLastChanged passwordLastUsed }
```
Example output:
```mql
aws.iam.credentialReport.where: [
0: {
mfaActive: true
}
]
```
remediation: |
Note: This check uses the AWS Credential Report, which has a grace period of 4 hours before changes to credentials take effect.
__Terraform__
The following snippet demonstrates creating a virtual device for the root user and returning the QRCode.
After creating the virtual MFA device, the root user can follow the procedure described under the AWS Console section.
```hcl
resource \"aws_iam_virtual_mfa_device\" \"root_mfa\" {
virtual_mfa_device_name = \"root\"
}
output \"root_qr_code\" {
value = tomap({
(aws_iam_virtual_mfa_device.root_mfa.virtual_mfa_device_name) = aws_iam_virtual_mfa_device.root_mfa.qr_code_png
})
}
```
__AWS Console__
MFA devices in AWS can be either hardware-based or virtual. To enable an MFA device for the root user, either:
- [Enable a virtual MFA device for your AWS account root user (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html#enable-virt-mfa-for-root)
or:
- [Enable a hardware MFA device for the AWS account root user (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html#enable-hw-mfa-for-root)
__AWS CLI__
Similarly to non-root users, you can use the AWS CLI to:
Create a virtual MFA device:
```bash
aws iam create-virtual-mfa-device \\
--virtual-mfa-device-name \"root\" \\
--outfile ./QRCode.png \\
--bootstrap-method QRCodePNG
```
Activate an MFA device:
```bash
aws iam enable-mfa-device \\
--user-name \"root\" \\
--serial-number \"arn:aws:iam::123456976749:mfa/root\" \\
--authentication-code1 123456 \\
--authentication-code2 654321
```
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa
title: Enable a virtual MFA device for your AWS account root user (console)
- uid: mondoo-aws-security-iam-password-policy
title: Ensure strong account password policy requirements are used
impact: 60
props:
- uid: mondooAWSSecurityIamPasswordPolicyMaxPasswordAge
title: Define the maximum number of days a password is allowed to exist before being rotated
mql: "90"
- uid: mondooAWSSecurityIamPasswordPolicyMinimumPasswordLength
title: Minimum password length
mql: "14"
- uid: mondooAWSSecurityIamPasswordPolicyPasswordReusePrevention
title: Number of passwords before allowing reuse
mql: "24"
- uid: mondooAWSSecurityIamPasswordPolicyRequireLowercaseCharacters
title: Denotes whether lowercase characters are required for passwords
mql: "true"
- uid: mondooAWSSecurityIamPasswordPolicyRequireNumbers
title: Denotes whether numbers are required for passwords
mql: "true"
- uid: mondooAWSSecurityIamPasswordPolicyRequireSymbols
title: Denotes whether symbols are required for passwords
mql: "true"
- uid: mondooAWSSecurityIamPasswordPolicyRequireUppercaseCharacters
title: Denotes whether uppercase characters are required for passwords
mql: "true"
mql: |
// Ensure properties do exist.
aws.iam.accountPasswordPolicy.RequireUppercaseCharacters != empty
aws.iam.accountPasswordPolicy.RequireLowercaseCharacters != empty
aws.iam.accountPasswordPolicy.RequireSymbols != empty
aws.iam.accountPasswordPolicy.RequireNumbers != empty
aws.iam.accountPasswordPolicy.MinimumPasswordLength != empty
aws.iam.accountPasswordPolicy.PasswordReusePrevention != empty
aws.iam.accountPasswordPolicy.MaxPasswordAge != empty
// Validate each policy setting against props
aws.iam.accountPasswordPolicy.where(RequireUppercaseCharacters != empty).all(RequireUppercaseCharacters == props.mondooAWSSecurityIamPasswordPolicyRequireUppercaseCharacters)
aws.iam.accountPasswordPolicy.where(RequireLowercaseCharacters != empty).all(RequireLowercaseCharacters == props.mondooAWSSecurityIamPasswordPolicyRequireLowercaseCharacters)
aws.iam.accountPasswordPolicy.where(RequireSymbols != empty).all(RequireSymbols == props.mondooAWSSecurityIamPasswordPolicyRequireSymbols)
aws.iam.accountPasswordPolicy.where(RequireNumbers != empty).all(RequireNumbers == props.mondooAWSSecurityIamPasswordPolicyRequireNumbers)
aws.iam.accountPasswordPolicy.where(MinimumPasswordLength != empty).all(MinimumPasswordLength >= props.mondooAWSSecurityIamPasswordPolicyMinimumPasswordLength)
aws.iam.accountPasswordPolicy.where(PasswordReusePrevention != empty).all(PasswordReusePrevention >= props.mondooAWSSecurityIamPasswordPolicyPasswordReusePrevention)
aws.iam.accountPasswordPolicy.where(MaxPasswordAge != empty).all(MaxPasswordAge <= props.mondooAWSSecurityIamPasswordPolicyMaxPasswordAge)
docs:
desc: |
AWS allows custom password policies on your AWS account to specify complexity requirements and mandatory rotation periods for your IAM users' passwords. IAM user passwords must meet the default AWS password policy if you don't set a custom password policy. AWS security best practices recommend these password complexity requirements:
- Require at least one uppercase character in passwords.
- Require at least one lowercase character in passwords.
- Require at least one symbol in passwords.
- Require at least one number in passwords.
- Require a minimum password length of at least 14 characters.
- Require at least 24 passwords before allowing reuse.
- Require at least 90 before password expiration.
This check ensures all of the specified password policy requirements are in place.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.accountPasswordPolicy
```
Example output:
```mql
aws.iam.accountPasswordPolicy: {
AllowUsersToChangePassword: true
ExpirePasswords: true
HardExpiry: false
MaxPasswordAge: "180"
MinimumPasswordLength: "14"
PasswordReusePrevention: "24"
RequireLowercaseCharacters: true
RequireNumbers: true
RequireSymbols: true
RequireUppercaseCharacters: true
}
```
remediation: |
__Terraform__
```hcl
resource \"aws_iam_account_password_policy\" \"strict\" {
allow_users_to_change_password = true
require_uppercase_characters = true
require_lowercase_characters = true
require_symbols = true
require_numbers = true
minimum_password_length = 14
password_reuse_prevention = 24
max_password_age = 90
}
```
__AWS Console__
To create a custom password policy:
1. Sign into the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/.
2. In the navigation pane, select **Account settings**.
3. In the Password policy section, select **Change password policy**.
4. Select the options you want to apply to your password policy and select **Save changes**.
To change a custom password policy:
1. Sign into the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/.
2. In the navigation pane, select **Account settings**.
3. In the **Password policy** section, select **Change**.
4. Select the options you want to apply to your password policy and select **Save changes**.
__AWS CLI__
```bash
aws iam update-account-password-policy \\
--allow-users-to-change-password \\
--require-uppercase-characters \\
--require-lowercase-characters \\
--require-symbols \\
--require-numbers \\
--minimum-password-length 14 \\
--password-reuse-prevention 24 \\
--max-password-age 90
```
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords.html
title: Managing user passwords in AWS
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html
title: Setting an account password policy for IAM users
- uid: mondoo-aws-security-access-keys-rotated
title: Ensure active access keys are rotated
impact: 70
props:
- uid: mondooAWSSecurityMaxAccessKeyAge
title: Define the maximum number of days an IAM key is allowed to exist before rotation
mql: "90"
mql: |
aws.iam.credentialReport.where(accessKey1Active == true && time.now - userCreationTime > props.mondooAWSSecurityMaxAccessKeyAge * time.day).all(time.now - accessKey1LastRotated < props.mondooAWSSecurityMaxAccessKeyAge * time.day)
aws.iam.credentialReport.where(accessKey2Active == true && time.now - userCreationTime > props.mondooAWSSecurityMaxAccessKeyAge * time.day).all(time.now - accessKey2LastRotated < props.mondooAWSSecurityMaxAccessKeyAge * time.day)
docs:
desc: |
It is highly recommended that you regularly rotate (change) IAM user access keys to reduce the risk of unwanted access to your account. Change the value enforced in this check by modifying the mondooAWSSecurityMaxAccessKeyAge property.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.credentialReport.where( accessKey1Active == true || accessKey2Active == true ) { properties['user'] accessKey1Active accessKey2Active accessKey1LastRotated accessKey2LastRotated }
```
Example output:
```mql
aws.iam.credentialReport.where: [
0: {
accessKey1LastRotated: 2021-09-01 01:32:29 +0000 +0000
accessKey2LastRotated: Never
accessKey1Active: true
accessKey2Active: false
properties[user]: \"jimmy\"
}
1: {
accessKey1LastRotated: 2021-09-09 19:16:35 +0000 +0000
accessKey2LastRotated: Never
accessKey1Active: true
accessKey2Active: false
properties[user]: \"robert\"
}
2: {
accessKey1LastRotated: 2021-06-15 07:18:34 +0000 +0000
accessKey2LastRotated: Never
accessKey1Active: true
accessKey2Active: false
properties[user]: \"johnpaul\"
}
3: {
accessKey1LastRotated: 2021-09-29 21:53:04 +0000 +0000
accessKey2LastRotated: Never
accessKey1Active: true
accessKey2Active: false
properties[user]: \"bonzo\"
}
]
```
remediation: |
To learn how to rotate AWS access keys, read [Rotating access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_RotateAccessKey) in the AWS documentation.
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html
title: AWS Documentation - Managing access keys for IAM users
- uid: mondoo-aws-security-mfa-enabled-for-iam-console-access
title: Ensure Multi-Factor Authentication is Enabled for All IAM users with console access
impact: 90
mql: |
aws.iam.credentialReport.where(passwordEnabled == true).all(mfaActive == true)
docs:
desc: |
Multi-factor authentication (MFA) is a best practice that adds an extra layer of protection on top of user names and passwords. With MFA, when a user signs in to the AWS Management Console, they are required to provide a time-sensitive authentication code provided by a registered virtual or physical device.
audit: |
__cnspec shell__
1. Open a terminal.
2. Run this command: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.credentialReport.where(
mfaActive != true
) {arn properties[\"user\"]}
```
Example output:
```mql
aws.iam.credentialReport.where: [
0: {
properties[user]: \"test-iam-user\"
arn: \"arn:aws:iam::053121068929:user/users/test-iam-user\"
}
]
```
remediation: |
Note: This check uses the AWS Credential Report, which has a grace period of 4 hours before changes to credentials take effect.
__Terraform__
When it comes to Terraform, there are a few options to remediate the absence of MFA devices. You probably already have a sensible structure for organizing your users into groups and restrictive policies.
The following example shows how to:
1. Create users.
2. Create users' login profiles with a PGP public key.
3. Create a group and group policy that allows self-management of IAM profiles.
4. Attach users to a group.
5. Create Virtual MFA devices for users.
6. Provide each user with the output QR Code and password.
```hcl
variable \"users\" {
type = set(string)
default = [
\"mondoo-test@mondoo.com\",
\"mondoo-test2@mondoo.com\"
]
}
resource \"aws_iam_user\" \"mondoo_test_users\" {
for_each = toset(var.users)
name = each.key
}
resource \"aws_iam_user_login_profile\" \"mondoo_test_users_profile\" {
for_each = var.users
user = each.key
# Key pair created using GnuPG. This is the public key
pgp_key = file(\"path/to/gpg_pub_key_base64.pem\")
password_reset_required = true
lifecycle {
ignore_changes = [
password_length,
password_reset_required,
pgp_key,
]
}
}
resource \"aws_iam_virtual_mfa_device\" \"mondoo_test_mfa\" {
for_each = toset(var.users)
virtual_mfa_device_name = each.key
}
resource \"aws_iam_group\" \"enforce_mfa_group\" {
name = \"EnforceMFAGroup\"
}
resource \"aws_iam_group_membership\" \"enforce_mfa_group_membership\" {
name = \"EnforceMFAGroupMembership\"
group = aws_iam_group.enforce_mfa_group.name
users = [for k in aws_iam_user.mondoo_test_users : k.name]
}
resource \"aws_iam_group_policy\" \"enforce_mfa_policy\" {
name = \"EnforceMFAGroupPolicy\"
group = aws_iam_group.enforce_mfa_group.id
policy = <<POLICY
{
\"Version\": \"2012-10-17\",
\"Statement\": [
{
\"Sid\": \"AllowViewAccountInfo\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:GetAccountPasswordPolicy\",
\"iam:ListVirtualMFADevices\"
],
\"Resource\": \"*\"
},
{
\"Sid\": \"AllowManageOwnPasswords\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:ChangePassword\",
\"iam:GetUser\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnAccessKeys\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:CreateAccessKey\",
\"iam:DeleteAccessKey\",
\"iam:ListAccessKeys\",
\"iam:UpdateAccessKey\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnSigningCertificates\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:DeleteSigningCertificate\",
\"iam:ListSigningCertificates\",
\"iam:UpdateSigningCertificate\",
\"iam:UploadSigningCertificate\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnSSHPublicKeys\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:DeleteSSHPublicKey\",
\"iam:GetSSHPublicKey\",
\"iam:ListSSHPublicKeys\",
\"iam:UpdateSSHPublicKey\",
\"iam:UploadSSHPublicKey\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnGitCredentials\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:CreateServiceSpecificCredential\",
\"iam:DeleteServiceSpecificCredential\",
\"iam:ListServiceSpecificCredentials\",
\"iam:ResetServiceSpecificCredential\",
\"iam:UpdateServiceSpecificCredential\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnVirtualMFADevice\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:CreateVirtualMFADevice\",
\"iam:DeleteVirtualMFADevice\"
],
\"Resource\": \"arn:aws:iam::*:mfa/$${aws:username}\"
},
{
\"Sid\": \"AllowManageOwnUserMFA\",
\"Effect\": \"Allow\",
\"Action\": [
\"iam:DeactivateMFADevice\",
\"iam:EnableMFADevice\",
\"iam:ListMFADevices\",
\"iam:ResyncMFADevice\"
],
\"Resource\": \"arn:aws:iam::*:user/$${aws:username}\"
},
{
\"Sid\": \"DenyAllExceptListedIfNoMFA\",
\"Effect\": \"Deny\",
\"NotAction\": [
\"iam:CreateVirtualMFADevice\",
\"iam:EnableMFADevice\",
\"iam:GetUser\",
\"iam:ListMFADevices\",
\"iam:ListVirtualMFADevices\",
\"iam:ResyncMFADevice\",
\"sts:GetSessionToken\"
],
\"Resource\": \"*\",
\"Condition\": {
\"BoolIfExists\": {
\"aws:MultiFactorAuthPresent\": \"false\"
}
}
}
]
}
POLICY
}
output \"user_password_map\" {
# Outputs a map in the format {\"mondoo-test@mondoo.com\": <PGPEncryptedPassword>, \"mondoo-test2@mondoo.com\": <PGPEncryptedPassword>}
value = { for k, v in aws_iam_user_login_profile.mondoo_test_users_profile : k => v.password }
}
output \"user_qr_map\" {
# Outputs a map in the format {\"mondoo-test@mondoo.com\": <QRCode>, \"mondoo-test2@mondoo.com\": <QRCode>}
value = { for k, v in aws_iam_virtual_mfa_device.mondoo_test_mfa : k => v.qr_code_png }
}
__AWS Console__
To learn how to enable MFA for any user accounts with AWS console access, read [Enabling a virtual multi-factor authentication (MFA) device (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html) in the AWS documentation.
Enable a virtual MFA device for an IAM user:
1. Sign into the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/.
2. In the navigation pane, select **Users**.
3. In the **User Name** list, select the name of the intended MFA user.
4. select the **Security credentials** tab. Next to Assigned MFA device, select **Manage**.
5. In the Manage MFA Device wizard, select **Virtual MFA device** and then select **Continue**.
6. IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic represents the \"secret configuration key\" available for manual entry on devices that do not support QR codes.
7. Open your virtual MFA app. For a list of apps you can use to host virtual MFA devices, read [Multi-Factor Authentication](https://aws.amazon.com/iam/features/mfa/).
8. If the virtual MFA app supports multiple virtual MFA devices or accounts, select the option to create a new virtual MFA device or account.
9. Determine whether the MFA app supports QR codes, and then either:
- From the wizard, select **Show QR code**, and then use the app to scan the QR code. For example, you might select the camera icon or select an option similar to Scan code, and then use the device's camera to scan the code.
or:
- In the Manage MFA Device wizard, select **Show secret key** and type the secret key into your MFA app.
10. When you finish, the virtual MFA device generates one-time passwords.
11. In the Manage MFA Device wizard, in the **MFA code 1** box, type the one-time password that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password, then type the second one-time password into the **MFA code 2 box**.
12. select **Assign MFA**.
__AWS CLI__
Create an MFA device:
```bash
aws iam create-virtual-mfa-device \\
--virtual-mfa-device-name \"mondoo.test@mondoo.com\" \\
--outfile ./QRCode.png \\
--bootstrap-method QRCodePNG
```
Enable MFA device for existing user:
```bash
aws iam enable-mfa-device \\
--user-name \"mondoo.test@mondoo.com\" \\
--serial-number \"arn:aws:iam::123456976749:mfa/mondoo.test@mondoo.com\" \\
--authentication-code1 123456 \\
--authentication-code2 654321
```
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html
title: Using multi-factor authentication (MFA) in AWS
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html
title: Enabling a virtual multi-factor authentication (MFA) device (console)
- url: https://registry.terraform.io/providers/hashicorp/aws/latest/docs
title: Terraform Documentation - AWS Provider
- uid: mondoo-aws-security-iam-group-has-users-check
title: Ensure IAM Groups are utilized by Assigning at Least One user
impact: 30
docs:
desc: |
AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations by ensuring that IAM groups have at least one IAM user. Placing IAM users in groups based on their associated permissions or job function is one way to incorporate least privilege.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.groups.where( usernames.length == 0 ) {*}
```
Example output:
```mql
aws.iam.groups.where: [
0: {
name: \"MyUserGroup\"
id: \"AGPASSOFBMF7OMHVGHACB\"
createDate: 2022-01-11 18:19:26 +0000 UTC
usernames: []
arn: \"arn:aws:iam::177043759486:group/MyUserGroup\"
}
]
```
remediation: |
To delete empty IAM groups, read [Deleting an IAM user group](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups_manage_delete.html) in the AWS documentation.
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups_manage.html
title: AWS Documentation -Managing IAM user groups
variants:
- uid: mondoo-aws-security-iam-group-has-users-check-account
- uid: mondoo-aws-security-iam-group-has-users-check-single-group
- uid: mondoo-aws-security-iam-group-has-users-check-account
filters: asset.platform == "aws"
mql: aws.iam.groups.all(usernames != empty)
- uid: mondoo-aws-security-iam-group-has-users-check-single-group
filters: asset.platform == "aws-iam-group"
mql: aws.iam.group.usernames != empty
- uid: mondoo-aws-security-iam-users-only-one-access-key
title: Ensure there is only one active access key available for any single IAM user
impact: 70
mql: |
aws.iam.users.where(accessKeys.flat.where(Status == "Active")).all(accessKeys[0].length <= 1)
docs:
desc: |
This check ensures for the existence of more than one access key for each user within an AWS account. Each AWS key within an account must be protected and rotated regularly. Because AWS access keys are long-term credentials, one of the best ways to protect your account is to not allow users to have multiple access keys, which reduces the overall number of keys and the risk of exposure.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.users.where(accessKeys[0].length >= 1)
```
remediation: |
__AWS Console:__
1. Sign into the AWS Management Console and navigate to IAM dashboard at https://console.aws.amazon.com/iam/.
2. In the left navigation panel, select **Users**.
3. Select the IAM user you want to examine.
4. On the IAM user configuration page, select the **Security Credentials** tab.
5. In the **Access Keys** section, select an access key that is fewer than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working.
6. In the same **Access Keys** section, identify your non-operational access keys (other than the chosen one) and deactivate them by selecting the **Make Inactive** link.
If the Change Key Status confirmation displays, select **Deactivate** to turn off the selected key.
Repeat steps 3 - 7 for each IAM user in your AWS account.
__AWS CLI:__
Using the IAM user and access key information provided in the Audit CLI, select an access key that is fewer than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working.
Run the `update-access-key` command (shown below) using the IAM user name and the non-operational access key IDs to deactivate the unnecessary key(s). To learn how to identify the unnecessary access key ID for the selected IAM user, read the _Audit_ section above.
Note: This command does not return any output:
```bash
aws iam update-access-key --access-key-id <access-key-id> --status Inactive --user-name <user-name>
```
To confirm that the selected access key pair has been successfully deactivated, run the `list-access-keys`` audit command again for the IAM User:
```bash
aws iam list-access-keys --user-name <user-name>
```
The command output exposes the metadata for each access key associated with the IAM user. If the non-operational key pair(s) Status is set to Inactive, the key has been successfully deactivated and the IAM user access configuration adheres now to this recommendation.
Repeat steps 1 - 3 for each IAM user in your AWS account.
- uid: mondoo-aws-security-iam-user-no-inline-policies-check
title: Ensure IAM users receive permissions only through groups
impact: 70
docs:
desc: |
AWS recommends that IAM users must inherit permissions from IAM groups or roles. This policy checks that none of your IAM users have policies attached directly to the user. The rule is NONCOMPLIANT if there is at least one IAM user with policies attached.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.iam.users.where( policies.length != 0 || attachedPolicies.length != 0 ) { name arn policies attachedPolicies }
```
Example output:
```mql
aws.iam.users.where: [
0: {
arn: \"arn:aws:iam::1234567890987:user/1234567890987-alice\"
name: \"1234567890987-alice\"
attachedPolicies: []
policies: [
0: \"excess_policy\"
]
}
1: {
arn: \"arn:aws:iam::1234567890987:user/maria\"
name: \"maria\"
attachedPolicies: [
0: aws.iam.policy id = arn:aws:iam::1234567890987:policy/ec2-instance-connect-sendssh
]
policies: []
}
2: {
arn: \"arn:aws:iam::1234567890987:user/bobby\"
name: \"bobby\"
attachedPolicies: [
0: aws.iam.policy id = arn:aws:iam::1234567890987:policy/terraform20210901011436036200000004
]
policies: []
}
]
```
remediation: |
To learn how to remove inline policies from IAM users, read [Removing a permissions policy from a user (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-remove-policy-console) in the AWS documentation.
refs:
- url: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html
title: Managed policies and inline policies
variants:
- uid: mondoo-aws-security-iam-user-no-inline-policies-check-account
- uid: mondoo-aws-security-iam-user-no-inline-policies-check-single-user
- uid: mondoo-aws-security-iam-user-no-inline-policies-check-account
filters: asset.platform == "aws"
mql: |
aws.iam.users.all(policies == empty)
aws.iam.users.all(attachedPolicies == empty)
- uid: mondoo-aws-security-iam-user-no-inline-policies-check-single-user
filters: asset.platform == "aws-iam-user"
mql: |
aws.iam.user.policies == empty
aws.iam.user.attachedPolicies == empty
- uid: mondoo-aws-security-vpc-default-security-group-closed
title: Ensure the default security group of every VPC restricts all traffic
impact: 80
docs:
desc: |
The rules for a default security group allow all ingress and egress traffic. To keep users from using the default security group (which cannot be deleted) of a VPC, delete all ingress and egress rules to block all traffic.
audit: |
__cnspec shell__
1. Open a terminal.
2. Connect cnspec shell to your AWS environment: `cnspec shell aws`
3. Run this query:
```mql
aws.ec2.securityGroups.where(
name == \"default\"
).where(
ipPermissions.length != 0
|| ipPermissionsEgress.length != 0
){id name region ipPermissions{*} ipPermissionsEgress{*}}
```
Example output:
```mql
aws.ec2.securityGroups.where.where: [
0: {
ipPermissions: [
0: {
id: \"sg-0bd4b1ef47132d3de-0\"
fromPort: 0
toPort: 0
ipProtocol: \"-1\"
ipv6Ranges: []
ipRanges: []
}
]
ipPermissionsEgress: []
name: \"default\"
region: \"eu-north-1\"
id: \"sg-0bd4b1ef47132d3de\"
}
]
```
remediation: |
__Terraform__
Terraform provides the resource `aws_default_security_group` which, unlike other Terraform resources, has these effects in the state of the infrastructure:
- \"Adopts\" the default security group for the provided `vpc_id`.
- Removes all inbound (ingress) and outbound (egress) rules for the security group.
To remediate this check using Terraform, apply the following logic for every region the account has access to by aliasing the providers.
Note: You must create a new security group for all VPCs in order to reassign any resources that previously used (or were created with) the default security groups.
```hcl
provider \"aws\" {
alias = \"us_east_1\"
region = \"us-east-1\"
}
data \"aws_vpcs\" \"us_east_1\" {
provider = aws.us_east_1
}
resource \"aws_security_group\" \"replacement_for_default\" {
name = \"AllowOrDenySomething\"
for_each = toset(data.aws_vpcs.us_east_1.ids)
vpc_id = each.value
ingress {
# ... other configuration ...
}
egress {
# ... other configuration ...
}
}
resource \"aws_default_security_group\" \"us_east_1\" {
for_each = toset(data.aws_vpcs.us_east_1.ids)
vpc_id = each.value
provider = aws.us_east_1
}
```
__AWS Console__
To remediate this issue, create new security groups and assign those security groups to your resources (if needed). To prevent the default security groups from being used, remove their inbound and outbound rules.
To create new security groups and assign them to your resources:
1. Open the Amazon VPC console at https://console.aws.amazon.com/vpc/.
2. In the navigation pane, select **Security groups**. View the default security groups details to see the resources that are assigned to them.
3. Create a set of least-privilege security groups for the resources. To learn how to create security groups, read [Creating a security group](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#CreatingSecurityGroups) in the Amazon VPC User Guide.
4. Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/.
5. On the Amazon EC2 console, change the security group for the resources that use the default security groups to the least-privilege security group you created. To learn how, read [Changing an instance's security groups](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#SG_Changing_Group_Membership) in the Amazon VPC User Guide.
After you assign the new security groups to the resources, remove the inbound and outbound rules from the default security groups. This ensures that the default security groups are not used.
To remove the rules from the default security group:
1. Open the Amazon VPC console at https://console.aws.amazon.com/vpc/.
2. In the navigation pane, select **Security groups**.
3. Select a default security group and select the **Inbound rules** tab. select Edit inbound rules. Delete all inbound rules and select **Save rules**.
4. Repeat the previous step for each default security group.
5. Select a default security group and select the Outbound rule tab. Select **Edit outbound rules**. Delete all outbound rules and select **Save rules**.
6. Repeat the previous step for each default security group.
To learn more, read [Working with security groups](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#WorkingWithSecurityGroups) in the Amazon VPC User Guide.
__AWS CLI__
Apply the same logic to the AWS CLI to remediate this check.
Note: Perform these tasks for all regions your account has access to.
1. Get the security groups in the region.
```bash
aws ec2 describe-security-groups
```