Skip to content

Commit

Permalink
Merge pull request #151 from Skyscanner/blocked-wildcard-resource-res…
Browse files Browse the repository at this point in the history
…ource-exemptions

Update Wildcard Resource rule to allow for certain resources to be excluded
  • Loading branch information
ocrawford555 committed Feb 10, 2021
2 parents 169b652 + 5cd7f17 commit 4c0d1b3
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

## [0.23.3] - 2021-02-11
### Improvements
- Update `WildcardResourceRule` to allow for certain resources to be excluded.

## [0.23.2] - 2021-02-04
### Bugfix
- `GenericWildcardPrincipalRule` to ignore account IDs where full or partial wildcard is required in the Principal.
Expand Down
2 changes: 1 addition & 1 deletion cfripper/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
VERSION = (0, 23, 2)
VERSION = (0, 23, 3)

__version__ = ".".join(map(str, VERSION))
36 changes: 18 additions & 18 deletions cfripper/rules/wildcard_resource_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@
import logging
from typing import Dict, Optional

from pycfmodel.model.cf_model import CFModel
from pycfmodel.model.resources.generic_resource import GenericResource
from pycfmodel.model.resources.iam_role import IAMRole
from pycfmodel.model.resources.kms_key import KMSKey
from pycfmodel.model.resources.properties.policy_document import PolicyDocument
from pycfmodel.model.resources.properties.statement import Statement
from pycfmodel.model.resources.resource import Resource

from cfripper.cloudformation_actions_only_accepts_wildcard import CLOUDFORMATION_ACTIONS_ONLY_ACCEPTS_WILDCARD
from cfripper.config.regex import REGEX_IS_STAR
from cfripper.model.enums import RuleGranularity
from cfripper.model.result import Result
from cfripper.rules.base_rules import Rule
from cfripper.rules.base_rules import ResourceSpecificRule

logger = logging.getLogger(__file__)


class WildcardResourceRule(Rule):
class WildcardResourceRule(ResourceSpecificRule):
"""
Generic rule that detects actions that accept a resource and are using a wildcard.
Expand All @@ -41,27 +41,27 @@ class WildcardResourceRule(Rule):
|`action` | `Optional[str]` | Action that has a wildcard resource. If None, means all actions |
"""

RESOURCE_TYPES = (Resource,)
REASON_WITH_POLICY_NAME = '"{}" is using a wildcard resource in "{}" for "{}"'
REASON_WITHOUT_POLICY_NAME = '"{}" is using a wildcard resource for "{}"'
REASON_ALL_ACTIONS_WITH_POLICY_NAME = '"{}" is using a wildcard resource in "{}" allowing all actions'
REASON_ALL_ACTIONS_WITHOUT_POLICY_NAME = '"{}" is using a wildcard resource allowing all actions'

def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
def resource_invoke(self, resource: Resource, logical_id: str, extras: Optional[Dict] = None) -> Result:
result = Result()
for logical_id, resource in cfmodel.Resources.items():
for policy in resource.policy_documents:
self._check_policy_document(result, logical_id, policy.policy_document, policy.name, extras)
if isinstance(resource, IAMRole):
self._check_policy_document(
result, logical_id, resource.Properties.AssumeRolePolicyDocument, None, extras
)
elif isinstance(resource, KMSKey):
self._check_policy_document(result, logical_id, resource.Properties.KeyPolicy, None, extras)
elif isinstance(resource, GenericResource):
if hasattr(resource, "Properties"):
policy_document = resource.Properties.get("PolicyDocument")
if policy_document:
self._check_policy_document(result, logical_id, PolicyDocument(**policy_document), None, extras)

for policy in resource.policy_documents:
self._check_policy_document(result, logical_id, policy.policy_document, policy.name, extras)
if isinstance(resource, IAMRole):
self._check_policy_document(result, logical_id, resource.Properties.AssumeRolePolicyDocument, None, extras)
elif isinstance(resource, KMSKey):
self._check_policy_document(result, logical_id, resource.Properties.KeyPolicy, None, extras)
elif isinstance(resource, GenericResource):
if hasattr(resource, "Properties"):
policy_document = resource.Properties.get("PolicyDocument")
if policy_document:
self._check_policy_document(result, logical_id, PolicyDocument(**policy_document), None, extras)

return result

def _check_policy_document(
Expand Down
14 changes: 14 additions & 0 deletions tests/rules/test_WildcardResourceRule.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from pycfmodel.model.resources.iam_policy import IAMPolicy

from cfripper.model.result import Failure
from cfripper.rules.wildcard_resource_rule import WildcardResourceRule
Expand Down Expand Up @@ -94,6 +95,19 @@ def test_kms_key_with_wildcard_resource_not_whitelisted_is_not_flagged(kms_key_w
assert result.failed_monitored_rules == []


def test_exclude_certain_resources_on_rule(iam_policy_with_wildcard_resource_and_wildcard_action):
# Any subclass of this rule may want to exclude certain resource types. As a test, let's exclude IAM Policies.
rule = WildcardResourceRule(None)
rule._config.stack_name = "stack3"
rule.all_cf_actions = set()
rule.EXCLUDED_RESOURCE_TYPES = (IAMPolicy,)
result = rule.invoke(iam_policy_with_wildcard_resource_and_wildcard_action)

assert result.valid
assert result.failed_rules == []
assert result.failed_monitored_rules == []


def test_policy_document_with_wildcard_resource_is_detected(iam_policy_with_wildcard_resource_and_wildcard_action):
rule = WildcardResourceRule(None)
rule._config.stack_name = "stack3"
Expand Down

0 comments on commit 4c0d1b3

Please sign in to comment.