Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/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

446 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, generate_arn 

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 def get_arns(self, resources): 

368 return [self.generate_arn(r['DatabaseName'] + '/' + r['Name']) for r in resources] 

369 

370 

371@query.sources.register('describe-table') 

372class DescribeTable(query.ChildDescribeSource): 

373 

374 def get_query(self): 

375 return super(DescribeTable, self).get_query(capture_parent_id=True) 

376 

377 def augment(self, resources): 

378 result = [] 

379 for parent_id, r in resources: 

380 r['DatabaseName'] = parent_id 

381 result.append(r) 

382 return result 

383 

384 

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

386class DeleteTable(BaseAction): 

387 

388 schema = type_schema('delete') 

389 permissions = ('glue:DeleteTable',) 

390 

391 def process(self, resources): 

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

393 for r in resources: 

394 try: 

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

396 except client.exceptions.EntityNotFoundException: 

397 continue 

398 

399 

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

401class GlueClassifier(QueryResourceManager): 

402 

403 class resource_type(TypeInfo): 

404 service = 'glue' 

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

406 id = name = 'Name' 

407 date = 'CreationTime' 

408 arn_type = 'classifier' 

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

410 

411 

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

413class DeleteClassifier(BaseAction): 

414 

415 schema = type_schema('delete') 

416 permissions = ('glue:DeleteClassifier',) 

417 

418 def process(self, resources): 

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

420 for r in resources: 

421 # Extract the classifier from the resource, see below 

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

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

424 try: 

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

426 except client.exceptions.EntityNotFoundException: 

427 continue 

428 

429 

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

431class GlueMLTransform(QueryResourceManager): 

432 

433 class resource_type(TypeInfo): 

434 service = 'glue' 

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

436 name = 'Name' 

437 id = 'TransformId' 

438 arn_type = 'mlTransform' 

439 universal_taggable = object() 

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

441 

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

443 'config': query.ConfigSource} 

444 

445 def get_permissions(self): 

446 return ('glue:GetMLTransforms',) 

447 

448 

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

450class DeleteMLTransform(BaseAction): 

451 

452 schema = type_schema('delete') 

453 permissions = ('glue:DeleteMLTransform',) 

454 

455 def process(self, resources): 

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

457 for r in resources: 

458 try: 

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

460 except client.exceptions.EntityNotFoundException: 

461 continue 

462 

463 

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

465class GlueSecurityConfiguration(QueryResourceManager): 

466 

467 class resource_type(TypeInfo): 

468 service = 'glue' 

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

470 id = name = 'Name' 

471 arn_type = 'securityConfiguration' 

472 date = 'CreatedTimeStamp' 

473 cfn_type = 'AWS::Glue::SecurityConfiguration' 

474 

475 

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

477class KmsFilter(KmsRelatedFilter): 

478 

479 schema = type_schema( 

480 'kms-key', 

481 rinherit=ValueFilter.schema, 

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

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

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

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

486 

487 RelatedIdsExpression = '' 

488 

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

490 super().__init__(data, manager) 

491 key_type_to_related_ids = { 

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

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

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

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

496 } 

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

498 self.RelatedIdsExpression = key_type_to_related_ids[key_type] 

499 

500 

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

502class DeleteSecurityConfiguration(BaseAction): 

503 

504 schema = type_schema('delete') 

505 permissions = ('glue:DeleteSecurityConfiguration',) 

506 

507 def process(self, resources): 

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

509 for r in resources: 

510 try: 

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

512 except client.exceptions.EntityNotFoundException: 

513 continue 

514 

515 

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

517class GlueTrigger(QueryResourceManager): 

518 

519 class resource_type(TypeInfo): 

520 service = 'glue' 

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

522 id = name = 'Name' 

523 arn_type = 'trigger' 

524 universal_taggable = object() 

525 cfn_type = 'AWS::Glue::Trigger' 

526 

527 augment = universal_augment 

528 

529 

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

531class DeleteTrigger(BaseAction): 

532 

533 schema = type_schema('delete') 

534 permissions = ('glue:DeleteTrigger',) 

535 

536 def process(self, resources): 

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

538 for r in resources: 

539 try: 

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

541 except client.exceptions.EntityNotFoundException: 

542 continue 

543 

544 

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

546class GlueWorkflow(QueryResourceManager): 

547 

548 class resource_type(TypeInfo): 

549 service = 'glue' 

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

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

552 id = name = 'Name' 

553 arn_type = 'workflow' 

554 universal_taggable = object() 

555 cfn_type = 'AWS::Glue::Workflow' 

556 

557 def augment(self, resources): 

558 return universal_augment( 

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

560 

561 

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

563class DeleteWorkflow(BaseAction): 

564 

565 schema = type_schema('delete') 

566 permissions = ('glue:DeleteWorkflow',) 

567 

568 def process(self, resources): 

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

570 for r in resources: 

571 try: 

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

573 except client.exceptions.EntityNotFoundException: 

574 continue 

575 

576 

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

578class GlueWorkflowSecurityConfigFilter(SecurityConfigFilter): 

579 RelatedIdsExpression = 'SecurityConfiguration' 

580 

581 

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

583class GlueDataCatalog(ResourceManager): 

584 

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

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

587 retry = staticmethod(QueryResourceManager.retry) 

588 

589 class resource_type(query.TypeInfo): 

590 service = 'glue' 

591 arn_type = 'catalog' 

592 id = name = 'CatalogId' 

593 cfn_type = 'AWS::Glue::DataCatalogEncryptionSettings' 

594 

595 @classmethod 

596 def get_permissions(cls): 

597 return ('glue:GetDataCatalogEncryptionSettings',) 

598 

599 @classmethod 

600 def has_arn(cls): 

601 return True 

602 

603 def get_arns(self, resources): 

604 return [self.generate_arn(res) for res in resources] 

605 

606 def generate_arn(self, res): 

607 """ 

608 https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsglue.html 

609 One resource per region and one arn per region 

610 """ 

611 return generate_arn( 

612 service=self.resource_type.service, 

613 resource=self.resource_type.arn_type, 

614 region=self.config.region, 

615 account_id=self.config.account_id 

616 ) 

617 

618 def get_model(self): 

619 return self.resource_type 

620 

621 def _get_catalog_encryption_settings(self): 

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

623 settings = client.get_data_catalog_encryption_settings() 

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

625 settings.pop('ResponseMetadata', None) 

626 return [settings] 

627 

628 def resources(self): 

629 return self.filter_resources(self._get_catalog_encryption_settings()) 

630 

631 def get_resources(self, resource_ids): 

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

633 

634 

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

636class GlueCatalogKmsFilter(KmsRelatedFilter): 

637 

638 schema = type_schema( 

639 'kms-key', 

640 rinherit=ValueFilter.schema, 

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

642 'EncryptionAtRest', 'ConnectionPasswordEncryption']}, 

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

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

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

646 

647 permissions = ('glue:GetDataCatalogEncryptionSettings',) 

648 

649 RelatedIdsExpression = '' 

650 

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

652 super().__init__(data, manager) 

653 key_type_to_related_ids = { 

654 'EncryptionAtRest': 'DataCatalogEncryptionSettings.EncryptionAtRest.SseAwsKmsKeyId', 

655 'ConnectionPasswordEncryption': 

656 'DataCatalogEncryptionSettings.ConnectionPasswordEncryption.AwsKmsKeyId' 

657 } 

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

659 

660 

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

662class GlueDataCatalogEncryption(BaseAction): 

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

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

665 not both 

666 

667 :example: 

668 

669 .. code-block:: yaml 

670 

671 policies: 

672 - name: data-catalog-encryption 

673 resource: glue-catalog 

674 filters: 

675 - type: value 

676 key: DataCatalogEncryptionSettings.EncryptionAtRest.CatalogEncryptionMode 

677 value: DISABLED 

678 op: eq 

679 actions: 

680 - type: set-encryption 

681 attributes: 

682 EncryptionAtRest: 

683 CatalogEncryptionMode: SSE-KMS 

684 SseAwsKmsKeyId: alias/aws/glue 

685 """ 

686 

687 schema = type_schema( 

688 'set-encryption', 

689 required=['attributes'], 

690 attributes={ 

691 'type': 'object', 

692 'additionalProperties': False, 

693 'properties': { 

694 'EncryptionAtRest': { 

695 'type': 'object', 

696 'additionalProperties': False, 

697 'required': ['CatalogEncryptionMode'], 

698 'properties': { 

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

700 'SseAwsKmsKeyId': {'type': 'string'} 

701 } 

702 }, 

703 'ConnectionPasswordEncryption': { 

704 'type': 'object', 

705 'additionalProperties': False, 

706 'required': ['ReturnConnectionPasswordEncrypted'], 

707 'properties': { 

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

709 'AwsKmsKeyId': {'type': 'string'} 

710 } 

711 } 

712 } 

713 } 

714 ) 

715 

716 permissions = ('glue:PutDataCatalogEncryptionSettings',) 

717 

718 def process(self, resources): 

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

720 self.process_catalog_encryption(client, resources) 

721 

722 def process_catalog_encryption(self, client, resources): 

723 # there is one glue data catalog per account 

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

725 resources = self.manager.resources() 

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

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

728 if enc_config == updated_config: 

729 return 

730 client.put_data_catalog_encryption_settings( 

731 DataCatalogEncryptionSettings=updated_config) 

732 

733 

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

735class GlueCatalogEncryptionFilter(GlueCatalogEncryptionEnabled): 

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

737 

738 :example: 

739 

740 .. code-block:: yaml 

741 

742 policies: 

743 - name: glue-catalog-security-config 

744 resource: aws.glue-catalog 

745 filters: 

746 - type: glue-security-config 

747 SseAwsKmsKeyId: alias/aws/glue 

748 

749 """ 

750 

751 

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

753class GlueCatalogCrossAccount(CrossAccountAccessFilter): 

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

755 

756 :example: 

757 

758 .. code-block:: yaml 

759 

760 policies: 

761 - name: catalog-cross-account 

762 resource: aws.glue-catalog 

763 filters: 

764 - type: cross-account 

765 

766 """ 

767 permissions = ('glue:GetResourcePolicy',) 

768 policy_annotation = "c7n:AccessPolicy" 

769 

770 def get_resource_policy(self, r): 

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

772 if self.policy_annotation in r: 

773 return r[self.policy_annotation] 

774 try: 

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

776 except client.exceptions.EntityNotFoundException: 

777 policy = {} 

778 r[self.policy_annotation] = policy 

779 return policy 

780 

781 

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

783class RemovePolicyStatement(RemovePolicyBase): 

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

785 

786 :example: 

787 

788 .. code-block:: yaml 

789 

790 policies: 

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

792 resource: aws.glue-catalog 

793 filters: 

794 - type: cross-account 

795 actions: 

796 - type: remove-statements 

797 statement_ids: matched 

798 """ 

799 permissions = ('glue:PutResourcePolicy',) 

800 policy_annotation = "c7n:AccessPolicy" 

801 

802 def validate(self): 

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

804 if isinstance(f, GlueCatalogCrossAccount): 

805 return self 

806 raise PolicyValidationError( 

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

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

809 

810 def process(self, resources): 

811 resource = resources[0] 

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

813 if resource.get(self.policy_annotation): 

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

815 statements, found = self.process_policy( 

816 p, resource, CrossAccountAccessFilter.annotation_key) 

817 if not found: 

818 return 

819 if statements: 

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

821 else: 

822 client.delete_resource_policy()