def default_allow_all_config(): return Config( rules=DEFAULT_RULES, aws_account_id="123456789012", stack_name="mockstack", rules_filters=[ Filter( rule_mode=RuleMode.ALLOWED, eval={ "and": [ { "exists": { "ref": "config.stack_name" } }, { "eq": [{ "ref": "config.stack_name" }, "mockstack"] }, ] }, rules=set(DEFAULT_RULES.keys()), ), ], )
def test_stack_whitelist_joins_all_whitelisted_matching_stack_names(self): mock_whitelist = { "stackname": [ "S3CrossAccountTrustRule", ], "notstackname": [ "IAMRolesOverprivilegedRule", ], "stackname_withmorethings": [ "CrossAccountTrustRule", "ManagedPolicyOnUserRule", ] } config = Config( project_name="project_mock", service_name="service_mock", stack_name="stackname_withmorethings", stack_whitelist=mock_whitelist, rules=DEFAULT_RULES.keys(), ) whitelisted_rules = config.get_whitelisted_rules() assert set(whitelisted_rules) == { "CrossAccountTrustRule", "ManagedPolicyOnUserRule", "S3CrossAccountTrustRule", }
def test_with_templates(cf_path): with open(cf_path) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) config = Config(project_name=cf_path, service_name=cf_path, stack_name=cf_path, rules=DEFAULT_RULES.keys()) # Scan result cfmodel = pycfmodel.parse(cf_template).resolve() rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(cfmodel, config) # Use this to print the stack if there is an IAMManagedPolicyWildcardActionRule an error if len(result.exceptions): print(cf_path) traceback.print_tb(result.exceptions[0].__traceback__) assert len(result.exceptions) == 0
def handler(event, context): """ Main entry point of the Lambda function. :param event: { "stack_template_url": String, "project": String, "stack": { "name": String, }, "event": String, "region": String, "account": { "name": String, "id": String, }, "user_agent": String, } :param context: :return: """ setup_logging() if not event.get("stack_template_url") and not event.get("stack", {}).get("name"): raise ValueError( "Invalid event type: no parameter 'stack_template_url' or 'stack::name' in request." ) result = Result() template = get_template(event) if not template: # In case of an invalid script log a warning and return early result.add_exception( TypeError( f"Malformed Event - could not parse!! Event: {str(event)}")) logger.exception( f"Malformed Event - could not parse!! Event: {str(event)}") return { "valid": True, "reason": "", "failed_rules": [], "exceptions": [x.args[0] for x in result.exceptions] } # Process Rules config = Config( project_name=event.get("project"), service_name=event.get("serviceName"), stack_name=event.get("stack", {}).get("name"), rules=DEFAULT_RULES.keys(), event=event.get("event"), template_url=event.get("stack_template_url", "N/A"), aws_region=event.get("region", "N/A"), aws_account_name=event.get("account", {}).get("name", "N/A"), aws_account_id=event.get("account", {}).get("id", "N/A"), aws_user_agent=event.get("user_agent", "N/A"), ) logger.info("Scan started for: {}; {}; {};".format(config.project_name, config.service_name, config.stack_name)) rules = [DEFAULT_RULES.get(rule)(config, result) for rule in config.rules] processor = RuleProcessor(*rules) processor.process_cf_template(template, config, result) perform_logging(result, config, event) return { "valid": result.valid, "reason": ",".join([ "{}-{}".format(r["rule"], r["reason"]) for r in result.failed_rules ]), "failed_rules": RuleProcessor.remove_debug_rules(rules=result.failed_rules), "exceptions": [x.args[0] for x in result.exceptions], "warnings": RuleProcessor.remove_debug_rules(rules=result.failed_monitored_rules), }
def init_cfripper() -> Tuple[Config, RuleProcessor]: config = Config(rules=DEFAULT_RULES.keys()) rule_processor = RuleProcessor( *[DEFAULT_RULES.get(rule)(config) for rule in config.rules]) return config, rule_processor
def test_with_templates(self): dir_path = os.path.dirname(os.path.realpath(__file__)) test_templates = glob.glob(f"{dir_path}/test_templates/*.*") for template in test_templates: with open(template) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) config = Config( project_name=template, service_name=template, stack_name=template, rules=DEFAULT_RULES.keys() ) # Scan result result = Result() rules = [DEFAULT_RULES.get(rule)(config, result) for rule in config.rules] processor = RuleProcessor(*rules) processor.process_cf_template(cf_template, config, result) # Use this to print the stack if there's an error if len(result.exceptions): print(template) traceback.print_tb(result.exceptions[0].__traceback__) no_resource_templates = ["vulgar_bad_syntax.yml", "rubbish.json"] if template.split("/")[-1] in no_resource_templates: assert len(result.exceptions) == 1 else: assert len(result.exceptions) == 0