Skip to content

Commit

Permalink
[resotocore][feat] Allow multiple result kinds for ReportCheck (#1862)
Browse files Browse the repository at this point in the history
  • Loading branch information
aquamatthias authored Dec 20, 2023
1 parent 54b5f52 commit 177ea49
Show file tree
Hide file tree
Showing 16 changed files with 119 additions and 117 deletions.
6 changes: 4 additions & 2 deletions resotocore/resotocore/report/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class ReportCheck:
provider: str
service: str
title: str
result_kind: str
result_kinds: List[str]
categories: List[str]
severity: ReportSeverity
risk: str
Expand All @@ -80,6 +80,8 @@ def environment(self, values: Json) -> Json:

def to_node(self) -> Json:
reported = to_js(self)
# backward compatibility
reported["result_kind"] = self.result_kinds[0]
return dict(id=self.id, kind="report_check", type="node", reported=reported)


Expand Down Expand Up @@ -153,7 +155,7 @@ def from_node(js: Json) -> CheckResult:
provider=reported["provider"],
service=reported["service"],
title=reported["title"],
result_kind=reported["result_kind"],
result_kinds=reported["result_kinds"],
categories=reported["categories"],
severity=ReportSeverity(reported["severity"]),
risk=reported["risk"],
Expand Down
3 changes: 2 additions & 1 deletion resotocore/resotocore/report/benchmark_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ def render_check_result(check_result: CheckResult, account: str) -> str:
failed = account in check_result.number_of_resources_failing_by_account
result = f"- {cross_mark if failed else check_mark} **{check.severity.name}**: {check.title}\n\n"
if failed:
kinds = ", ".join(f"`{k}`" for k in check.result_kinds)
result += f" - Risk: {check.risk}\n\n"
result += f" - There are {check_result.number_of_resources_failing_by_account[account]} `{check.result_kind}` "
result += f" - There are {check_result.number_of_resources_failing_by_account[account]} {kinds} "
result += "resources failing this check.\n\n"
result += (
f" - Remediation: {check.remediation.text}. See [Link]({check.remediation.url}) for more details.\n\n"
Expand Down
10 changes: 2 additions & 8 deletions resotocore/resotocore/report/inspector_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def inspection_matches(inspection: ReportCheck) -> bool:
(provider is None or provider == inspection.provider)
and (service is None or service == inspection.service)
and (category is None or category in inspection.categories)
and (kind is None or kind == inspection.result_kind)
and (kind is None or kind in inspection.result_kinds)
and (check_ids is None or inspection.id in check_ids)
and (context is None or context.includes_severity(inspection.severity))
)
Expand Down Expand Up @@ -285,9 +285,6 @@ async def __list_failing_resources(
# final environment: defaults are coming from the check and are eventually overriden in the config
env = inspection.environment(config)
account_id_prop = "ancestors.account.reported.id"
# if the result kind is an account, we need to use the id directly instead of walking the graph
if (result_kind := model.get(inspection.result_kind)) and "account" in result_kind.kind_hierarchy():
account_id_prop = "reported.id"

async def perform_search(search: str) -> AsyncIterator[Json]:
# parse query
Expand Down Expand Up @@ -374,11 +371,8 @@ async def __perform_check(
self, graph: GraphName, model: Model, inspection: ReportCheck, config: Json, context: CheckContext
) -> SingleCheckResult:
resources_by_account = defaultdict(list)
# if the result kind is an account, we need to use the id directly instead of walking the graph
is_account = (rk := model.get(inspection.result_kind)) and "account" in rk.kind_hierarchy()
account_id_path = NodePath.reported_id if is_account else NodePath.ancestor_account_id
async for resource in await self.__list_failing_resources(graph, model, inspection, config, context):
account_id = value_in_path(resource, account_id_path)
account_id = value_in_path(resource, NodePath.ancestor_account_id)
if account_id:
resources_by_account[account_id].append(bend(ReportResourceData, resource))
return resources_by_account
Expand Down
7 changes: 6 additions & 1 deletion resotocore/resotocore/report/report_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class ReportCheckConfig:
}
)
title: str = field(metadata={"description": "Title of the check."})
result_kind: str = field(metadata={"description": "Resulting kind this check will emit. Example: aws_ec2_instance"})
result_kinds: List[str] = field(
metadata={"description": "Resulting kind this check will emit. Example: aws_ec2_instance"}
)
categories: List[str] = field(metadata={"description": "Categories of the check. Example: ['security', 'cost']"})
severity: ReportSeverity = field(metadata={"description": "Severity of the check."})
risk: str = field(metadata={"description": "What is the risk associated with related resources."})
Expand Down Expand Up @@ -86,6 +88,9 @@ def report_check(pdr: str, svc: str, check: Json) -> ReportCheck:
cr["provider"] = pdr
cr["service"] = svc
cr["id"] = f"{pdr}_{svc}_{check['name']}"
# handle legacy result_kind
if "result_kind" in cr and "result_kinds" not in cr:
cr["result_kinds"] = [cr.pop("result_kind")]
return from_js(cr, ReportCheck)

pdr = js["provider"]
Expand Down
2 changes: 1 addition & 1 deletion resotocore/resotocore/static/report/check_template.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "",
"title": "",
"kind": "result kind returned by the query",
"result_kinds": ["result kind returned by the query"],
"categories": [
"insights",
"security",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "authorizers_enabled",
"title": "Check if API Gateway has configured authorizers.",
"result_kind": "aws_api_gateway_rest_api",
"result_kinds": ["aws_api_gateway_rest_api"],
"categories": ["security", "compliance"],
"risk": "If no authorizer is defined, anyone can use the service.",
"severity": "medium",
Expand All @@ -23,7 +23,7 @@
{
"name": "client_certificate_enabled",
"title": "Check if API Gateway has client certificate enabled to access your backend endpoint.",
"result_kind": "aws_api_gateway_stage",
"result_kinds": ["aws_api_gateway_stage"],
"categories": ["security", "compliance"],
"risk": "Man in the middle attacks are possible and other similar risks.",
"severity": "medium",
Expand All @@ -39,7 +39,7 @@
{
"name": "logging_enabled",
"title": "Check if API Gateway has logging enabled.",
"result_kind": "aws_api_gateway_stage",
"result_kinds": ["aws_api_gateway_stage"],
"categories": ["compliance"],
"risk": "If not enabled, monitoring of service use is not possible. Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms.",
"severity": "medium",
Expand All @@ -54,7 +54,7 @@
{
"name": "waf_acl_attached",
"title": "Check if API Gateway has a WAF ACL attached.",
"result_kind": "aws_api_gateway_stage",
"result_kinds": ["aws_api_gateway_stage"],
"categories": ["security"],
"risk": "Potential attacks and / or abuse of service for internet reachable services.",
"severity": "medium",
Expand Down
52 changes: 26 additions & 26 deletions resotocore/resotocore/static/report/checks/aws/aws_cloudtrail.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "logging_in_all_regions_enabled",
"title": "Ensure CloudTrail is enabled and set up for logging in all regions",
"result_kind": "aws_region",
"result_kinds": ["aws_region"],
"categories": [
"security",
"compliance"
Expand All @@ -23,7 +23,7 @@
{
"name": "log_file_validation_enabled",
"title": "Ensure CloudTrail log file validation is enabled",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -41,7 +41,7 @@
{
"name": "logs_s3_bucket_is_not_publicly_accessible",
"title": "Ensure the S3 bucket CloudTrail logs is not publicly accessible",
"result_kind": "aws_s3_bucket",
"result_kinds": ["aws_s3_bucket"],
"categories": [
"security",
"compliance"
Expand All @@ -59,7 +59,7 @@
{
"name": "no_logging_enabled",
"title": "Ensure CloudTrail has logging enabled",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -77,7 +77,7 @@
{
"name": "no_recent_log_event",
"title": "Ensure CloudTrail has log events in the configured duration",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -98,7 +98,7 @@
{
"name": "s3_bucket_logging_enabled",
"title": "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -116,7 +116,7 @@
{
"name": "uses_encryption_at_rest",
"title": "Ensure CloudTrail logs are encrypted at rest using KMS CMKs",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -134,7 +134,7 @@
{
"name": "s3_data_events_write_enabled",
"title": "Check all regions and make sure S3 buckets have Object-level logging for write events is enabled in CloudTrail.",
"result_kind": "aws_region",
"result_kinds": ["aws_region"],
"categories": [
"security",
"compliance"
Expand All @@ -152,7 +152,7 @@
{
"name": "s3_data_events_read_enabled",
"title": "Check all regions and make sure S3 buckets have Object-level logging for read events is enabled in CloudTrail.",
"result_kind": "aws_region",
"result_kinds": ["aws_region"],
"categories": [
"security",
"compliance"
Expand All @@ -170,7 +170,7 @@
{
"name": "log_metric_filters_unauthorized_api_calls",
"title": "Ensure a log metric filter and alarm exist for unauthorized API calls.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -188,7 +188,7 @@
{
"name": "log_metric_filters_sign_in_without_mfa",
"title": "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -206,7 +206,7 @@
{
"name": "log_metric_filters_console_login_no_mfa",
"title": "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -224,7 +224,7 @@
{
"name": "log_metric_filters_root_account_usage",
"title": "Ensure a log metric filter and alarm exist for usage of root account.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -242,7 +242,7 @@
{
"name": "log_metric_filters_iam_policy_changes",
"title": "Ensure a log metric filter and alarm exist for IAM policy changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -260,7 +260,7 @@
{
"name": "log_metric_filters_cloud_trail_configuration_changes",
"title": "Ensure a log metric filter and alarm exist for CloudTrail configuration changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -278,7 +278,7 @@
{
"name": "log_metric_filters_authentication_failures",
"title": "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -296,7 +296,7 @@
{
"name": "log_metric_filters_kms_key_deletion",
"title": "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created KMS CMKs.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -314,7 +314,7 @@
{
"name": "log_metric_filters_s3_bucket_policy_changes",
"title": "Ensure a log metric filter and alarm exist for S3 bucket policy changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -332,7 +332,7 @@
{
"name": "log_metric_filters_config_configuration_changes",
"title": "Ensure a log metric filter and alarm exist for AWS Config configuration changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -350,7 +350,7 @@
{
"name": "log_metric_filters_security_group_changes",
"title": "Ensure a log metric filter and alarm exist for security group changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -368,7 +368,7 @@
{
"name": "log_metric_filters_network_acl_changes",
"title": "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL).",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -386,7 +386,7 @@
{
"name": "log_metric_filters_network_gateway_changes",
"title": "Ensure a log metric filter and alarm exist for changes to network gateways.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -404,7 +404,7 @@
{
"name": "log_metric_filters_route_table_changes",
"title": "Ensure a log metric filter and alarm exist for route table changes",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -422,7 +422,7 @@
{
"name": "log_metric_filters_vpc_changes",
"title": "Ensure a log metric filter and alarm exist for VPC changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -440,7 +440,7 @@
{
"name": "log_metric_filters_aws_org_changes",
"title": "Ensure a log metric filter and alarm exist for AWS Organizations changes.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand All @@ -458,7 +458,7 @@
{
"name": "security_hub_enabled",
"title": "Check if Security Hub is enabled and its standard subscriptions.",
"result_kind": "aws_cloud_trail",
"result_kinds": ["aws_cloud_trail"],
"categories": [
"security",
"compliance"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "enabled_in_all_regions",
"title": "Ensure AWS Config is enabled in all regions.",
"result_kind": "aws_region",
"result_kinds": ["aws_region"],
"categories": ["security", "compliance"],
"risk": "The AWS configuration item history captured by AWS Config enables security analysis, resource change tracking and compliance auditing.",
"severity": "medium",
Expand Down
Loading

0 comments on commit 177ea49

Please sign in to comment.