Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
kentnsw committed Dec 1, 2022
2 parents 3d9bdee + c52daf8 commit 258af9f
Show file tree
Hide file tree
Showing 176 changed files with 6,275 additions and 1,657 deletions.
2 changes: 1 addition & 1 deletion .github/composites/docker-build-push/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ inputs:
default: false
poetry_version:
description: "Poetry Version to use"
default: "1.2.1"
default: "1.2.2"
trivy_version:
description: "Trivy version to use"
default: "0.5.4"
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "CI"
env:
POETRY_VERSION: "1.2.1"
POETRY_VERSION: "1.2.2"
on:
push:
branches:
Expand All @@ -10,7 +10,9 @@ on:
branches:
- master
- main

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
Lint:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion c7n/filters/iamaccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def check_actions(self):

@property
def whitelist_conditions(self):
return self.checker_config.get('whitelist_conditions', ())
return set(v.lower() for v in self.checker_config.get('whitelist_conditions', ()))

@property
def allowed_vpce(self):
Expand Down
61 changes: 59 additions & 2 deletions c7n/resources/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ class CloudTrailEnabled(Filter):
Of particular note, the current-region option will evaluate whether cloudtrail is available
in the current region, either as a multi region trail or as a trail with it as the home region.
The log-metric-filter-pattern option checks for the existence of a cloudwatch alarm and a
corresponding SNS subscription for a specific filter pattern
:example:
.. code-block:: yaml
Expand All @@ -166,6 +169,8 @@ class CloudTrailEnabled(Filter):
global-events: true
multi-region: true
running: true
include-management-events: true
log-metric-filter-pattern: "{ ($.eventName = \\"ConsoleLogin\\") }"
"""
schema = type_schema(
'check-cloudtrail',
Expand All @@ -176,9 +181,13 @@ class CloudTrailEnabled(Filter):
'notifies': {'type': 'boolean'},
'file-digest': {'type': 'boolean'},
'kms': {'type': 'boolean'},
'kms-key': {'type': 'string'}})
'kms-key': {'type': 'string'},
'include-management-events': {'type': 'boolean'},
'log-metric-filter-pattern': {'type': 'string'}})

permissions = ('cloudtrail:DescribeTrails', 'cloudtrail:GetTrailStatus')
permissions = ('cloudtrail:DescribeTrails', 'cloudtrail:GetTrailStatus',
'cloudtrail:GetEventSelectors', 'cloudwatch:DescribeAlarmsForMetric',
'logs:DescribeMetricFilters', 'sns:ListSubscriptions')

def process(self, resources, event=None):
session = local_session(self.manager.session_factory)
Expand Down Expand Up @@ -212,6 +221,54 @@ def process(self, resources, event=None):
'LatestDeliveryError'):
running.append(t)
trails = running
if self.data.get('include-management-events'):
matched = []
for t in list(trails):
selectors = client.get_event_selectors(TrailName=t['TrailARN'])
if 'EventSelectors' in selectors.keys():
for s in selectors['EventSelectors']:
if s['IncludeManagementEvents'] and s['ReadWriteType'] == 'All':
matched.append(t)
trails = matched
if self.data.get('log-metric-filter-pattern'):
client_logs = session.client('logs')
client_cw = session.client('cloudwatch')
sns_manager = self.manager.get_resource_manager('sns-subscription')
matched = []
for t in list(trails):
if 'CloudWatchLogsLogGroupArn' not in t.keys():
continue
log_group_name = t['CloudWatchLogsLogGroupArn'].split(':')[6]
try:
metric_filters_log_group = \
client_logs.describe_metric_filters(
logGroupName=log_group_name)['metricFilters']
except ClientError as e:
if e.response['Error']['Code'] == 'ResourceNotFoundException':
continue
filter_matched = None
if metric_filters_log_group:
for f in metric_filters_log_group:
if f['filterPattern'] == self.data.get('log-metric-filter-pattern'):
filter_matched = f
break
if not filter_matched:
continue
alarms = client_cw.describe_alarms_for_metric(
MetricName=filter_matched["metricTransformations"][0]["metricName"],
Namespace=filter_matched["metricTransformations"][0]["metricNamespace"]
)['MetricAlarms']
alarm_actions = []
for a in alarms:
alarm_actions.extend(a['AlarmActions'])
if not alarm_actions:
continue
alarm_actions = set(alarm_actions)
sns_subscriptions = sns_manager.resources()
for s in sns_subscriptions:
if s['TopicArn'] in alarm_actions:
matched.append(t)
trails = matched
if trails:
return []
return resources
Expand Down
22 changes: 15 additions & 7 deletions c7n/resources/cloudfront.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,26 @@ class IsWafV2Enabled(Filter):
policies:
- name: filter-distribution-wafv2
description: |
match resources that are NOT associated with any wafV2 web-acls
resource: distribution
filters:
- type: wafv2-enabled
state: false
- name: filter-distribution-wafv2-specific-acl
description: |
match resources that are NOT associated with wafV2's testv2 web-acl
resource: distribution
filters:
- type: wafv2-enabled
state: false
web-acl: testv2
- name: filter-distribution-wafv2-regex
description: |
match resources that are NOT associated with specified
wafV2 web-acl regex
resource: distribution
filters:
- type: wafv2-enabled
Expand All @@ -206,19 +219,14 @@ def process(self, resources, event=None):
state = self.data.get('state', False)
target_acl_ids = [v for k, v in waf_name_id_map.items() if
re.match(target_acl, k)]

results = []
for r in resources:
r_web_acl_id = r.get('WebACLId')
if state:
if not target_acl and r_web_acl_id:
results.append(r)
elif target_acl and r_web_acl_id in target_acl_ids:
if r_web_acl_id and r_web_acl_id in target_acl_ids:
results.append(r)
else:
if not target_acl and not r_web_acl_id:
results.append(r)
elif target_acl and r_web_acl_id not in target_acl_ids:
if not r_web_acl_id or r_web_acl_id not in target_acl_ids:
results.append(r)
return results

Expand Down
3 changes: 1 addition & 2 deletions c7n/resources/cloudtrail.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def get_trail_groups(session_factory, trails):

@resources.register('cloudtrail')
class CloudTrail(QueryResourceManager):

class resource_type(TypeInfo):
service = 'cloudtrail'
enum_spec = ('describe_trails', 'trailList', None)
Expand Down Expand Up @@ -72,7 +71,7 @@ def process(self, resources, event=None):
trails = [t for t in resources if (self.is_shadow(t) == self.data.get('state', True))]
if len(trails) != rcount and self.embedded:
self.log.info("implicitly filtering shadow trails %d -> %d",
rcount, len(trails))
rcount, len(trails))
return trails

def is_shadow(self, t):
Expand Down
62 changes: 51 additions & 11 deletions c7n/resources/cw.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from c7n.resources.aws import ArnResolver
from c7n.tags import universal_augment
from c7n.utils import type_schema, local_session, chunks, get_retry
from botocore.config import Config


class DescribeAlarm(DescribeSource):
Expand All @@ -31,7 +32,6 @@ def augment(self, resources):

@resources.register('alarm')
class Alarm(QueryResourceManager):

class resource_type(TypeInfo):
service = 'cloudwatch'
arn_type = 'alarm'
Expand Down Expand Up @@ -143,7 +143,6 @@ def process(self, resources):

@resources.register('event-bus')
class EventBus(QueryResourceManager):

class resource_type(TypeInfo):
service = 'events'
arn_type = 'event-bus'
Expand All @@ -157,14 +156,12 @@ class resource_type(TypeInfo):

@EventBus.filter_registry.register('cross-account')
class EventBusCrossAccountFilter(CrossAccountAccessFilter):

# dummy permission
permissions = ('events:ListEventBuses',)


@resources.register('event-rule')
class EventRule(QueryResourceManager):

class resource_type(TypeInfo):
service = 'events'
arn_type = 'rule'
Expand Down Expand Up @@ -364,9 +361,58 @@ def process(self, resources):
client.delete_rule(Name=r['Name'])


@EventRule.action_registry.register('set-rule-state')
class SetRuleState(BaseAction):
"""
This action allows to enable/disable a rule
:example:
.. code-block:: yaml
policies:
- name: test-rule
resource: aws.event-rule
filters:
- Name: my-event-rule
actions:
- type: set-rule-state
enabled: true
"""

schema = type_schema(
'set-rule-state',
**{'enabled': {'default': True, 'type': 'boolean'}}
)
permissions = ('events:EnableRule', 'events:DisableRule',)

def process(self, resources):
config = Config(
retries={
'max_attempts': 8,
'mode': 'standard'
}
)
client = local_session(self.manager.session_factory).client('events', config=config)
retry = get_retry(('TooManyRequestsException', 'ResourceConflictException'))
enabled = self.data.get('enabled')
for resource in resources:
try:
if enabled:
retry(
client.enable_rule,
Name=resource['Name']
)
else:
retry(
client.disable_rule,
Name=resource['Name']
)
except (client.exceptions.ResourceNotFoundException,
client.exceptions.ManagedRuleException):
continue


@resources.register('event-rule-target')
class EventRuleTarget(ChildResourceManager):

class resource_type(TypeInfo):
service = 'events'
arn = False
Expand All @@ -378,7 +424,6 @@ class resource_type(TypeInfo):

@EventRuleTarget.filter_registry.register('cross-account')
class CrossAccountFilter(CrossAccountAccessFilter):

schema = type_schema(
'cross-account',
# white list accounts
Expand All @@ -395,7 +440,6 @@ def __call__(self, r):

@EventRuleTarget.action_registry.register('delete')
class DeleteTarget(BaseAction):

schema = type_schema('delete')
permissions = ('events:RemoveTargets',)

Expand All @@ -413,7 +457,6 @@ def process(self, resources):

@resources.register('log-group')
class LogGroup(QueryResourceManager):

class resource_type(TypeInfo):
service = 'logs'
arn_type = 'log-group'
Expand All @@ -437,7 +480,6 @@ def get_arns(self, resources):

@resources.register('insight-rule')
class InsightRule(QueryResourceManager):

class resource_type(TypeInfo):
service = 'cloudwatch'
arn_type = 'insight-rule'
Expand Down Expand Up @@ -721,7 +763,6 @@ def check_group(self, client, group):

@LogGroup.filter_registry.register('cross-account')
class LogCrossAccountFilter(CrossAccountAccessFilter):

schema = type_schema(
'cross-account',
# white list accounts
Expand Down Expand Up @@ -807,7 +848,6 @@ def process(self, resources, event=None):

@LogGroup.filter_registry.register('kms-key')
class KmsFilter(KmsRelatedFilter):

RelatedIdsExpression = 'kmsKeyId'


Expand Down
11 changes: 2 additions & 9 deletions c7n/resources/dlm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from c7n.manager import resources
from c7n.query import QueryResourceManager, TypeInfo
from c7n.tags import Tag, RemoveTag
from c7n.utils import get_partition


@resources.register('dlm-policy')
Expand All @@ -17,7 +16,8 @@ class resource_type(TypeInfo):
detail_spec = ('get_lifecycle_policy', 'PolicyId', 'PolicyId', 'Policy')
filter_name = 'PolicyIds'
filter_type = 'list'
arn = True
arn = 'PolicyArn'
arn_type = 'policy'
cfn_type = 'AWS::DLM::LifecyclePolicy'
# arn:aws:dlm:us-east-1:532725030595:policy/policy-0e23a047d0fdb7761

Expand All @@ -27,13 +27,6 @@ def augment(self, resources):
r['Tags'] = [{'Key': k, 'Value': v} for k, v in r.get('Tags', {}).items()]
return resources

def get_arns(self, resources):
partition = get_partition(self.region)
return [
f"arn:{partition}:dlm:{self.region}:{self.account_id}:policy/{r['PolicyId']}"
for r in resources
]


@DLMPolicy.action_registry.register('tag')
class TagDLMPolicy(Tag):
Expand Down
Loading

0 comments on commit 258af9f

Please sign in to comment.