1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
3import json
4from botocore.exceptions import ClientError
5from concurrent.futures import as_completed
6from c7n.manager import resources, ResourceManager
7from c7n.query import QueryResourceManager, TypeInfo
8from c7n.utils import local_session, chunks, type_schema
9from c7n.actions import BaseAction, ActionRegistry, RemovePolicyBase
10from c7n.exceptions import PolicyValidationError
11from c7n.filters.vpc import SubnetFilter, SecurityGroupFilter
12from c7n.filters.related import RelatedResourceFilter
13from c7n.tags import universal_augment
14from c7n.filters import ValueFilter, FilterRegistry, CrossAccountAccessFilter
15from c7n import query, utils
16from c7n.resources.account import GlueCatalogEncryptionEnabled
17from c7n.filters.kms import KmsRelatedFilter
18
19
20@resources.register('glue-connection')
21class GlueConnection(QueryResourceManager):
22
23 class resource_type(TypeInfo):
24 service = 'glue'
25 enum_spec = ('get_connections', 'ConnectionList', {'HidePassword': True})
26 id = name = 'Name'
27 date = 'CreationTime'
28 arn_type = "connection"
29 cfn_type = 'AWS::Glue::Connection'
30 universal_taggable = object()
31
32 augment = universal_augment
33
34
35@GlueConnection.filter_registry.register('subnet')
36class ConnectionSubnetFilter(SubnetFilter):
37
38 RelatedIdsExpression = 'PhysicalConnectionRequirements.SubnetId'
39
40
41@GlueConnection.filter_registry.register('security-group')
42class ConnectionSecurityGroupFilter(SecurityGroupFilter):
43
44 RelatedIdsExpression = 'PhysicalConnectionRequirements.' \
45 'SecurityGroupIdList[]'
46
47
48@GlueConnection.action_registry.register('delete')
49class DeleteConnection(BaseAction):
50 """Delete a connection from the data catalog
51
52 :example:
53
54 .. code-block:: yaml
55
56 policies:
57 - name: delete-jdbc-connections
58 resource: glue-connection
59 filters:
60 - ConnectionType: JDBC
61 actions:
62 - type: delete
63 """
64 schema = type_schema('delete')
65 permissions = ('glue:DeleteConnection',)
66
67 def delete_connection(self, r):
68 client = local_session(self.manager.session_factory).client('glue')
69 try:
70 client.delete_connection(ConnectionName=r['Name'])
71 except ClientError as e:
72 if e.response['Error']['Code'] != 'EntityNotFoundException':
73 raise
74
75 def process(self, resources):
76 with self.executor_factory(max_workers=2) as w:
77 list(w.map(self.delete_connection, resources))
78
79
80@resources.register('glue-dev-endpoint')
81class GlueDevEndpoint(QueryResourceManager):
82
83 class resource_type(TypeInfo):
84 service = 'glue'
85 enum_spec = ('get_dev_endpoints', 'DevEndpoints', None)
86 id = name = 'EndpointName'
87 date = 'CreatedTimestamp'
88 arn_type = "devEndpoint"
89 universal_taggable = True
90 cfn_type = 'AWS::Glue::DevEndpoint'
91
92 augment = universal_augment
93
94
95@GlueDevEndpoint.filter_registry.register('subnet')
96class EndpointSubnetFilter(SubnetFilter):
97
98 RelatedIdsExpression = 'SubnetId'
99
100
101@GlueDevEndpoint.action_registry.register('delete')
102class DeleteDevEndpoint(BaseAction):
103 """Deletes public Glue Dev Endpoints
104
105 :example:
106
107 .. code-block:: yaml
108
109 policies:
110 - name: delete-public-dev-endpoints
111 resource: glue-dev-endpoint
112 filters:
113 - PublicAddress: present
114 actions:
115 - type: delete
116 """
117 schema = type_schema('delete')
118 permissions = ('glue:DeleteDevEndpoint',)
119
120 def delete_dev_endpoint(self, client, endpoint_set):
121 for e in endpoint_set:
122 try:
123 client.delete_dev_endpoint(EndpointName=e['EndpointName'])
124 except client.exceptions.AlreadyExistsException:
125 pass
126
127 def process(self, resources):
128 futures = []
129 client = local_session(self.manager.session_factory).client('glue')
130 with self.executor_factory(max_workers=2) as w:
131 for endpoint_set in chunks(resources, size=5):
132 futures.append(w.submit(self.delete_dev_endpoint, client, endpoint_set))
133 for f in as_completed(futures):
134 if f.exception():
135 self.log.error(
136 "Exception deleting glue dev endpoint \n %s",
137 f.exception())
138
139
140@resources.register('glue-job')
141class GlueJob(QueryResourceManager):
142
143 class resource_type(TypeInfo):
144 service = 'glue'
145 enum_spec = ('get_jobs', 'Jobs', None)
146 id = name = 'Name'
147 date = 'CreatedOn'
148 arn_type = 'job'
149 universal_taggable = True
150 cfn_type = 'AWS::Glue::Job'
151
152 permissions = ('glue:GetJobs',)
153 augment = universal_augment
154
155
156@GlueJob.action_registry.register('delete')
157class DeleteJob(BaseAction):
158
159 schema = type_schema('delete')
160 permissions = ('glue:DeleteJob',)
161
162 def process(self, resources):
163 client = local_session(self.manager.session_factory).client('glue')
164 for r in resources:
165 try:
166 client.delete_job(JobName=r['Name'])
167 except client.exceptions.EntityNotFoundException:
168 continue
169
170
171@GlueJob.action_registry.register('toggle-metrics')
172class GlueJobToggleMetrics(BaseAction):
173 """Enable or disable CloudWatch metrics for a Glue job
174
175 :example:
176
177 .. code-block:: yaml
178
179 policies:
180 - name: gluejob-enable-metrics
181 resource: glue-job
182 filters:
183 - type: value
184 key: 'DefaultArguments."--enable-metrics"'
185 value: absent
186 actions:
187 - type: toggle-metrics
188 enabled: true
189 """
190 schema = type_schema(
191 'toggle-metrics',
192 enabled={'type': 'boolean'},
193 required=['enabled'],
194 )
195 permissions = ('glue:UpdateJob',)
196
197 def prepare_params(self, r):
198 client = local_session(self.manager.session_factory).client('glue')
199 update_keys = client.meta._service_model.shape_for('JobUpdate').members
200 want_keys = set(r).intersection(update_keys) - {'AllocatedCapacity'}
201 params = {k: r[k] for k in want_keys}
202
203 # Can't specify MaxCapacity when updating/creating a job if
204 # job configuration includes WorkerType or NumberOfWorkers
205 if 'WorkerType' in params or 'NumberOfWorkers' in params:
206 del params['MaxCapacity']
207
208 # Can't specify Timeout when updating Ray jobs.
209 # Removing Timeout preserves default setting.
210 if params['Command']['Name'] == 'glueray':
211 del params['Timeout']
212
213 if self.data.get('enabled'):
214 if 'DefaultArguments' not in params:
215 params['DefaultArguments'] = {}
216 params["DefaultArguments"]["--enable-metrics"] = ""
217 else:
218 if 'DefaultArguments' in params and \
219 '--enable-metrics' in params['DefaultArguments']:
220 del params["DefaultArguments"]["--enable-metrics"]
221
222 return params
223
224 def process(self, resources):
225 client = local_session(self.manager.session_factory).client('glue')
226
227 for r in resources:
228 try:
229 job_name = r["Name"]
230 updated_resource = self.prepare_params(r)
231 client.update_job(JobName=job_name, JobUpdate=updated_resource)
232 except Exception as e:
233 self.log.error('Error updating glue job: {}'.format(e))
234
235
236@resources.register('glue-crawler')
237class GlueCrawler(QueryResourceManager):
238
239 class resource_type(TypeInfo):
240 service = 'glue'
241 enum_spec = ('get_crawlers', 'Crawlers', None)
242 id = name = 'Name'
243 date = 'CreatedOn'
244 arn_type = 'crawler'
245 state_key = 'State'
246 universal_taggable = True
247 cfn_type = 'AWS::Glue::Crawler'
248
249 augment = universal_augment
250
251
252class SecurityConfigFilter(RelatedResourceFilter):
253 """Filters glue crawlers with security configurations
254
255 :example:
256
257 .. code-block:: yaml
258
259 policies:
260 - name: need-kms-cloudwatch
261 resource: glue-crawler
262 filters:
263 - type: security-config
264 key: EncryptionConfiguration.CloudWatchEncryption.CloudWatchEncryptionMode
265 op: ne
266 value: SSE-KMS
267
268 To find resources missing any security configuration all set `missing: true` on the filter.
269 """
270
271 RelatedResource = "c7n.resources.glue.GlueSecurityConfiguration"
272 AnnotationKey = "matched-security-config"
273 RelatedIdsExpression = None
274
275 schema = type_schema(
276 'security-config',
277 missing={'type': 'boolean', 'default': False},
278 rinherit=ValueFilter.schema)
279
280 def validate(self):
281 if self.data.get('missing'):
282 return self
283 else:
284 return super(SecurityConfigFilter, self).validate()
285
286 def process(self, resources, event=None):
287 if self.data.get('missing'):
288 return [r for r in resources if self.RelatedIdsExpression not in r]
289 return super(SecurityConfigFilter, self).process(resources, event=None)
290
291
292@GlueDevEndpoint.filter_registry.register('security-config')
293class DevEndpointSecurityConfigFilter(SecurityConfigFilter):
294 RelatedIdsExpression = 'SecurityConfiguration'
295
296
297@GlueJob.filter_registry.register('security-config')
298class GlueJobSecurityConfigFilter(SecurityConfigFilter):
299 RelatedIdsExpression = 'SecurityConfiguration'
300
301
302@GlueCrawler.filter_registry.register('security-config')
303class GlueCrawlerSecurityConfigFilter(SecurityConfigFilter):
304
305 RelatedIdsExpression = 'CrawlerSecurityConfiguration'
306
307
308@GlueCrawler.action_registry.register('delete')
309class DeleteCrawler(BaseAction):
310
311 schema = type_schema('delete')
312 permissions = ('glue:DeleteCrawler',)
313 valid_origin_states = ('READY', 'FAILED')
314
315 def process(self, resources):
316 resources = self.filter_resources(resources, 'State', self.valid_origin_states)
317
318 client = local_session(self.manager.session_factory).client('glue')
319 for r in resources:
320 try:
321 client.delete_crawler(Name=r['Name'])
322 except client.exceptions.EntityNotFoundException:
323 continue
324
325
326@resources.register('glue-database')
327class GlueDatabase(QueryResourceManager):
328
329 class resource_type(TypeInfo):
330 service = 'glue'
331 enum_spec = ('get_databases', 'DatabaseList', None)
332 id = name = 'Name'
333 date = 'CreatedOn'
334 arn_type = 'database'
335 state_key = 'State'
336 cfn_type = 'AWS::Glue::Database'
337
338
339@GlueDatabase.action_registry.register('delete')
340class DeleteDatabase(BaseAction):
341
342 schema = type_schema('delete')
343 permissions = ('glue:DeleteDatabase',)
344
345 def process(self, resources):
346 client = local_session(self.manager.session_factory).client('glue')
347 for r in resources:
348 try:
349 client.delete_database(Name=r['Name'])
350 except client.exceptions.EntityNotFoundException:
351 continue
352
353
354@resources.register('glue-table')
355class GlueTable(query.ChildResourceManager):
356
357 child_source = 'describe-table'
358
359 class resource_type(TypeInfo):
360 service = 'glue'
361 parent_spec = ('glue-database', 'DatabaseName', None)
362 enum_spec = ('get_tables', 'TableList', None)
363 id = name = 'Name'
364 date = 'CreatedOn'
365 arn_type = 'table'
366
367
368@query.sources.register('describe-table')
369class DescribeTable(query.ChildDescribeSource):
370
371 def get_query(self):
372 return super(DescribeTable, self).get_query(capture_parent_id=True)
373
374 def augment(self, resources):
375 result = []
376 for parent_id, r in resources:
377 r['DatabaseName'] = parent_id
378 result.append(r)
379 return result
380
381
382@GlueTable.action_registry.register('delete')
383class DeleteTable(BaseAction):
384
385 schema = type_schema('delete')
386 permissions = ('glue:DeleteTable',)
387
388 def process(self, resources):
389 client = local_session(self.manager.session_factory).client('glue')
390 for r in resources:
391 try:
392 client.delete_table(DatabaseName=r['DatabaseName'], Name=r['Name'])
393 except client.exceptions.EntityNotFoundException:
394 continue
395
396
397@resources.register('glue-classifier')
398class GlueClassifier(QueryResourceManager):
399
400 class resource_type(TypeInfo):
401 service = 'glue'
402 enum_spec = ('get_classifiers', 'Classifiers', None)
403 id = name = 'Name'
404 date = 'CreationTime'
405 arn_type = 'classifier'
406 config_type = cfn_type = 'AWS::Glue::Classifier'
407
408
409@GlueClassifier.action_registry.register('delete')
410class DeleteClassifier(BaseAction):
411
412 schema = type_schema('delete')
413 permissions = ('glue:DeleteClassifier',)
414
415 def process(self, resources):
416 client = local_session(self.manager.session_factory).client('glue')
417 for r in resources:
418 # Extract the classifier from the resource, see below
419 # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_classifier
420 classifier = list(r.values())[0]
421 try:
422 client.delete_classifier(Name=classifier['Name'])
423 except client.exceptions.EntityNotFoundException:
424 continue
425
426
427@resources.register('glue-ml-transform')
428class GlueMLTransform(QueryResourceManager):
429
430 class resource_type(TypeInfo):
431 service = 'glue'
432 enum_spec = ('get_ml_transforms', 'Transforms', None)
433 name = 'Name'
434 id = 'TransformId'
435 arn_type = 'mlTransform'
436 universal_taggable = object()
437 config_type = cfn_type = 'AWS::Glue::MLTransform'
438
439 source_mapping = {'describe': query.DescribeWithResourceTags,
440 'config': query.ConfigSource}
441
442 def get_permissions(self):
443 return ('glue:GetMLTransforms',)
444
445
446@GlueMLTransform.action_registry.register('delete')
447class DeleteMLTransform(BaseAction):
448
449 schema = type_schema('delete')
450 permissions = ('glue:DeleteMLTransform',)
451
452 def process(self, resources):
453 client = local_session(self.manager.session_factory).client('glue')
454 for r in resources:
455 try:
456 client.delete_ml_transform(TransformId=r['TransformId'])
457 except client.exceptions.EntityNotFoundException:
458 continue
459
460
461@resources.register('glue-security-configuration')
462class GlueSecurityConfiguration(QueryResourceManager):
463
464 class resource_type(TypeInfo):
465 service = 'glue'
466 enum_spec = ('get_security_configurations', 'SecurityConfigurations', None)
467 id = name = 'Name'
468 arn_type = 'securityConfiguration'
469 date = 'CreatedTimeStamp'
470 cfn_type = 'AWS::Glue::SecurityConfiguration'
471
472
473@GlueSecurityConfiguration.filter_registry.register('kms-key')
474class KmsFilter(KmsRelatedFilter):
475
476 schema = type_schema(
477 'kms-key',
478 rinherit=ValueFilter.schema,
479 **{'key-type': {'type': 'string', 'enum': [
480 's3', 'cloudwatch', 'job-bookmarks', 'all']},
481 'match-resource': {'type': 'boolean'},
482 'operator': {'enum': ['and', 'or']}})
483
484 RelatedIdsExpression = ''
485
486 def __init__(self, data, manager=None):
487 super().__init__(data, manager)
488 key_type_to_related_ids = {
489 's3': 'EncryptionConfiguration.S3Encryption[].KmsKeyArn',
490 'cloudwatch': 'EncryptionConfiguration.CloudWatchEncryption.KmsKeyArn',
491 'job-bookmarks': 'EncryptionConfiguration.JobBookmarksEncryption.KmsKeyArn',
492 'all': 'EncryptionConfiguration.*[][].KmsKeyArn'
493 }
494 key_type = self.data.get('key_type', 'all')
495 self.RelatedIdsExpression = key_type_to_related_ids[key_type]
496
497
498@GlueSecurityConfiguration.action_registry.register('delete')
499class DeleteSecurityConfiguration(BaseAction):
500
501 schema = type_schema('delete')
502 permissions = ('glue:DeleteSecurityConfiguration',)
503
504 def process(self, resources):
505 client = local_session(self.manager.session_factory).client('glue')
506 for r in resources:
507 try:
508 client.delete_security_configuration(Name=r['Name'])
509 except client.exceptions.EntityNotFoundException:
510 continue
511
512
513@resources.register('glue-trigger')
514class GlueTrigger(QueryResourceManager):
515
516 class resource_type(TypeInfo):
517 service = 'glue'
518 enum_spec = ('get_triggers', 'Triggers', None)
519 id = name = 'Name'
520 arn_type = 'trigger'
521 universal_taggable = object()
522 cfn_type = 'AWS::Glue::Trigger'
523
524 augment = universal_augment
525
526
527@GlueTrigger.action_registry.register('delete')
528class DeleteTrigger(BaseAction):
529
530 schema = type_schema('delete')
531 permissions = ('glue:DeleteTrigger',)
532
533 def process(self, resources):
534 client = local_session(self.manager.session_factory).client('glue')
535 for r in resources:
536 try:
537 client.delete_trigger(Name=r['Name'])
538 except client.exceptions.EntityNotFoundException:
539 continue
540
541
542@resources.register('glue-workflow')
543class GlueWorkflow(QueryResourceManager):
544
545 class resource_type(TypeInfo):
546 service = 'glue'
547 enum_spec = ('list_workflows', 'Workflows', None)
548 detail_spec = ('get_workflow', 'Name', None, 'Workflow')
549 id = name = 'Name'
550 arn_type = 'workflow'
551 universal_taggable = object()
552 cfn_type = 'AWS::Glue::Workflow'
553
554 def augment(self, resources):
555 return universal_augment(
556 self, super(GlueWorkflow, self).augment(resources))
557
558
559@GlueWorkflow.action_registry.register('delete')
560class DeleteWorkflow(BaseAction):
561
562 schema = type_schema('delete')
563 permissions = ('glue:DeleteWorkflow',)
564
565 def process(self, resources):
566 client = local_session(self.manager.session_factory).client('glue')
567 for r in resources:
568 try:
569 client.delete_workflow(Name=r['Name'])
570 except client.exceptions.EntityNotFoundException:
571 continue
572
573
574@GlueWorkflow.filter_registry.register('security-config')
575class GlueWorkflowSecurityConfigFilter(SecurityConfigFilter):
576 RelatedIdsExpression = 'SecurityConfiguration'
577
578
579@resources.register('glue-catalog')
580class GlueDataCatalog(ResourceManager):
581
582 filter_registry = FilterRegistry('glue-catalog.filters')
583 action_registry = ActionRegistry('glue-catalog.actions')
584 retry = staticmethod(QueryResourceManager.retry)
585
586 class resource_type(query.TypeInfo):
587 service = 'glue'
588 arn_type = 'catalog'
589 id = name = 'CatalogId'
590 cfn_type = 'AWS::Glue::DataCatalogEncryptionSettings'
591
592 @classmethod
593 def get_permissions(cls):
594 return ('glue:GetDataCatalogEncryptionSettings',)
595
596 @classmethod
597 def has_arn(cls):
598 return True
599
600 def get_model(self):
601 return self.resource_type
602
603 def _get_catalog_encryption_settings(self):
604 client = utils.local_session(self.session_factory).client('glue')
605 settings = client.get_data_catalog_encryption_settings()
606 settings['CatalogId'] = self.config.account_id
607 settings.pop('ResponseMetadata', None)
608 return [settings]
609
610 def resources(self):
611 return self.filter_resources(self._get_catalog_encryption_settings())
612
613 def get_resources(self, resource_ids):
614 return [{'CatalogId': self.config.account_id}]
615
616
617@GlueDataCatalog.filter_registry.register('kms-key')
618class GlueCatalogKmsFilter(KmsRelatedFilter):
619
620 schema = type_schema(
621 'kms-key',
622 rinherit=ValueFilter.schema,
623 **{'key-type': {'type': 'string', 'enum': [
624 'EncryptionAtRest', 'ConnectionPasswordEncryption']},
625 'required': ['key-type'],
626 'match-resource': {'type': 'boolean'},
627 'operator': {'enum': ['and', 'or']}})
628
629 permissions = ('glue:GetDataCatalogEncryptionSettings',)
630
631 RelatedIdsExpression = ''
632
633 def __init__(self, data, manager=None):
634 super().__init__(data, manager)
635 key_type_to_related_ids = {
636 'EncryptionAtRest': 'DataCatalogEncryptionSettings.EncryptionAtRest.SseAwsKmsKeyId',
637 'ConnectionPasswordEncryption':
638 'DataCatalogEncryptionSettings.ConnectionPasswordEncryption.AwsKmsKeyId'
639 }
640 self.RelatedIdsExpression = key_type_to_related_ids.get(self.data.get('key-type'))
641
642
643@GlueDataCatalog.action_registry.register('set-encryption')
644class GlueDataCatalogEncryption(BaseAction):
645 """Modifies glue data catalog encryption based on specified parameter
646 As per docs, we can enable catalog encryption or only password encryption,
647 not both
648
649 :example:
650
651 .. code-block:: yaml
652
653 policies:
654 - name: data-catalog-encryption
655 resource: glue-catalog
656 filters:
657 - type: value
658 key: DataCatalogEncryptionSettings.EncryptionAtRest.CatalogEncryptionMode
659 value: DISABLED
660 op: eq
661 actions:
662 - type: set-encryption
663 attributes:
664 EncryptionAtRest:
665 CatalogEncryptionMode: SSE-KMS
666 SseAwsKmsKeyId: alias/aws/glue
667 """
668
669 schema = type_schema(
670 'set-encryption',
671 required=['attributes'],
672 attributes={
673 'type': 'object',
674 'additionalProperties': False,
675 'properties': {
676 'EncryptionAtRest': {
677 'type': 'object',
678 'additionalProperties': False,
679 'required': ['CatalogEncryptionMode'],
680 'properties': {
681 'CatalogEncryptionMode': {'enum': ['DISABLED', 'SSE-KMS']},
682 'SseAwsKmsKeyId': {'type': 'string'}
683 }
684 },
685 'ConnectionPasswordEncryption': {
686 'type': 'object',
687 'additionalProperties': False,
688 'required': ['ReturnConnectionPasswordEncrypted'],
689 'properties': {
690 'ReturnConnectionPasswordEncrypted': {'type': 'boolean'},
691 'AwsKmsKeyId': {'type': 'string'}
692 }
693 }
694 }
695 }
696 )
697
698 permissions = ('glue:PutDataCatalogEncryptionSettings',)
699
700 def process(self, resources):
701 client = local_session(self.manager.session_factory).client('glue')
702 self.process_catalog_encryption(client, resources)
703
704 def process_catalog_encryption(self, client, resources):
705 # there is one glue data catalog per account
706 if 'DataCatalogEncryptionSettings' not in resources[0]:
707 resources = self.manager.resources()
708 enc_config = resources[0]['DataCatalogEncryptionSettings']
709 updated_config = {**enc_config, **self.data['attributes']}
710 if enc_config == updated_config:
711 return
712 client.put_data_catalog_encryption_settings(
713 DataCatalogEncryptionSettings=updated_config)
714
715
716@GlueDataCatalog.filter_registry.register('glue-security-config')
717class GlueCatalogEncryptionFilter(GlueCatalogEncryptionEnabled):
718 """Filter glue catalog by its glue encryption status and KMS key
719
720 :example:
721
722 .. code-block:: yaml
723
724 policies:
725 - name: glue-catalog-security-config
726 resource: aws.glue-catalog
727 filters:
728 - type: glue-security-config
729 SseAwsKmsKeyId: alias/aws/glue
730
731 """
732
733
734@GlueDataCatalog.filter_registry.register('cross-account')
735class GlueCatalogCrossAccount(CrossAccountAccessFilter):
736 """Filter glue catalog if it has cross account permissions
737
738 :example:
739
740 .. code-block:: yaml
741
742 policies:
743 - name: catalog-cross-account
744 resource: aws.glue-catalog
745 filters:
746 - type: cross-account
747
748 """
749 permissions = ('glue:GetResourcePolicy',)
750 policy_annotation = "c7n:AccessPolicy"
751
752 def get_resource_policy(self, r):
753 client = local_session(self.manager.session_factory).client('glue')
754 if self.policy_annotation in r:
755 return r[self.policy_annotation]
756 try:
757 policy = client.get_resource_policy().get('PolicyInJson')
758 except client.exceptions.EntityNotFoundException:
759 policy = {}
760 r[self.policy_annotation] = policy
761 return policy
762
763
764@GlueDataCatalog.action_registry.register('remove-statements')
765class RemovePolicyStatement(RemovePolicyBase):
766 """Action to remove policy statements from Glue Data Catalog
767
768 :example:
769
770 .. code-block:: yaml
771
772 policies:
773 - name: remove-glue-catalog-cross-account
774 resource: aws.glue-catalog
775 filters:
776 - type: cross-account
777 actions:
778 - type: remove-statements
779 statement_ids: matched
780 """
781 permissions = ('glue:PutResourcePolicy',)
782 policy_annotation = "c7n:AccessPolicy"
783
784 def validate(self):
785 for f in self.manager.iter_filters():
786 if isinstance(f, GlueCatalogCrossAccount):
787 return self
788 raise PolicyValidationError(
789 '`remove-statements` may only be used in '
790 'conjunction with `cross-account` filter on %s' % (self.manager.data,))
791
792 def process(self, resources):
793 resource = resources[0]
794 client = local_session(self.manager.session_factory).client('glue')
795 if resource.get(self.policy_annotation):
796 p = json.loads(resource[self.policy_annotation])
797 statements, found = self.process_policy(
798 p, resource, CrossAccountAccessFilter.annotation_key)
799 if not found:
800 return
801 if statements:
802 client.put_resource_policy(PolicyInJson=json.dumps(p))
803 else:
804 client.delete_resource_policy()