mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(regions): add regions to resources (#1285)
This commit is contained in:
@@ -55,7 +55,7 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
|
|
||||||
- id: safety
|
- id: safety
|
||||||
name: bandit
|
name: safety
|
||||||
description: 'Safety is a tool that checks your installed dependencies for known security vulnerabilities'
|
description: 'Safety is a tool that checks your installed dependencies for known security vulnerabilities'
|
||||||
entry: bash -c 'safety check'
|
entry: bash -c 'safety check'
|
||||||
language: system
|
language: system
|
||||||
|
|||||||
@@ -42,53 +42,59 @@ def report(check_findings, output_options, audit_info):
|
|||||||
csv_fields,
|
csv_fields,
|
||||||
)
|
)
|
||||||
|
|
||||||
for finding in check_findings:
|
if check_findings:
|
||||||
# Print findings by stdout
|
for finding in check_findings:
|
||||||
color = set_report_color(finding.status)
|
# Print findings by stdout
|
||||||
if output_options.is_quiet and "FAIL" in finding.status:
|
color = set_report_color(finding.status)
|
||||||
print(
|
if output_options.is_quiet and "FAIL" in finding.status:
|
||||||
f"\t{color}{finding.status}{Style.RESET_ALL} {finding.region}: {finding.status_extended}"
|
print(
|
||||||
)
|
f"\t{color}{finding.status}{Style.RESET_ALL} {finding.region}: {finding.status_extended}"
|
||||||
elif not output_options.is_quiet:
|
|
||||||
print(
|
|
||||||
f"\t{color}{finding.status}{Style.RESET_ALL} {finding.region}: {finding.status_extended}"
|
|
||||||
)
|
|
||||||
if file_descriptors:
|
|
||||||
|
|
||||||
# sending the finding to input options
|
|
||||||
if "csv" in file_descriptors:
|
|
||||||
finding_output = Check_Output_CSV(
|
|
||||||
audit_info.audited_account,
|
|
||||||
audit_info.profile,
|
|
||||||
finding,
|
|
||||||
audit_info.organizations_metadata,
|
|
||||||
)
|
)
|
||||||
csv_writer = DictWriter(
|
elif not output_options.is_quiet:
|
||||||
file_descriptors["csv"], fieldnames=csv_fields, delimiter=";"
|
print(
|
||||||
|
f"\t{color}{finding.status}{Style.RESET_ALL} {finding.region}: {finding.status_extended}"
|
||||||
)
|
)
|
||||||
csv_writer.writerow(finding_output.__dict__)
|
|
||||||
|
if file_descriptors:
|
||||||
|
|
||||||
if "json" in file_descriptors:
|
# sending the finding to input options
|
||||||
finding_output = Check_Output_JSON(**finding.check_metadata.dict())
|
if "csv" in file_descriptors:
|
||||||
fill_json(finding_output, audit_info, finding)
|
finding_output = Check_Output_CSV(
|
||||||
|
audit_info.audited_account,
|
||||||
|
audit_info.profile,
|
||||||
|
finding,
|
||||||
|
audit_info.organizations_metadata,
|
||||||
|
)
|
||||||
|
csv_writer = DictWriter(
|
||||||
|
file_descriptors["csv"], fieldnames=csv_fields, delimiter=";"
|
||||||
|
)
|
||||||
|
csv_writer.writerow(finding_output.__dict__)
|
||||||
|
|
||||||
json.dump(finding_output.dict(), file_descriptors["json"], indent=4)
|
if "json" in file_descriptors:
|
||||||
file_descriptors["json"].write(",")
|
finding_output = Check_Output_JSON(**finding.check_metadata.dict())
|
||||||
|
fill_json(finding_output, audit_info, finding)
|
||||||
|
|
||||||
if "json-asff" in file_descriptors:
|
json.dump(finding_output.dict(), file_descriptors["json"], indent=4)
|
||||||
finding_output = Check_Output_JSON_ASFF()
|
file_descriptors["json"].write(",")
|
||||||
fill_json_asff(finding_output, audit_info, finding)
|
|
||||||
|
|
||||||
json.dump(
|
if "json-asff" in file_descriptors:
|
||||||
finding_output.dict(), file_descriptors["json-asff"], indent=4
|
finding_output = Check_Output_JSON_ASFF()
|
||||||
)
|
fill_json_asff(finding_output, audit_info, finding)
|
||||||
file_descriptors["json-asff"].write(",")
|
|
||||||
|
|
||||||
# Check if it is needed to send findings to security hub
|
json.dump(
|
||||||
if output_options.security_hub_enabled:
|
finding_output.dict(), file_descriptors["json-asff"], indent=4
|
||||||
send_to_security_hub(
|
)
|
||||||
finding.region, finding_output, audit_info.audit_session
|
file_descriptors["json-asff"].write(",")
|
||||||
)
|
|
||||||
|
# Check if it is needed to send findings to security hub
|
||||||
|
if output_options.security_hub_enabled:
|
||||||
|
send_to_security_hub(
|
||||||
|
finding.region, finding_output, audit_info.audit_session
|
||||||
|
)
|
||||||
|
else: # No service resources in the whole account
|
||||||
|
color = set_report_color("PASS")
|
||||||
|
if not output_options.is_quiet:
|
||||||
|
print(f"{color}PASS{Style.RESET_ALL} There are no resources.")
|
||||||
|
|
||||||
if file_descriptors:
|
if file_descriptors:
|
||||||
# Close all file descriptors
|
# Close all file descriptors
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ def get_organizations_metadata(
|
|||||||
|
|
||||||
|
|
||||||
def generate_regional_clients(service, audit_info):
|
def generate_regional_clients(service, audit_info):
|
||||||
regional_clients = []
|
regional_clients = {}
|
||||||
# Get json locally
|
# Get json locally
|
||||||
f = open_file(aws_services_json_file)
|
f = open_file(aws_services_json_file)
|
||||||
data = parse_json_file(f)
|
data = parse_json_file(f)
|
||||||
@@ -323,8 +323,8 @@ def generate_regional_clients(service, audit_info):
|
|||||||
for region in regions:
|
for region in regions:
|
||||||
regional_client = audit_info.audit_session.client(service, region_name=region)
|
regional_client = audit_info.audit_session.client(service, region_name=region)
|
||||||
regional_client.region = region
|
regional_client.region = region
|
||||||
regional_clients.append(regional_client)
|
regional_clients[region] = regional_client
|
||||||
|
# regional_clients.append(regional_client)
|
||||||
return regional_clients
|
return regional_clients
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,31 +5,19 @@ from providers.aws.services.ec2.ec2_service import ec2_client
|
|||||||
class ec2_ebs_public_snapshot(Check):
|
class ec2_ebs_public_snapshot(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in ec2_client.regional_clients:
|
for snapshot in ec2_client.snapshots:
|
||||||
region = regional_client.region
|
report = Check_Report(self.metadata)
|
||||||
if regional_client.snapshots:
|
report.region = snapshot.region
|
||||||
for snapshot in regional_client.snapshots:
|
if not snapshot.public:
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.region = region
|
|
||||||
if not snapshot.public:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = (
|
|
||||||
f"EBS Snapshot {snapshot.id} is not Public"
|
|
||||||
)
|
|
||||||
report.resource_id = snapshot.id
|
|
||||||
else:
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = (
|
|
||||||
f"EBS Snapshot {snapshot.id} is currently Public"
|
|
||||||
)
|
|
||||||
report.resource_id = snapshot.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no EC2 EBS snapshots"
|
report.status_extended = f"EBS Snapshot {snapshot.id} is not Public"
|
||||||
report.region = region
|
report.resource_id = snapshot.id
|
||||||
|
else:
|
||||||
findings.append(report)
|
report.status = "FAIL"
|
||||||
|
report.status_extended = (
|
||||||
|
f"EBS Snapshot {snapshot.id} is currently Public"
|
||||||
|
)
|
||||||
|
report.resource_id = snapshot.id
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -5,31 +5,17 @@ from providers.aws.services.ec2.ec2_service import ec2_client
|
|||||||
class ec2_ebs_snapshots_encrypted(Check):
|
class ec2_ebs_snapshots_encrypted(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in ec2_client.regional_clients:
|
for snapshot in ec2_client.snapshots:
|
||||||
region = regional_client.region
|
report = Check_Report(self.metadata)
|
||||||
if regional_client.snapshots:
|
report.region = snapshot.region
|
||||||
for snapshot in regional_client.snapshots:
|
if snapshot.encrypted:
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.region = region
|
|
||||||
if snapshot.encrypted:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = (
|
|
||||||
f"EBS Snapshot {snapshot.id} is encrypted"
|
|
||||||
)
|
|
||||||
report.resource_id = snapshot.id
|
|
||||||
else:
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = (
|
|
||||||
f"EBS Snapshot {snapshot.id} is unencrypted"
|
|
||||||
)
|
|
||||||
report.resource_id = snapshot.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no EC2 EBS snapshots"
|
report.status_extended = f"EBS Snapshot {snapshot.id} is encrypted"
|
||||||
report.region = region
|
report.resource_id = snapshot.id
|
||||||
|
else:
|
||||||
findings.append(report)
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"EBS Snapshot {snapshot.id} is unencrypted"
|
||||||
|
report.resource_id = snapshot.id
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -5,29 +5,19 @@ from providers.aws.services.ec2.ec2_service import ec2_client
|
|||||||
class ec2_instance_public_ip(Check):
|
class ec2_instance_public_ip(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in ec2_client.regional_clients:
|
for instance in ec2_client.instances:
|
||||||
region = regional_client.region
|
report = Check_Report(self.metadata)
|
||||||
if regional_client.instances:
|
report.region = instance.region
|
||||||
for instance in regional_client.instances:
|
if instance.public_ip:
|
||||||
report = Check_Report(self.metadata)
|
report.status = "FAIL"
|
||||||
report.region = region
|
report.status_extended = f"EC2 instance {instance.id} has a Public IP: {instance.public_ip} ({instance.public_dns})."
|
||||||
if instance.public_ip:
|
report.resource_id = instance.id
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = f"EC2 instance {instance.id} has a Public IP: {instance.public_ip} ({instance.public_dns})."
|
|
||||||
report.resource_id = instance.id
|
|
||||||
else:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = (
|
|
||||||
f"EC2 instance {instance.id} has not a Public IP."
|
|
||||||
)
|
|
||||||
report.resource_id = instance.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
else:
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no EC2 instances."
|
report.status_extended = (
|
||||||
report.region = region
|
f"EC2 instance {instance.id} has not a Public IP."
|
||||||
|
)
|
||||||
findings.append(report)
|
report.resource_id = instance.id
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,40 +6,32 @@ class ec2_networkacl_allow_ingress_tcp_port_22(Check):
|
|||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_port = 22
|
check_port = 22
|
||||||
for regional_client in ec2_client.regional_clients:
|
for network_acl in ec2_client.network_acls:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.network_acls:
|
report = Check_Report(self.metadata)
|
||||||
for network_acl in regional_client.network_acls:
|
report.region = network_acl.region
|
||||||
public = False
|
for entry in network_acl.entries:
|
||||||
report = Check_Report(self.metadata)
|
if (
|
||||||
report.region = region
|
entry["CidrBlock"] == "0.0.0.0/0"
|
||||||
for entry in network_acl.entries:
|
and entry["RuleAction"] == "allow"
|
||||||
if (
|
and not entry["Egress"]
|
||||||
entry["CidrBlock"] == "0.0.0.0/0"
|
):
|
||||||
and entry["RuleAction"] == "allow"
|
if entry["Protocol"] == "-1":
|
||||||
and not entry["Egress"]
|
public = True
|
||||||
and "PortRange" in entry
|
elif (
|
||||||
and entry["Protocol"] == "6" # 6 relates to tcp protocol
|
entry["PortRange"]["From"] == check_port
|
||||||
):
|
and entry["PortRange"]["To"] == check_port
|
||||||
if (
|
and entry["Protocol"] == "6"
|
||||||
entry["PortRange"]["From"] == check_port
|
):
|
||||||
and entry["PortRange"]["To"] == check_port
|
public = True
|
||||||
):
|
if not public:
|
||||||
public = True
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = f"Network ACL {network_acl.id} has SSH port 22 open to the Internet."
|
|
||||||
report.resource_id = network_acl.id
|
|
||||||
if not public:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Network ACL {network_acl.id} has not SSH port 22 open to the Internet."
|
|
||||||
report.resource_id = network_acl.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no EC2 network acls."
|
report.status_extended = f"Network ACL {network_acl.id} has not SSH port 22 open to the Internet."
|
||||||
report.region = region
|
report.resource_id = network_acl.id
|
||||||
|
else:
|
||||||
findings.append(report)
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"Network ACL {network_acl.id} has SSH port 22 open to the Internet."
|
||||||
|
report.resource_id = network_acl.id
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,40 +6,32 @@ class ec2_networkacl_allow_ingress_tcp_port_3389(Check):
|
|||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_port = 3389
|
check_port = 3389
|
||||||
for regional_client in ec2_client.regional_clients:
|
for network_acl in ec2_client.network_acls:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.network_acls:
|
report = Check_Report(self.metadata)
|
||||||
for network_acl in regional_client.network_acls:
|
report.region = network_acl.region
|
||||||
public = False
|
for entry in network_acl.entries:
|
||||||
report = Check_Report(self.metadata)
|
if (
|
||||||
report.region = region
|
entry["CidrBlock"] == "0.0.0.0/0"
|
||||||
for entry in network_acl.entries:
|
and entry["RuleAction"] == "allow"
|
||||||
if (
|
and not entry["Egress"]
|
||||||
entry["CidrBlock"] == "0.0.0.0/0"
|
):
|
||||||
and entry["RuleAction"] == "allow"
|
if entry["Protocol"] == "-1":
|
||||||
and not entry["Egress"]
|
public = True
|
||||||
and "PortRange" in entry
|
elif (
|
||||||
and entry["Protocol"] == "6" # 6 relates to tcp protocol
|
entry["PortRange"]["From"] == check_port
|
||||||
):
|
and entry["PortRange"]["To"] == check_port
|
||||||
if (
|
and entry["Protocol"] == "6"
|
||||||
entry["PortRange"]["From"] == check_port
|
):
|
||||||
and entry["PortRange"]["To"] == check_port
|
public = True
|
||||||
):
|
if not public:
|
||||||
public = True
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = f"Network ACL {network_acl.id} has Microsoft RDP port 3389 open to the Internet."
|
|
||||||
report.resource_id = network_acl.id
|
|
||||||
if not public:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Network ACL {network_acl.id} has not Microsoft RDP port 3389 open to the Internet."
|
|
||||||
report.resource_id = network_acl.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no EC2 network acls."
|
report.status_extended = f"Network ACL {network_acl.id} has not Microsoft RDP port 3389 open to the Internet."
|
||||||
report.region = region
|
report.resource_id = network_acl.id
|
||||||
|
else:
|
||||||
findings.append(report)
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"Network ACL {network_acl.id} has Microsoft RDP port 3389 open to the Internet."
|
||||||
|
report.resource_id = network_acl.id
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -5,32 +5,22 @@ from providers.aws.services.ec2.ec2_service import check_security_group, ec2_cli
|
|||||||
class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check):
|
class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in ec2_client.regional_clients:
|
for security_group in ec2_client.security_groups:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.security_groups:
|
report = Check_Report(self.metadata)
|
||||||
for security_group in regional_client.security_groups:
|
report.region = security_group.region
|
||||||
public = False
|
# Loop through every security group's ingress rule and check it
|
||||||
report = Check_Report(self.metadata)
|
for ingress_rule in security_group.ingress_rules:
|
||||||
report.region = region
|
public = check_security_group(ingress_rule, "-1")
|
||||||
# Loop through every security group's ingress rule and check it
|
# Check
|
||||||
for ingress_rule in security_group.ingress_rules:
|
if public:
|
||||||
public = check_security_group(ingress_rule, "-1")
|
report.status = "FAIL"
|
||||||
# Check
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has all ports open to the Internet."
|
||||||
if public:
|
report.resource_id = security_group.id
|
||||||
report.status = "FAIL"
|
else:
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has all ports open to the Internet."
|
report.status = "PASS"
|
||||||
report.resource_id = security_group.id
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not all ports open to the Internet."
|
||||||
else:
|
report.resource_id = security_group.id
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not all ports open to the Internet."
|
|
||||||
report.resource_id = security_group.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There are no EC2 security groups."
|
|
||||||
report.region = region
|
|
||||||
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,32 +6,22 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22(Check):
|
|||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_ports = [22]
|
check_ports = [22]
|
||||||
for regional_client in ec2_client.regional_clients:
|
for security_group in ec2_client.security_groups:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.security_groups:
|
report = Check_Report(self.metadata)
|
||||||
for security_group in regional_client.security_groups:
|
report.region = security_group.region
|
||||||
public = False
|
# Loop through every security group's ingress rule and check it
|
||||||
report = Check_Report(self.metadata)
|
for ingress_rule in security_group.ingress_rules:
|
||||||
report.region = region
|
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||||
# Loop through every security group's ingress rule and check it
|
# Check
|
||||||
for ingress_rule in security_group.ingress_rules:
|
if public:
|
||||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
report.status = "FAIL"
|
||||||
# Check
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the SSH port 22 open to the Internet."
|
||||||
if public:
|
report.resource_id = security_group.id
|
||||||
report.status = "FAIL"
|
else:
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the SSH port 22 open to the Internet."
|
report.status = "PASS"
|
||||||
report.resource_id = security_group.id
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not SSH port 22 open to the Internet."
|
||||||
else:
|
report.resource_id = security_group.id
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not SSH port 22 open to the Internet."
|
|
||||||
report.resource_id = security_group.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There are no EC2 security groups."
|
|
||||||
report.region = region
|
|
||||||
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -1,37 +1,26 @@
|
|||||||
from lib.check.models import Check, Check_Report
|
from lib.check.models import Check, Check_Report
|
||||||
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
||||||
|
|
||||||
|
|
||||||
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389(Check):
|
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_ports = [3389]
|
check_ports = [3389]
|
||||||
for regional_client in ec2_client.regional_clients:
|
for security_group in ec2_client.security_groups:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.security_groups:
|
report = Check_Report(self.metadata)
|
||||||
for security_group in regional_client.security_groups:
|
report.region = security_group.region
|
||||||
public = False
|
# Loop through every security group's ingress rule and check it
|
||||||
report = Check_Report(self.metadata)
|
for ingress_rule in security_group.ingress_rules:
|
||||||
report.region = region
|
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||||
# Loop through every security group's ingress rule and check it
|
# Check
|
||||||
for ingress_rule in security_group.ingress_rules:
|
if public:
|
||||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
report.status = "FAIL"
|
||||||
# Check
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Microsoft RDP port 3389 open to the Internet."
|
||||||
if public:
|
report.resource_id = security_group.id
|
||||||
report.status = "FAIL"
|
else:
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Microsoft RDP port 3389 open to the Internet."
|
report.status = "PASS"
|
||||||
report.resource_id = security_group.id
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Microsoft RDP port 3389 open to the Internet."
|
||||||
else:
|
report.resource_id = security_group.id
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Microsoft RDP port 3389 open to the Internet."
|
|
||||||
report.resource_id = security_group.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There are no EC2 security groups."
|
|
||||||
report.region = region
|
|
||||||
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -1,37 +1,26 @@
|
|||||||
from lib.check.models import Check, Check_Report
|
from lib.check.models import Check, Check_Report
|
||||||
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
||||||
|
|
||||||
|
|
||||||
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306(Check):
|
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_ports = [3306]
|
check_ports = [3306]
|
||||||
for regional_client in ec2_client.regional_clients:
|
for security_group in ec2_client.security_groups:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.security_groups:
|
report = Check_Report(self.metadata)
|
||||||
for security_group in regional_client.security_groups:
|
report.region = security_group.region
|
||||||
public = False
|
# Loop through every security group's ingress rule and check it
|
||||||
report = Check_Report(self.metadata)
|
for ingress_rule in security_group.ingress_rules:
|
||||||
report.region = region
|
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||||
# Loop through every security group's ingress rule and check it
|
# Check
|
||||||
for ingress_rule in security_group.ingress_rules:
|
if public:
|
||||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
report.status = "FAIL"
|
||||||
# Check
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the MySQL port 3306 open to the Internet."
|
||||||
if public:
|
report.resource_id = security_group.id
|
||||||
report.status = "FAIL"
|
else:
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the MySQL port 3306 open to the Internet."
|
report.status = "PASS"
|
||||||
report.resource_id = security_group.id
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not MySQL port 3306 open to the Internet."
|
||||||
else:
|
report.resource_id = security_group.id
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not MySQL port 3306 open to the Internet."
|
|
||||||
report.resource_id = security_group.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There are no EC2 security groups."
|
|
||||||
report.region = region
|
|
||||||
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -1,37 +1,26 @@
|
|||||||
from lib.check.models import Check, Check_Report
|
from lib.check.models import Check, Check_Report
|
||||||
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
from providers.aws.services.ec2.ec2_service import check_security_group, ec2_client
|
||||||
|
|
||||||
|
|
||||||
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483(Check):
|
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
check_ports = [1521, 2483]
|
check_ports = [1521, 2483]
|
||||||
for regional_client in ec2_client.regional_clients:
|
for security_group in ec2_client.security_groups:
|
||||||
region = regional_client.region
|
public = False
|
||||||
if regional_client.security_groups:
|
report = Check_Report(self.metadata)
|
||||||
for security_group in regional_client.security_groups:
|
report.region = security_group.region
|
||||||
public = False
|
# Loop through every security group's ingress rule and check it
|
||||||
report = Check_Report(self.metadata)
|
for ingress_rule in security_group.ingress_rules:
|
||||||
report.region = region
|
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||||
# Loop through every security group's ingress rule and check it
|
# Check
|
||||||
for ingress_rule in security_group.ingress_rules:
|
if public:
|
||||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
report.status = "FAIL"
|
||||||
# Check
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Oracle ports 1521 and 2483 open to the Internet."
|
||||||
if public:
|
report.resource_id = security_group.id
|
||||||
report.status = "FAIL"
|
else:
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Oracle ports 1521 and 2483 open to the Internet."
|
report.status = "PASS"
|
||||||
report.resource_id = security_group.id
|
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Oracle ports 1521 and 2483 open to the Internet."
|
||||||
else:
|
report.resource_id = security_group.id
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Oracle ports 1521 and 2483 open to the Internet."
|
|
||||||
report.resource_id = security_group.id
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There are no EC2 security groups."
|
|
||||||
report.region = region
|
|
||||||
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
@@ -13,18 +13,22 @@ class EC2:
|
|||||||
self.session = audit_info.audit_session
|
self.session = audit_info.audit_session
|
||||||
self.audited_account = audit_info.audited_account
|
self.audited_account = audit_info.audited_account
|
||||||
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
||||||
|
self.instances = []
|
||||||
self.__threading_call__(self.__describe_instances__)
|
self.__threading_call__(self.__describe_instances__)
|
||||||
|
self.security_groups = []
|
||||||
self.__threading_call__(self.__describe_security_groups__)
|
self.__threading_call__(self.__describe_security_groups__)
|
||||||
|
self.network_acls = []
|
||||||
self.__threading_call__(self.__describe_network_acls__)
|
self.__threading_call__(self.__describe_network_acls__)
|
||||||
|
self.snapshots = []
|
||||||
self.__threading_call__(self.__describe_snapshots__)
|
self.__threading_call__(self.__describe_snapshots__)
|
||||||
self.__threading_call__(self.__get_snapshot_public__)
|
self.__get_snapshot_public__()
|
||||||
|
|
||||||
def __get_session__(self):
|
def __get_session__(self):
|
||||||
return self.session
|
return self.session
|
||||||
|
|
||||||
def __threading_call__(self, call):
|
def __threading_call__(self, call):
|
||||||
threads = []
|
threads = []
|
||||||
for regional_client in self.regional_clients:
|
for regional_client in self.regional_clients.values():
|
||||||
threads.append(threading.Thread(target=call, args=(regional_client,)))
|
threads.append(threading.Thread(target=call, args=(regional_client,)))
|
||||||
for t in threads:
|
for t in threads:
|
||||||
t.start()
|
t.start()
|
||||||
@@ -37,7 +41,6 @@ class EC2:
|
|||||||
describe_instances_paginator = regional_client.get_paginator(
|
describe_instances_paginator = regional_client.get_paginator(
|
||||||
"describe_instances"
|
"describe_instances"
|
||||||
)
|
)
|
||||||
instances = []
|
|
||||||
for page in describe_instances_paginator.paginate():
|
for page in describe_instances_paginator.paginate():
|
||||||
for reservation in page["Reservations"]:
|
for reservation in page["Reservations"]:
|
||||||
for instance in reservation["Instances"]:
|
for instance in reservation["Instances"]:
|
||||||
@@ -45,9 +48,10 @@ class EC2:
|
|||||||
"PublicDnsName" in instance
|
"PublicDnsName" in instance
|
||||||
and "PublicIpAddress" in instance
|
and "PublicIpAddress" in instance
|
||||||
):
|
):
|
||||||
instances.append(
|
self.instances.append(
|
||||||
Instance(
|
Instance(
|
||||||
instance["InstanceId"],
|
instance["InstanceId"],
|
||||||
|
regional_client.region,
|
||||||
instance["InstanceType"],
|
instance["InstanceType"],
|
||||||
instance["ImageId"],
|
instance["ImageId"],
|
||||||
instance["LaunchTime"],
|
instance["LaunchTime"],
|
||||||
@@ -58,9 +62,10 @@ class EC2:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
instances.append(
|
self.instances.append(
|
||||||
Instance(
|
Instance(
|
||||||
instance["InstanceId"],
|
instance["InstanceId"],
|
||||||
|
regional_client.region,
|
||||||
instance["InstanceType"],
|
instance["InstanceType"],
|
||||||
instance["ImageId"],
|
instance["ImageId"],
|
||||||
instance["LaunchTime"],
|
instance["LaunchTime"],
|
||||||
@@ -74,9 +79,6 @@ class EC2:
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
)
|
)
|
||||||
regional_client.instances = []
|
|
||||||
else:
|
|
||||||
regional_client.instances = instances
|
|
||||||
|
|
||||||
def __describe_security_groups__(self, regional_client):
|
def __describe_security_groups__(self, regional_client):
|
||||||
logger.info("EC2 - Describing Security Groups...")
|
logger.info("EC2 - Describing Security Groups...")
|
||||||
@@ -84,12 +86,12 @@ class EC2:
|
|||||||
describe_security_groups_paginator = regional_client.get_paginator(
|
describe_security_groups_paginator = regional_client.get_paginator(
|
||||||
"describe_security_groups"
|
"describe_security_groups"
|
||||||
)
|
)
|
||||||
security_groups = []
|
|
||||||
for page in describe_security_groups_paginator.paginate():
|
for page in describe_security_groups_paginator.paginate():
|
||||||
for sg in page["SecurityGroups"]:
|
for sg in page["SecurityGroups"]:
|
||||||
security_groups.append(
|
self.security_groups.append(
|
||||||
SecurityGroup(
|
SecurityGroup(
|
||||||
sg["GroupName"],
|
sg["GroupName"],
|
||||||
|
regional_client.region,
|
||||||
sg["GroupId"],
|
sg["GroupId"],
|
||||||
sg["IpPermissions"],
|
sg["IpPermissions"],
|
||||||
sg["IpPermissionsEgress"],
|
sg["IpPermissionsEgress"],
|
||||||
@@ -99,9 +101,6 @@ class EC2:
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
)
|
)
|
||||||
regional_client.security_groups = []
|
|
||||||
else:
|
|
||||||
regional_client.security_groups = security_groups
|
|
||||||
|
|
||||||
def __describe_network_acls__(self, regional_client):
|
def __describe_network_acls__(self, regional_client):
|
||||||
logger.info("EC2 - Describing Security Groups...")
|
logger.info("EC2 - Describing Security Groups...")
|
||||||
@@ -109,19 +108,19 @@ class EC2:
|
|||||||
describe_network_acls_paginator = regional_client.get_paginator(
|
describe_network_acls_paginator = regional_client.get_paginator(
|
||||||
"describe_network_acls"
|
"describe_network_acls"
|
||||||
)
|
)
|
||||||
network_acls = []
|
|
||||||
for page in describe_network_acls_paginator.paginate():
|
for page in describe_network_acls_paginator.paginate():
|
||||||
for nacl in page["NetworkAcls"]:
|
for nacl in page["NetworkAcls"]:
|
||||||
network_acls.append(
|
self.network_acls.append(
|
||||||
NetworkACL(nacl["NetworkAclId"], nacl["Entries"])
|
NetworkACL(
|
||||||
|
nacl["NetworkAclId"],
|
||||||
|
regional_client.region,
|
||||||
|
nacl["Entries"],
|
||||||
|
)
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
)
|
)
|
||||||
regional_client.network_acls = []
|
|
||||||
else:
|
|
||||||
regional_client.network_acls = network_acls
|
|
||||||
|
|
||||||
def __describe_snapshots__(self, regional_client):
|
def __describe_snapshots__(self, regional_client):
|
||||||
logger.info("EC2 - Describing Snapshots...")
|
logger.info("EC2 - Describing Snapshots...")
|
||||||
@@ -129,7 +128,6 @@ class EC2:
|
|||||||
describe_snapshots_paginator = regional_client.get_paginator(
|
describe_snapshots_paginator = regional_client.get_paginator(
|
||||||
"describe_snapshots"
|
"describe_snapshots"
|
||||||
)
|
)
|
||||||
snapshots = []
|
|
||||||
encrypted = False
|
encrypted = False
|
||||||
for page in describe_snapshots_paginator.paginate(
|
for page in describe_snapshots_paginator.paginate(
|
||||||
OwnerIds=[self.audited_account]
|
OwnerIds=[self.audited_account]
|
||||||
@@ -137,36 +135,36 @@ class EC2:
|
|||||||
for snapshot in page["Snapshots"]:
|
for snapshot in page["Snapshots"]:
|
||||||
if snapshot["Encrypted"]:
|
if snapshot["Encrypted"]:
|
||||||
encrypted = True
|
encrypted = True
|
||||||
snapshots.append(Snapshot(snapshot["SnapshotId"], encrypted))
|
self.snapshots.append(
|
||||||
|
Snapshot(
|
||||||
|
snapshot["SnapshotId"], regional_client.region, encrypted
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
)
|
)
|
||||||
regional_client.snapshots = []
|
|
||||||
else:
|
|
||||||
regional_client.snapshots = snapshots
|
|
||||||
|
|
||||||
def __get_snapshot_public__(self, regional_client):
|
def __get_snapshot_public__(self):
|
||||||
logger.info("EC2 - Get snapshots encryption...")
|
logger.info("EC2 - Get snapshots encryption...")
|
||||||
try:
|
try:
|
||||||
if hasattr(regional_client, "snapshots"):
|
for snapshot in self.snapshots:
|
||||||
for snapshot in regional_client.snapshots:
|
regional_client = self.regional_clients[snapshot.region]
|
||||||
snapshot_public = regional_client.describe_snapshot_attribute(
|
snapshot_public = regional_client.describe_snapshot_attribute(
|
||||||
Attribute="createVolumePermission", SnapshotId=snapshot.id
|
Attribute="createVolumePermission", SnapshotId=snapshot.id
|
||||||
)
|
)
|
||||||
for permission in snapshot_public["CreateVolumePermissions"]:
|
for permission in snapshot_public["CreateVolumePermissions"]:
|
||||||
if "Group" in permission:
|
if "Group" in permission:
|
||||||
if permission["Group"] == "all":
|
if permission["Group"] == "all":
|
||||||
snapshot.public = True
|
snapshot.public = True
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(f"{error.__class__.__name__}: {error}")
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Instance:
|
class Instance:
|
||||||
id: str
|
id: str
|
||||||
|
region: str
|
||||||
type: str
|
type: str
|
||||||
image_id: str
|
image_id: str
|
||||||
launch_time: str
|
launch_time: str
|
||||||
@@ -178,6 +176,7 @@ class Instance:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
id,
|
id,
|
||||||
|
region,
|
||||||
type,
|
type,
|
||||||
image_id,
|
image_id,
|
||||||
launch_time,
|
launch_time,
|
||||||
@@ -187,6 +186,7 @@ class Instance:
|
|||||||
public_ip,
|
public_ip,
|
||||||
):
|
):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
self.region = region
|
||||||
self.type = type
|
self.type = type
|
||||||
self.image_id = image_id
|
self.image_id = image_id
|
||||||
self.launch_time = launch_time
|
self.launch_time = launch_time
|
||||||
@@ -199,11 +199,13 @@ class Instance:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Snapshot:
|
class Snapshot:
|
||||||
id: str
|
id: str
|
||||||
|
region: str
|
||||||
encrypted: bool
|
encrypted: bool
|
||||||
public: bool
|
public: bool
|
||||||
|
|
||||||
def __init__(self, id, encrypted):
|
def __init__(self, id, region, encrypted):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
self.region = region
|
||||||
self.encrypted = encrypted
|
self.encrypted = encrypted
|
||||||
self.public = False
|
self.public = False
|
||||||
|
|
||||||
@@ -211,12 +213,14 @@ class Snapshot:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class SecurityGroup:
|
class SecurityGroup:
|
||||||
name: str
|
name: str
|
||||||
|
region: str
|
||||||
id: str
|
id: str
|
||||||
ingress_rules: list[dict]
|
ingress_rules: list[dict]
|
||||||
egress_rules: list[dict]
|
egress_rules: list[dict]
|
||||||
|
|
||||||
def __init__(self, name, id, ingress_rules, egress_rules):
|
def __init__(self, name, region, id, ingress_rules, egress_rules):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.region = region
|
||||||
self.id = id
|
self.id = id
|
||||||
self.ingress_rules = ingress_rules
|
self.ingress_rules = ingress_rules
|
||||||
self.egress_rules = egress_rules
|
self.egress_rules = egress_rules
|
||||||
@@ -227,8 +231,9 @@ class NetworkACL:
|
|||||||
id: str
|
id: str
|
||||||
entries: list[dict]
|
entries: list[dict]
|
||||||
|
|
||||||
def __init__(self, id, entries):
|
def __init__(self, id, region, entries):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
self.region = region
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,58 +7,50 @@ class iam_administrator_access_with_mfa(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.groups
|
response = iam_client.groups
|
||||||
|
|
||||||
if response:
|
for group in response:
|
||||||
for group in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.resource_id = group.name
|
|
||||||
report.resource_arn = group.arn
|
|
||||||
report.region = iam_client.region
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
report.resource_id = group.name
|
||||||
report.status_extended = "There is no IAM groups."
|
report.resource_arn = group.arn
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
findings.append(report)
|
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)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -11,51 +11,50 @@ class iam_avoid_root_usage(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.credential_report
|
response = iam_client.credential_report
|
||||||
|
|
||||||
if response:
|
for user in response:
|
||||||
for user in response:
|
if user["user"] == "<root_account>":
|
||||||
if user["user"] == "<root_account>":
|
report = Check_Report(self.metadata)
|
||||||
report = Check_Report(self.metadata)
|
report.region = iam_client.region
|
||||||
report.region = iam_client.region
|
report.resource_id = user["user"]
|
||||||
report.resource_id = user["user"]
|
report.resource_arn = user["arn"]
|
||||||
report.resource_arn = user["arn"]
|
if (
|
||||||
if (
|
user["password_last_used"] != "no_information"
|
||||||
user["password_last_used"] != "no_information"
|
or user["access_key_1_last_used_date"] != "N/A"
|
||||||
or user["access_key_1_last_used_date"] != "N/A"
|
or user["access_key_2_last_used_date"] != "N/A"
|
||||||
or user["access_key_2_last_used_date"] != "N/A"
|
):
|
||||||
):
|
if user["password_last_used"] != "no_information":
|
||||||
if user["password_last_used"] != "no_information":
|
days_since_accessed = (
|
||||||
days_since_accessed = (
|
datetime.datetime.now()
|
||||||
datetime.datetime.now()
|
- datetime.datetime.strptime(
|
||||||
- datetime.datetime.strptime(
|
user["password_last_used"],
|
||||||
user["password_last_used"],
|
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
)
|
||||||
)
|
).days
|
||||||
).days
|
elif user["access_key_1_last_used_date"] != "N/A":
|
||||||
elif user["access_key_1_last_used_date"] != "N/A":
|
days_since_accessed = (
|
||||||
days_since_accessed = (
|
datetime.datetime.now()
|
||||||
datetime.datetime.now()
|
- datetime.datetime.strptime(
|
||||||
- datetime.datetime.strptime(
|
user["access_key_1_last_used_date"],
|
||||||
user["access_key_1_last_used_date"],
|
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
)
|
||||||
)
|
).days
|
||||||
).days
|
elif user["access_key_2_last_used_date"] != "N/A":
|
||||||
elif user["access_key_2_last_used_date"] != "N/A":
|
days_since_accessed = (
|
||||||
days_since_accessed = (
|
datetime.datetime.now()
|
||||||
datetime.datetime.now()
|
- datetime.datetime.strptime(
|
||||||
- datetime.datetime.strptime(
|
user["access_key_2_last_used_date"],
|
||||||
user["access_key_2_last_used_date"],
|
"%Y-%m-%dT%H:%M:%S+00:00",
|
||||||
"%Y-%m-%dT%H:%M:%S+00:00",
|
)
|
||||||
)
|
).days
|
||||||
).days
|
if days_since_accessed > maximum_access_days:
|
||||||
if days_since_accessed > maximum_access_days:
|
report.status = "FAIL"
|
||||||
report.status = "FAIL"
|
report.status_extended = f"Root user in the account was last accessed {days_since_accessed} days ago."
|
||||||
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:
|
else:
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
|
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
|
||||||
findings.append(report)
|
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
|
return findings
|
||||||
|
|||||||
@@ -11,42 +11,35 @@ class iam_disable_30_days_credentials(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.users
|
response = iam_client.users
|
||||||
|
|
||||||
if response:
|
for user in response:
|
||||||
for user in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.resource_id = user.name
|
|
||||||
report.resource_arn = user.arn
|
|
||||||
report.region = iam_client.region
|
|
||||||
if user.password_last_used and user.password_last_used != "":
|
|
||||||
try:
|
|
||||||
time_since_insertion = (
|
|
||||||
datetime.datetime.now()
|
|
||||||
- datetime.datetime.strptime(
|
|
||||||
str(user.password_last_used), "%Y-%m-%d %H:%M:%S+00:00"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if time_since_insertion.days > maximum_expiration_days:
|
|
||||||
report.status = "FAIL"
|
|
||||||
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.name} has logged into the console in the past 30 days."
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
report.status = "PASS"
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
report.resource_id = user.name
|
||||||
report.status_extended = "There is no IAM users."
|
report.resource_arn = user.arn
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
|
if user.password_last_used and user.password_last_used != "":
|
||||||
|
try:
|
||||||
|
time_since_insertion = (
|
||||||
|
datetime.datetime.now()
|
||||||
|
- datetime.datetime.strptime(
|
||||||
|
str(user.password_last_used), "%Y-%m-%d %H:%M:%S+00:00"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if time_since_insertion.days > maximum_expiration_days:
|
||||||
|
report.status = "FAIL"
|
||||||
|
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.name} has logged into the console in the past 30 days."
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
report.status = "PASS"
|
||||||
|
report.status_extended = (
|
||||||
|
f"User {user.name} has not a console password or is unused."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Append report
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -11,42 +11,35 @@ class iam_disable_90_days_credentials(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.users
|
response = iam_client.users
|
||||||
|
|
||||||
if response:
|
for user in response:
|
||||||
for user in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.region = iam_client.region
|
|
||||||
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.datetime.strptime(
|
|
||||||
str(user.password_last_used), "%Y-%m-%d %H:%M:%S+00:00"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if time_since_insertion.days > maximum_expiration_days:
|
|
||||||
report.status = "FAIL"
|
|
||||||
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.name} has logged into the console in the past 90 days."
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
report.status = "PASS"
|
|
||||||
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There is no IAM users."
|
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
|
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.datetime.strptime(
|
||||||
|
str(user.password_last_used), "%Y-%m-%d %H:%M:%S+00:00"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if time_since_insertion.days > maximum_expiration_days:
|
||||||
|
report.status = "FAIL"
|
||||||
|
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.name} has logged into the console in the past 90 days."
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
report.status = "PASS"
|
||||||
|
|
||||||
|
report.status_extended = (
|
||||||
|
f"User {user.name} has not a console password or is unused."
|
||||||
|
)
|
||||||
|
# Append report
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,19 +6,18 @@ class iam_root_mfa_enabled(Check):
|
|||||||
def execute(self) -> Check_Report:
|
def execute(self) -> Check_Report:
|
||||||
findings = []
|
findings = []
|
||||||
|
|
||||||
if iam_client.credential_report:
|
for user in iam_client.credential_report:
|
||||||
for user in iam_client.credential_report:
|
if user["user"] == "<root_account>":
|
||||||
if user["user"] == "<root_account>":
|
report = Check_Report(self.metadata)
|
||||||
report = Check_Report(self.metadata)
|
report.region = iam_client.region
|
||||||
report.region = iam_client.region
|
report.resource_id = user["user"]
|
||||||
report.resource_id = user["user"]
|
report.resource_arn = user["arn"]
|
||||||
report.resource_arn = user["arn"]
|
if user["mfa_active"] == "false":
|
||||||
if user["mfa_active"] == "false":
|
report.status = "FAIL"
|
||||||
report.status = "FAIL"
|
report.status_extended = "MFA is not enabled for root account."
|
||||||
report.status_extended = "MFA is not enabled for root account."
|
else:
|
||||||
else:
|
report.status = "PASS"
|
||||||
report.status = "PASS"
|
report.status_extended = "MFA is enabled for root account."
|
||||||
report.status_extended = "MFA is enabled for root account."
|
findings.append(report)
|
||||||
findings.append(report)
|
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -11,53 +11,48 @@ class iam_rotate_access_key_90_days(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.credential_report
|
response = iam_client.credential_report
|
||||||
|
|
||||||
if response:
|
for user in response:
|
||||||
for user in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.region = iam_client.region
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There is no IAM users."
|
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
|
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)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -7,35 +7,28 @@ class iam_user_hardware_mfa_enabled(Check):
|
|||||||
findings = []
|
findings = []
|
||||||
response = iam_client.users
|
response = iam_client.users
|
||||||
|
|
||||||
if response:
|
for user in response:
|
||||||
for user in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.resource_id = user.name
|
|
||||||
report.resource_arn = user.arn
|
|
||||||
report.region = iam_client.region
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
report.resource_id = user.name
|
||||||
report.status_extended = "There is no IAM users."
|
report.resource_arn = user.arn
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
findings.append(report)
|
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)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,31 +6,23 @@ class iam_user_mfa_enabled_console_access(Check):
|
|||||||
def execute(self) -> Check_Report:
|
def execute(self) -> Check_Report:
|
||||||
findings = []
|
findings = []
|
||||||
response = iam_client.credential_report
|
response = iam_client.credential_report
|
||||||
|
for user in response:
|
||||||
if response:
|
report = Check_Report(self.metadata)
|
||||||
for user in response:
|
report.resource_id = user["user"]
|
||||||
report = Check_Report(self.metadata)
|
report.resource_arn = user["arn"]
|
||||||
report.resource_id = user["user"]
|
report.region = iam_client.region
|
||||||
report.resource_arn = user["arn"]
|
if user["password_enabled"] != "not_supported":
|
||||||
report.region = iam_client.region
|
if user["mfa_active"] == "false":
|
||||||
if user["password_enabled"] != "not_supported":
|
report.status = "FAIL"
|
||||||
if user["mfa_active"] == "false":
|
report.status_extended = f"User {user['user']} has Console Password enabled but MFA disabled."
|
||||||
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:
|
else:
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = (
|
report.status_extended = f"User {user['user']} has Console Password enabled and MFA enabled."
|
||||||
f"User {user['user']} has not Console Password enabled."
|
else:
|
||||||
)
|
report.status = "PASS"
|
||||||
findings.append(report)
|
report.status_extended = (
|
||||||
else:
|
f"User {user['user']} has not Console Password enabled."
|
||||||
report = Check_Report(self.metadata)
|
)
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = "There is no IAM users."
|
|
||||||
report.region = iam_client.region
|
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -6,33 +6,24 @@ class iam_user_two_active_access_key(Check):
|
|||||||
def execute(self) -> Check_Report:
|
def execute(self) -> Check_Report:
|
||||||
findings = []
|
findings = []
|
||||||
response = iam_client.credential_report
|
response = iam_client.credential_report
|
||||||
|
for user in response:
|
||||||
if response:
|
|
||||||
for user in response:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.resource_id = user["user"]
|
|
||||||
report.resource_arn = user["arn"]
|
|
||||||
report.region = iam_client.region
|
|
||||||
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 = Check_Report(self.metadata)
|
||||||
report.status = "PASS"
|
report.resource_id = user["user"]
|
||||||
report.status_extended = "There is no IAM users."
|
report.resource_arn = user["arn"]
|
||||||
report.region = iam_client.region
|
report.region = iam_client.region
|
||||||
|
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."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
report.status = "PASS"
|
||||||
|
report.status_extended = (
|
||||||
|
f"User {user['user']} has not 2 active access keys."
|
||||||
|
)
|
||||||
findings.append(report)
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -5,29 +5,20 @@ from providers.aws.services.s3.s3_service import s3_client
|
|||||||
class s3_bucket_object_versioning(Check):
|
class s3_bucket_object_versioning(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in s3_client.regional_clients:
|
for bucket in s3_client.buckets:
|
||||||
region = regional_client.region
|
report = Check_Report(self.metadata)
|
||||||
if regional_client.buckets:
|
report.region = bucket.region
|
||||||
for bucket in regional_client.buckets:
|
report.resource_id = bucket.name
|
||||||
report = Check_Report(self.metadata)
|
if bucket.versioning:
|
||||||
report.region = region
|
|
||||||
report.resource_id = bucket.name
|
|
||||||
if bucket.versioning:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = (
|
|
||||||
f"S3 Bucket {bucket.name} has versioning enabled."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = (
|
|
||||||
f"S3 Bucket {bucket.name} has versioning disabled."
|
|
||||||
)
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no S3 buckets."
|
report.status_extended = (
|
||||||
report.region = region
|
f"S3 Bucket {bucket.name} has versioning enabled."
|
||||||
findings.append(report)
|
)
|
||||||
|
else:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = (
|
||||||
|
f"S3 Bucket {bucket.name} has versioning disabled."
|
||||||
|
)
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -5,25 +5,20 @@ from providers.aws.services.s3.s3_service import s3_client
|
|||||||
class s3_bucket_server_access_logging_enabled(Check):
|
class s3_bucket_server_access_logging_enabled(Check):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
findings = []
|
findings = []
|
||||||
for regional_client in s3_client.regional_clients:
|
for bucket in s3_client.buckets:
|
||||||
region = regional_client.region
|
report = Check_Report(self.metadata)
|
||||||
if regional_client.buckets:
|
report.region = bucket.region
|
||||||
for bucket in regional_client.buckets:
|
report.resource_id = bucket.name
|
||||||
report = Check_Report(self.metadata)
|
if bucket.logging:
|
||||||
report.region = region
|
|
||||||
report.resource_id = bucket.name
|
|
||||||
if bucket.logging:
|
|
||||||
report.status = "PASS"
|
|
||||||
report.status_extended = f"S3 Bucket {bucket.name} has server access logging enabled."
|
|
||||||
else:
|
|
||||||
report.status = "FAIL"
|
|
||||||
report.status_extended = f"S3 Bucket {bucket.name} has server access logging disabled."
|
|
||||||
findings.append(report)
|
|
||||||
else:
|
|
||||||
report = Check_Report(self.metadata)
|
|
||||||
report.status = "PASS"
|
report.status = "PASS"
|
||||||
report.status_extended = "There are no S3 buckets."
|
report.status_extended = (
|
||||||
report.region = region
|
f"S3 Bucket {bucket.name} has server access logging enabled."
|
||||||
findings.append(report)
|
)
|
||||||
|
else:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = (
|
||||||
|
f"S3 Bucket {bucket.name} has server access logging disabled."
|
||||||
|
)
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
return findings
|
return findings
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ class S3:
|
|||||||
def __init__(self, audit_info):
|
def __init__(self, audit_info):
|
||||||
self.service = "s3"
|
self.service = "s3"
|
||||||
self.session = audit_info.audit_session
|
self.session = audit_info.audit_session
|
||||||
|
self.client = self.session.client(self.service)
|
||||||
self.audited_account = audit_info.audited_account
|
self.audited_account = audit_info.audited_account
|
||||||
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
||||||
self.__threading_call__(self.__list_buckets__)
|
self.buckets = self.__list_buckets__()
|
||||||
self.__threading_call__(self.__get_bucket_versioning__)
|
self.__threading_call__(self.__get_bucket_versioning__)
|
||||||
self.__threading_call__(self.__get_bucket_logging__)
|
self.__threading_call__(self.__get_bucket_logging__)
|
||||||
|
|
||||||
@@ -21,64 +22,50 @@ class S3:
|
|||||||
|
|
||||||
def __threading_call__(self, call):
|
def __threading_call__(self, call):
|
||||||
threads = []
|
threads = []
|
||||||
for regional_client in self.regional_clients:
|
for bucket in self.buckets:
|
||||||
threads.append(threading.Thread(target=call, args=(regional_client,)))
|
threads.append(threading.Thread(target=call, args=(bucket,)))
|
||||||
for t in threads:
|
for t in threads:
|
||||||
t.start()
|
t.start()
|
||||||
for t in threads:
|
for t in threads:
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
def __list_buckets__(self, regional_client):
|
def __list_buckets__(self):
|
||||||
logger.info("S3 - Listing buckets...")
|
logger.info("S3 - Listing buckets...")
|
||||||
try:
|
try:
|
||||||
list_buckets = regional_client.list_buckets()
|
|
||||||
buckets = []
|
buckets = []
|
||||||
|
list_buckets = self.client.list_buckets()
|
||||||
for bucket in list_buckets["Buckets"]:
|
for bucket in list_buckets["Buckets"]:
|
||||||
try:
|
bucket_region = self.client.get_bucket_location(Bucket=bucket["Name"])[
|
||||||
bucket_region = regional_client.get_bucket_location(
|
"LocationConstraint"
|
||||||
Bucket=bucket["Name"]
|
]
|
||||||
)["LocationConstraint"]
|
if not bucket_region: # If us-east-1, bucket_region is none
|
||||||
if regional_client.region == bucket_region or (
|
buckets.append(Bucket(bucket["Name"], "us-east-1"))
|
||||||
regional_client.region == "us-east-1" and not bucket_region
|
else:
|
||||||
): # If us-east-1, bucket_region is none
|
buckets.append(Bucket(bucket["Name"], bucket_region))
|
||||||
buckets.append(Bucket(bucket["Name"]))
|
return buckets
|
||||||
except Exception as error:
|
|
||||||
if error.__class__.__name__ != "NoSuchBucket":
|
|
||||||
logger.error(
|
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
|
||||||
)
|
|
||||||
regional_client.buckets = buckets
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(f"{bucket_region} -- {error.__class__.__name__}: {error}")
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __get_bucket_versioning__(self, regional_client):
|
def __get_bucket_versioning__(self, bucket):
|
||||||
logger.info("S3 - Get buckets versioning...")
|
logger.info("S3 - Get buckets versioning...")
|
||||||
try:
|
try:
|
||||||
if hasattr(regional_client, "buckets"):
|
regional_client = self.regional_clients[bucket.region]
|
||||||
for bucket in regional_client.buckets:
|
bucket_versioning = regional_client.get_bucket_versioning(
|
||||||
bucket_versioning = regional_client.get_bucket_versioning(
|
Bucket=bucket.name
|
||||||
Bucket=bucket.name
|
|
||||||
)
|
|
||||||
if "Status" in bucket_versioning:
|
|
||||||
if "Enabled" == bucket_versioning["Status"]:
|
|
||||||
bucket.versioning = True
|
|
||||||
except Exception as error:
|
|
||||||
logger.error(
|
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
|
||||||
)
|
)
|
||||||
|
if "Status" in bucket_versioning:
|
||||||
|
if "Enabled" == bucket_versioning["Status"]:
|
||||||
|
bucket.versioning = True
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(f"{bucket.region} -- {error.__class__.__name__}: {error}")
|
||||||
|
|
||||||
def __get_bucket_logging__(self, regional_client):
|
def __get_bucket_logging__(self, bucket):
|
||||||
logger.info("S3 - Get buckets logging...")
|
logger.info("S3 - Get buckets logging...")
|
||||||
try:
|
try:
|
||||||
if hasattr(regional_client, "buckets"):
|
regional_client = self.regional_clients[bucket.region]
|
||||||
for bucket in regional_client.buckets:
|
bucket_logging = regional_client.get_bucket_logging(Bucket=bucket.name)
|
||||||
bucket_logging = regional_client.get_bucket_logging(
|
if "LoggingEnabled" in bucket_logging:
|
||||||
Bucket=bucket.name
|
bucket.logging = True
|
||||||
)
|
|
||||||
if "LoggingEnabled" in bucket_logging:
|
|
||||||
bucket.logging = True
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
@@ -90,11 +77,13 @@ class Bucket:
|
|||||||
name: str
|
name: str
|
||||||
versioning: bool
|
versioning: bool
|
||||||
logging: bool
|
logging: bool
|
||||||
|
region: str
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name, region):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.versioning = False
|
self.versioning = False
|
||||||
self.logging = False
|
self.logging = False
|
||||||
|
self.region = region
|
||||||
|
|
||||||
|
|
||||||
s3_client = S3(current_audit_info)
|
s3_client = S3(current_audit_info)
|
||||||
|
|||||||
Reference in New Issue
Block a user