Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/c7n/resources/efs.py: 48%
190 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
3import json
5from c7n.actions import Action, BaseAction
6from c7n.exceptions import PolicyValidationError
7from c7n.filters.kms import KmsRelatedFilter
8from c7n.filters import Filter
9from c7n.manager import resources
10from c7n.filters.vpc import SecurityGroupFilter, SubnetFilter, NetworkLocation
11from c7n.filters.policystatement import HasStatementFilter
12from c7n.query import (
13 QueryResourceManager, ChildResourceManager, TypeInfo, DescribeSource, ConfigSource
14)
15from c7n.tags import universal_augment
16from c7n.utils import local_session, type_schema, get_retry
17from .aws import shape_validate
18from c7n.filters.backup import ConsecutiveAwsBackupsFilter
21class EFSDescribe(DescribeSource):
23 def augment(self, resources):
24 return universal_augment(self.manager, resources)
27@resources.register('efs')
28class ElasticFileSystem(QueryResourceManager):
30 class resource_type(TypeInfo):
31 service = 'efs'
32 enum_spec = ('describe_file_systems', 'FileSystems', None)
33 id = 'FileSystemId'
34 name = 'Name'
35 date = 'CreationTime'
36 dimension = 'FileSystemId'
37 arn_type = 'file-system'
38 permission_prefix = arn_service = 'elasticfilesystem'
39 filter_name = 'FileSystemId'
40 filter_type = 'scalar'
41 universal_taggable = True
42 config_type = cfn_type = 'AWS::EFS::FileSystem'
43 arn = 'FileSystemArn'
45 source_mapping = {
46 'describe': EFSDescribe,
47 'config': ConfigSource
48 }
51@resources.register('efs-mount-target')
52class ElasticFileSystemMountTarget(ChildResourceManager):
54 class resource_type(TypeInfo):
55 service = 'efs'
56 parent_spec = ('efs', 'FileSystemId', None)
57 enum_spec = ('describe_mount_targets', 'MountTargets', None)
58 permission_prefix = 'elasticfilesystem'
59 name = id = 'MountTargetId'
60 arn = False
61 cfn_type = 'AWS::EFS::MountTarget'
62 supports_trailevents = True
65@ElasticFileSystemMountTarget.filter_registry.register('subnet')
66class Subnet(SubnetFilter):
68 RelatedIdsExpression = "SubnetId"
71@ElasticFileSystemMountTarget.filter_registry.register('security-group')
72class SecurityGroup(SecurityGroupFilter):
74 efs_group_cache = None
76 RelatedIdsExpression = ""
78 def get_related_ids(self, resources):
80 if self.efs_group_cache:
81 group_ids = set()
82 for r in resources:
83 group_ids.update(
84 self.efs_group_cache.get(r['MountTargetId'], ()))
85 return list(group_ids)
87 client = local_session(self.manager.session_factory).client('efs')
88 groups = {}
89 group_ids = set()
90 retry = get_retry(('Throttled',), 12)
92 for r in resources:
93 groups[r['MountTargetId']] = retry(
94 client.describe_mount_target_security_groups,
95 MountTargetId=r['MountTargetId'])['SecurityGroups']
96 group_ids.update(groups[r['MountTargetId']])
98 self.efs_group_cache = groups
99 return list(group_ids)
102@ElasticFileSystemMountTarget.filter_registry.register('network-location', NetworkLocation)
105@ElasticFileSystem.filter_registry.register('kms-key')
106class KmsFilter(KmsRelatedFilter):
108 RelatedIdsExpression = 'KmsKeyId'
111@ElasticFileSystem.action_registry.register('delete')
112class Delete(Action):
114 schema = type_schema('delete')
115 permissions = ('elasticfilesystem:DescribeMountTargets',
116 'elasticfilesystem:DeleteMountTarget',
117 'elasticfilesystem:DeleteFileSystem')
119 def process(self, resources):
120 client = local_session(self.manager.session_factory).client('efs')
121 self.unmount_filesystems(resources)
122 retry = get_retry(('FileSystemInUse',), 12)
123 for r in resources:
124 retry(client.delete_file_system, FileSystemId=r['FileSystemId'])
126 def unmount_filesystems(self, resources):
127 client = local_session(self.manager.session_factory).client('efs')
128 for r in resources:
129 if not r['NumberOfMountTargets']:
130 continue
131 for t in client.describe_mount_targets(
132 FileSystemId=r['FileSystemId'])['MountTargets']:
133 client.delete_mount_target(MountTargetId=t['MountTargetId'])
136@ElasticFileSystem.action_registry.register('configure-lifecycle-policy')
137class ConfigureLifecycle(BaseAction):
138 """Enable/disable lifecycle policy for efs.
140 :example:
142 .. code-block:: yaml
144 policies:
145 - name: efs-apply-lifecycle
146 resource: efs
147 actions:
148 - type: configure-lifecycle-policy
149 state: enable
150 rules:
151 - 'TransitionToIA': 'AFTER_7_DAYS'
153 """
154 schema = type_schema(
155 'configure-lifecycle-policy',
156 state={'enum': ['enable', 'disable']},
157 rules={
158 'type': 'array',
159 'items': {'type': 'object'}},
160 required=['state'])
162 permissions = ('elasticfilesystem:PutLifecycleConfiguration',)
163 shape = 'PutLifecycleConfigurationRequest'
165 def validate(self):
166 if self.data.get('state') == 'enable' and 'rules' not in self.data:
167 raise PolicyValidationError(
168 'rules are required to enable lifecycle configuration %s' % (self.manager.data))
169 if self.data.get('state') == 'disable' and 'rules' in self.data:
170 raise PolicyValidationError(
171 'rules not required to disable lifecycle configuration %s' % (self.manager.data))
172 if self.data.get('rules'):
173 attrs = {}
174 attrs['LifecyclePolicies'] = self.data['rules']
175 attrs['FileSystemId'] = 'PolicyValidator'
176 return shape_validate(attrs, self.shape, 'efs')
178 def process(self, resources):
179 client = local_session(self.manager.session_factory).client('efs')
180 op_map = {'enable': self.data.get('rules'), 'disable': []}
181 for r in resources:
182 try:
183 client.put_lifecycle_configuration(
184 FileSystemId=r['FileSystemId'],
185 LifecyclePolicies=op_map.get(self.data.get('state')))
186 except client.exceptions.FileSystemNotFound:
187 continue
190@ElasticFileSystem.filter_registry.register('lifecycle-policy')
191class LifecyclePolicy(Filter):
192 """Filters efs based on the state of lifecycle policies
194 :example:
196 .. code-block:: yaml
198 policies:
199 - name: efs-filter-lifecycle
200 resource: efs
201 filters:
202 - type: lifecycle-policy
203 state: present
204 value: AFTER_7_DAYS
206 """
207 schema = type_schema(
208 'lifecycle-policy',
209 state={'enum': ['present', 'absent']},
210 value={'type': 'string'},
211 required=['state'])
213 permissions = ('elasticfilesystem:DescribeLifecycleConfiguration',)
215 def process(self, resources, event=None):
216 resources = self.fetch_resources_lfc(resources)
217 if self.data.get('value'):
218 config = {'TransitionToIA': self.data.get('value')}
219 if self.data.get('state') == 'present':
220 return [r for r in resources if config in r.get('c7n:LifecyclePolicies')]
221 return [r for r in resources if config not in r.get('c7n:LifecyclePolicies')]
222 else:
223 if self.data.get('state') == 'present':
224 return [r for r in resources if r.get('c7n:LifecyclePolicies')]
225 return [r for r in resources if r.get('c7n:LifecyclePolicies') == []]
227 def fetch_resources_lfc(self, resources):
228 client = local_session(self.manager.session_factory).client('efs')
229 for r in resources:
230 try:
231 lfc = client.describe_lifecycle_configuration(
232 FileSystemId=r['FileSystemId']).get('LifecyclePolicies')
233 r['c7n:LifecyclePolicies'] = lfc
234 except client.exceptions.FileSystemNotFound:
235 continue
236 return resources
239@ElasticFileSystem.filter_registry.register('check-secure-transport')
240class CheckSecureTransport(Filter):
241 """Find EFS that does not enforce secure transport
243 :Example:
245 .. code-block:: yaml
247 - name: efs-securetransport-check-policy
248 resource: efs
249 filters:
250 - check-secure-transport
252 To configure an EFS to enforce secure transport, set up the appropriate
253 Effect and Condition for its policy document. For example:
255 .. code-block:: json
257 {
258 "Sid": "efs-statement-b3f6b59b-d938-4001-9154-508f67707073",
259 "Effect": "Deny",
260 "Principal": { "AWS": "*" },
261 "Action": "*",
262 "Condition": {
263 "Bool": { "aws:SecureTransport": "false" }
264 }
265 }
266 """
268 schema = type_schema('check-secure-transport')
269 permissions = ('elasticfilesystem:DescribeFileSystemPolicy',)
271 policy_annotation = 'c7n:Policy'
273 def get_policy(self, client, resource):
274 if self.policy_annotation in resource:
275 return resource[self.policy_annotation]
276 try:
277 result = client.describe_file_system_policy(
278 FileSystemId=resource['FileSystemId'])
279 except client.exceptions.PolicyNotFound:
280 return None
281 resource[self.policy_annotation] = json.loads(result['Policy'])
282 return resource[self.policy_annotation]
284 def securetransport_check_policy(self, client, resource):
285 policy = self.get_policy(client, resource)
286 if not policy:
287 return True
289 statements = policy['Statement']
290 if isinstance(statements, dict):
291 statements = [statements]
293 for s in statements:
294 try:
295 effect = s['Effect']
296 secureTransportValue = s['Condition']['Bool']['aws:SecureTransport']
297 if ((effect == 'Deny' and secureTransportValue == 'false') or
298 (effect == 'Allow' and secureTransportValue == 'true')):
299 return False
300 except (KeyError, TypeError):
301 pass
303 return True
305 def process(self, resources, event=None):
306 c = local_session(self.manager.session_factory).client('efs')
307 results = [r for r in resources if self.securetransport_check_policy(c, r)]
308 self.log.info(
309 "%d of %d EFS policies don't enforce secure transport",
310 len(results), len(resources))
311 return results
314@ElasticFileSystem.filter_registry.register('has-statement')
315class EFSHasStatementFilter(HasStatementFilter):
317 def __init__(self, data, manager=None):
318 super().__init__(data, manager)
319 self.policy_attribute = 'c7n:Policy'
321 def process(self, resources, event=None):
322 resources = [self.policy_annotate(r) for r in resources]
323 return super().process(resources, event)
325 def policy_annotate(self, resource):
326 client = local_session(self.manager.session_factory).client('efs')
327 if self.policy_attribute in resource:
328 return resource
329 try:
330 result = client.describe_file_system_policy(
331 FileSystemId=resource['FileSystemId'])
332 resource[self.policy_attribute] = result['Policy']
333 except client.exceptions.PolicyNotFound:
334 resource[self.policy_attribute] = None
335 return resource
336 return resource
338 def get_std_format_args(self, fs):
339 return {
340 'fs_arn': fs['FileSystemArn'],
341 'account_id': self.manager.config.account_id,
342 'region': self.manager.config.region
343 }
346ElasticFileSystem.filter_registry.register('consecutive-aws-backups', ConsecutiveAwsBackupsFilter)