def resource_invoke(self, resource: S3BucketPolicy, logical_id: str, extras: Optional[Dict] = None) -> Result: result = Result() for statement in resource.Properties.PolicyDocument._statement_as_list( ): for principal in statement.get_principal_list(): account_id = get_account_id_from_principal(principal) if not account_id: continue if account_id not in self.valid_principals: if statement.Condition and statement.Condition.dict(): logger.warning( f"Not adding {type(self).__name__} failure in {logical_id} " f"because there are conditions: {statement.Condition}" ) else: self.add_failure_to_result( result, self.REASON.format(logical_id, account_id), resource_ids={logical_id}, context={ "config": self._config, "extras": extras, "logical_id": logical_id, "resource": resource, "statement": statement, "principal": principal, "account_id": account_id, }, ) return result
def _do_statement_check(self, logical_id, statement): if statement.Effect == "Allow": for principal in statement.get_principal_list(): account_id = get_account_id_from_principal(principal) if ( # checks if principal is a canonical id and is whitelisted principal not in self.valid_principals # if it wasn't a canonical id and contains a valid account id and account_id not in self.valid_principals # if principal is an AWS service and not principal.endswith(".amazonaws.com")): if statement.Condition and statement.Condition.dict(): logger.warning( f"Not adding {type(self).__name__} failure in {logical_id} " f"because there are conditions: {statement.Condition}" ) elif not self._config.aws_account_id: logger.warning( f"Not adding {type(self).__name__} failure in {logical_id} " f"because no AWS Account ID was found in the config." ) elif "GETATT" in principal or "UNDEFINED_" in principal: self.add_failure( type(self).__name__, self.REASON.format(logical_id, principal), rule_mode=RuleMode.DEBUG, resource_ids={logical_id}, ) else: self.add_failure(type(self).__name__, self.REASON.format( logical_id, principal), resource_ids={logical_id})
def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: result = Result() for logical_id, resource in cfmodel.Resources.items(): if isinstance(resource, S3BucketPolicy): for statement in resource.Properties.PolicyDocument._statement_as_list( ): for principal in statement.get_principal_list(): account_id = get_account_id_from_principal(principal) if not account_id: continue if account_id not in self.valid_principals: if statement.Condition and statement.Condition.dict( ): logger.warning( f"Not adding {type(self).__name__} failure in {logical_id} " f"because there are conditions: {statement.Condition}" ) else: self.add_failure_to_result( result, self.REASON.format(logical_id, account_id), resource_ids={logical_id}, ) return result
def resource_invoke(self, resource: S3BucketPolicy, logical_id: str, extras: Optional[Dict] = None) -> Result: result = Result() for statement in resource.Properties.PolicyDocument._statement_as_list( ): for principal in statement.get_principal_list(): account_id = get_account_id_from_principal(principal) if not account_id: continue if account_id not in self.valid_principals: if statement.Condition and statement.Condition.dict(): # Ignoring condition checks since they will get reviewed in other rules and future improvements pass else: self.add_failure_to_result( result, self.REASON.format(logical_id, account_id), resource_ids={logical_id}, resource_types={resource.Type}, context={ "config": self._config, "extras": extras, "logical_id": logical_id, "resource": resource, "statement": statement, "principal": principal, "account_id": account_id, }, ) return result
def _do_statement_check(self, result: Result, logical_id: str, statement: Statement, filters_available_context: Dict, resource: Resource): if statement.Effect == "Allow": for principal in statement.get_principal_list(): account_id = get_account_id_from_principal(principal) filters_available_context["principal"] = principal filters_available_context["account_id"] = account_id if ( # checks if principal is a canonical id and is allowed principal not in self.valid_principals # if it wasn't a canonical id and contains a valid account id and account_id not in self.valid_principals # if principal is an AWS service and not principal.endswith(".amazonaws.com")): if statement.Condition and statement.Condition.dict(): # Ignoring condition checks since they will get reviewed in other rules and future improvements pass elif not self._config.aws_account_id: logger.warning( f"Not adding {type(self).__name__} failure in {logical_id} " f"because no AWS Account ID was found in the config." ) elif principal.startswith( "GETATT") or principal.startswith("UNDEFINED_"): self.add_failure_to_result( result, self.REASON.format(logical_id, principal), rule_mode=RuleMode.DEBUG, resource_ids={logical_id}, context=filters_available_context, resource_types={resource.Type}, ) else: self.add_failure_to_result( result, self.REASON.format(logical_id, principal), resource_ids={logical_id}, context=filters_available_context, resource_types={resource.Type}, )
def check_for_wildcards( self, result: Result, logical_id: str, resource: PolicyDocument, resource_type: str, extras: Optional[Dict] = None, ): for statement in resource.statement_as_list(): filtered_principals = statement.principals_with(self.FULL_REGEX) if statement.Effect == "Allow" and filtered_principals: for principal in filtered_principals: # if we can't find the account ID it might be a canonical ID identifier = get_account_id_from_principal( principal) or principal # Check if account ID / canonical ID is allowed. `self._get_allowed_from_config()` used here # to reduce number of false negatives and only allow exemptions for accounts # which belong to AWS Services (such as ELB and ElastiCache). if identifier in self._get_allowed_from_config(): continue if statement.Condition and statement.Condition.dict(): # Ignoring condition checks since they will get reviewed in other rules and future improvements continue else: self.add_failure_to_result( result, self.REASON_WILDCARD_PRINCIPAL.format( logical_id, principal), resource_ids={logical_id}, resource_types={resource_type}, context={ "config": self._config, "extras": extras, "logical_id": logical_id, "resource": resource, "statement": statement, "principal": principal, "account_id": identifier, }, )