Skip to content

Commit

Permalink
Feature/added filter by severity option (#295)
Browse files Browse the repository at this point in the history
* severity field on json output and option to filter results by severity

* fix type in option filter severity

* generate new example report

* add new dependencies to setup

* -f option on scan_policy_file and scan_multi_account and "critical" and "none" as options

* remove added dependencies

* removed js dependencies, fixed unit tests for new output format

* revert package-lock and fix mypy issues

* fix typo
  • Loading branch information
Melânia Pereira authored Jul 1, 2023
1 parent 2be95c0 commit 996ef75
Show file tree
Hide file tree
Showing 31 changed files with 53,920 additions and 18,721 deletions.
32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM --platform=linux/amd64 alpine:3.17.2

COPY . ./app

WORKDIR /app
### install prerequesites

RUN apk add --update --no-cache python3==3.10.11-r0 && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools==67.6.0
RUN apk add nodejs==18.16.0-r0
RUN apk add npm==9.1.2-r0
RUN apk add make==4.3-r1
###### install requirements.txt
RUN python3 -m pip install -r requirements.txt
### remove unnecassary
RUN rm -rf dist/
RUN rm -rf build/
RUN rm -rf *.egg-info
RUN find . -name '*.pyc' -delete
RUN find . -name '*.pyo' -delete
RUN find . -name '*.egg-link' -delete
RUN find . -name '*.pyc' -exec rm --force {} +
RUN find . -name '*.pyo' -exec rm --force {} +
#### seorate requirements
RUN python3 -m pip install --upgrade setuptools==67.6.0 wheel==0.40.0
RUN python3 -m setup -q sdist bdist_wheel
RUN python3 -m pip install -q ./dist/cloudsplaining*.tar.gz
######## NPM installation
RUN npm install

ENTRYPOINT ["cloudsplaining"]
23 changes: 18 additions & 5 deletions cloudsplaining/command/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
@click.option("-m", "--minimize", required=False, default=False, is_flag=True, help="Reduce the size of the HTML Report by pulling the Cloudsplaining Javascript code over the internet.")
@click.option("-aR", "--flag-all-risky-actions", is_flag=True, help="Flag all risky actions, regardless of whether resource ARN constraints or conditions are used.")
@click.option("-v", "--verbose", "verbosity", help="Log verbosity level.", count=True)
@click.option("-f", "--filter-severity", "severity", help="Filter the severity of findings to be reported.", multiple=True,type=click.Choice(['CRITICAL','HIGH', 'MEDIUM','LOW','NONE'], case_sensitive=False))

# fmt: on
def scan(
input_file: str,
Expand All @@ -46,6 +48,7 @@ def scan(
minimize: bool,
flag_all_risky_actions: bool,
verbosity: int,
severity: List[str],
) -> None: # pragma: no cover
"""
Given the path to account authorization details files and the exclusions config file, scan all inline and
Expand Down Expand Up @@ -85,6 +88,7 @@ def scan(
minimize=minimize,
flag_conditional_statements=flag_conditional_statements,
flag_resource_arn_statements=flag_resource_arn_statements,
severity=severity,
)
html_output_file = os.path.join(output, f"iam-report-{account_name}.html")
logger.info("Saving the report to %s", html_output_file)
Expand Down Expand Up @@ -122,6 +126,7 @@ def scan(
output,
write_data_files=True,
minimize=minimize,
severity=severity,
)
html_output_file = os.path.join(output, f"iam-report-{account_name}.html")
logger.info("Saving the report to %s", html_output_file)
Expand Down Expand Up @@ -153,6 +158,7 @@ def scan_account_authorization_details(
return_json_results: bool = False,
flag_conditional_statements: bool = False,
flag_resource_arn_statements: bool = False,
severity: List[str] = [],
) -> Any: # pragma: no cover
"""
Given the path to account authorization details files and the exclusions config file, scan all inline and
Expand All @@ -165,9 +171,11 @@ def scan_account_authorization_details(
)
check_authorization_details_schema(account_authorization_details_cfg)
authorization_details = AuthorizationDetails(
account_authorization_details_cfg, exclusions=exclusions,
account_authorization_details_cfg,
exclusions=exclusions,
flag_conditional_statements=flag_conditional_statements,
flag_resource_arn_statements=flag_resource_arn_statements
flag_resource_arn_statements=flag_resource_arn_statements,
severity=severity,
)
results = authorization_details.results

Expand Down Expand Up @@ -207,9 +215,9 @@ def scan_account_authorization_details(

if return_json_results:
return {
"iam_results" : authorization_details.results,
"iam_findings" : results,
"rendered_report" : rendered_report
"iam_results": authorization_details.results,
"iam_findings": results,
"rendered_report": rendered_report,
}
else:
return rendered_report
Expand All @@ -233,3 +241,8 @@ def get_authorization_files_in_directory(
if valid_schema:
new_file_list.append(str(file))
return new_file_list


@click.pass_context
def getSeverity(context: Any) -> Any:
return context.params["severity"]
17 changes: 15 additions & 2 deletions cloudsplaining/command/scan_multi_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def _accounts(self) -> Dict[str, str]:
@optgroup.group("Other Options", help="")
@optgroup.option("-w", "--write-data-file", is_flag=True, required=False, default=False, help="Save the cloudsplaining JSON-formatted data results.")
@click.option("-v", "--verbose", "verbosity", help="Log verbosity level.", count=True)
@click.option("-f", "--filter-severity", "severity", help="Filter the severity of findings to be reported.", multiple=True,type=click.Choice(['CRITICAL','HIGH', 'MEDIUM','LOW','NONE'], case_sensitive=False))

def scan_multi_account(
config_file: str,
profile: str,
Expand All @@ -60,6 +62,7 @@ def scan_multi_account(
output_bucket: str,
write_data_file: bool,
verbosity: int,
severity: List[str],
) -> None:
"""Scan multiple accounts via AssumeRole"""
set_log_level(verbosity)
Expand All @@ -79,6 +82,7 @@ def scan_multi_account(
output_directory=output_directory,
output_bucket=output_bucket,
write_data_file=write_data_file,
severity=severity,
)


Expand All @@ -90,6 +94,7 @@ def scan_accounts(
profile: Optional[str] = None,
output_directory: Optional[str] = None,
output_bucket: Optional[str] = None,
severity: List[str] = [],
) -> None:
"""Use this method as a library to scan multiple accounts"""
# TODO: Speed improvements? Multithreading? This currently runs sequentially.
Expand All @@ -102,12 +107,14 @@ def scan_accounts(
target_role_name=role_name,
exclusions=exclusions,
profile=profile,
severity=severity,
)
html_report = HTMLReport(
account_id=target_account_id,
account_name=target_account_name,
results=results,
minimize=True,
## minimize has to be false because changes were made on javascript code so it cannot be pulled over the internet, unless these changes are updated on the internet code
minimize=False,
)
rendered_report = html_report.get_html_report()
if not output_directory and not output_bucket:
Expand Down Expand Up @@ -159,6 +166,7 @@ def scan_account(
target_role_name: str,
exclusions: Exclusions,
profile: Optional[str] = None,
severity: List[str] = [],
) -> Dict[str, Dict[str, Any]]:
"""Scan a target account in one shot"""
account_authorization_details = download_account_authorization_details(
Expand All @@ -167,7 +175,7 @@ def scan_account(
profile=profile,
)
check_authorization_details_schema(account_authorization_details)
authorization_details = AuthorizationDetails(account_authorization_details, exclusions)
authorization_details = AuthorizationDetails(account_authorization_details, exclusions=exclusions,severity=severity)
results = authorization_details.results
return results

Expand Down Expand Up @@ -211,3 +219,8 @@ def get_exclusions(exclusions_file: Optional[str] = None) -> Exclusions:
else:
exclusions = DEFAULT_EXCLUSIONS
return exclusions


@click.pass_context
def getSeverity(context: Any) -> Any:
return context.params["severity"]
Loading

0 comments on commit 996ef75

Please sign in to comment.