def run_kubernetes_scan():
     current_dir = os.path.dirname(os.path.realpath(__file__))
     test_files_dir = os.path.join(current_dir, repo_name)
     runner_filter = RunnerFilter()
     runner_registry = RunnerRegistry(banner, runner_filter, k8_runner())
     reports = runner_registry.run(root_folder=test_files_dir)
     assert len(reports) > 0
 def test_multi_iac(self):
     current_dir = os.path.dirname(os.path.realpath(__file__))
     test_files_dir = current_dir + "/example_multi_iac"
     runner_filter = RunnerFilter(framework=None, checks=None, skip_checks=None)
     runner_registry = RunnerRegistry(
         banner, runner_filter, tf_runner(), cfn_runner(), k8_runner()
     )
     reports = runner_registry.run(root_folder=test_files_dir)
     for report in reports:
         self.assertGreater(len(report.passed_checks), 1)
 def verify_empty_report(self, test_files_dir, files=None):
     runner_filter = RunnerFilter(framework=None, checks=None, skip_checks=None)
     runner_registry = RunnerRegistry(
         banner, runner_filter, tf_runner(), cfn_runner(), k8_runner()
     )
     reports = runner_registry.run(root_folder=test_files_dir, files=files)
     for report in reports:
         self.assertEqual(report.failed_checks, [])
         self.assertEqual(report.skipped_checks, [])
         self.assertEqual(report.passed_checks, [])
     return runner_registry
    def test_resource_counts(self):
        current_dir = os.path.dirname(os.path.realpath(__file__))
        test_files_dir = current_dir + "/example_multi_iac"
        runner_filter = RunnerFilter(framework=None, checks=None, skip_checks=None)
        runner_registry = RunnerRegistry(
            banner, runner_filter, tf_runner(), cfn_runner(), k8_runner()
        )
        reports = runner_registry.run(root_folder=test_files_dir)

        # The number of resources that will get scan results. Note that this may change if we add policies covering new resource types.
        counts_by_type = {"kubernetes": 10, "terraform": 3, "cloudformation": 4}

        for report in reports:
            self.assertEqual(
                counts_by_type[report.check_type],
                report.get_summary()["resource_count"],
            )
Beispiel #5
0
from checkov.secrets.runner import Runner as secrets_runner
from checkov.serverless.runner import Runner as sls_runner
from checkov.terraform.plan_runner import Runner as tf_plan_runner
from checkov.terraform.runner import Runner as tf_graph_runner
from checkov.version import version

outer_registry = None

logging_init()
logger = logging.getLogger(__name__)
checkov_runners = [
    'cloudformation', 'terraform', 'kubernetes', 'serverless', 'arm',
    'terraform_plan', 'helm', 'dockerfile', 'secrets'
]

DEFAULT_RUNNERS = (tf_graph_runner(), cfn_runner(), k8_runner(), sls_runner(),
                   arm_runner(), tf_plan_runner(), helm_runner(),
                   dockerfile_runner(), secrets_runner())


def run(banner=checkov_banner, argv=sys.argv[1:]):
    default_config_paths = get_default_config_paths(sys.argv[1:])
    parser = ExtArgumentParser(
        description='Infrastructure as code static analysis',
        default_config_files=default_config_paths,
        config_file_parser_class=configargparse.YAMLConfigFileParser,
        add_env_var_help=True)
    add_parser_args(parser)
    config = parser.parse_args(argv)
    # bridgecrew uses both the urllib3 and requests libraries, while checkov uses the requests library.
    # Allow the user to specify a CA bundle to be used by both libraries.
Beispiel #6
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)
    runner_filter = RunnerFilter(
        framework=args.framework,
        checks=args.check,
        skip_checks=args.skip_check,
        download_external_modules=convert_str_to_bool(
            args.download_external_modules),
        external_modules_download_path=args.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(args.evaluate_variables))
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(),
                                         cfn_runner(), k8_runner(),
                                         sls_runner(), arm_runner(),
                                         tf_plan_runner())
    if args.version:
        print(version)
        return
    if args.bc_api_key:
        if args.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error(
                "--repo-id argument format should be 'organization/repository_name' E.g "
                "bridgecrewio/checkov")
        bc_integration.setup_bridgecrew_credentials(bc_api_key=args.bc_api_key,
                                                    repo_id=args.repo_id)

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error(
            "--check and --skip-check can not be applied together. please use only one of them"
        )
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    if args.directory:
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                bc_integration.commit_repository(args.branch)
            runner_registry.print_reports(scan_reports, args)
        return
    elif args.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=args.file,
            guidelines=guidelines)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            bc_integration.commit_repository(args.branch)
        runner_registry.print_reports(scan_reports, args)
    else:
        print(f"{banner}")

        bc_integration.onboarding()
Beispiel #7
0
    def run(self, root_folder, external_checks_dir=None, files=None, runner_filter=RunnerFilter(),
            collect_skip_comments=True):

        if external_checks_dir:
            for directory in external_checks_dir:
                registry.load_external_checks(directory)

        chart_directories = self.find_chart_directories(root_folder, files, runner_filter.excluded_paths)

        report = Report(self.check_type)

        chart_dir_and_meta = parallel_runner.run_function(
            lambda cd: (cd, self.parse_helm_chart_details(cd)), chart_directories)
        for chart_dir, chart_meta in chart_dir_and_meta:
            # chart_name = os.path.basename(chart_dir)
            logging.info(
                f"Processing chart found at: {chart_dir}, name: {chart_meta['name']}, version: {chart_meta['version']}")
            with tempfile.TemporaryDirectory() as target_dir:
                # dependency list is nicer to parse than dependency update.
                proc = subprocess.Popen([self.helm_command, 'dependency', 'list', chart_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # nosec
                o, e = proc.communicate()
                if e:
                    if "Warning: Dependencies" in str(e, 'utf-8'):
                        logging.info(
                            f"V1 API chart without Chart.yaml dependancies. Skipping chart dependancy list for {chart_meta['name']} at dir: {chart_dir}. Working dir: {target_dir}. Error details: {str(e, 'utf-8')}")
                    else:
                        logging.info(
                            f"Error processing helm dependancies for {chart_meta['name']} at source dir: {chart_dir}. Working dir: {target_dir}. Error details: {str(e, 'utf-8')}")

                self.parse_helm_dependency_output(o)

                try:
                    # --dependency-update needed to pull in deps before templating.
                    proc = subprocess.Popen([self.helm_command, 'template', '--dependency-update', chart_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # nosec
                    o, e = proc.communicate()
                    logging.debug(
                        f"Ran helm command to template chart output. Chart: {chart_meta['name']}. dir: {target_dir}. Output: {str(o, 'utf-8')}")

                except Exception:
                    logging.info(
                        f"Error processing helm chart {chart_meta['name']} at dir: {chart_dir}. Working dir: {target_dir}. Error details: {str(e, 'utf-8')}")

                output = str(o, 'utf-8')
                reader = io.StringIO(output)
                cur_source_file = None
                cur_writer = None
                last_line_dashes = False
                line_num = 1
                for s in reader:
                    s = s.rstrip()
                    if s == '---':
                        last_line_dashes = True
                        continue

                    if last_line_dashes:
                        # The next line should contain a "Source" comment saying the name of the file it came from
                        # So we will close the old file, open a new file, and write the dashes from last iteration plus this line

                        if not s.startswith('# Source: '):
                            raise Exception(f'Line {line_num}: Expected line to start with # Source: {s}')
                        source = s[10:]
                        if source != cur_source_file:
                            if cur_writer:
                                cur_writer.close()
                            file_path = os.path.join(target_dir, source)
                            parent = os.path.dirname(file_path)
                            os.makedirs(parent, exist_ok=True)
                            cur_source_file = source
                            cur_writer = open(os.path.join(target_dir, source), 'a')
                        cur_writer.write('---' + os.linesep)
                        cur_writer.write(s + os.linesep)

                        last_line_dashes = False
                    else:
                        if s.startswith('# Source: '):
                            raise Exception(f'Line {line_num}: Unexpected line starting with # Source: {s}')

                        if not cur_writer:
                            continue
                        else:
                            cur_writer.write(s + os.linesep)

                    line_num += 1

                if cur_writer:
                    cur_writer.close()

                try:
                    k8s_runner = k8_runner()
                    chart_results = k8s_runner.run(target_dir, external_checks_dir=external_checks_dir,
                                                   runner_filter=runner_filter, helmChart=chart_meta['name'])
                    logging.debug(f"Sucessfully ran k8s scan on {chart_meta['name']}. Scan dir : {target_dir}")
                    report.failed_checks += chart_results.failed_checks
                    report.passed_checks += chart_results.passed_checks
                    report.parsing_errors += chart_results.parsing_errors
                    report.skipped_checks += chart_results.skipped_checks
                    report.resources.update(chart_results.resources)

                except Exception as e:
                    logging.warning(e, stack_info=True)
                    with tempfile.TemporaryDirectory() as save_error_dir:
                        logging.debug(
                            f"Error running k8s scan on {chart_meta['name']}. Scan dir: {target_dir}. Saved context dir: {save_error_dir}")
                        shutil.move(target_dir, save_error_dir)

                        ## TODO: Export helm dependancies for the chart we've extracted in chart_dependencies
        return report
Beispiel #8
0
def run(banner=checkov_banner):
    parser = argparse.ArgumentParser(
        description='Infrastructure as code static analysis')
    parser.add_argument('-v', '--version', help='version', action='store_true')
    parser.add_argument(
        '-d',
        '--directory',
        action='append',
        help=
        'IaC root directory (can not be used together with --file). Can be repeated'
    )
    parser.add_argument(
        '-f',
        '--file',
        action='append',
        help='IaC file(can not be used together with --directory)')
    parser.add_argument(
        '--external-checks-dir',
        action='append',
        help='Directory for custom checks to be loaded. Can be repeated')
    parser.add_argument('-l',
                        '--list',
                        help='List checks',
                        action='store_true')
    parser.add_argument(
        '-o',
        '--output',
        nargs='?',
        choices=['cli', 'json', 'junitxml', 'github_failed_only'],
        default='cli',
        help='Report output format')
    parser.add_argument(
        '--framework',
        help=
        'filter scan to run only on a specific infrastructure code frameworks',
        choices=['cloudformation', 'terraform', 'kubernetes', 'all'],
        default='all')
    parser.add_argument(
        '-c',
        '--check',
        help=
        'filter scan to run only on a specific check identifier(whitelist), You can '
        'specify multiple checks separated by comma delimiter',
        default=None)
    parser.add_argument(
        '--skip-check',
        help=
        'filter scan to run on all check but a specific check identifier(blacklist), You can '
        'specify multiple checks separated by comma delimiter',
        default=None)
    parser.add_argument('-s',
                        '--soft-fail',
                        help='Runs checks but suppresses error code',
                        action='store_true')
    parser.add_argument('--bc-api-key', help='Bridgecrew API key')
    parser.add_argument(
        '--repo-id',
        help=
        'Identity string of the repository, with form <repo_owner>/<repo_name>'
    )
    parser.add_argument(
        '-b',
        '--branch',
        help=
        "Selected branch of the persisted repository. Only has effect when using the --bc-api-key flag",
        default='master')
    args = parser.parse_args()
    bc_integration = BcPlatformIntegration()
    runner_filter = RunnerFilter(framework=args.framework,
                                 checks=args.check,
                                 skip_checks=args.skip_check)
    runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(),
                                     cfn_runner(), k8_runner())
    if args.version:
        print(version)
        return
    if args.bc_api_key:
        if args.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
            if len(args.repo_id.split('/')) != 2:
                parser.error(
                    "--repo-id argument format should be 'organization/repository_name' E.g "
                    "bridgecrewio/checkov")
        bc_integration.setup_bridgecrew_credentials(bc_api_key=args.bc_api_key,
                                                    repo_id=args.repo_id)
    if args.check and args.skip_check:
        parser.error(
            "--check and --skip-check can not be applied together. please use only one of them"
        )
        return
    if args.list:
        print_checks()
        return
    if args.directory:
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=args.external_checks_dir,
                files=file)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                bc_integration.commit_repository(args.branch)
            runner_registry.print_reports(scan_reports, args)
        return
    elif args.file:
        scan_reports = runner_registry.run(
            external_checks_dir=args.external_checks_dir, files=args.file)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            bc_integration.commit_repository(args.branch)
        runner_registry.print_reports(scan_reports, args)
    else:
        print("No argument given. Try ` --help` for further information")
Beispiel #9
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)
    # Disable runners with missing system dependencies
    args.skip_framework = runnerDependencyHandler.disable_incompatible_runners(
        args.skip_framework)

    runner_filter = RunnerFilter(
        framework=args.framework,
        skip_framework=args.skip_framework,
        checks=args.check,
        skip_checks=args.skip_check,
        download_external_modules=convert_str_to_bool(
            args.download_external_modules),
        external_modules_download_path=args.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(args.evaluate_variables),
        runners=checkov_runners)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(),
                                         cfn_runner(), k8_runner(),
                                         sls_runner(), arm_runner(),
                                         tf_plan_runner(), helm_runner())
    if args.version:
        print(version)
        return
    if args.bc_api_key:
        if args.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error(
                "--repo-id argument format should be 'organization/repository_name' E.g "
                "bridgecrewio/checkov")

        source = os.getenv('BC_SOURCE', 'cli')
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source}, version = {source_version}')
        try:
            bc_integration.setup_bridgecrew_credentials(
                bc_api_key=args.bc_api_key,
                repo_id=args.repo_id,
                skip_fixes=args.skip_fixes,
                skip_suppressions=args.skip_suppressions,
                source=source,
                source_version=source_version)
        except Exception as e:
            logger.error(
                'An error occurred setting up the Bridgecrew platform integration. Please check your API token and try again.',
                exc_info=True)
            return

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error(
            "--check and --skip-check can not be applied together. please use only one of them"
        )
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    url = None

    if args.directory:
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines,
                bc_integration=bc_integration)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(args.branch)

            runner_registry.print_reports(scan_reports, args, url)
        return
    elif args.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=args.file,
            guidelines=guidelines,
            bc_integration=bc_integration)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(args.branch)
        runner_registry.print_reports(scan_reports, args, url)
    else:
        print(f"{banner}")

        bc_integration.onboarding()
Beispiel #10
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)

    # bridgecrew uses both the urllib3 and requests libraries, while checkov uses the requests library.
    # Allow the user to specify a CA bundle to be used by both libraries.
    bc_integration.setup_http_manager(args.ca_certificate)

    # Disable runners with missing system dependencies
    args.skip_framework = runnerDependencyHandler.disable_incompatible_runners(args.skip_framework)

    runner_filter = RunnerFilter(framework=args.framework, skip_framework=args.skip_framework, checks=args.check, skip_checks=args.skip_check,
                                 download_external_modules=convert_str_to_bool(args.download_external_modules),
                                 external_modules_download_path=args.external_modules_download_path,
                                 evaluate_variables=convert_str_to_bool(args.evaluate_variables), runners=checkov_runners)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_graph_runner(), cfn_runner(), k8_runner(), sls_runner(),
                                         arm_runner(), tf_plan_runner(), helm_runner(),dockerfile_runner())
    if args.version:
        print(version)
        return

    if args.bc_api_key == '':
        parser.error('The --bc-api-key flag was specified but the value was blank. If this value was passed as a secret, you may need to double check the mapping.')
    elif args.bc_api_key:
        logger.debug(f'Using API key ending with {args.bc_api_key[-8:]}')

        if args.repo_id is None:
            parser.error("--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error("--repo-id argument format should be 'organization/repository_name' E.g "
                         "bridgecrewio/checkov")

        source = os.getenv('BC_SOURCE', 'cli')
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source}, version = {source_version}')
        try:
            bc_integration.setup_bridgecrew_credentials(bc_api_key=args.bc_api_key, repo_id=args.repo_id, 
                                                        skip_fixes=args.skip_fixes,
                                                        skip_suppressions=args.skip_suppressions,
                                                        source=source, source_version=source_version, repo_branch=args.branch)
        except Exception as e:
            logger.error('An error occurred setting up the Bridgecrew platform integration. Please check your API token and try again.', exc_info=True)
            return
    else:
        logger.debug('No API key found. Scanning locally only.')

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error("--check and --skip-check can not be applied together. please use only one of them")
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    url = None

    if args.directory:
        exit_codes = []
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(root_folder=root_folder, external_checks_dir=external_checks_dir,
                                               files=file, guidelines=guidelines, bc_integration=bc_integration)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(args.branch)

            exit_codes.append(runner_registry.print_reports(scan_reports, args, url))

        exit_code = 1 if 1 in exit_codes else 0
        return exit_code
    elif args.file:
        scan_reports = runner_registry.run(external_checks_dir=external_checks_dir, files=args.file,
                                           guidelines=guidelines, bc_integration=bc_integration)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(args.branch)
        return runner_registry.print_reports(scan_reports, args, url)
    elif args.docker_image:
        if args.bc_api_key is None:
            parser.error("--bc-api-key argument is required when using --docker-image")
            return
        if args.dockerfile_path is None:
            parser.error("--dockerfile-path argument is required when using --docker-image")
            return
        if args.branch is None:
            parser.error("--branch argument is required when using --docker-image")
            return
        image_scanner.scan(args.docker_image, args.dockerfile_path)
    else:
        print(f"{banner}")

        bc_integration.onboarding()