Skip to content

Commit

Permalink
Improve impact module (#55)
Browse files Browse the repository at this point in the history
* add-resource-AwsElastiCacheReplicationGroup

* remove-checks-from-context

* improve-impact-checks

* new-checks
  • Loading branch information
gabrielsoltz authored Nov 10, 2023
1 parent af0e8d2 commit 9711a4b
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 335 deletions.
48 changes: 25 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,28 +129,30 @@ The following are the impact criteria that MetaHub evaluates by default:

**Exposure** evaluates the how the the affected resource is exposed to other networks. For example, if the affected resource is public, if it is part of a VPC, if it has a public IP or if it is protected by a firewall or a security group.

| **Possible Statuses** | **Description** |
| ----------------------- | --------------- |
| 🔴 effectively-public | |
| 🟠 restricted-public | |
| 🟠 unrestricted-private | |
| 🟢 restricted | |
| 🔵 unknown | |
| **Possible Statuses** | **Description** |
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
| 🔴 effectively-public | The resource is effectively public from the Internet. |
| 🟠 restricted-public | The resource is public, but there is a restriction like a Security Group. |
| 🟠 unrestricted-private | The resource is private but unrestricted, like an open security group. |
| 🟠 launch-public | These are resources that can launch other resources as public. For example, an Auto Scaling group or a Subnet. |
| 🟢 restricted | The resource is restricted. |
| 🔵 unknown | The resource couldn't be checked |

## Access

**Access** evaluates the resource policy layer. MetaHub checks every available policy including: IAM Managed policies, IAM Inline policies, Resource Policies, and any association to other resources like IAM Roles which are then also analyzed as part of the affected resource. An unrestricted policy is not only an itsue itself of that policy, it afected any other resource which is using it.
**Access** evaluates the resource policy layer. MetaHub checks every available policy including: IAM Managed policies, IAM Inline policies, Resource Policies, Bucket ACLS, and any association to other resources like IAM Roles which its policies are also analyzed . An unrestricted policy is not only an itsue itself of that policy, it afected any other resource which is using it.

| **Possible Statuses** | **Description** |
| -------------------------- | --------------- |
| 🔴 unrestricted | |
| 🔴 untrusted-principal | |
| 🟠 unrestricted-principal | |
| 🟠 cross-account-principal | |
| 🟠 unrestricted-actions | |
| 🟠 dangerous-actions | |
| 🟢 restricted | |
| 🔵 unknown | |
| **Possible Statuses** | **Description** |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| 🔴 unrestricted | The principal is unrestricted, without any condition or restriction. |
| 🔴 untrusted-principal | The principal is an AWS Account, not part of your trusted accounts. |
| 🟠 unrestricted-principal | The principal is not restricted, defined with a wildcard. It could be conditions restricting it or other restrictions like s3 public blocks. |
| 🟠 cross-account-principal | The principal is from another AWS account. |
| 🟠 unrestricted-actions | The actions are defined using wildcards. |
| 🟠 dangerous-actions | Some dangerous actions are defined as part of this policy. |
| 🟠 unrestricted-service | The policy allows an AWS service as principal without restriction. |
| 🟢 restricted | The policy is restricted. |
| 🔵 unknown | The policy couldn't be checked. |

## Encryption

Expand All @@ -168,10 +170,10 @@ The following are the impact criteria that MetaHub evaluates by default:

| **Possible Statuses** | **Description** |
| --------------------- | --------------- |
| 🔴 not-attached | |
| 🔴 not-running | |
| 🟢 attached | |
| 🟢 running | |
| 🟠 attached | |
| 🟠 running | |
| 🟢 not-attached | |
| 🟢 not-running | |
| 🔵 unknown | |

## Environment
Expand All @@ -180,7 +182,7 @@ The following are the impact criteria that MetaHub evaluates by default:

| **Possible Statuses** | **Description** |
| --------------------- | --------------- |
| 🔴 production | |
| 🟠 production | |
| 🟢 staging | |
| 🟢 development | |
| 🔵 unknown | |
Expand Down
111 changes: 111 additions & 0 deletions lib/context/resources/AwsElastiCacheReplicationGroup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""ResourceType: AwsElastiCacheReplicationGroup"""

from botocore.exceptions import ClientError

from lib.AwsHelpers import get_boto3_client
from lib.context.resources.Base import ContextBase


class Metacheck(ContextBase):
def __init__(
self,
logger,
finding,
mh_filters_config,
sess,
drilled=False,
):
self.logger = logger
self.sess = sess
self.mh_filters_config = mh_filters_config
self.parse_finding(finding, drilled)
self.client = get_boto3_client(
self.logger, "elasticache", self.region, self.sess
)
# Describe
self.replication_group = self.describe_replication_groups()
if not self.replication_group:
return False
# Associated MetaChecks

def parse_finding(self, finding, drilled):
self.finding = finding
self.region = finding["Region"]
self.account = finding["AwsAccountId"]
self.partition = finding["Resources"][0]["Id"].split(":")[1]
self.resource_arn = finding["Resources"][0]["Id"]
self.resource_type = finding["Resources"][0]["Type"]
if finding["Resources"][0]["Id"].split(":")[5] == "replicationgroup":
self.resource_id = finding["Resources"][0]["Id"].split(":")[-1]
else:
self.logger.error(
"Error parsing elasticache cluster resource id: %s",
self.resource_arn,
)
self.resource_id = finding["Resources"][0]["Id"]

# Describe functions

def describe_replication_groups(self):
try:
response = self.client.describe_replication_groups(
ReplicationGroupId=self.resource_id,
)
if response["ReplicationGroups"]:
return response["ReplicationGroups"][0]
except ClientError as err:
if not err.response["Error"]["Code"] == "ReplicationGroupNotFoundFault":
self.logger.error(
"Failed to describe_replication_groups: {}, {}".format(
self.resource_id, err
)
)
return False

# Context Config

def endpoint(self):
endpoints = []
if self.replication_group:
if self.replication_group.get("ConfigurationEndpoint"):
return self.replication_group["ConfigurationEndpoint"]["Address"]
if endpoints:
return endpoints
return False

def at_rest_encryption(self):
if self.replication_group:
if self.replication_group["AtRestEncryptionEnabled"]:
return True
return False

def transit_encryption(self):
if self.replication_group:
if self.replication_group["TransitEncryptionEnabled"]:
return True
return False

def resource_policy(self):
return None

def trust_policy(self):
return None

def public(self):
if self.endpoint():
return True
return False

def associations(self):
associations = {}
return associations

def checks(self):
checks = {
"endpoint": self.endpoint(),
"rest_encrypted": self.at_rest_encryption(),
"transit_encrypted": self.transit_encryption(),
"public": self.public(),
"resource_policy": self.resource_policy(),
}
return checks
33 changes: 1 addition & 32 deletions lib/context/resources/AwsS3Bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,36 +157,6 @@ def describe_resource_policy(self):

# Context Config

def bucket_acl_cross_account(self):
acl_with_cross_account = []
if self.bucket_acl:
for grant in self.bucket_acl:
if grant["Grantee"]["Type"] == "CanonicalUser":
if grant["Grantee"]["ID"] != self.cannonical_user_id:
# perm = grant["Permission"]
acl_with_cross_account.append(grant)
if acl_with_cross_account:
return acl_with_cross_account
return False

def bucket_acl_public(self):
public_acls = []
if self.bucket_acl:
for grant in self.bucket_acl:
if grant["Grantee"]["Type"] == "Group":
# use only last part of URL as a key:
# http://acs.amazonaws.com/groups/global/AuthenticatedUsers
# http://acs.amazonaws.com/groups/global/AllUsers
who = grant["Grantee"]["URI"].split("/")[-1]
if who == "AllUsers" or who == "AuthenticatedUsers":
# perm = grant["Permission"]
# group all permissions (READ(_ACP), WRITE(_ACP), FULL_CONTROL) by AWS predefined groups
# public_acls.setdefault(who, []).append(perm)
public_acls.append(grant)
if public_acls:
return public_acls
return False

def public_access_block_enabled(self):
if self.bucket_public_access_block:
for key, value in self.bucket_public_access_block.items():
Expand Down Expand Up @@ -235,8 +205,7 @@ def checks(self):
"resource_policy": self.resource_policy,
"website_enabled": self.website_enabled(),
"bucket_acl": self.bucket_acl,
"bucket_acl_cross_account": self.bucket_acl_cross_account(),
"bucket_acl_public": self.bucket_acl_public(),
"cannonical_user_id": self.cannonical_user_id,
"public_access_block_enabled": self.public_access_block_enabled(),
"account_public_access_block_enabled": self.account_public_access_block_enabled(),
"public": self.public(),
Expand Down
1 change: 1 addition & 0 deletions lib/context/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
AwsEfsFileSystem,
AwsEksCluster,
AwsElastiCacheCacheCluster,
AwsElastiCacheReplicationGroup,
AwsElasticsearchDomain,
AwsElbLoadBalancer,
AwsElbv2LoadBalancer,
Expand Down
14 changes: 7 additions & 7 deletions lib/html/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
if (value === "effectively-public") {
color = "red";
emoji = "🔴";
} else if (value === "restricted-public" || value === "unrestricted-private") {
} else if (value === "restricted-public" || value === "unrestricted-private" || value === "launch-public") {
color = "orange";
emoji = "🟠";
} else if (value === "restricted") {
Expand All @@ -198,7 +198,7 @@
if (value === "unrestricted" || value === "untrusted-principal") {
color = "red";
emoji = "🔴";
} else if (value === "unrestricted-principal" || value === "cross-account-principal" || value === "unrestricted-actions" || value == "dangerous-actions" ) {
} else if (value === "unrestricted-principal" || value === "cross-account-principal" || value === "unrestricted-actions" || value == "dangerous-actions" || value == "unrestricted-service") {
color = "orange";
emoji = "🟠";
} else if (value === "restricted") {
Expand Down Expand Up @@ -245,11 +245,11 @@
var color;
var emoji;
if (value === "not-attached" || value === "not-running") {
color = "red";
emoji = "🔴";
} else if (value === "attached" || value === "running") {
color = "green";
emoji = "🟢";
} else if (value === "attached" || value === "running") {
color = "orange";
emoji = "🟠";
} else if (value === "unknown") {
color = "blue";
emoji = "🔵";
Expand All @@ -268,8 +268,8 @@
var color;
var emoji;
if (value === "production") {
color = "red";
emoji = "🔴";
color = "orange";
emoji = "🟠";
} else if (value === "staging" || value === "development") {
color = "green";
emoji = "🟢";
Expand Down
Loading

0 comments on commit 9711a4b

Please sign in to comment.