mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(iam_checks): add several checks for iam (#1264)
* feat(extra71): add iam_administrator_access_with_mfa check. * feat(checks): add extra7125 and extra7123 * feat(checks): add check14 * feat(checks): add check112 * feat(checks): add check11 * feat(checks): add check114 and check113 * feat(checks): add check12 * feat(classes): add IAM classess. * Update iam_root_hardware_mfa_enabled.py * fix(comments): Resolve comments. Co-authored-by: sergargar <sergio@verica.io>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "extra71",
|
||||
"CheckID": "iam_administrator_access_with_mfa",
|
||||
"CheckName": "iam_administrator_access_with_mfa",
|
||||
"CheckTitle": "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled",
|
||||
"CheckType": "Infrastructure Security",
|
||||
"Compliance": [],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure this repository and its contents should be publicly accessible.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "Policy may allow Anonymous users to perform actions.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "high",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_administrator_access_with_mfa(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.groups
|
||||
|
||||
if response:
|
||||
for group in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.resource_id = group.name
|
||||
report.resource_arn = group.arn
|
||||
report.region = "us-east-1"
|
||||
if group.attached_policies:
|
||||
admin_policy = False
|
||||
for group_policy in group.attached_policies:
|
||||
if (
|
||||
group_policy["PolicyArn"]
|
||||
== "arn:aws:iam::aws:policy/AdministratorAccess"
|
||||
):
|
||||
admin_policy = True
|
||||
# users in group are Administrators
|
||||
if group.users:
|
||||
for group_user in group.users:
|
||||
for user in iam_client.credential_report:
|
||||
if (
|
||||
user["user"] == group_user.name
|
||||
and user["mfa_active"] == "false"
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Group {group.name} provides administrator access to User {group_user.name} with MFA disabled."
|
||||
findings.append(report)
|
||||
elif (
|
||||
user["user"] == group_user.name
|
||||
and user["mfa_active"] == "true"
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Group {group.name} provides administrator access to User {group_user.name} with MFA enabled."
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Group {group.name} provides administrative access but does not have users."
|
||||
findings.append(report)
|
||||
if not admin_policy:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Group {group.name} provides non-administrative access."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Group {group.name} has no policies."
|
||||
findings.append(report)
|
||||
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM groups."
|
||||
report.region = iam_client.region
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check11",
|
||||
"CheckID": "iam_avoid_root_usage",
|
||||
"CheckName": "iam_avoid_root_usage",
|
||||
"CheckTitle": "Avoid the use of the root accounts",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"1.1"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Avoid the use of the root account",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Follow the remediation instructions of the Ensure IAM policies are attached only to groups or roles recommendation.",
|
||||
"Url": "http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "The root account has unrestricted access to all resources in the AWS account. It is highly recommended that the use of this account be avoided.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "high",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import datetime
|
||||
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
maximum_access_days = 1
|
||||
|
||||
|
||||
class iam_avoid_root_usage(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.credential_report
|
||||
|
||||
if response:
|
||||
for user in response:
|
||||
if user["user"] == "<root_account>":
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
if (
|
||||
user["password_last_used"] != "no_information"
|
||||
or user["access_key_1_last_used_date"] != "N/A"
|
||||
or user["access_key_2_last_used_date"] != "N/A"
|
||||
):
|
||||
if user["password_last_used"] != "no_information":
|
||||
days_since_accessed = (
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user["password_last_used"],
|
||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||
)
|
||||
).days
|
||||
elif user["access_key_1_last_used_date"] != "N/A":
|
||||
days_since_accessed = (
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user["access_key_1_last_used_date"],
|
||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||
)
|
||||
).days
|
||||
elif user["access_key_2_last_used_date"] != "N/A":
|
||||
days_since_accessed = (
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user["access_key_2_last_used_date"],
|
||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||
)
|
||||
).days
|
||||
if days_since_accessed > maximum_access_days:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Root user in the account was last accessed {days_since_accessed} days ago."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -1,56 +1,35 @@
|
||||
{
|
||||
"Categories": [
|
||||
"cat1",
|
||||
"cat2"
|
||||
],
|
||||
"Categories": [],
|
||||
"CheckAlias": "extra774",
|
||||
"CheckID": "iam_disable_30_days_credentials",
|
||||
"CheckName": "iam_disable_30_days_credentials",
|
||||
"CheckTitle": "Ensure credentials unused for 30 days or greater are disabled",
|
||||
"CheckType": "Software and Configuration Checks",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"4.4"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1",
|
||||
"level2"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [
|
||||
"othercheck1",
|
||||
"othercheck2"
|
||||
],
|
||||
"Compliance": [],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure credentials unused for 30 days or greater are disabled",
|
||||
"Notes": "additional information",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [
|
||||
"othercheck3",
|
||||
"othercheck4"
|
||||
],
|
||||
"RelatedUrl": "https://serviceofficialsiteorpageforthissubject",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "cli command or URL to the cli command location.",
|
||||
"NativeIaC": "code or URL to the code location.",
|
||||
"Other": "cli command or URL to the cli command location.",
|
||||
"Terraform": "code or URL to the code location."
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Run sudo yum update and cross your fingers and toes.",
|
||||
"Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html"
|
||||
"Text": "Find the credentials that they were using and ensure that they are no longer operational. Ideally; you delete credentials if they are no longer needed. You can always recreate them at a later date if the need arises. At the very least; you should change the password or deactivate the access keys so that the former users no longer have access.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamAccessAnalyzer",
|
||||
"Risk": "Risk associated.",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "To increase the security of your AWS account; remove IAM user credentials (that is; passwords and access keys) that are not needed. For example; when users leave your organization or no longer need AWS access.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "low",
|
||||
"SubServiceName": "accessanalyzer",
|
||||
"Severity": "medium",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
@@ -14,34 +14,38 @@ class iam_disable_30_days_credentials(Check):
|
||||
if response:
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.resource_id = user["UserName"]
|
||||
report.resource_arn = user["Arn"]
|
||||
report.resource_id = user.name
|
||||
report.resource_arn = user.arn
|
||||
report.region = "us-east-1"
|
||||
if "PasswordLastUsed" in user and user["PasswordLastUsed"] != "":
|
||||
if user.password_last_used and user.password_last_used != "":
|
||||
try:
|
||||
time_since_insertion = (
|
||||
datetime.datetime.now(datetime.timezone.utc)
|
||||
- user["PasswordLastUsed"]
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user.password_last_used, "%Y-%m-%dT%H:%M:%S+00:00"
|
||||
)
|
||||
)
|
||||
if time_since_insertion.days > maximum_expiration_days:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user['UserName']} has not logged into the console in the past 30 days"
|
||||
report.status_extended = f"User {user.name} has not logged into the console in the past 30 days."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['UserName']} has logged into the console in the past 30 days"
|
||||
report.status_extended = f"User {user.name} has logged into the console in the past 30 days."
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['UserName']} has not a console password or is unused."
|
||||
report.status_extended = (
|
||||
f"User {user.name} has not a console password or is unused."
|
||||
)
|
||||
|
||||
# Append report
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = iam_client.region
|
||||
findings.append(report)
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{
|
||||
"Categories": [
|
||||
"cat1",
|
||||
"cat2"
|
||||
],
|
||||
"Categories": [],
|
||||
"CheckAlias": "check13",
|
||||
"CheckID": "iam_disable_90_days_credentials",
|
||||
"CheckName": "iam_disable_90_days_credentials",
|
||||
@@ -11,46 +8,39 @@
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"4.4"
|
||||
"1.3"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1",
|
||||
"level2"
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [
|
||||
"othercheck1",
|
||||
"othercheck2"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure credentials unused for 90 days or greater are disabled",
|
||||
"Notes": "additional information",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [
|
||||
"othercheck3",
|
||||
"othercheck4"
|
||||
],
|
||||
"RelatedUrl": "https://serviceofficialsiteorpageforthissubject",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "cli command or URL to the cli command location.",
|
||||
"NativeIaC": "code or URL to the code location.",
|
||||
"Other": "cli command or URL to the cli command location.",
|
||||
"Terraform": "code or URL to the code location."
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Run sudo yum update and cross your fingers and toes.",
|
||||
"Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html"
|
||||
"Text": "Find the credentials that they were using and ensure that they are no longer operational. Ideally; you delete credentials if they are no longer needed. You can always recreate them at a later date if the need arises. At the very least; you should change the password or deactivate the access keys so that the former users no longer have access.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamAccessAnalyzer",
|
||||
"Risk": "Risk associated.",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "AWS IAM users can access AWS resources using different types of credentials (passwords or access keys). It is recommended that all credentials that have been unused in 90 or greater days be removed or deactivated.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "low",
|
||||
"SubServiceName": "accessanalyzer",
|
||||
"Severity": "medium",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
@@ -15,33 +15,37 @@ class iam_disable_90_days_credentials(Check):
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = user["UserName"]
|
||||
report.resource_arn = user["Arn"]
|
||||
if "PasswordLastUsed" in user and user["PasswordLastUsed"] != "":
|
||||
report.resource_id = user.name
|
||||
report.resource_arn = user.arn
|
||||
if user.password_last_used and user.password_last_used != "":
|
||||
try:
|
||||
time_since_insertion = (
|
||||
datetime.datetime.now(datetime.timezone.utc)
|
||||
- user["PasswordLastUsed"]
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user.password_last_used, "%Y-%m-%dT%H:%M:%S+00:00"
|
||||
)
|
||||
)
|
||||
if time_since_insertion.days > maximum_expiration_days:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user['UserName']} has not logged into the console in the past 90 days"
|
||||
report.status_extended = f"User {user.name} has not logged into the console in the past 90 days."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['UserName']} has logged into the console in the past 90 days"
|
||||
report.status_extended = f"User {user.name} has logged into the console in the past 90 days."
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
report.status = "PASS"
|
||||
|
||||
report.status_extended = f"User {user['UserName']} has not a console password or is unused."
|
||||
report.status_extended = (
|
||||
f"User {user.name} has not a console password or is unused."
|
||||
)
|
||||
# Append report
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = "us-east-1"
|
||||
findings.append(report)
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check112",
|
||||
"CheckID": "iam_no_root_access_key",
|
||||
"CheckName": "iam_no_root_access_key",
|
||||
"CheckTitle": "Ensure no root account access key exists",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"1.12"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure no root account access key exists",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Use the credential report to that the user and ensure the access_key_1_active and access_key_2_active fields are set to FALSE.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "The root account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root account be removed. Removing access keys associated with the root account limits vectors by which the account can be compromised. Removing the root access keys encourages the creation and use of role based accounts that are least privileged.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "critical",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_no_root_access_key(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.credential_report
|
||||
|
||||
for user in response:
|
||||
if user["user"] == "<root_account>":
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
if (
|
||||
user["access_key_1_active"] == "false"
|
||||
and user["access_key_2_active"] == "false"
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['user']} has not access keys."
|
||||
elif (
|
||||
user["access_key_1_active"] == "true"
|
||||
and user["access_key_2_active"] == "true"
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"User {user['user']} has two active access keys."
|
||||
)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"User {user['user']} has one active access key."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check114",
|
||||
"CheckID": "iam_root_hardware_mfa_enabled",
|
||||
"CheckName": "iam_root_hardware_mfa_enabled",
|
||||
"CheckTitle": "Ensure hardware MFA is enabled for the root account",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"1.14"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure hardware MFA is enabled for the root account",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Using IAM console navigate to Dashboard and expand Activate MFA on your root account.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled when a user signs in to an AWS website they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2 it is recommended that the root account be protected with a hardware MFA.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "critical",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_root_hardware_mfa_enabled(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
virtual_mfa = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = "root"
|
||||
report.resource_arn = f"arn:aws:iam::{iam_client.account}:root"
|
||||
|
||||
if iam_client.account_summary["SummaryMap"]["AccountMFAEnabled"] > 0:
|
||||
virtual_mfas = iam_client.virtual_mfa_devices
|
||||
for mfa in virtual_mfas:
|
||||
if "root" in mfa["SerialNumber"]:
|
||||
virtual_mfa = True
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Root account has a virtual MFA instead of a hardware MFA enabled."
|
||||
if not virtual_mfa:
|
||||
report.status = "PASS"
|
||||
report.status_extended = "Root account has hardware MFA enabled."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "MFA is not enabled for root account."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check113",
|
||||
"CheckID": "iam_root_mfa_enabled",
|
||||
"CheckName": "iam_root_mfa_enabled",
|
||||
"CheckTitle": "Ensure MFA is enabled for the root account",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"1.13"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure MFA is enabled for the root account",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Using IAM console navigate to Dashboard and expand Activate MFA on your root account.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled when a user signs in to an AWS website they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. When virtual MFA is used for root accounts it is recommended that the device used is NOT a personal device but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (non-personal virtual MFA) This lessens the risks of losing access to the MFA due to device loss / trade-in or if the individual owning the device is no longer employed at the company.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "critical",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_root_mfa_enabled(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
|
||||
if iam_client.credential_report:
|
||||
for user in iam_client.credential_report:
|
||||
if user["user"] == "<root_account>":
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
if user["mfa_active"] == "false":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "MFA is not enabled for root account."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = "MFA is enabled for root account."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check14",
|
||||
"CheckID": "iam_rotate_access_key_90_days",
|
||||
"CheckName": "iam_rotate_access_key_90_days",
|
||||
"CheckTitle": "Ensure access keys are rotated every 90 days or less",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [
|
||||
{
|
||||
"Control": [
|
||||
"1.4"
|
||||
],
|
||||
"Framework": "CIS-AWS",
|
||||
"Group": [
|
||||
"level1"
|
||||
],
|
||||
"Version": "1.4"
|
||||
}
|
||||
],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure access keys are rotated every 90 days or less",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Use the credential report to ensure access_key_X_last_rotated is less than 90 days ago.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "Access keys consist of an access key ID and secret access key which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI)- Tools for Windows PowerShell- the AWS SDKs- or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "medium",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import datetime
|
||||
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
maximum_expiration_days = 90
|
||||
|
||||
|
||||
class iam_rotate_access_key_90_days(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.credential_report
|
||||
|
||||
if response:
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
if (
|
||||
user["access_key_1_last_rotated"] == "N/A"
|
||||
and user["access_key_2_last_rotated"] == "N/A"
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['user']} has not access keys."
|
||||
else:
|
||||
old_access_keys = False
|
||||
if user["access_key_1_last_rotated"] != "N/A":
|
||||
access_key_1_last_rotated = (
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user["access_key_1_last_rotated"],
|
||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||
)
|
||||
)
|
||||
if access_key_1_last_rotated.days > maximum_expiration_days:
|
||||
old_access_keys = True
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user['user']} has not rotated access key 1 in over 90 days ({access_key_1_last_rotated.days} days)."
|
||||
if user["access_key_2_last_rotated"] != "N/A":
|
||||
access_key_2_last_rotated = (
|
||||
datetime.datetime.now()
|
||||
- datetime.datetime.strptime(
|
||||
user["access_key_2_last_rotated"],
|
||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||
)
|
||||
)
|
||||
if access_key_2_last_rotated.days > maximum_expiration_days:
|
||||
old_access_keys = True
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user['user']} has not rotated access key 2 in over 90 days ({access_key_2_last_rotated.days} days)."
|
||||
if not old_access_keys:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['user']} has access keys not older than 90 days."
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = "us-east-1"
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -1,4 +1,5 @@
|
||||
import sys
|
||||
import csv
|
||||
from dataclasses import dataclass
|
||||
|
||||
from lib.logger import logger
|
||||
from providers.aws.aws_provider import current_audit_info
|
||||
@@ -9,13 +10,19 @@ class IAM:
|
||||
def __init__(self, audit_info):
|
||||
self.service = "iam"
|
||||
self.session = audit_info.audit_session
|
||||
self.account = audit_info.audited_account
|
||||
self.client = self.session.client(self.service)
|
||||
self.region = audit_info.profile_region
|
||||
self.users = self.__get_users__()
|
||||
self.roles = self.__get_roles__()
|
||||
self.account_summary = self.__get_account_summary__()
|
||||
self.virtual_mfa_devices = self.__list_virtual_mfa_devices__()
|
||||
self.customer_managed_policies = self.__get_customer_managed_policies__()
|
||||
self.credential_report = self.__get_credential_report__()
|
||||
self.groups = self.__get_groups__()
|
||||
self.__get_group_users__()
|
||||
self.__list_attached_group_policies__()
|
||||
self.__list_mfa_devices__()
|
||||
|
||||
def __get_client__(self):
|
||||
return self.client
|
||||
@@ -47,7 +54,12 @@ class IAM:
|
||||
if report_status["State"] == "COMPLETE":
|
||||
report_is_completed = True
|
||||
|
||||
return self.client.get_credential_report()
|
||||
# Convert credential report to list of dictionaries
|
||||
credential = self.client.get_credential_report()["Content"].decode("utf-8")
|
||||
credential_lines = credential.split("\n")
|
||||
csv_reader = csv.DictReader(credential_lines, delimiter=",")
|
||||
credential_list = list(csv_reader)
|
||||
return credential_list
|
||||
|
||||
def __get_groups__(self):
|
||||
try:
|
||||
@@ -58,7 +70,7 @@ class IAM:
|
||||
groups = []
|
||||
for page in get_groups_paginator.paginate():
|
||||
for group in page["Groups"]:
|
||||
groups.append(group)
|
||||
groups.append(Group(group["GroupName"], group["Arn"]))
|
||||
|
||||
return groups
|
||||
|
||||
@@ -77,6 +89,15 @@ class IAM:
|
||||
|
||||
return customer_managed_policies
|
||||
|
||||
def __get_account_summary__(self):
|
||||
try:
|
||||
account_summary = self.client.get_account_summary()
|
||||
except Exception as error:
|
||||
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
|
||||
else:
|
||||
|
||||
return account_summary
|
||||
|
||||
def __get_users__(self):
|
||||
try:
|
||||
get_users_paginator = self.client.get_paginator("list_users")
|
||||
@@ -86,13 +107,127 @@ class IAM:
|
||||
users = []
|
||||
for page in get_users_paginator.paginate():
|
||||
for user in page["Users"]:
|
||||
users.append(user)
|
||||
if "PasswordLastUsed" not in user:
|
||||
users.append(User(user["UserName"], user["Arn"], None))
|
||||
else:
|
||||
users.append(
|
||||
User(
|
||||
user["UserName"], user["Arn"], user["PasswordLastUsed"]
|
||||
)
|
||||
)
|
||||
|
||||
return users
|
||||
|
||||
def __list_virtual_mfa_devices__(self):
|
||||
try:
|
||||
list_virtual_mfa_devices_paginator = self.client.get_paginator(
|
||||
"list_virtual_mfa_devices"
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
|
||||
else:
|
||||
mfa_devices = []
|
||||
for page in list_virtual_mfa_devices_paginator.paginate():
|
||||
for mfa_device in page["VirtualMFADevices"]:
|
||||
mfa_devices.append(mfa_device)
|
||||
|
||||
try:
|
||||
iam_client = IAM(current_audit_info)
|
||||
except Exception as error:
|
||||
logger.critical(f"{error.__class__.__name__} -- {error}")
|
||||
sys.exit()
|
||||
return mfa_devices
|
||||
|
||||
def __list_attached_group_policies__(self):
|
||||
try:
|
||||
for group in self.groups:
|
||||
list_attached_group_policies_paginator = self.client.get_paginator(
|
||||
"list_attached_group_policies"
|
||||
)
|
||||
attached_group_policies = []
|
||||
for page in list_attached_group_policies_paginator.paginate(
|
||||
GroupName=group.name
|
||||
):
|
||||
for attached_group_policy in page["AttachedPolicies"]:
|
||||
attached_group_policies.append(attached_group_policy)
|
||||
|
||||
group.attached_policies = attached_group_policies
|
||||
except Exception as error:
|
||||
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
|
||||
|
||||
def __get_group_users__(self):
|
||||
try:
|
||||
for group in self.groups:
|
||||
get_group_paginator = self.client.get_paginator("get_group")
|
||||
group_users = []
|
||||
for page in get_group_paginator.paginate(GroupName=group.name):
|
||||
for user in page["Users"]:
|
||||
if "PasswordLastUsed" not in user:
|
||||
group_users.append(
|
||||
User(user["UserName"], user["Arn"], None)
|
||||
)
|
||||
else:
|
||||
group_users.append(
|
||||
User(
|
||||
user["UserName"],
|
||||
user["Arn"],
|
||||
user["PasswordLastUsed"],
|
||||
)
|
||||
)
|
||||
group.users = group_users
|
||||
except Exception as error:
|
||||
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
|
||||
|
||||
def __list_mfa_devices__(self):
|
||||
try:
|
||||
for user in self.users:
|
||||
list_mfa_devices_paginator = self.client.get_paginator(
|
||||
"list_mfa_devices"
|
||||
)
|
||||
mfa_devices = []
|
||||
for page in list_mfa_devices_paginator.paginate(UserName=user.name):
|
||||
for mfa_device in page["MFADevices"]:
|
||||
mfa_serial_number = mfa_device["SerialNumber"]
|
||||
mfa_type = (
|
||||
mfa_device["SerialNumber"].split(":")[5].split("/")[0]
|
||||
)
|
||||
mfa_devices.append(MFADevice(mfa_serial_number, mfa_type))
|
||||
user.mfa_devices = mfa_devices
|
||||
except Exception as error:
|
||||
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
|
||||
|
||||
|
||||
@dataclass
|
||||
class MFADevice:
|
||||
serial_number: str
|
||||
type: str
|
||||
|
||||
def __init__(self, serial_number, type):
|
||||
self.serial_number = serial_number
|
||||
self.type = type
|
||||
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
name: str
|
||||
arn: str
|
||||
mfa_devices: list[MFADevice]
|
||||
password_last_used: str
|
||||
|
||||
def __init__(self, name, arn, password_last_used):
|
||||
self.name = name
|
||||
self.arn = arn
|
||||
self.password_last_used = password_last_used
|
||||
self.mfa_devices = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class Group:
|
||||
name: str
|
||||
arn: str
|
||||
attached_policies: list[dict]
|
||||
users: list[User]
|
||||
|
||||
def __init__(self, name, arn):
|
||||
self.name = name
|
||||
self.arn = arn
|
||||
self.attached_policies = []
|
||||
self.users = []
|
||||
|
||||
|
||||
iam_client = IAM(current_audit_info)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "extra7125",
|
||||
"CheckID": "iam_user_hardware_mfa_enabled",
|
||||
"CheckName": "iam_user_hardware_mfa_enabled",
|
||||
"CheckTitle": "Check if IAM users have Hardware MFA enabled.",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [],
|
||||
"DependsOn": [],
|
||||
"Description": "Check if IAM users have Hardware MFA enabled.",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable hardware MFA device for an IAM user from the AWS Management Console; the command line; or the IAM API.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "Hardware MFA is preferred over virtual MFA.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "medium",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_user_hardware_mfa_enabled(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.users
|
||||
|
||||
if response:
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.resource_id = user.name
|
||||
report.resource_arn = user.arn
|
||||
report.region = "us-east-1"
|
||||
if user.mfa_devices:
|
||||
for mfa_device in user.mfa_devices:
|
||||
if mfa_device.type == "mfa" or mfa_device.type == "sms-mfa":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user.name} has a virtual MFA instead of a hardware MFA enabled."
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"User {user.name} has hardware MFA enabled."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"User {user.name} has not any type of MFA enabled."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = iam_client.region
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "check12",
|
||||
"CheckID": "iam_user_mfa_enabled_console_access",
|
||||
"CheckName": "iam_user_mfa_enabled_console_access",
|
||||
"CheckTitle": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password.",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [],
|
||||
"DependsOn": [],
|
||||
"Description": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password.",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable MFA for users account. MFA is a simple best practice that adds an extra layer of protection on top of your user name and password. Recommended to use hardware keys over virtual MFA.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "Unauthorized access to this critical account if password is not secure or it is disclosed in any way.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "high",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_user_mfa_enabled_console_access(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.credential_report
|
||||
|
||||
if response:
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
report.region = "us-east-1"
|
||||
if user["password_enabled"] != "not_supported":
|
||||
if user["mfa_active"] == "false":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user['user']} has Console Password enabled but MFA disabled."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user['user']} has Console Password enabled and MFA enabled."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"User {user['user']} has not Console Password enabled."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = iam_client.region
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Categories": [],
|
||||
"CheckAlias": "extra7123",
|
||||
"CheckID": "iam_user_two_active_access_key",
|
||||
"CheckName": "iam_user_two_active_access_key",
|
||||
"CheckTitle": "Check if IAM users have two active access keys",
|
||||
"CheckType": "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark",
|
||||
"Compliance": [],
|
||||
"DependsOn": [],
|
||||
"Description": "Check if IAM users have two active access keys",
|
||||
"Notes": "",
|
||||
"Provider": "aws",
|
||||
"RelatedTo": [],
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Avoid using long lived access keys.",
|
||||
"Url": "https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html"
|
||||
}
|
||||
},
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"ResourceType": "AwsIamUser",
|
||||
"Risk": "Access Keys could be lost or stolen. It creates a critical risk.",
|
||||
"ServiceName": "iam",
|
||||
"Severity": "medium",
|
||||
"SubServiceName": "",
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.iam.iam_service import iam_client
|
||||
|
||||
|
||||
class iam_user_two_active_access_key(Check):
|
||||
def execute(self) -> Check_Report:
|
||||
findings = []
|
||||
response = iam_client.credential_report
|
||||
|
||||
if response:
|
||||
for user in response:
|
||||
report = Check_Report(self.metadata)
|
||||
report.resource_id = user["user"]
|
||||
report.resource_arn = user["arn"]
|
||||
report.region = "us-east-1"
|
||||
if (
|
||||
user["access_key_1_active"] == "true"
|
||||
and user["access_key_2_active"] == "true"
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"User {user['user']} has 2 active access keys."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"User {user['user']} has not 2 active access keys."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "PASS"
|
||||
report.status_extended = "There is no IAM users."
|
||||
report.region = iam_client.region
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
Reference in New Issue
Block a user