diff --git a/providers/aws/services/iam/check110 b/providers/aws/services/iam/check110 deleted file mode 100644 index 7054ea8d..00000000 --- a/providers/aws/services/iam/check110 +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check110="1.10" -CHECK_TITLE_check110="[check110] Ensure IAM password policy prevents password reuse: 24 or greater" -CHECK_SCORED_check110="SCORED" -CHECK_CIS_LEVEL_check110="LEVEL1" -CHECK_SEVERITY_check110="Medium" -CHECK_ASFF_TYPE_check110="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check110="check110" -CHECK_SERVICENAME_check110="iam" -CHECK_RISK_check110='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check110='Ensure "Number of passwords to remember" is set to 24.' -CHECK_DOC_check110='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check110='IAM' - -check110(){ - # "Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" - COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) - if [[ $COMMAND110 ]];then - if [[ $COMMAND110 -gt "23" ]];then - textPass "$REGION: Password Policy limits reuse" "$REGION" "password policy" - else - textFail "$REGION: Password Policy has weak reuse requirement (lower than 24)" "$REGION" "password policy" - fi - else - textFail "$REGION: Password Policy missing reuse requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/check15 b/providers/aws/services/iam/check15 deleted file mode 100644 index a5d0d749..00000000 --- a/providers/aws/services/iam/check15 +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check15="1.5" -CHECK_TITLE_check15="[check15] Ensure IAM password policy requires at least one uppercase letter" -CHECK_SCORED_check15="SCORED" -CHECK_CIS_LEVEL_check15="LEVEL1" -CHECK_SEVERITY_check15="Medium" -CHECK_ASFF_TYPE_check15="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check105="check15" -CHECK_SERVICENAME_check15="iam" -CHECK_RISK_check15='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check15='Ensure "Requires at least one uppercase letter" is checked under "Password Policy".' -CHECK_DOC_check15='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check15='IAM' - -check15(){ - # "Ensure IAM password policy requires at least one uppercase letter (Scored)" - COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true - if [[ "$COMMAND15" == "true" ]];then - textPass "$REGION: Password Policy requires upper case" "$REGION" "password policy" - else - textFail "$REGION: Password Policy missing upper-case requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/check16 b/providers/aws/services/iam/check16 deleted file mode 100644 index 4ba1c855..00000000 --- a/providers/aws/services/iam/check16 +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check16="1.6" -CHECK_TITLE_check16="[check16] Ensure IAM password policy require at least one lowercase letter" -CHECK_SCORED_check16="SCORED" -CHECK_CIS_LEVEL_check16="LEVEL1" -CHECK_SEVERITY_check16="Medium" -CHECK_ASFF_TYPE_check16="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check106="check16" -CHECK_SERVICENAME_check16="iam" -CHECK_RISK_check16='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check16='Ensure "Requires at least one lowercase letter" is checked under "Password Policy".' -CHECK_DOC_check16='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check16='IAM' - -check16(){ - # "Ensure IAM password policy require at least one lowercase letter (Scored)" - COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true - if [[ "$COMMAND16" == "true" ]];then - textPass "$REGION: Password Policy requires lower case" "$REGION" "password policy" - else - textFail "$REGION: Password Policy missing lower-case requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/check17 b/providers/aws/services/iam/check17 deleted file mode 100644 index 92a97039..00000000 --- a/providers/aws/services/iam/check17 +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check17="1.7" -CHECK_TITLE_check17="[check17] Ensure IAM password policy require at least one symbol" -CHECK_SCORED_check17="SCORED" -CHECK_CIS_LEVEL_check17="LEVEL1" -CHECK_SEVERITY_check17="Medium" -CHECK_ASFF_TYPE_check17="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check107="check17" -CHECK_SERVICENAME_check17="iam" -CHECK_RISK_check17='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check17='Ensure "Require at least one non-alphanumeric character" is checked under "Password Policy".' -CHECK_DOC_check17='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check17='IAM' - -check17(){ - # "Ensure IAM password policy require at least one symbol (Scored)" - COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true - if [[ "$COMMAND17" == "true" ]];then - textPass "$REGION: Password Policy requires symbol" "$REGION" "password policy" - else - textFail "$REGION: Password Policy missing symbol requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/check18 b/providers/aws/services/iam/check18 deleted file mode 100644 index a4e27d24..00000000 --- a/providers/aws/services/iam/check18 +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check18="1.8" -CHECK_TITLE_check18="[check18] Ensure IAM password policy require at least one number" -CHECK_SCORED_check18="SCORED" -CHECK_CIS_LEVEL_check18="LEVEL1" -CHECK_SEVERITY_check18="Medium" -CHECK_ASFF_TYPE_check18="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check108="check18" -CHECK_SERVICENAME_check18="iam" -CHECK_RISK_check18='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check18='Ensure "Require at least one number " is checked under "Password Policy".' -CHECK_DOC_check18='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check18='IAM' - -check18(){ - # "Ensure IAM password policy require at least one number (Scored)" - COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true - if [[ "$COMMAND18" == "true" ]];then - textPass "$REGION: Password Policy requires number" "$REGION" "password policy" - else - textFail "$REGION: Password Policy missing number requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/check19 b/providers/aws/services/iam/check19 deleted file mode 100644 index 49656b59..00000000 --- a/providers/aws/services/iam/check19 +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. - -CHECK_ID_check19="1.9" -CHECK_TITLE_check19="[check19] Ensure IAM password policy requires minimum length of 14 or greater" -CHECK_SCORED_check19="SCORED" -CHECK_CIS_LEVEL_check19="LEVEL1" -CHECK_SEVERITY_check19="Medium" -CHECK_ASFF_TYPE_check19="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" -CHECK_ALTERNATE_check109="check19" -CHECK_SERVICENAME_check19="iam" -CHECK_RISK_check19='Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.' -CHECK_REMEDIATION_check19='Ensure "Minimum password length" is set to 14 or greater.' -CHECK_DOC_check19='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html' -CHECK_CAF_EPIC_check19='IAM' - -check19(){ - # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" - COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) - if [[ $COMMAND19 -gt "13" ]];then - textPass "$REGION: Password Policy requires more than 13 characters" "$REGION" "password policy" - else - textFail "$REGION: Password Policy missing or weak length requirement" "$REGION" "password policy" - fi -} diff --git a/providers/aws/services/iam/iam_password_policy_lowercase/__init__.py b/providers/aws/services/iam/iam_password_policy_lowercase/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.metadata.json b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.metadata.json new file mode 100644 index 00000000..bbb68c03 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_lowercase", + "CheckTitle": "Ensure IAM password policy require at least one lowercase letter", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy requires at least one uppercase letter", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one lowercase letter.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Requires at least one lowercase letter\" is checked under \"Password Policy\".", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.6" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.py b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.py new file mode 100644 index 00000000..293084c7 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase.py @@ -0,0 +1,26 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_lowercase(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check if lowercase flag is set + if iam_client.password_policy.lowercase: + report.status = "PASS" + report.status_extended = "IAM password policy does not require at least one lowercase letter." + else: + report.status = "FAIL" + report.status_extended = ( + "IAM password policy require at least one lowercase letter." + ) + else: + report.status = "FAIL" + report.status_extended = f"Password policy cannot be found" + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase_test.py b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase_test.py new file mode 100644 index 00000000..edb06eb2 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_lowercase/iam_password_policy_lowercase_test.py @@ -0,0 +1,50 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_lowercase: + @mock_iam + def test_iam_password_policy_no_lowercase_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireLowercaseCharacters=False) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_lowercase.iam_password_policy_lowercase.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_lowercase.iam_password_policy_lowercase import ( + iam_password_policy_lowercase, + ) + + check = iam_password_policy_lowercase() + result = check.execute() + assert result[0].status == "FAIL" + + @mock_iam + def test_iam_password_policy_lowercase_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireLowercaseCharacters=True) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_lowercase.iam_password_policy_lowercase.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_lowercase.iam_password_policy_lowercase import ( + iam_password_policy_lowercase, + ) + + check = iam_password_policy_lowercase() + result = check.execute() + assert result[0].status == "PASS" diff --git a/providers/aws/services/iam/iam_password_policy_minimum_length_14/__init__.py b/providers/aws/services/iam/iam_password_policy_minimum_length_14/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.metadata.json b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.metadata.json new file mode 100644 index 00000000..256679b8 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_minimum_length_14", + "CheckTitle": "Ensure IAM password policy requires minimum length of 14 or greater", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy requires minimum length of 14 or greater", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require minimum length of 14 or greater.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Minimum password length\" is checked under \"Password Policy\".", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.9" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.py b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.py new file mode 100644 index 00000000..a3351cb2 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14.py @@ -0,0 +1,29 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_minimum_length_14(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check password policy length + if ( + iam_client.password_policy.length + and iam_client.password_policy.length >= 14 + ): + report.status = "PASS" + report.status_extended = "IAM password policy does not requires minimum length of 14 characters." + else: + report.status = "FAIL" + report.status_extended = ( + "IAM password policy requires minimum length of 14 characters." + ) + else: + report.status = "FAIL" + report.status_extended = "Password policy cannot be found" + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14_test.py b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14_test.py new file mode 100644 index 00000000..21888b50 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_minimum_length_14/iam_password_policy_minimum_length_14_test.py @@ -0,0 +1,72 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_minimum_length_14: + @mock_iam + def test_iam_password_policy_minimum_length_equal_14(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(MinimumPasswordLength=14) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14 import ( + iam_password_policy_minimum_length_14, + ) + + check = iam_password_policy_minimum_length_14() + result = check.execute() + assert result[0].status == "PASS" + + @mock_iam + def test_iam_password_policy_minimum_length_greater_14(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(MinimumPasswordLength=20) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14 import ( + iam_password_policy_minimum_length_14, + ) + + check = iam_password_policy_minimum_length_14() + result = check.execute() + assert result[0].status == "PASS" + + @mock_iam + def test_iam_password_policy_minimum_length_less_14(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(MinimumPasswordLength=10) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_minimum_length_14.iam_password_policy_minimum_length_14 import ( + iam_password_policy_minimum_length_14, + ) + + check = iam_password_policy_minimum_length_14() + result = check.execute() + assert result[0].status == "FAIL" diff --git a/providers/aws/services/iam/iam_password_policy_number/__init__.py b/providers/aws/services/iam/iam_password_policy_number/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.metadata.json b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.metadata.json new file mode 100644 index 00000000..57269fcf --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_number", + "CheckTitle": "Ensure IAM password policy require at least one number", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy require at least one number", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one number.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Require at least one number\" is checked under \"Password Policy\".", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.8" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.py b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.py new file mode 100644 index 00000000..ec8d2d9b --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number.py @@ -0,0 +1,28 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_number(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check if number flag is set + if iam_client.password_policy.numbers: + report.status = "PASS" + report.status_extended = ( + "IAM password policy does not require at least one number" + ) + else: + report.status = "FAIL" + report.status_extended = ( + "IAM password policy require at least one number." + ) + else: + report.status = "FAIL" + report.status_extended = "There is no password policy." + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number_test.py b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number_test.py new file mode 100644 index 00000000..0e02bdbb --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_number/iam_password_policy_number_test.py @@ -0,0 +1,50 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_number: + @mock_iam + def test_iam_password_policy_no_number_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireNumbers=False) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_number.iam_password_policy_number.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_number.iam_password_policy_number import ( + iam_password_policy_number, + ) + + check = iam_password_policy_number() + result = check.execute() + assert result[0].status == "FAIL" + + @mock_iam + def test_iam_password_policy_number_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireNumbers=True) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_number.iam_password_policy_number.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_number.iam_password_policy_number import ( + iam_password_policy_number, + ) + + check = iam_password_policy_number() + result = check.execute() + assert result[0].status == "PASS" diff --git a/providers/aws/services/iam/iam_password_policy_reuse_24/__init__.py b/providers/aws/services/iam/iam_password_policy_reuse_24/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.metadata.json b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.metadata.json new file mode 100644 index 00000000..7f0e22fe --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_reuse_24", + "CheckTitle": "Ensure IAM password policy prevents password reuse: 24 or greater", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy prevents password reuse: 24 or greater", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy prevents at least password reuse of 24 or greater.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Number of passwords to remember\" is set to 24.", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.10" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.py b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.py new file mode 100644 index 00000000..cc63d28d --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24.py @@ -0,0 +1,31 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_reuse_24(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check if reuse prevention flag is set + if ( + iam_client.password_policy.reuse_prevention + and iam_client.password_policy.reuse_prevention == 24 + ): + report.status = "PASS" + report.status_extended = ( + "IAM password policy reuse prevention is equal to 24." + ) + else: + report.status = "FAIL" + report.status_extended = ( + "IAM password policy reuse prevention is less than 24 or not set." + ) + else: + report.status = "FAIL" + report.status_extended = "Password policy cannot be found" + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24_test.py b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24_test.py new file mode 100644 index 00000000..7eff03d4 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_reuse_24/iam_password_policy_reuse_24_test.py @@ -0,0 +1,50 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_reuse_24: + @mock_iam + def test_iam_password_policy_reuse_prevention_equal_24(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(PasswordReusePrevention=24) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_reuse_24.iam_password_policy_reuse_24.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_reuse_24.iam_password_policy_reuse_24 import ( + iam_password_policy_reuse_24, + ) + + check = iam_password_policy_reuse_24() + result = check.execute() + assert result[0].status == "PASS" + + @mock_iam + def test_iam_password_policy_reuse_prevention_less_24(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(PasswordReusePrevention=20) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_reuse_24.iam_password_policy_reuse_24.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_reuse_24.iam_password_policy_reuse_24 import ( + iam_password_policy_reuse_24, + ) + + check = iam_password_policy_reuse_24() + result = check.execute() + assert result[0].status == "FAIL" diff --git a/providers/aws/services/iam/iam_password_policy_symbol/__init__.py b/providers/aws/services/iam/iam_password_policy_symbol/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.metadata.json b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.metadata.json new file mode 100644 index 00000000..cc499207 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_symbol", + "CheckTitle": "Ensure IAM password policy require at least one symbol", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy require at least one symbol", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one non-alphanumeric character.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Require at least one non-alphanumeric character\" is checked under \"Password Policy\".", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.7" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.py b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.py new file mode 100644 index 00000000..864b8cee --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol.py @@ -0,0 +1,28 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_symbol(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check if symbol flag is set + if iam_client.password_policy.symbols: + report.status = "PASS" + report.status_extended = ( + "IAM password policy does not require at least one symbol." + ) + else: + report.status = "FAIL" + report.status_extended = ( + "IAM password policy requires at least one symbol." + ) + else: + report.status = "FAIL" + report.status_extended = "There is no password policy." + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol_test.py b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol_test.py new file mode 100644 index 00000000..92963bab --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_symbol/iam_password_policy_symbol_test.py @@ -0,0 +1,50 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_symbol: + @mock_iam + def test_iam_password_policy_no_symbol_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireSymbols=False) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_symbol.iam_password_policy_symbol.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_symbol.iam_password_policy_symbol import ( + iam_password_policy_symbol, + ) + + check = iam_password_policy_symbol() + result = check.execute() + assert result[0].status == "FAIL" + + @mock_iam + def test_iam_password_policy_symbol_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireSymbols=True) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_symbol.iam_password_policy_symbol.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_symbol.iam_password_policy_symbol import ( + iam_password_policy_symbol, + ) + + check = iam_password_policy_symbol() + result = check.execute() + assert result[0].status == "PASS" diff --git a/providers/aws/services/iam/iam_password_policy_uppercase/__init__.py b/providers/aws/services/iam/iam_password_policy_uppercase/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.metadata.json b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.metadata.json new file mode 100644 index 00000000..17e73d32 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.metadata.json @@ -0,0 +1,46 @@ +{ + "Provider": "aws", + "CheckID": "iam_password_policy_uppercase", + "CheckTitle": "Ensure IAM password policy requires at least one uppercase letter", + "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsIamPasswordPolicy", + "Description": "Ensure IAM password policy requires at least one uppercase letter", + "Risk": "Password policies are used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure \"Requires at least one uppercase letter\" is checked under \"Password Policy\".", + "Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html" + } + }, + "Categories": [], + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + }, + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + "Compliance": [ + { + "Control": [ + "1.5" + ], + "Framework": "CIS-AWS", + "Group": [ + "level1" + ], + "Version": "1.4" + } + ] +} diff --git a/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.py b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.py new file mode 100644 index 00000000..55aad3d3 --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase.py @@ -0,0 +1,26 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.iam.iam_client import iam_client + + +class iam_password_policy_uppercase(Check): + def execute(self) -> Check_Report: + findings = [] + report = Check_Report(self.metadata) + report.region = iam_client.region + report.resource_id = "password_policy" + # Check if password policy exists + if iam_client.password_policy: + # Check if uppercase flag is set + if iam_client.password_policy.uppercase: + report.status = "PASS" + report.status_extended = ( + "IAM password policy requires at least one uppercase letter." + ) + else: + report.status = "FAIL" + report.status_extended = "IAM password policy does not require at least one uppercase letter." + else: + report.status = "FAIL" + report.status_extended = "There is no password policy." + findings.append(report) + return findings diff --git a/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase_test.py b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase_test.py new file mode 100644 index 00000000..99d3a10f --- /dev/null +++ b/providers/aws/services/iam/iam_password_policy_uppercase/iam_password_policy_uppercase_test.py @@ -0,0 +1,50 @@ +from unittest import mock + +from boto3 import client +from moto import mock_iam + + +class Test_iam_password_policy_uppercase: + @mock_iam + def test_iam_password_policy_no_uppercase_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireUppercaseCharacters=False) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_uppercase.iam_password_policy_uppercase.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_uppercase.iam_password_policy_uppercase import ( + iam_password_policy_uppercase, + ) + + check = iam_password_policy_uppercase() + result = check.execute() + assert result[0].status == "FAIL" + + @mock_iam + def test_iam_password_policy_uppercase_flag(self): + iam_client = client("iam") + # update password policy + iam_client.update_account_password_policy(RequireUppercaseCharacters=True) + + from providers.aws.lib.audit_info.audit_info import current_audit_info + from providers.aws.services.iam.iam_service import IAM + + with mock.patch( + "providers.aws.services.iam.iam_password_policy_uppercase.iam_password_policy_uppercase.iam_client", + new=IAM(current_audit_info), + ): + # Test Check + from providers.aws.services.iam.iam_password_policy_uppercase.iam_password_policy_uppercase import ( + iam_password_policy_uppercase, + ) + + check = iam_password_policy_uppercase() + result = check.execute() + assert result[0].status == "PASS"