Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/c7n/resources/glue.py: 63%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

439 statements  

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()