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

441 statements  

« 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 

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 query = super(DescribeTable, self).get_query() 

373 query.capture_parent_id = True 

374 return query 

375 

376 def augment(self, resources): 

377 result = [] 

378 for parent_id, r in resources: 

379 r['DatabaseName'] = parent_id 

380 result.append(r) 

381 return result 

382 

383 

384@GlueTable.action_registry.register('delete') 

385class DeleteTable(BaseAction): 

386 

387 schema = type_schema('delete') 

388 permissions = ('glue:DeleteTable',) 

389 

390 def process(self, resources): 

391 client = local_session(self.manager.session_factory).client('glue') 

392 for r in resources: 

393 try: 

394 client.delete_table(DatabaseName=r['DatabaseName'], Name=r['Name']) 

395 except client.exceptions.EntityNotFoundException: 

396 continue 

397 

398 

399@resources.register('glue-classifier') 

400class GlueClassifier(QueryResourceManager): 

401 

402 class resource_type(TypeInfo): 

403 service = 'glue' 

404 enum_spec = ('get_classifiers', 'Classifiers', None) 

405 id = name = 'Name' 

406 date = 'CreationTime' 

407 arn_type = 'classifier' 

408 config_type = cfn_type = 'AWS::Glue::Classifier' 

409 

410 

411@GlueClassifier.action_registry.register('delete') 

412class DeleteClassifier(BaseAction): 

413 

414 schema = type_schema('delete') 

415 permissions = ('glue:DeleteClassifier',) 

416 

417 def process(self, resources): 

418 client = local_session(self.manager.session_factory).client('glue') 

419 for r in resources: 

420 # Extract the classifier from the resource, see below 

421 # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_classifier 

422 classifier = list(r.values())[0] 

423 try: 

424 client.delete_classifier(Name=classifier['Name']) 

425 except client.exceptions.EntityNotFoundException: 

426 continue 

427 

428 

429@resources.register('glue-ml-transform') 

430class GlueMLTransform(QueryResourceManager): 

431 

432 class resource_type(TypeInfo): 

433 service = 'glue' 

434 enum_spec = ('get_ml_transforms', 'Transforms', None) 

435 name = 'Name' 

436 id = 'TransformId' 

437 arn_type = 'mlTransform' 

438 universal_taggable = object() 

439 config_type = cfn_type = 'AWS::Glue::MLTransform' 

440 

441 source_mapping = {'describe': query.DescribeWithResourceTags, 

442 'config': query.ConfigSource} 

443 

444 def get_permissions(self): 

445 return ('glue:GetMLTransforms',) 

446 

447 

448@GlueMLTransform.action_registry.register('delete') 

449class DeleteMLTransform(BaseAction): 

450 

451 schema = type_schema('delete') 

452 permissions = ('glue:DeleteMLTransform',) 

453 

454 def process(self, resources): 

455 client = local_session(self.manager.session_factory).client('glue') 

456 for r in resources: 

457 try: 

458 client.delete_ml_transform(TransformId=r['TransformId']) 

459 except client.exceptions.EntityNotFoundException: 

460 continue 

461 

462 

463@resources.register('glue-security-configuration') 

464class GlueSecurityConfiguration(QueryResourceManager): 

465 

466 class resource_type(TypeInfo): 

467 service = 'glue' 

468 enum_spec = ('get_security_configurations', 'SecurityConfigurations', None) 

469 id = name = 'Name' 

470 arn_type = 'securityConfiguration' 

471 date = 'CreatedTimeStamp' 

472 cfn_type = 'AWS::Glue::SecurityConfiguration' 

473 

474 

475@GlueSecurityConfiguration.filter_registry.register('kms-key') 

476class KmsFilter(KmsRelatedFilter): 

477 

478 schema = type_schema( 

479 'kms-key', 

480 rinherit=ValueFilter.schema, 

481 **{'key-type': {'type': 'string', 'enum': [ 

482 's3', 'cloudwatch', 'job-bookmarks', 'all']}, 

483 'match-resource': {'type': 'boolean'}, 

484 'operator': {'enum': ['and', 'or']}}) 

485 

486 RelatedIdsExpression = '' 

487 

488 def __init__(self, data, manager=None): 

489 super().__init__(data, manager) 

490 key_type_to_related_ids = { 

491 's3': 'EncryptionConfiguration.S3Encryption[].KmsKeyArn', 

492 'cloudwatch': 'EncryptionConfiguration.CloudWatchEncryption.KmsKeyArn', 

493 'job-bookmarks': 'EncryptionConfiguration.JobBookmarksEncryption.KmsKeyArn', 

494 'all': 'EncryptionConfiguration.*[][].KmsKeyArn' 

495 } 

496 key_type = self.data.get('key_type', 'all') 

497 self.RelatedIdsExpression = key_type_to_related_ids[key_type] 

498 

499 

500@GlueSecurityConfiguration.action_registry.register('delete') 

501class DeleteSecurityConfiguration(BaseAction): 

502 

503 schema = type_schema('delete') 

504 permissions = ('glue:DeleteSecurityConfiguration',) 

505 

506 def process(self, resources): 

507 client = local_session(self.manager.session_factory).client('glue') 

508 for r in resources: 

509 try: 

510 client.delete_security_configuration(Name=r['Name']) 

511 except client.exceptions.EntityNotFoundException: 

512 continue 

513 

514 

515@resources.register('glue-trigger') 

516class GlueTrigger(QueryResourceManager): 

517 

518 class resource_type(TypeInfo): 

519 service = 'glue' 

520 enum_spec = ('get_triggers', 'Triggers', None) 

521 id = name = 'Name' 

522 arn_type = 'trigger' 

523 universal_taggable = object() 

524 cfn_type = 'AWS::Glue::Trigger' 

525 

526 augment = universal_augment 

527 

528 

529@GlueTrigger.action_registry.register('delete') 

530class DeleteTrigger(BaseAction): 

531 

532 schema = type_schema('delete') 

533 permissions = ('glue:DeleteTrigger',) 

534 

535 def process(self, resources): 

536 client = local_session(self.manager.session_factory).client('glue') 

537 for r in resources: 

538 try: 

539 client.delete_trigger(Name=r['Name']) 

540 except client.exceptions.EntityNotFoundException: 

541 continue 

542 

543 

544@resources.register('glue-workflow') 

545class GlueWorkflow(QueryResourceManager): 

546 

547 class resource_type(TypeInfo): 

548 service = 'glue' 

549 enum_spec = ('list_workflows', 'Workflows', None) 

550 detail_spec = ('get_workflow', 'Name', None, 'Workflow') 

551 id = name = 'Name' 

552 arn_type = 'workflow' 

553 universal_taggable = object() 

554 cfn_type = 'AWS::Glue::Workflow' 

555 

556 def augment(self, resources): 

557 return universal_augment( 

558 self, super(GlueWorkflow, self).augment(resources)) 

559 

560 

561@GlueWorkflow.action_registry.register('delete') 

562class DeleteWorkflow(BaseAction): 

563 

564 schema = type_schema('delete') 

565 permissions = ('glue:DeleteWorkflow',) 

566 

567 def process(self, resources): 

568 client = local_session(self.manager.session_factory).client('glue') 

569 for r in resources: 

570 try: 

571 client.delete_workflow(Name=r['Name']) 

572 except client.exceptions.EntityNotFoundException: 

573 continue 

574 

575 

576@GlueWorkflow.filter_registry.register('security-config') 

577class GlueWorkflowSecurityConfigFilter(SecurityConfigFilter): 

578 RelatedIdsExpression = 'SecurityConfiguration' 

579 

580 

581@resources.register('glue-catalog') 

582class GlueDataCatalog(ResourceManager): 

583 

584 filter_registry = FilterRegistry('glue-catalog.filters') 

585 action_registry = ActionRegistry('glue-catalog.actions') 

586 retry = staticmethod(QueryResourceManager.retry) 

587 

588 class resource_type(query.TypeInfo): 

589 service = 'glue' 

590 arn_type = 'catalog' 

591 id = name = 'CatalogId' 

592 cfn_type = 'AWS::Glue::DataCatalogEncryptionSettings' 

593 

594 @classmethod 

595 def get_permissions(cls): 

596 return ('glue:GetDataCatalogEncryptionSettings',) 

597 

598 @classmethod 

599 def has_arn(cls): 

600 return True 

601 

602 def get_model(self): 

603 return self.resource_type 

604 

605 def _get_catalog_encryption_settings(self): 

606 client = utils.local_session(self.session_factory).client('glue') 

607 settings = client.get_data_catalog_encryption_settings() 

608 settings['CatalogId'] = self.config.account_id 

609 settings.pop('ResponseMetadata', None) 

610 return [settings] 

611 

612 def resources(self): 

613 return self.filter_resources(self._get_catalog_encryption_settings()) 

614 

615 def get_resources(self, resource_ids): 

616 return [{'CatalogId': self.config.account_id}] 

617 

618 

619@GlueDataCatalog.filter_registry.register('kms-key') 

620class GlueCatalogKmsFilter(KmsRelatedFilter): 

621 

622 schema = type_schema( 

623 'kms-key', 

624 rinherit=ValueFilter.schema, 

625 **{'key-type': {'type': 'string', 'enum': [ 

626 'EncryptionAtRest', 'ConnectionPasswordEncryption']}, 

627 'required': ['key-type'], 

628 'match-resource': {'type': 'boolean'}, 

629 'operator': {'enum': ['and', 'or']}}) 

630 

631 permissions = ('glue:GetDataCatalogEncryptionSettings',) 

632 

633 RelatedIdsExpression = '' 

634 

635 def __init__(self, data, manager=None): 

636 super().__init__(data, manager) 

637 key_type_to_related_ids = { 

638 'EncryptionAtRest': 'DataCatalogEncryptionSettings.EncryptionAtRest.SseAwsKmsKeyId', 

639 'ConnectionPasswordEncryption': 

640 'DataCatalogEncryptionSettings.ConnectionPasswordEncryption.AwsKmsKeyId' 

641 } 

642 self.RelatedIdsExpression = key_type_to_related_ids.get(self.data.get('key-type')) 

643 

644 

645@GlueDataCatalog.action_registry.register('set-encryption') 

646class GlueDataCatalogEncryption(BaseAction): 

647 """Modifies glue data catalog encryption based on specified parameter 

648 As per docs, we can enable catalog encryption or only password encryption, 

649 not both 

650 

651 :example: 

652 

653 .. code-block:: yaml 

654 

655 policies: 

656 - name: data-catalog-encryption 

657 resource: glue-catalog 

658 filters: 

659 - type: value 

660 key: DataCatalogEncryptionSettings.EncryptionAtRest.CatalogEncryptionMode 

661 value: DISABLED 

662 op: eq 

663 actions: 

664 - type: set-encryption 

665 attributes: 

666 EncryptionAtRest: 

667 CatalogEncryptionMode: SSE-KMS 

668 SseAwsKmsKeyId: alias/aws/glue 

669 """ 

670 

671 schema = type_schema( 

672 'set-encryption', 

673 required=['attributes'], 

674 attributes={ 

675 'type': 'object', 

676 'additionalProperties': False, 

677 'properties': { 

678 'EncryptionAtRest': { 

679 'type': 'object', 

680 'additionalProperties': False, 

681 'required': ['CatalogEncryptionMode'], 

682 'properties': { 

683 'CatalogEncryptionMode': {'enum': ['DISABLED', 'SSE-KMS']}, 

684 'SseAwsKmsKeyId': {'type': 'string'} 

685 } 

686 }, 

687 'ConnectionPasswordEncryption': { 

688 'type': 'object', 

689 'additionalProperties': False, 

690 'required': ['ReturnConnectionPasswordEncrypted'], 

691 'properties': { 

692 'ReturnConnectionPasswordEncrypted': {'type': 'boolean'}, 

693 'AwsKmsKeyId': {'type': 'string'} 

694 } 

695 } 

696 } 

697 } 

698 ) 

699 

700 permissions = ('glue:PutDataCatalogEncryptionSettings',) 

701 

702 def process(self, resources): 

703 client = local_session(self.manager.session_factory).client('glue') 

704 self.process_catalog_encryption(client, resources) 

705 

706 def process_catalog_encryption(self, client, resources): 

707 # there is one glue data catalog per account 

708 if 'DataCatalogEncryptionSettings' not in resources[0]: 

709 resources = self.manager.resources() 

710 enc_config = resources[0]['DataCatalogEncryptionSettings'] 

711 updated_config = {**enc_config, **self.data['attributes']} 

712 if enc_config == updated_config: 

713 return 

714 client.put_data_catalog_encryption_settings( 

715 DataCatalogEncryptionSettings=updated_config) 

716 

717 

718@GlueDataCatalog.filter_registry.register('glue-security-config') 

719class GlueCatalogEncryptionFilter(GlueCatalogEncryptionEnabled): 

720 """Filter glue catalog by its glue encryption status and KMS key 

721 

722 :example: 

723 

724 .. code-block:: yaml 

725 

726 policies: 

727 - name: glue-catalog-security-config 

728 resource: aws.glue-catalog 

729 filters: 

730 - type: glue-security-config 

731 SseAwsKmsKeyId: alias/aws/glue 

732 

733 """ 

734 

735 

736@GlueDataCatalog.filter_registry.register('cross-account') 

737class GlueCatalogCrossAccount(CrossAccountAccessFilter): 

738 """Filter glue catalog if it has cross account permissions 

739 

740 :example: 

741 

742 .. code-block:: yaml 

743 

744 policies: 

745 - name: catalog-cross-account 

746 resource: aws.glue-catalog 

747 filters: 

748 - type: cross-account 

749 

750 """ 

751 permissions = ('glue:GetResourcePolicy',) 

752 policy_annotation = "c7n:AccessPolicy" 

753 

754 def get_resource_policy(self, r): 

755 client = local_session(self.manager.session_factory).client('glue') 

756 if self.policy_annotation in r: 

757 return r[self.policy_annotation] 

758 try: 

759 policy = client.get_resource_policy().get('PolicyInJson') 

760 except client.exceptions.EntityNotFoundException: 

761 policy = {} 

762 r[self.policy_annotation] = policy 

763 return policy 

764 

765 

766@GlueDataCatalog.action_registry.register('remove-statements') 

767class RemovePolicyStatement(RemovePolicyBase): 

768 """Action to remove policy statements from Glue Data Catalog 

769 

770 :example: 

771 

772 .. code-block:: yaml 

773 

774 policies: 

775 - name: remove-glue-catalog-cross-account 

776 resource: aws.glue-catalog 

777 filters: 

778 - type: cross-account 

779 actions: 

780 - type: remove-statements 

781 statement_ids: matched 

782 """ 

783 permissions = ('glue:PutResourcePolicy',) 

784 policy_annotation = "c7n:AccessPolicy" 

785 

786 def validate(self): 

787 for f in self.manager.iter_filters(): 

788 if isinstance(f, GlueCatalogCrossAccount): 

789 return self 

790 raise PolicyValidationError( 

791 '`remove-statements` may only be used in ' 

792 'conjunction with `cross-account` filter on %s' % (self.manager.data,)) 

793 

794 def process(self, resources): 

795 resource = resources[0] 

796 client = local_session(self.manager.session_factory).client('glue') 

797 if resource.get(self.policy_annotation): 

798 p = json.loads(resource[self.policy_annotation]) 

799 statements, found = self.process_policy( 

800 p, resource, CrossAccountAccessFilter.annotation_key) 

801 if not found: 

802 return 

803 if statements: 

804 client.put_resource_policy(PolicyInJson=json.dumps(p)) 

805 else: 

806 client.delete_resource_policy()