Skip to content

Commit

Permalink
Merge branch 'main' into redefine-install-discover
Browse files Browse the repository at this point in the history
  • Loading branch information
GerevSec authored Sep 3, 2023
2 parents 542e4a9 + 5a51de9 commit 2477d01
Show file tree
Hide file tree
Showing 57 changed files with 4,974 additions and 2,249 deletions.
31 changes: 30 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
# CHANGELOG

## [Unreleased](https://github.com/bridgecrewio/checkov/compare/2.4.14...HEAD)
## [Unreleased](https://github.com/bridgecrewio/checkov/compare/2.4.22...HEAD)

## [2.4.22](https://github.com/bridgecrewio/checkov/compare/2.4.18...2.4.22) - 2023-08-31

### Feature

- **arm:** implement CKV_AZURE_112 for arm - [#5507](https://github.com/bridgecrewio/checkov/pull/5507)
- **arm:** implement CKV_AZURE_40 for ARM - [#5499](https://github.com/bridgecrewio/checkov/pull/5499)
- **arm:** implement CKV_AZURE_58 for ARM - [#5497](https://github.com/bridgecrewio/checkov/pull/5497)
- **arm:** implement CKV_AZURE_94 for arm - [#5508](https://github.com/bridgecrewio/checkov/pull/5508)

### Bug Fix

- **helm:** Changed error message to failure to better differentiate problems - [#5517](https://github.com/bridgecrewio/checkov/pull/5517)
- **terraform_json:** correctly parse data blocks in Terraform JSON - [#5509](https://github.com/bridgecrewio/checkov/pull/5509)
- **terraform:** continue processing of TF modules in the same file - [#5503](https://github.com/bridgecrewio/checkov/pull/5503)
- **terraform:** fix error type - [#5513](https://github.com/bridgecrewio/checkov/pull/5513)

## [2.4.18](https://github.com/bridgecrewio/checkov/compare/2.4.14...2.4.18) - 2023-08-30

### Feature

- **arm:** implement CKV_AZURE_100 for arm - [#5490](https://github.com/bridgecrewio/checkov/pull/5490)
- **arm:** implement CKV_AZURE_114 for arm - [#5489](https://github.com/bridgecrewio/checkov/pull/5489)
- **arm:** implement CKV_AZURE_130 for arm - [#5485](https://github.com/bridgecrewio/checkov/pull/5485)
- **arm:** implement CKV_AZURE_151 for arm - [#5484](https://github.com/bridgecrewio/checkov/pull/5484)

### Bug Fix

- **arm:** correctly handle json files with comments and output parsing errors - [#5495](https://github.com/bridgecrewio/checkov/pull/5495)

## [2.4.14](https://github.com/bridgecrewio/checkov/compare/2.4.10...2.4.14) - 2023-08-27

Expand Down
142 changes: 81 additions & 61 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![PyPI](https://img.shields.io/pypi/v/checkov)](https://pypi.org/project/checkov/)
[![Python Version](https://img.shields.io/pypi/pyversions/checkov)](#)
[![Terraform Version](https://img.shields.io/badge/tf-%3E%3D0.12.0-blue.svg)](#)
[![Downloads](https://pepy.tech/badge/checkov)](https://pepy.tech/project/checkov)
[![Downloads](https://static.pepy.tech/badge/checkov)](https://pepy.tech/project/checkov)
[![Docker Pulls](https://img.shields.io/docker/pulls/bridgecrew/checkov.svg)](https://hub.docker.com/r/bridgecrew/checkov)
[![slack-community](https://img.shields.io/badge/Slack-4A154B?style=plastic&logo=slack&logoColor=white)](https://slack.bridgecrew.io/)

Expand Down
21 changes: 21 additions & 0 deletions checkov/arm/checks/resource/CosmosDBHaveCMK.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from checkov.common.models.consts import ANY_VALUE
from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck


class CosmosDBHaveCMK(BaseResourceValueCheck):
def __init__(self):
name = "Ensure that Cosmos DB accounts have customer-managed keys to encrypt data at rest"
id = "CKV_AZURE_100"
supported_resources = ['Microsoft.DocumentDb/databaseAccounts']
categories = [CheckCategories.NETWORKING]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self):
return 'properties/keyVaultKeyUri'

def get_expected_value(self):
return ANY_VALUE


check = CosmosDBHaveCMK()
23 changes: 23 additions & 0 deletions checkov/arm/checks/resource/KeyBackedByHSM.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck


class KeyBackedByHSM(BaseResourceValueCheck):
def __init__(self):
name = "Ensure that key vault key is backed by HSM"
id = "CKV_AZURE_112"
supported_resources = ['Microsoft.KeyVault/vaults/keys']
categories = [CheckCategories.BACKUP_AND_RECOVERY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self):
return 'properties/kty'

def get_expected_value(self):
return 'RSA-HSM'

def get_expected_values(self):
return [self.get_expected_value(), 'EC-HSM']


check = KeyBackedByHSM()
21 changes: 21 additions & 0 deletions checkov/arm/checks/resource/KeyExpirationDate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck
from checkov.common.models.consts import ANY_VALUE


class KeyExpirationDate(BaseResourceValueCheck):
def __init__(self) -> None:
name = "Ensure that the expiration date is set on all keys"
id = "CKV_AZURE_40"
supported_resources = ['Microsoft.KeyVault/vaults/keys']
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self) -> str:
return 'properties/rotationPolicy/attributes/expiryTime'

def get_expected_value(self) -> str:
return ANY_VALUE


check = KeyExpirationDate()
17 changes: 17 additions & 0 deletions checkov/arm/checks/resource/MySQLGeoBackupEnabled.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck


class MySQLGeoBackupEnabled(BaseResourceValueCheck):
def __init__(self):
name = "Ensure that My SQL server enables geo-redundant backups"
id = "CKV_AZURE_94"
supported_resources = ['Microsoft.DBforMySQL/flexibleServers']
categories = [CheckCategories.BACKUP_AND_RECOVERY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self):
return 'properties/Backup/geoRedundantBackup'


check = MySQLGeoBackupEnabled()
24 changes: 24 additions & 0 deletions checkov/arm/checks/resource/SecretContentType.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

from typing import Any
from checkov.common.models.consts import ANY_VALUE
from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck


class SecretContentType(BaseResourceValueCheck):
def __init__(self):
name = "Ensure that key vault secrets have \"content_type\" set"
id = "CKV_AZURE_114"
supported_resources = ['Microsoft.KeyVault/vaults/secrets']
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self) -> str:
return "properties/contentType"

def get_expected_value(self) -> Any:
return ANY_VALUE


check = SecretContentType()
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import annotations


from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_negative_value_check import BaseResourceNegativeValueCheck


class SynapseWorkspaceEnablesManagedVirtualNetworks(BaseResourceNegativeValueCheck):
def __init__(self) -> None:
name = "Ensure that Azure Synapse workspaces enables managed virtual networks"
id = "CKV_AZURE_58"
supported_resources = ['Microsoft.Synapse/workspaces']
categories = [CheckCategories.NETWORKING]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self) -> str:
return 'properties/managedVirtualNetwork'

def get_forbidden_values(self) -> str:
return "default"


check = SynapseWorkspaceEnablesManagedVirtualNetworks()
2 changes: 1 addition & 1 deletion checkov/arm/graph_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def build_graph_from_source_directory(
) -> tuple[ArmLocalGraph, dict[str, dict[str, Any]]]:
file_paths = get_scannable_file_paths(root_folder=source_dir, excluded_paths=excluded_paths)
filepath_fn = lambda f: f"/{os.path.relpath(f, os.path.commonprefix((source_dir, f)))}"
definitions, _ = get_files_definitions(files=file_paths, filepath_fn=filepath_fn)
definitions, _, _ = get_files_definitions(files=file_paths, filepath_fn=filepath_fn)

local_graph = self.build_graph_from_definitions(definitions=definitions)

Expand Down
3 changes: 2 additions & 1 deletion checkov/arm/parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def parse(filename: str) -> tuple[dict[str, Any], list[tuple[int, str]]] | tuple
LOGGER.error(f"Template {filename} is malformed: {err.problem}")
LOGGER.error(f"Tried to parse {filename} as JSON", exc_info=True)
except YAMLError:
pass
LOGGER.info(f"Failed to parse {filename}")
LOGGER.debug("With Exception", exc_info=True)

if template is None or template_lines is None:
return None, None
Expand Down
4 changes: 3 additions & 1 deletion checkov/arm/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ def run(

files_list = get_scannable_file_paths(root_folder=root_folder, excluded_paths=runner_filter.excluded_paths)

self.definitions, self.definitions_raw = get_files_definitions(files_list, filepath_fn)
self.definitions, self.definitions_raw, parsing_errors = get_files_definitions(files_list, filepath_fn)

report.add_parsing_errors(parsing_errors)

if CHECKOV_CREATE_GRAPH and self.graph_registry and self.graph_manager:
logging.info("Creating ARM graph")
Expand Down
9 changes: 6 additions & 3 deletions checkov/arm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,22 @@ def get_scannable_file_paths(root_folder: str | None = None, excluded_paths: lis

def get_files_definitions(
files: Iterable[str], filepath_fn: Callable[[str], str] | None = None
) -> tuple[dict[str, dict[str, Any]], dict[str, list[tuple[int, str]]]]:
) -> tuple[dict[str, dict[str, Any]], dict[str, list[tuple[int, str]]], list[str]]:
"""Parses ARM files into its definitions and raw data"""

definitions = {}
definitions_raw = {}
parsing_errors = []

for file in files:
result = parse(file)

definition, definition_raw = result
if definition and definition_raw:
if definition is not None and definition_raw is not None: # this has to be a 'None' check
path = filepath_fn(file) if filepath_fn else file
definitions[path] = definition
definitions_raw[path] = definition_raw
else:
parsing_errors.append(os.path.normpath(file))

return definitions, definitions_raw
return definitions, definitions_raw, parsing_errors
2 changes: 1 addition & 1 deletion checkov/common/output/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def write_section(file: str, header: list[str], rows: list[dict[str, Any]], is_a
CSVSBOM.arrange_rows(rows)

with open(file, "w", newline="") as f:
print(f"Persisting SBOM to {os.path.abspath(file)}")
logging.info(f"Persisting SBOM to {os.path.abspath(file)}")
if is_api_key:
dict_writer = csv.DictWriter(f, fieldnames=header)
dict_writer.writeheader()
Expand Down
2 changes: 1 addition & 1 deletion checkov/helm/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def get_binary_output(
signal.alarm(0)
if e:
logging.warning(
f"Error processing helm chart {chart_name} at dir: {chart_dir}. Working dir: {target_dir}. Error details: {str(e, 'utf-8')}")
f"Failed processing helm chart {chart_name} at dir: {chart_dir}. Working dir: {target_dir}. Failure details: {str(e, 'utf-8')}")
return None, None
logging.debug(
f"Ran helm command to template chart output. Chart: {chart_name}. dir: {target_dir}. Output: {str(o, 'utf-8')}. Errors: {str(e, 'utf-8')}")
Expand Down
2 changes: 1 addition & 1 deletion checkov/terraform/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ def get_entity_context_and_evaluations(self, entity: dict[str, Any]) -> dict[str
logging.warning(f'Failed to find context for {".".join(entity_context_path)}')
return None
entity_context['definition_path'] = definition_path
except StopIteration:
except KeyError:
logging.error(f"Did not find context for key {full_file_path}")
return {}
return entity_context
Expand Down
13 changes: 9 additions & 4 deletions checkov/terraform/tf_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,15 @@ def _load_modules(self, root_dir: str, module_loader_registry: ModuleLoaderRegis
resolved_loc_list = self.module_to_resolved[current_nested_data]
self.module_to_resolved[current_nested_data] = resolved_loc_list

specified_vars = {k: v[0] if isinstance(v, list) and v else v for k, v in module_call_data.items()
if k != "source" and k != "version"}
skipped_a_module = self.should_skip_a_module(specified_vars, ignore_unresolved_params)
if skipped_a_module:
specified_vars = {
k: v[0] if isinstance(v, list) and v else v
for k, v in module_call_data.items()
if k != "source" and k != "version"
}
skip_module = self.should_skip_a_module(specified_vars, ignore_unresolved_params)
if skip_module:
# keep module skip info till the end
skipped_a_module = True
continue

version = self.get_module_version(module_call_data)
Expand Down
4 changes: 2 additions & 2 deletions checkov/terraform_json/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def prepare_definition(definition: dict[str, Any]) -> dict[str, Any]:
if block_name == COMMENT_FIELD_NAME or block_name in LINE_FIELD_NAMES:
continue

if block_type == BlockType.RESOURCE:
# resource have an extra nested level resource_type -> resource_name -> resource_config
if block_type in (BlockType.RESOURCE, BlockType.DATA):
# data/resource have an extra nested level resource_type -> resource_name -> resource_config
for resource_name, resource_config in config.items():
if resource_name in IGNORE_FILED_NAMES:
continue
Expand Down
4 changes: 2 additions & 2 deletions checkov/terraform_json/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from checkov.terraform.checks.resource.registry import resource_registry
from checkov.terraform.graph_builder.local_graph import TerraformLocalGraph
from checkov.terraform.runner import Runner as TerraformRunner
from checkov.terraform_json.utils import get_scannable_file_paths, TF_JSON_POSSIBLE_FILE_ENDINGS, create_definitions
from checkov.terraform_json.utils import get_scannable_file_paths, create_definitions

if TYPE_CHECKING:
from checkov.common.graph.checks_infra.registry import BaseRegistry
Expand Down Expand Up @@ -48,7 +48,7 @@ def __init__(
external_registries=external_registries,
source=source,
)
self.file_extensions = TF_JSON_POSSIBLE_FILE_ENDINGS # override what gets set from the TF runner
self.file_extensions = (".json",) # just '.json' not 'tf.json' otherwise it will be filtered out
self.graph_registry = get_graph_checks_registry(super().check_type)

self.definitions: dict[str, dict[str, Any]] = {} # type:ignore[assignment] # need to check, how to support subclass differences
Expand Down
2 changes: 1 addition & 1 deletion checkov/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = '2.4.15'
version = '2.4.23'
Loading

0 comments on commit 2477d01

Please sign in to comment.