Skip to content

Commit

Permalink
Impact scoring (#56)
Browse files Browse the repository at this point in the history
* AwsEc2Subnet-improvements

* handle-unknown

* update-impact-scores
  • Loading branch information
gabrielsoltz committed Nov 16, 2023
1 parent 9711a4b commit 5df3607
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 15 deletions.
30 changes: 16 additions & 14 deletions lib/config/impact.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Score: Score for this value

status:
weight: 10
weight: 50
values:
- attached:
score: 1
Expand All @@ -21,43 +21,45 @@ status:
score: 0

exposure:
weight: 1
weight: 25
values:
- effectively-public:
score: 1
- restricted-public:
score: 0.4
- unknown-public:
score: 0
- unrestricted-private:
score: 0.5
score: 0.3
- launch-public:
score: 0.1
- restricted:
score: 0
- unknown:
score: 0

access:
weight: 1
weight: 25
values:
- unrestricted:
score: 1
- untrusted-principal:
score: 0.8
score: 0.7
- unrestricted-principal:
score: 0.5
score: 0.4
- cross-account-principal:
score: 0.5
- unrestricted-actions:
score: 0.5
score: 0.3
- dangerous-actions:
score: 0.5
score: 0.3
- unrestricted-actions:
score: 0.3
- unrestricted-service:
score: 0.1
- restricted:
score: 0
- unknown:
score: 0

encryption:
weight: 0.1
weight: 10
values:
- unencrypted:
score: 1
Expand All @@ -67,7 +69,7 @@ encryption:
score: 0

environment:
weight: 1
weight: 15
values:
- production:
score: 1
Expand Down
78 changes: 78 additions & 0 deletions lib/context/resources/AwsEc2Subnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def __init__(
self.subnet = self.describe_subnets()
if not self.subnet:
return False
self.all_network_interfaces = self.describe_network_interfaces()
self.network_interfaces = self._describe_network_interfaces_interfaces()
self.instances = self._describe_network_interfaces_instances()
# Associated MetaChecks
self.route_tables = self.describe_route_tables()

Expand Down Expand Up @@ -98,6 +101,52 @@ def describe_route_tables(self):

return route_tables

def describe_network_interfaces(self):
response = self.client.describe_network_interfaces(
Filters=[
{
"Name": "subnet-id",
"Values": [
self.resource_id,
],
},
],
)
return response["NetworkInterfaces"]

def _describe_network_interfaces_interfaces(self):
network_interfaces = {}
if self.all_network_interfaces:
for network_interface in self.all_network_interfaces:
arn = generate_arn(
network_interface["NetworkInterfaceId"],
"ec2",
"network_interface",
self.region,
self.account,
self.partition,
)
network_interfaces[arn] = {}
return network_interfaces

def _describe_network_interfaces_instances(self):
instances = {}
if self.all_network_interfaces:
for network_interface in self.all_network_interfaces:
if network_interface.get("Attachment") and network_interface.get(
"Attachment"
).get("InstanceId"):
arn = generate_arn(
network_interface.get("Attachment").get("InstanceId"),
"ec2",
"instance",
self.region,
self.account,
self.partition,
)
instances[arn] = {}
return instances

# Context Config

def cidr(self):
Expand Down Expand Up @@ -129,9 +178,35 @@ def public(self):
return True
return False

def attached(self):
if self.subnet:
if self.network_interfaces:
return True
return False

def managed_services(self):
managed_services = []
if self.all_network_interfaces:
for network_interface in self.all_network_interfaces:
if network_interface.get("RequesterManaged"):
managed_services.append(network_interface.get("Description"))
return managed_services

def public_ips(self):
public_ips = []
if self.all_network_interfaces:
for network_interface in self.all_network_interfaces:
if network_interface.get("Association"):
public_ips.append(
network_interface.get("Association").get("PublicIp")
)
return public_ips

def associations(self):
associations = {
"route_tables": self.route_tables,
"network_interfaces": self.network_interfaces,
"instances": self.instances,
}
return associations

Expand All @@ -142,5 +217,8 @@ def checks(self):
"default": self.default(),
"public": self.public(),
"resource_policy": self.resource_policy(),
"public_ips": self.public_ips(),
"managed_services": self.managed_services(),
"attached": self.attached(),
}
return checks
10 changes: 10 additions & 0 deletions lib/impact/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ def check_bucket_acl_and_update(policy_json, policy_name):
):
return {"unknown": access_checks}

# Resources without policies are unknown.
if (
bucket_acl is None
and resource_policy is None
and inline_policies is None
and iam_policies is None
and iam_roles is None
):
return {"unknown": access_checks}

# We return the most critical access check
if "unrestricted" in access_checks:
return {"unrestricted": access_checks}
Expand Down
4 changes: 4 additions & 0 deletions lib/impact/encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def get_encryption(self, resource_arn, resource_values):
):
return {"unknown": encryption_checks}

# Resources without unencrypted resources and no encryption config are unknown.
if not unencrypted_resources and resource_encryption_config is None:
return {"unknown": encryption_checks}

if unencrypted_resources or resource_encryption_config is False:
return {"unencrypted": encryption_checks}

Expand Down
10 changes: 9 additions & 1 deletion lib/impact/exposure.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ def get_exposure(self, resource_arn, resource_values):
):
return {"unknown": exposure_checks}

# Resources without public config, security groups or resource policy are unknown.
if (
resource_public_config is None
and not unrestricted_ingress_rules
and not unrestricted_policy_access
):
return {"unknown": exposure_checks}

# Effectively Public If:
# 1. Public config and unrestricted SG ingress rules
# 2. Public config and no SG and no resource policy
Expand Down Expand Up @@ -154,7 +162,7 @@ def get_exposure(self, resource_arn, resource_values):

# Restricted Private If:
# 1. No public config and unrestricted SG ingress rules or unrestricted policy access
if not resource_public_config and (
if resource_public_config is False and (
unrestricted_ingress_rules or unrestricted_policy_access
):
return {"unrestricted-private": exposure_checks}
Expand Down

0 comments on commit 5df3607

Please sign in to comment.