Skip to content

Commit

Permalink
aws - datalake-location - add resource, deregister action, cross-acco…
Browse files Browse the repository at this point in the history
…unt filter (#7668)
  • Loading branch information
PratMis authored and HappyKid117 committed Oct 16, 2022
1 parent e517e3b commit 499ec3e
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 0 deletions.
67 changes: 67 additions & 0 deletions c7n/resources/lakeformation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from c7n.manager import resources
from c7n.query import QueryResourceManager, TypeInfo
from c7n.actions import BaseAction
from c7n.utils import local_session, type_schema
from .aws import Arn
from c7n.filters import Filter, ValueFilter


@resources.register('datalake-location')
class LakeFormationRegisteredLocation(QueryResourceManager):

class resource_type(TypeInfo):
service = 'lakeformation'
enum_spec = ('list_resources', 'ResourceInfoList', None)
name = arn = id = 'ResourceArn'
cfn_type = "AWS::LakeFormation::Resource"
arn_type = ''


@LakeFormationRegisteredLocation.action_registry.register('deregister')
class DeleteRegisteredLocation(BaseAction):
schema = type_schema('deregister')
permissions = ('lakeformation:DeregisterResource',)

def process(self, resources):
client = local_session(self.manager.session_factory).client('lakeformation')
for r in resources:
try:
self.manager.retry(client.deregister_resource, ResourceArn=r['ResourceArn'])
except client.exceptions.InvalidInputException:
continue


@LakeFormationRegisteredLocation.filter_registry.register('cross-account')
class DataLakeLocationsCrossAccount(Filter):
"""Flags all registered datalake locations if it's cross account.
:example:
.. code-block:: yaml
policies:
- name: lakeformation-cross-account-location
resource: aws.datalake-location
filters:
- type: cross-account
"""

schema = type_schema('cross-account', rinherit=ValueFilter.schema)
schema_alias = False
permissions = ('lakeformation:ListResources',)

def process(self, resources, event=None):
results = []
for r in resources:
if self.process_account(r):
results.append(r)
return results

def process_account(self, r):
lake_bucket = {Arn.parse(r.get('ResourceArn')).resource}
buckets = {
b['Name'] for b in
self.manager.get_resource_manager('s3').resources(augment=False)}
cross_account = lake_bucket.difference(buckets)
return cross_account
1 change: 1 addition & 0 deletions c7n/resources/resource_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
"aws.kinesis-video": "c7n.resources.kinesis.KinesisVideoStream",
"aws.kms": "c7n.resources.kms.KeyAlias",
"aws.kms-key": "c7n.resources.kms.Key",
"aws.datalake-location": "c7n.resources.lakeformation.LakeFormationRegisteredLocation",
"aws.lambda": "c7n.resources.awslambda.AWSLambda",
"aws.lambda-layer": "c7n.resources.awslambda.LambdaLayerVersion",
"aws.launch-config": "c7n.resources.asg.LaunchConfig",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"status_code": 200,
"data": {
"ResponseMetadata": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"status_code": 200,
"data": {
"ResponseMetadata": {},
"ResourceInfoList": [
{
"ResourceArn": "arn:aws:s3:::c7n-test-abc",
"RoleArn": "arn:aws:iam::644160558196:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess",
"LastModified": {
"__class__": "datetime",
"year": 2022,
"month": 8,
"day": 18,
"hour": 14,
"minute": 35,
"second": 41,
"microsecond": 967000
}
},
{
"ResourceArn": "arn:aws:s3:::unknown-bucket",
"RoleArn": "arn:aws:iam::644160558196:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess",
"LastModified": {
"__class__": "datetime",
"year": 2022,
"month": 8,
"day": 22,
"hour": 15,
"minute": 16,
"second": 12,
"microsecond": 811000
}
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"status_code": 200,
"data": {
"ResponseMetadata": {},
"ResourceInfoList": [
{
"ResourceArn": "arn:aws:s3:::c7n-test-abc",
"RoleArn": "arn:aws:iam::644160558196:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess",
"LastModified": {
"__class__": "datetime",
"year": 2022,
"month": 8,
"day": 18,
"hour": 14,
"minute": 35,
"second": 41,
"microsecond": 967000
}
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"status_code": 200,
"data": {
"ResponseMetadata": {},
"Buckets": [
{
"Name": "c7n-test-abc",
"CreationDate": {
"__class__": "datetime",
"year": 2020,
"month": 9,
"day": 18,
"hour": 20,
"minute": 31,
"second": 12,
"microsecond": 0
}
},
{
"Name": "c7n-test-arn",
"CreationDate": {
"__class__": "datetime",
"year": 2020,
"month": 12,
"day": 15,
"hour": 19,
"minute": 13,
"second": 28,
"microsecond": 0
}
}
],
"Owner": {
"DisplayName": "mandeep.bal",
"ID": "e7c8bb65a5fc49cf906715eae09de9e4bb7861a96361ba79b833aa45f6833b15"
}
}
}
20 changes: 20 additions & 0 deletions tests/test_lakeformation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from .common import BaseTest


class DataLakeRegisteredLocation(BaseTest):

def test_datalake_cross_account_deregister(self):
factory = self.replay_flight_data('test_datalake_cross_account_deregister')
p = self.load_policy({
'name': 'datalake-location-cross-account',
'resource': 'datalake-location',
'filters': [{'type': 'cross-account'}],
'actions': [{'type': 'deregister'}]},
session_factory=factory)
resources = p.run()
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0]['ResourceArn'], 'arn:aws:s3:::unknown-bucket')
client = factory().client("lakeformation")
reg_loc = client.list_resources()['ResourceInfoList']
self.assertEqual(len(reg_loc), 1)
self.assertNotEqual((r.get('ResourceArn') for r in reg_loc), 'arn:aws:s3:::pratyush-123')

0 comments on commit 499ec3e

Please sign in to comment.