Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iam): add new check iam_policy_cloudshell_admin_not_attached #5437

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "iam_policy_cloudshell_admin_not_attached",
"CheckTitle": "Check if IAM identities (users,groups,roles) have the AWSCloudShellFullAccess policy attached.",
"CheckType": [
"Software and Configuration Checks/AWS Security Best Practices/CIS AWS Foundations Benchmark"
],
"ServiceName": "iam",
"SubServiceName": "",
"ResourceIdTemplate": "arn:aws:iam::{account-id}:{resource-type}/{resource-id}",
"Severity": "medium",
"ResourceType": "AwsIamPolicy",
"Description": "This control checks whether an IAM identity (user, role, or group) has the AWS managed policy AWSCloudShellFullAccess attached. The control fails if an IAM identity has the AWSCloudShellFullAccess policy attached.",
"Risk": "Attaching the AWSCloudShellFullAccess policy to IAM identities grants broad permissions, including internet access and file transfer capabilities, which can lead to security risks such as data exfiltration. The principle of least privilege should be followed to avoid excessive permissions.",
"RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/iam-policy-blacklisted-check.html",
"Remediation": {
"Code": {
"CLI": "aws iam detach-user/role/group-policy --user/role/group-name <user/role/group-name> --policy-arn arn:aws:iam::aws:policy/AWSCloudShellFullAccess",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/iam-controls.html#iam-27",
"Terraform": ""
},
"Recommendation": {
"Text": "Detach the AWSCloudShellFullAccess policy from the IAM identity to restrict excessive permissions and adhere to the principle of least privilege.",
"Url": "https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html"
}
},
"Categories": [
"trustboundaries"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.iam_client import iam_client


class iam_policy_cloudshell_admin_not_attached(Check):
def execute(self) -> Check_Report_AWS:
findings = []
if iam_client.entities_attached_to_cloudshell_policy is not None:
report = Check_Report_AWS(self.metadata())
report.region = iam_client.region
report.resource_id = iam_client.audited_account
report.resource_arn = f"arn:{iam_client.audited_partition}:iam::aws:policy/AWSCloudShellFullAccess"
report.status = "PASS"
report.status_extended = (
"AWS CloudShellFullAccess policy is not attached to any IAM entity."
)
if (
iam_client.entities_attached_to_cloudshell_policy["Users"]
or iam_client.entities_attached_to_cloudshell_policy["Groups"]
or iam_client.entities_attached_to_cloudshell_policy["Roles"]
):
report.status = "FAIL"
if (
len(iam_client.entities_attached_to_cloudshell_policy["Users"]) > 0
and len(iam_client.entities_attached_to_cloudshell_policy["Groups"])
> 0
and len(iam_client.entities_attached_to_cloudshell_policy["Roles"])
> 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Users: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Users'])}, Groups {', '.join(iam_client.entities_attached_to_cloudshell_policy['Groups'])}, Roles {', '.join(iam_client.entities_attached_to_cloudshell_policy['Roles'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Users"]) > 0
and len(iam_client.entities_attached_to_cloudshell_policy["Groups"])
> 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Users: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Users'])}, Groups {', '.join(iam_client.entities_attached_to_cloudshell_policy['Groups'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Users"]) > 0
and len(iam_client.entities_attached_to_cloudshell_policy["Roles"])
> 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Users: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Users'])}, Roles {', '.join(iam_client.entities_attached_to_cloudshell_policy['Roles'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Groups"]) > 0
and len(iam_client.entities_attached_to_cloudshell_policy["Roles"])
> 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Groups: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Groups'])}, Roles {', '.join(iam_client.entities_attached_to_cloudshell_policy['Roles'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Users"]) > 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Users: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Users'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Groups"]) > 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Groups: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Groups'])}."
elif (
len(iam_client.entities_attached_to_cloudshell_policy["Roles"]) > 0
):
report.status_extended = f"AWS CloudShellFullAccess policy attached to IAM Roles: {', '.join(iam_client.entities_attached_to_cloudshell_policy['Roles'])}."
findings.append(report)
return findings
44 changes: 44 additions & 0 deletions prowler/providers/aws/services/iam/iam_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def __init__(self, provider):
self.entities_role_attached_to_securityaudit_policy = (
self._list_entities_role_for_policy(securityaudit_policy_arn)
)
cloudshell_admin_policy_arn = (
f"arn:{self.audited_partition}:iam::aws:policy/AWSCloudShellFullAccess"
)
self.entities_attached_to_cloudshell_policy = self._list_entities_for_policy(
cloudshell_admin_policy_arn
)
# List both Customer (attached and unattached) and AWS Managed (only attached) policies
self.policies = []
self.policies.extend(self._list_policies("AWS"))
Expand Down Expand Up @@ -685,6 +691,44 @@ def _list_entities_role_for_policy(self, policy_arn):
finally:
return roles

def _list_entities_for_policy(self, policy_arn):
logger.info("IAM - List Entities Role For Policy...")
try:
entities = {
"Users": [],
"Groups": [],
"Roles": [],
}

paginator = self.client.get_paginator("list_entities_for_policy")
for response in paginator.paginate(PolicyArn=policy_arn):
entities["Users"].extend(
user["UserName"] for user in response.get("PolicyUsers", [])
)
entities["Groups"].extend(
group["GroupName"] for group in response.get("PolicyGroups", [])
)
entities["Roles"].extend(
role["RoleName"] for role in response.get("PolicyRoles", [])
)
return entities
except ClientError as error:
if error.response["Error"]["Code"] == "AccessDenied":
logger.error(
f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
entities = None
else:
logger.error(
f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
finally:
return entities

def _list_policies(self, scope):
logger.info("IAM - List Policies...")
try:
Expand Down
Loading