mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(CIS checks): Complete CIS checks (#1461)
Co-authored-by: sergargar <sergio@verica.io> Co-authored-by: Nacho Rivera <59198746+n4ch04@users.noreply.github.com> Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra7138="7.138"
|
||||
CHECK_TITLE_extra7138="[extra7138] Ensure no Network ACLs allow ingress from 0.0.0.0/0 to any port"
|
||||
CHECK_SCORED_extra7138="NOT SCORED"
|
||||
CHECK_CIS_LEVEL_extra7138="LEVEL2"
|
||||
CHECK_SEVERITY_extra7138="High"
|
||||
CHECK_ASFF_TYPE_extra7138="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7138="AwsEc2NetworkAcl"
|
||||
CHECK_ALTERNATE_check7138="extra7138"
|
||||
CHECK_SERVICENAME_extra7138="ec2"
|
||||
CHECK_RISK_extra7138='Even having a perimeter firewall; having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.'
|
||||
CHECK_REMEDIATION_extra7138='Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.'
|
||||
CHECK_DOC_extra7138='https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html'
|
||||
CHECK_CAF_EPIC_extra7138='Infrastructure Security'
|
||||
|
||||
extra7138(){
|
||||
for regx in $REGIONS; do
|
||||
NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?((!PortRange) && (CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text 2>&1)
|
||||
if [[ $(echo "$NACL_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to describe network acls" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $NACL_LIST ]];then
|
||||
for NACL in $NACL_LIST;do
|
||||
textInfo "$regx: Found Network ACL: $NACL open to 0.0.0.0/0 for any port" "$regx" "$NACL"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Network ACL found with any port open to 0.0.0.0/0" "$regx" "$NACL"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra729="7.29"
|
||||
CHECK_TITLE_extra729="[extra729] Ensure there are no EBS Volumes unencrypted"
|
||||
CHECK_SCORED_extra729="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra729="EXTRA"
|
||||
CHECK_SEVERITY_extra729="Medium"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra729="AwsEc2Volume"
|
||||
CHECK_ALTERNATE_check729="extra729"
|
||||
CHECK_ASFF_COMPLIANCE_TYPE_extra729="ens-mp.info.3.aws.ebs.1"
|
||||
CHECK_SERVICENAME_extra729="ec2"
|
||||
CHECK_RISK_extra729='Data encryption at rest prevents data visibility in the event of its unauthorized access or theft.'
|
||||
CHECK_REMEDIATION_extra729='Encrypt all EBS volumes and Enable Encryption by default You can configure your AWS account to enforce the encryption of the new EBS volumes and snapshot copies that you create. For example; Amazon EBS encrypts the EBS volumes created when you launch an instance and the snapshots that you copy from an unencrypted snapshot.'
|
||||
CHECK_DOC_extra729='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html'
|
||||
CHECK_CAF_EPIC_extra729='Data Protection'
|
||||
|
||||
extra729(){
|
||||
# "Ensure there are no EBS Volumes unencrypted "
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_EBS_NON_ENC_VOLUMES=$($AWSCLI ec2 describe-volumes $PROFILE_OPT --region $regx --query 'Volumes[?Encrypted==`false`].VolumeId' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_OF_EBS_NON_ENC_VOLUMES" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
|
||||
textInfo "$regx: Access Denied trying to describe volumes" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_OF_EBS_NON_ENC_VOLUMES ]];then
|
||||
for volume in $LIST_OF_EBS_NON_ENC_VOLUMES; do
|
||||
textFail "$regx: $volume is not encrypted!" "$regx" "$volume"
|
||||
done
|
||||
fi
|
||||
LIST_OF_EBS_ENC_VOLUMES=$($AWSCLI ec2 describe-volumes $PROFILE_OPT --region $regx --query 'Volumes[?Encrypted==`true`].VolumeId' --output text)
|
||||
if [[ $LIST_OF_EBS_ENC_VOLUMES ]];then
|
||||
for volume in $LIST_OF_EBS_ENC_VOLUMES; do
|
||||
textPass "$regx: $volume is encrypted" "$regx" "$volume"
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "ec2_ebs_volume_encryption",
|
||||
"CheckTitle": "Ensure there are no EBS Volumes unencrypted.",
|
||||
"CheckType": ["Data Protection"],
|
||||
"ServiceName": "ec2",
|
||||
"SubServiceName": "volume",
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsEc2Volume",
|
||||
"Description": "Ensure there are no EBS Volumes unencrypted.",
|
||||
"Risk": "Data encryption at rest prevents data visibility in the event of its unauthorized access or theft.",
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Encrypt all EBS volumes and Enable Encryption by default You can configure your AWS account to enforce the encryption of the new EBS volumes and snapshot copies that you create. For example; Amazon EBS encrypts the EBS volumes created when you launch an instance and the snapshots that you copy from an unencrypted snapshot.",
|
||||
"Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.ec2.ec2_client import ec2_client
|
||||
|
||||
|
||||
class ec2_ebs_volume_encryption(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for volume in ec2_client.volumes:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = volume.region
|
||||
report.resource_id = volume.id
|
||||
if volume.encrypted:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"EBS Snapshot {volume.id} is encrypted."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"EBS Snapshot {volume.id} is unencrypted."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,92 @@
|
||||
from unittest import mock
|
||||
|
||||
from boto3 import resource
|
||||
from moto import mock_ec2
|
||||
|
||||
AWS_REGION = "us-east-1"
|
||||
|
||||
|
||||
class Test_ec2_ebs_volume_encryption:
|
||||
@mock_ec2
|
||||
def test_ec2_no_volumes(self):
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption import (
|
||||
ec2_ebs_volume_encryption,
|
||||
)
|
||||
|
||||
check = ec2_ebs_volume_encryption()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_ec2
|
||||
def test_ec2_unencrypted_volume(self):
|
||||
# Create EC2 Mocked Resources
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
volume = ec2.create_volume(Size=80, AvailabilityZone=f"{AWS_REGION}a")
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption import (
|
||||
ec2_ebs_volume_encryption,
|
||||
)
|
||||
|
||||
check = ec2_ebs_volume_encryption()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended == f"EBS Snapshot {volume.id} is unencrypted."
|
||||
)
|
||||
|
||||
@mock_ec2
|
||||
def test_ec2_encrypted_volume(self):
|
||||
# Create EC2 Mocked Resources
|
||||
ec2 = resource("ec2", region_name=AWS_REGION)
|
||||
volume = ec2.create_volume(
|
||||
Size=80, AvailabilityZone=f"{AWS_REGION}a", Encrypted=True
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_ebs_volume_encryption.ec2_ebs_volume_encryption import (
|
||||
ec2_ebs_volume_encryption,
|
||||
)
|
||||
|
||||
check = ec2_ebs_volume_encryption()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended == f"EBS Snapshot {volume.id} is encrypted."
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "ec2_network_acls_allow_ingress_any_port",
|
||||
"CheckTitle": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to any port.",
|
||||
"CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards", "CIS AWS Foundations Benchmark"],
|
||||
"ServiceName": "ec2",
|
||||
"SubServiceName": "networkacl",
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"Severity": "high",
|
||||
"ResourceType": "AwsEc2NetworkAcl",
|
||||
"Description": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to any port.",
|
||||
"Risk": "Even having a perimeter firewall, having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.",
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.",
|
||||
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Infrastructure Security",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.ec2.ec2_client import ec2_client
|
||||
from providers.aws.services.ec2.lib.network_acls import check_network_acl
|
||||
|
||||
|
||||
class ec2_network_acls_allow_ingress_any_port(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
tcp_protocol = "-1"
|
||||
check_port = 0
|
||||
for network_acl in ec2_client.network_acls:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = network_acl.region
|
||||
report.resource_id = network_acl.id
|
||||
# If some entry allows it, that ACL is not securely configured
|
||||
if not check_network_acl(network_acl.entries, tcp_protocol, check_port):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Network ACL {network_acl.id} has not every port open to the Internet."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Network ACL {network_acl.id} has every port open to the Internet."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,153 @@
|
||||
from unittest import mock
|
||||
|
||||
from boto3 import client
|
||||
from moto import mock_ec2
|
||||
|
||||
AWS_REGION = "us-east-1"
|
||||
|
||||
|
||||
class Test_ec2_network_acls_allow_ingress_any_port:
|
||||
@mock_ec2
|
||||
def test_ec2_default_nacls(self):
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port import (
|
||||
ec2_network_acls_allow_ingress_any_port,
|
||||
)
|
||||
|
||||
check = ec2_network_acls_allow_ingress_any_port()
|
||||
result = check.execute()
|
||||
|
||||
# One default nacl per region
|
||||
assert len(result) == 23
|
||||
|
||||
@mock_ec2
|
||||
def test_ec2_non_default_compliant_nacl(self):
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port import (
|
||||
ec2_network_acls_allow_ingress_any_port,
|
||||
)
|
||||
|
||||
check = ec2_network_acls_allow_ingress_any_port()
|
||||
result = check.execute()
|
||||
|
||||
# One default sg per region
|
||||
assert len(result) == 23
|
||||
|
||||
# by default nacls are public
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network ACL {result[0].resource_id} has every port open to the Internet."
|
||||
)
|
||||
|
||||
@mock_ec2
|
||||
def test_ec2_non_compliant_nacl(self):
|
||||
# Create EC2 Mocked Resources
|
||||
ec2_client = client("ec2", region_name=AWS_REGION)
|
||||
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
|
||||
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
|
||||
"NetworkAclId"
|
||||
]
|
||||
ec2_client.create_network_acl_entry(
|
||||
NetworkAclId=nacl_id,
|
||||
RuleNumber=100,
|
||||
Protocol="-1",
|
||||
RuleAction="allow",
|
||||
Egress=False,
|
||||
CidrBlock="0.0.0.0/0",
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port import (
|
||||
ec2_network_acls_allow_ingress_any_port,
|
||||
)
|
||||
|
||||
check = ec2_network_acls_allow_ingress_any_port()
|
||||
result = check.execute()
|
||||
|
||||
# One default sg per region + default of new VPC + new NACL
|
||||
assert len(result) == 25
|
||||
# Search changed sg
|
||||
for nacl in result:
|
||||
print(nacl.status)
|
||||
if nacl.resource_id == nacl_id:
|
||||
assert nacl.status == "FAIL"
|
||||
assert (
|
||||
nacl.status_extended
|
||||
== f"Network ACL {nacl_id} has every port open to the Internet."
|
||||
)
|
||||
|
||||
@mock_ec2
|
||||
def test_ec2_compliant_nacl(self):
|
||||
# Create EC2 Mocked Resources
|
||||
ec2_client = client("ec2", region_name=AWS_REGION)
|
||||
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
|
||||
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
|
||||
"NetworkAclId"
|
||||
]
|
||||
ec2_client.create_network_acl_entry(
|
||||
NetworkAclId=nacl_id,
|
||||
RuleNumber=100,
|
||||
Protocol="-1",
|
||||
RuleAction="allow",
|
||||
Egress=False,
|
||||
CidrBlock="10.0.0.2/32",
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port.ec2_client",
|
||||
new=EC2(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.ec2.ec2_network_acls_allow_ingress_any_port.ec2_network_acls_allow_ingress_any_port import (
|
||||
ec2_network_acls_allow_ingress_any_port,
|
||||
)
|
||||
|
||||
check = ec2_network_acls_allow_ingress_any_port()
|
||||
result = check.execute()
|
||||
|
||||
# One default sg per region + default of new VPC + new NACL
|
||||
assert len(result) == 25
|
||||
# Search changed sg
|
||||
for nacl in result:
|
||||
print(nacl.status)
|
||||
if nacl.resource_id == nacl_id:
|
||||
assert nacl.status == "PASS"
|
||||
assert (
|
||||
nacl.status_extended
|
||||
== f"Network ACL {nacl_id} has not every port open to the Internet."
|
||||
)
|
||||
@@ -14,9 +14,9 @@
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"NativeIaC": "https://docs.bridgecrew.io/docs/ensure-aws-nacl-does-not-allow-ingress-from-00000-to-port-22#cloudformation",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-aws-nacl-does-not-allow-ingress-from-00000-to-port-22#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.",
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"NativeIaC": "https://docs.bridgecrew.io/docs/ensure-aws-nacl-does-not-allow-ingress-from-00000-to-port-3389#cloudformation",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-aws-nacl-does-not-allow-ingress-from-00000-to-port-3389#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.",
|
||||
|
||||
@@ -7,21 +7,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
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
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "-1")
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "-1"):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has all ports open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
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)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
|
||||
from providers.aws.services.ec2.ec2_client import ec2_client
|
||||
from providers.aws.services.ec2.lib.security_groups import check_security_group
|
||||
|
||||
@@ -9,21 +8,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21(Check)
|
||||
findings = []
|
||||
check_ports = [20, 21]
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not FTP ports 20 and 21 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "tcp", check_ports):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has FTP ports 20 and 21 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not FTP ports 20 and 21 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
findings.append(report)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -8,21 +8,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22(Check):
|
||||
findings = []
|
||||
check_ports = [22]
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
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
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "tcp", check_ports):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the SSH port 22 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
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)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -8,21 +8,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389(Check):
|
||||
findings = []
|
||||
check_ports = [3389]
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
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
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "tcp", check_ports):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Microsoft RDP port 3389 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
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)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -8,21 +8,18 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306(Check
|
||||
findings = []
|
||||
check_ports = [3306]
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
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."
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "tcp", check_ports):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the MySQL port 3306 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
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)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -8,21 +8,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483
|
||||
findings = []
|
||||
check_ports = [1521, 2483]
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
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."
|
||||
# Loop through every security group's ingress rule and check it
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "tcp", check_ports)
|
||||
# Check
|
||||
if public:
|
||||
if check_security_group(ingress_rule, "tcp", check_ports):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Oracle ports 1521 and 2483 open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
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)
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -7,21 +7,18 @@ class ec2_securitygroup_default_restrict_traffic(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for security_group in ec2_client.security_groups:
|
||||
public = False
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = security_group.region
|
||||
report.resource_id = security_group.id
|
||||
# Find default security group
|
||||
if security_group.name == "default":
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Default Security Group ({security_group.id}) is not open to the Internet."
|
||||
for ingress_rule in security_group.ingress_rules:
|
||||
public = check_security_group(ingress_rule, "-1")
|
||||
if public:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Default Security Group ({security_group.id}) is open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Default Security Group ({security_group.id}) is not open to the Internet."
|
||||
report.resource_id = security_group.id
|
||||
if check_security_group(ingress_rule, "-1"):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Default Security Group ({security_group.id}) is open to the Internet."
|
||||
break
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -23,6 +23,8 @@ class EC2:
|
||||
self.__get_snapshot_public__()
|
||||
self.elastic_ips = []
|
||||
self.__threading_call__(self.__describe_elastic_ips__)
|
||||
self.volumes = []
|
||||
self.__threading_call__(self.__describe_volumes__)
|
||||
|
||||
def __get_session__(self):
|
||||
return self.session
|
||||
@@ -164,7 +166,7 @@ class EC2:
|
||||
)
|
||||
|
||||
def __describe_elastic_ips__(self, regional_client):
|
||||
logger.info("EC2 - Describing Security Groups...")
|
||||
logger.info("EC2 - Describing Network Interfaces...")
|
||||
try:
|
||||
describe_network_interfaces_paginator = regional_client.get_paginator(
|
||||
"describe_network_interfaces"
|
||||
@@ -186,6 +188,26 @@ class EC2:
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_volumes__(self, regional_client):
|
||||
logger.info("EC2 - Describing Volumes...")
|
||||
try:
|
||||
describe_volumes_paginator = regional_client.get_paginator(
|
||||
"describe_volumes"
|
||||
)
|
||||
for page in describe_volumes_paginator.paginate():
|
||||
for volume in page["Volumes"]:
|
||||
self.volumes.append(
|
||||
Volume(
|
||||
volume["VolumeId"],
|
||||
regional_client.region,
|
||||
volume["Encrypted"],
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Instance:
|
||||
@@ -236,6 +258,18 @@ class Snapshot:
|
||||
self.public = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class Volume:
|
||||
id: str
|
||||
region: str
|
||||
encrypted: bool
|
||||
|
||||
def __init__(self, id, region, encrypted):
|
||||
self.id = id
|
||||
self.region = region
|
||||
self.encrypted = encrypted
|
||||
|
||||
|
||||
@dataclass
|
||||
class SecurityGroup:
|
||||
name: str
|
||||
|
||||
Reference in New Issue
Block a user