diff --git a/aws_cis_foundation_framework/aws-cis-foundation-benchmark-checklist.py b/aws_cis_foundation_framework/aws-cis-foundation-benchmark-checklist.py index 4c28862..9d69beb 100644 --- a/aws_cis_foundation_framework/aws-cis-foundation-benchmark-checklist.py +++ b/aws_cis_foundation_framework/aws-cis-foundation-benchmark-checklist.py @@ -96,6 +96,7 @@ def control_1_1_root_use(credreport): failReason = "" offenders = [] control = "1.1" + level = "1" description = "Avoid the use of the root account" scored = True if "Fail" in credreport: # Report failure in control @@ -135,7 +136,7 @@ def control_1_1_root_use(credreport): pass else: print("Something went wrong") - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) @@ -152,6 +153,7 @@ def control_1_2_mfa_on_password_enabled_iam(credreport): failReason = "" offenders = [] control = "1.2" + level = "1" description = "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" scored = True for i in range(len(credreport)): @@ -162,7 +164,7 @@ def control_1_2_mfa_on_password_enabled_iam(credreport): result = False failReason = "No MFA on users with password. " offenders.append(str(credreport[i]['arn'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) @@ -179,6 +181,7 @@ def control_1_3_unused_credentials(credreport): failReason = "" offenders = [] control = "1.3" + level = "1" description = "Ensure credentials unused for 90 days or greater are disabled" scored = True # Get current time @@ -218,7 +221,7 @@ def control_1_3_unused_credentials(credreport): except: # Never used pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.4 Ensure access keys are rotated every 90 days or less (Scored) @@ -235,6 +238,7 @@ def control_1_4_rotated_keys(credreport): failReason = "" offenders = [] control = "1.4" + level = "1" description = "Ensure access keys are rotated every 90 days or less" scored = True # Get current time @@ -283,7 +287,7 @@ def control_1_4_rotated_keys(credreport): offenders.append(str(credreport[i]['arn']) + ":unused key2") except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) @@ -300,6 +304,7 @@ def control_1_5_password_policy_uppercase(passwordpolicy): failReason = "" offenders = [] control = "1.5" + level = "1" description = "Ensure IAM password policy requires at least one uppercase letter" scored = True if passwordpolicy is False: @@ -309,7 +314,7 @@ def control_1_5_password_policy_uppercase(passwordpolicy): if passwordpolicy['RequireUppercaseCharacters'] is False: result = False failReason = "Password policy does not require at least one uppercase letter" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.6 Ensure IAM password policy requires at least one lowercase letter (Scored) @@ -326,6 +331,7 @@ def control_1_6_password_policy_lowercase(passwordpolicy): failReason = "" offenders = [] control = "1.6" + level = "1" description = "Ensure IAM password policy requires at least one lowercase letter" scored = True if passwordpolicy is False: @@ -335,7 +341,7 @@ def control_1_6_password_policy_lowercase(passwordpolicy): if passwordpolicy['RequireLowercaseCharacters'] is False: result = False failReason = "Password policy does not require at least one uppercase letter" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.7 Ensure IAM password policy requires at least one symbol (Scored) @@ -352,6 +358,7 @@ def control_1_7_password_policy_symbol(passwordpolicy): failReason = "" offenders = [] control = "1.7" + level = "1" description = "Ensure IAM password policy requires at least one symbol" scored = True if passwordpolicy is False: @@ -361,7 +368,7 @@ def control_1_7_password_policy_symbol(passwordpolicy): if passwordpolicy['RequireSymbols'] is False: result = False failReason = "Password policy does not require at least one symbol" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.8 Ensure IAM password policy requires at least one number (Scored) @@ -378,6 +385,7 @@ def control_1_8_password_policy_number(passwordpolicy): failReason = "" offenders = [] control = "1.8" + level = "1" description = "Ensure IAM password policy requires at least one number" scored = True if passwordpolicy is False: @@ -387,7 +395,7 @@ def control_1_8_password_policy_number(passwordpolicy): if passwordpolicy['RequireNumbers'] is False: result = False failReason = "Password policy does not require at least one number" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) @@ -404,6 +412,7 @@ def control_1_9_password_policy_length(passwordpolicy): failReason = "" offenders = [] control = "1.9" + level = "1" description = "Ensure IAM password policy requires minimum length of 14 or greater" scored = True if passwordpolicy is False: @@ -413,7 +422,7 @@ def control_1_9_password_policy_length(passwordpolicy): if passwordpolicy['MinimumPasswordLength'] < 14: result = False failReason = "Password policy does not require at least 14 characters" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.10 Ensure IAM password policy prevents password reuse (Scored) @@ -430,6 +439,7 @@ def control_1_10_password_policy_reuse(passwordpolicy): failReason = "" offenders = [] control = "1.10" + level = "1" description = "Ensure IAM password policy prevents password reuse" scored = True if passwordpolicy is False: @@ -445,7 +455,7 @@ def control_1_10_password_policy_reuse(passwordpolicy): except: result = False failReason = "Password policy does not prevent reusing last 24 passwords" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) @@ -462,6 +472,7 @@ def control_1_11_password_policy_expire(passwordpolicy): failReason = "" offenders = [] control = "1.11" + level = "1" description = "Ensure IAM password policy expires passwords within 90 days or less" scored = True if passwordpolicy is False: @@ -475,7 +486,7 @@ def control_1_11_password_policy_expire(passwordpolicy): else: result = False failReason = "Password policy does not expire passwords after 90 days or less" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.12 Ensure no root account access key exists (Scored) @@ -492,12 +503,13 @@ def control_1_12_root_key_exists(credreport): failReason = "" offenders = [] control = "1.12" + level = "1" description = "Ensure no root account access key exists" scored = True if (credreport[0]['access_key_1_active'] == "true") or (credreport[0]['access_key_2_active'] == "true"): result = False failReason = "Root have active access keys" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.13 Ensure MFA is enabled for the "root" account (Scored) @@ -511,13 +523,14 @@ def control_1_13_root_mfa_enabled(): failReason = "" offenders = [] control = "1.13" + level = "2" description = "Ensure MFA is enabled for the root account" scored = True response = IAM_CLIENT.get_account_summary() if response['SummaryMap']['AccountMFAEnabled'] != 1: result = False failReason = "Root account not using MFA" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.14 Ensure hardware MFA is enabled for the "root" account (Scored) @@ -531,6 +544,7 @@ def control_1_14_root_hardware_mfa_enabled(): failReason = "" offenders = [] control = "1.14" + level = "2" description = "Ensure hardware MFA is enabled for the root account" scored = True # First verify that root is using MFA (avoiding false positive) @@ -550,7 +564,7 @@ def control_1_14_root_hardware_mfa_enabled(): else: result = False failReason = "Root account not using MFA" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.15 Ensure security questions are registered in the AWS account (Not Scored/Manual) @@ -564,10 +578,11 @@ def control_1_15_security_questions_registered(): failReason = "" offenders = [] control = "1.15" + level = "1" description = "Ensure security questions are registered in the AWS account, please verify manually" scored = False failReason = "Control not implemented using API, please verify manually" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.16 Ensure IAM policies are attached only to groups or roles (Scored) @@ -581,6 +596,7 @@ def control_1_16_no_policies_on_iam_users(): failReason = "" offenders = [] control = "1.16" + level = "1" description = "Ensure IAM policies are attached only to groups or roles" scored = True paginator = IAM_CLIENT.get_paginator('list_users') @@ -599,7 +615,7 @@ def control_1_16_no_policies_on_iam_users(): result = False failReason = "IAM user have inline policy attached" offenders.append(str(n['Arn'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.17 Enable detailed billing (Scored) @@ -613,10 +629,11 @@ def control_1_17_detailed_billing_enabled(): failReason = "" offenders = [] control = "1.17" + level = "1" description = "Enable detailed billing, please verify manually" scored = True failReason = "Control not implemented using API, please verify manually" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.18 Ensure IAM Master and IAM Manager roles are active (Scored) @@ -630,9 +647,10 @@ def control_1_18_ensure_iam_master_and_manager_roles(): failReason = "No IAM Master or IAM Manager role created" offenders = [] control = "1.18" + level = "1" description = "Ensure IAM Master and IAM Manager roles are active. Control under review/investigation" scored = True - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.19 Maintain current contact details (Scored) @@ -646,10 +664,11 @@ def control_1_19_maintain_current_contact_details(): failReason = "" offenders = [] control = "1.19" + level = "1" description = "Maintain current contact details, please verify manually" scored = True failReason = "Control not implemented using API, please verify manually" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.20 Ensure security contact information is registered (Scored) @@ -663,10 +682,11 @@ def control_1_20_ensure_security_contact_details(): failReason = "" offenders = [] control = "1.20" + level = "1" description = "Ensure security contact information is registered, please verify manually" scored = True failReason = "Control not implemented using API, please verify manually" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.21 Ensure IAM instance roles are used for AWS resource access from instances (Scored) @@ -680,6 +700,7 @@ def control_1_21_ensure_iam_instance_roles_used(): failReason = "" offenders = [] control = "1.21" + level = "2" description = "Ensure IAM instance roles are used for AWS resource access from instances, application code is not audited" scored = True failReason = "Instance not assigned IAM role for EC2" @@ -693,7 +714,7 @@ def control_1_21_ensure_iam_instance_roles_used(): except: result = False offenders.append(str(response['Reservations'][n]['Instances'][0]['InstanceId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) @@ -707,6 +728,7 @@ def control_1_22_ensure_incident_management_roles(): failReason = "" offenders = [] control = "1.22" + level = "1" description = "Ensure a support role has been created to manage incidents with AWS Support" scored = True offenders = [] @@ -720,7 +742,7 @@ def control_1_22_ensure_incident_management_roles(): except: result = False failReason = "AWSSupportAccess policy not created" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) @@ -734,6 +756,7 @@ def control_1_23_no_active_initial_access_keys_with_iam_user(credreport): failReason = "" offenders = [] control = "1.23" + level = "1" description = "Do not setup access keys during initial user setup for all IAM users that have a console password" scored = False offenders = [] @@ -747,7 +770,7 @@ def control_1_23_no_active_initial_access_keys_with_iam_user(credreport): result = False failReason = "Users with keys created at user creation time found" offenders.append(str(credreport[n]['arn']) + ":" + str(m['AccessKeyId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) @@ -761,6 +784,7 @@ def control_1_24_no_overly_permissive_policies(): failReason = "" offenders = [] control = "1.24" + level = "1" description = "Ensure IAM policies that allow full administrative privileges are not created" scored = True offenders = [] @@ -794,7 +818,7 @@ def control_1_24_no_overly_permissive_policies(): result = False failReason = "Found full administrative policy" offenders.append(str(m['Arn'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # --- 2 Logging --- @@ -813,6 +837,7 @@ def control_2_1_ensure_cloud_trail_all_regions(cloudtrails): failReason = "" offenders = [] control = "2.1" + level = "1" description = "Ensure CloudTrail is enabled in all regions" scored = True for m, n in cloudtrails.iteritems(): @@ -827,7 +852,7 @@ def control_2_1_ensure_cloud_trail_all_regions(cloudtrails): break if result is False: failReason = "No enabled multi region trails found" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.2 Ensure CloudTrail log file validation is enabled (Scored) @@ -844,6 +869,7 @@ def control_2_2_ensure_cloudtrail_validation(cloudtrails): failReason = "" offenders = [] control = "2.2" + level = "2" description = "Ensure CloudTrail log file validation is enabled" scored = True for m, n in cloudtrails.iteritems(): @@ -854,7 +880,7 @@ def control_2_2_ensure_cloudtrail_validation(cloudtrails): offenders.append(str(o['TrailARN'])) offenders = set(offenders) offenders = list(offenders) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) @@ -871,6 +897,7 @@ def control_2_3_ensure_cloudtrail_bucket_not_public(cloudtrails): failReason = "" offenders = [] control = "2.3" + level = "1" description = "Ensure the S3 bucket CloudTrail logs to is not publicly accessible" scored = True for m, n in cloudtrails.iteritems(): @@ -904,7 +931,7 @@ def control_2_3_ensure_cloudtrail_bucket_not_public(cloudtrails): result = False offenders.append(str(o['TrailARN']) + "NoS3Logging") failReason = "Cloudtrail not configured to log to S3. " + failReason - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) @@ -921,6 +948,7 @@ def control_2_4_ensure_cloudtrail_cloudwatch_logs_integration(cloudtrails): failReason = "" offenders = [] control = "2.4" + level = "1" description = "Ensure CloudTrail trails are integrated with CloudWatch Logs" scored = True for m, n in cloudtrails.iteritems(): @@ -936,7 +964,7 @@ def control_2_4_ensure_cloudtrail_cloudwatch_logs_integration(cloudtrails): result = False failReason = "CloudTrails without CloudWatch Logs discovered" offenders.append(str(o['TrailARN'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.5 Ensure AWS Config is enabled in all regions (Scored) @@ -950,6 +978,7 @@ def control_2_5_ensure_config_all_regions(regions): failReason = "" offenders = [] control = "2.5" + level = "1" description = "Ensure AWS Config is enabled in all regions" scored = True globalConfigCapture = False # Only one region needs to capture global events @@ -1006,7 +1035,7 @@ def control_2_5_ensure_config_all_regions(regions): result = False failReason = "Config not enabled in all regions, not capturing all/global events or delivery channel errors" offenders.append("Global:NotRecording") - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) @@ -1023,6 +1052,7 @@ def control_2_6_ensure_cloudtrail_bucket_logging(cloudtrails): failReason = "" offenders = [] control = "2.6" + level = "1" description = "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" scored = True for m, n in cloudtrails.iteritems(): @@ -1041,7 +1071,7 @@ def control_2_6_ensure_cloudtrail_bucket_logging(cloudtrails): result = False failReason = failReason + "CloudTrail S3 bucket without logging discovered" offenders.append("Trail:" + str(o['TrailARN']) + " - S3Bucket:" + str(o['S3BucketName'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) @@ -1058,6 +1088,7 @@ def control_2_7_ensure_cloudtrail_encryption_kms(cloudtrails): failReason = "" offenders = [] control = "2.7" + level = "2" description = "Ensure CloudTrail logs are encrypted at rest using KMS CMKs" scored = True for m, n in cloudtrails.iteritems(): @@ -1069,7 +1100,7 @@ def control_2_7_ensure_cloudtrail_encryption_kms(cloudtrails): result = False failReason = "CloudTrail not using KMS CMK for encryption discovered" offenders.append("Trail:" + str(o['TrailARN'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 2.8 Ensure rotation for customer created CMKs is enabled (Scored) @@ -1083,6 +1114,7 @@ def control_2_8_ensure_kms_cmk_rotation(regions): failReason = "" offenders = [] control = "2.8" + level = "2" description = "Ensure rotation for customer created CMKs is enabled" scored = True for n in regions: @@ -1101,7 +1133,7 @@ def control_2_8_ensure_kms_cmk_rotation(regions): offenders.append("Key:" + str(keyDescription['KeyMetadata']['Arn'])) except: pass # Ignore keys without permission, for example ACM key - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # --- Monitoring --- @@ -1117,6 +1149,7 @@ def control_3_1_ensure_log_metric_filter_unauthorized_api_calls(cloudtrails): failReason = "" offenders = [] control = "3.1" + level = "1" description = "Ensure log metric filter unauthorized api calls" scored = True failReason = "Incorrect log metric alerts for unauthorized_api_calls" @@ -1146,7 +1179,7 @@ def control_3_1_ensure_log_metric_filter_unauthorized_api_calls(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) @@ -1160,6 +1193,7 @@ def control_3_2_ensure_log_metric_filter_console_signin_no_mfa(cloudtrails): failReason = "" offenders = [] control = "3.2" + level = "1" description = "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" scored = True failReason = "Incorrect log metric alerts for management console signin without MFA" @@ -1189,7 +1223,7 @@ def control_3_2_ensure_log_metric_filter_console_signin_no_mfa(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.3 Ensure a log metric filter and alarm exist for usage of "root" account (Scored) @@ -1203,6 +1237,7 @@ def control_3_3_ensure_log_metric_filter_root_usage(cloudtrails): failReason = "" offenders = [] control = "3.3" + level = "1" description = "Ensure a log metric filter and alarm exist for root usage" scored = True failReason = "Incorrect log metric alerts for root usage" @@ -1232,7 +1267,7 @@ def control_3_3_ensure_log_metric_filter_root_usage(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) @@ -1246,6 +1281,7 @@ def control_3_4_ensure_log_metric_iam_policy_change(cloudtrails): failReason = "" offenders = [] control = "3.4" + level = "1" description = "Ensure a log metric filter and alarm exist for IAM changes" scored = True failReason = "Incorrect log metric alerts for IAM policy changes" @@ -1275,7 +1311,7 @@ def control_3_4_ensure_log_metric_iam_policy_change(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) @@ -1289,6 +1325,7 @@ def control_3_5_ensure_log_metric_cloudtrail_configuration_changes(cloudtrails): failReason = "" offenders = [] control = "3.5" + level = "1" description = "Ensure a log metric filter and alarm exist for CloudTrail configuration changes" scored = True failReason = "Incorrect log metric alerts for CloudTrail configuration changes" @@ -1318,7 +1355,7 @@ def control_3_5_ensure_log_metric_cloudtrail_configuration_changes(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) @@ -1332,6 +1369,7 @@ def control_3_6_ensure_log_metric_console_auth_failures(cloudtrails): failReason = "" offenders = [] control = "3.6" + level = "2" description = "Ensure a log metric filter and alarm exist for console auth failures" scored = True failReason = "Ensure a log metric filter and alarm exist for console auth failures" @@ -1361,7 +1399,7 @@ def control_3_6_ensure_log_metric_console_auth_failures(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) @@ -1375,6 +1413,7 @@ def control_3_7_ensure_log_metric_disabling_scheduled_delete_of_kms_cmk(cloudtra failReason = "" offenders = [] control = "3.7" + level = "2" description = "Ensure a log metric filter and alarm exist for disabling or scheduling deletion of KMS CMK" scored = True failReason = "Ensure a log metric filter and alarm exist for disabling or scheduling deletion of KMS CMK" @@ -1404,7 +1443,7 @@ def control_3_7_ensure_log_metric_disabling_scheduled_delete_of_kms_cmk(cloudtra result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) @@ -1418,6 +1457,7 @@ def control_3_8_ensure_log_metric_s3_bucket_policy_changes(cloudtrails): failReason = "" offenders = [] control = "3.8" + level = "1" description = "Ensure a log metric filter and alarm exist for S3 bucket policy changes" scored = True failReason = "Ensure a log metric filter and alarm exist for S3 bucket policy changes" @@ -1447,7 +1487,7 @@ def control_3_8_ensure_log_metric_s3_bucket_policy_changes(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) @@ -1461,6 +1501,7 @@ def control_3_9_ensure_log_metric_config_configuration_changes(cloudtrails): failReason = "" offenders = [] control = "3.9" + level = "2" description = "Ensure a log metric filter and alarm exist for for AWS Config configuration changes" scored = True failReason = "Ensure a log metric filter and alarm exist for for AWS Config configuration changes" @@ -1490,7 +1531,7 @@ def control_3_9_ensure_log_metric_config_configuration_changes(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) @@ -1504,6 +1545,7 @@ def control_3_10_ensure_log_metric_security_group_changes(cloudtrails): failReason = "" offenders = [] control = "3.10" + level = "2" description = "Ensure a log metric filter and alarm exist for security group changes" scored = True failReason = "Ensure a log metric filter and alarm exist for security group changes" @@ -1533,7 +1575,7 @@ def control_3_10_ensure_log_metric_security_group_changes(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) @@ -1547,6 +1589,7 @@ def control_3_11_ensure_log_metric_nacl(cloudtrails): failReason = "" offenders = [] control = "3.11" + level = "2" description = "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" scored = True failReason = "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" @@ -1576,7 +1619,7 @@ def control_3_11_ensure_log_metric_nacl(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) @@ -1590,6 +1633,7 @@ def control_3_12_ensure_log_metric_changes_to_network_gateways(cloudtrails): failReason = "" offenders = [] control = "3.12" + level = "1" description = "Ensure a log metric filter and alarm exist for changes to network gateways" scored = True failReason = "Ensure a log metric filter and alarm exist for changes to network gateways" @@ -1619,7 +1663,7 @@ def control_3_12_ensure_log_metric_changes_to_network_gateways(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) @@ -1633,6 +1677,7 @@ def control_3_13_ensure_log_metric_changes_to_route_tables(cloudtrails): failReason = "" offenders = [] control = "3.13" + level = "1" description = "Ensure a log metric filter and alarm exist for route table changes" scored = True failReason = "Ensure a log metric filter and alarm exist for route table changes" @@ -1662,7 +1707,7 @@ def control_3_13_ensure_log_metric_changes_to_route_tables(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) @@ -1676,6 +1721,7 @@ def control_3_14_ensure_log_metric_changes_to_vpc(cloudtrails): failReason = "" offenders = [] control = "3.14" + level = "1" description = "Ensure a log metric filter and alarm exist for VPC changes" scored = True failReason = "Ensure a log metric filter and alarm exist for VPC changes" @@ -1705,7 +1751,7 @@ def control_3_14_ensure_log_metric_changes_to_vpc(cloudtrails): result = True except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) @@ -1719,10 +1765,11 @@ def control_3_15_verify_sns_subscribers(): failReason = "" offenders = [] control = "3.15" + level = "1" description = "Ensure appropriate subscribers to each SNS topic, please verify manually" scored = False failReason = "Control not implemented using API, please verify manually" - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # --- Networking --- @@ -1738,6 +1785,7 @@ def control_4_1_ensure_ssh_not_open_to_world(regions): failReason = "" offenders = [] control = "4.1" + level = "2" description = "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22" scored = True for n in regions: @@ -1756,7 +1804,7 @@ def control_4_1_ensure_ssh_not_open_to_world(regions): result = False failReason = "Found Security Group with port 22 open to the world (0.0.0.0/0)" offenders.append(str(n) + " : " + str(m['GroupId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) @@ -1770,6 +1818,7 @@ def control_4_2_ensure_rdp_not_open_to_world(regions): failReason = "" offenders = [] control = "4.2" + level = "2" description = "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389" scored = True for n in regions: @@ -1788,7 +1837,7 @@ def control_4_2_ensure_rdp_not_open_to_world(regions): result = False failReason = "Found Security Group with port 3389 open to the world (0.0.0.0/0)" offenders.append(str(n) + " : " + str(m['GroupId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 4.3 Ensure VPC flow logging is enabled in all VPCs (Scored) @@ -1802,6 +1851,7 @@ def control_4_3_ensure_flow_logs_enabled_on_all_vpc(regions): failReason = "" offenders = [] control = "4.3" + level = "2" description = "Ensure VPC flow logging is enabled in all VPCs" scored = True for n in regions: @@ -1828,7 +1878,7 @@ def control_4_3_ensure_flow_logs_enabled_on_all_vpc(regions): result = False failReason = "VPC without active VPC Flow Logs found" offenders.append(str(n) + " : " + str(m['VpcId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 4.4 Ensure the default security group of every VPC restricts all traffic (Scored) @@ -1842,6 +1892,7 @@ def control_4_4_ensure_default_security_groups_restricts_traffic(regions): failReason = "" offenders = [] control = "4.4" + level = "2" description = "Ensure the default security group of every VPC restricts all traffic" scored = True for n in regions: @@ -1861,7 +1912,7 @@ def control_4_4_ensure_default_security_groups_restricts_traffic(regions): result = False failReason = "Default security groups with ingress or egress rules discovered" offenders.append(str(n) + " : " + str(m['GroupId'])) - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) @@ -1875,6 +1926,7 @@ def control_4_5_ensure_route_tables_are_least_access(regions): failReason = "" offenders = [] control = "4.5" + level = "2" description = "Ensure routing tables for VPC peering are least access" scored = False for n in regions: @@ -1890,7 +1942,7 @@ def control_4_5_ensure_route_tables_are_least_access(regions): offenders.append(str(n) + " : " + str(m['RouteTableId'])) except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # 4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) @@ -1904,6 +1956,7 @@ def control_4_5_ensure_route_tables_are_least_access(regions): failReason = "" offenders = [] control = "4.5" + level = "2" description = "Ensure routing tables for VPC peering are least access" scored = False for n in regions: @@ -1919,7 +1972,7 @@ def control_4_5_ensure_route_tables_are_least_access(regions): offenders.append(str(n) + " : " + str(m['RouteTableId'])) except: pass - return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control} + return {'Result': result, 'failReason': failReason, 'Offenders': offenders, 'ScoredControl': scored, 'Description': description, 'ControlId': control, 'Level': level} # --- Central functions --- @@ -2108,6 +2161,7 @@ def json2html(controlResult, account): resultStyle = " style=\"background-color:lightgreen;\"" table.append("