Пример #1
0
def process_action(resource, action, action_issuer='unknown'):
    """Process an audit action for a resource, if possible

    Args:
        resource (:obj:`Resource`): A resource object to perform the action on
        action (`str`): Type of action to perform (`kill` or `stop`)
        action_issuer (`str`): The issuer of the action
    Returns:
        `ActionStatus`
    """
    from cinq_collector_aws import AWSRegionCollector

    func_action = action_mapper[resource.resource_type][action]
    extra_info = {}
    action_status = ActionStatus.UNKNOWN

    if func_action:
        if action_mapper[resource.resource_type]['service_name'] == 'lambda':
            client = get_aws_session(
                AWSAccount.get(
                    dbconfig.get('rds_collector_account',
                                 AWSRegionCollector.ns, ''))).client(
                                     'lambda',
                                     dbconfig.get('rds_collector_region',
                                                  AWSRegionCollector.ns, ''))
        else:
            client = get_aws_session(AWSAccount(resource.account)).client(
                action_mapper[resource.resource_type]['service_name'],
                region_name=resource.location)
        try:
            logger.info(
                f'Trying to {action} resource {resource.id} for account {resource.account.account_name} / region {resource.location}'
            )
            action_status, extra_info = func_action(client, resource)
            if action_status == ActionStatus.SUCCEED:
                Enforcement.create(resource.account.account_id, resource.id,
                                   action, datetime.now(), extra_info)
        except Exception as ex:
            action_status = ActionStatus.FAILED
            logger.exception('Failed to apply action {} to {}: {}'.format(
                action, resource.id, ex))
        finally:
            auditlog(event='{}.{}.{}.{}'.format(action_issuer,
                                                resource.resource_type, action,
                                                action_status),
                     actor=action_issuer,
                     data={
                         'resource_id': resource.id,
                         'account_name': resource.account.account_name,
                         'location': resource.location,
                         'info': extra_info
                     })
            return action_status
    else:
        logger.error('Failed to apply action {} to {}: Not supported'.format(
            action, resource.id))
        return ActionStatus.FAILED
Пример #2
0
    def manage_policies(self, accounts):
        if not accounts:
            return

        self.git_policies = self.get_policies_from_git()
        self.manage_roles = self.dbconfig.get('manage_roles', self.ns, True)
        self.cfg_roles = self.dbconfig.get('roles', self.ns)
        self.aws_managed_policies = {
            policy['PolicyName']: policy
            for policy in self.get_policies_from_aws(
                get_aws_session(accounts[0]).client('iam'), 'AWS')
        }

        for account in accounts:
            try:
                if not account.ad_group_base:
                    self.log.info(
                        'Account {} does not have AD Group Base set, skipping'.
                        format(account.account_name))
                    continue

                # List all policies and roles from AWS, and generate a list of policies from Git
                sess = get_aws_session(account)
                iam = sess.client('iam')

                aws_roles = {
                    role['RoleName']: role
                    for role in self.get_roles(iam)
                }
                aws_policies = {
                    policy['PolicyName']: policy
                    for policy in self.get_policies_from_aws(iam)
                }

                account_policies = copy.deepcopy(self.git_policies['GLOBAL'])

                if account.account_name in self.git_policies:
                    for role in self.git_policies[account.account_name]:
                        account_policies.update(
                            self.git_policies[account.account_name][role])

                aws_policies.update(
                    self.check_policies(account, account_policies,
                                        aws_policies))
                self.check_roles(account, aws_policies, aws_roles)
            except Exception as exception:
                self.log.info(
                    'Unable to process account {}. Unhandled Exception {}'.
                    format(account.account_name, exception))
Пример #3
0
    def run(self, **kwargs):
        self.kwargs = kwargs
        try:
            key_id = self.kwargs['key_id']

            if self.kwargs['data'].startswith('@'):
                path = self.kwargs['data'][1:]

                try:
                    with open(path, 'rb') as fh:
                        data = fh.read(-1)

                except Exception as ex:
                    self.log.exception(
                        'Failed loading data from file: {}'.format(ex))
                    return
            else:
                data = kwargs['data']

            session = get_local_aws_session()
            if session.get_credentials().method != 'iam-role':
                kms_account_name = app_config.kms_account_name
                if not kms_account_name:
                    print(
                        'you must set the kms_account_name setting in your configuration file to the name of the '
                        'account that is able to decrypt the user data')
                    return
                acct = Account.get(kms_account_name)
                if not acct:
                    print(
                        'You must add the {} account to the system for this to work'
                        .format(kms_account_name))
                    return

                session = get_aws_session(acct)

            kms = session.client('kms',
                                 region_name=self.dbconfig.get(
                                     'region', self.ns, 'us-west-2'))
            if kwargs['mode'] == 'encrypt':
                if not kwargs['key_id']:
                    print(
                        'You must provide a key id to use for encryption to work'
                    )
                    return

                compressed = zlib.compress(
                    bytes(json.dumps(json.loads(data)), 'utf-8'))
                res = kms.encrypt(KeyId=key_id, Plaintext=compressed)
                self.output(res['CiphertextBlob'])
            else:
                res = kms.decrypt(CiphertextBlob=b64decode(data))
                self.output(
                    json.dumps(json.loads(
                        str(zlib.decompress(res['Plaintext']), 'utf-8')),
                               indent=4))

        except Exception:
            self.log.exception(
                'An error occured while doing userdata.py stuff')
Пример #4
0
    def create_s3_bucket(cls, bucket_name, bucket_region, bucket_account,
                         template):
        """Creates the S3 bucket on the account specified as the destination account for log files

        Args:
            bucket_name (`str`): Name of the S3 bucket
            bucket_region (`str`): AWS Region for the bucket
            bucket_account (:obj:`Account`): Account to create the S3 bucket in
            template (:obj:`Template`): Jinja2 Template object for the bucket policy

        Returns:
            `None`
        """
        s3 = get_aws_session(bucket_account).client('s3',
                                                    region_name=bucket_region)

        # Check to see if the bucket already exists and if we have access to it
        try:
            s3.head_bucket(Bucket=bucket_name)
        except ClientError as ex:
            status_code = ex.response['ResponseMetadata']['HTTPStatusCode']

            # Bucket exists and we do not have access
            if status_code == 403:
                raise Exception(
                    'Bucket {} already exists but we do not have access to it and so cannot continue'
                    .format(bucket_name))

            # Bucket does not exist, lets create one
            elif status_code == 404:
                try:
                    s3.create_bucket(Bucket=bucket_name,
                                     CreateBucketConfiguration={
                                         'LocationConstraint': bucket_region
                                     })

                    auditlog(event='cloudtrail.create_s3_bucket',
                             actor=cls.ns,
                             data={
                                 'account': bucket_account.account_name,
                                 'bucket_region': bucket_region,
                                 'bucket_name': bucket_name
                             })
                except Exception:
                    raise Exception(
                        'An error occured while trying to create the bucket, cannot continue'
                    )

        try:
            bucket_acl = template.render(
                bucket_name=bucket_name,
                account_id=bucket_account.account_number)
            s3.put_bucket_policy(Bucket=bucket_name, Policy=bucket_acl)

        except Exception as ex:
            raise Warning(
                'An error occurred while setting bucket policy: {}'.format(ex))
Пример #5
0
    def check_policies(self, account, account_policies, aws_policies):
        """Iterate through the policies of a specific account and create or update the policy if its missing or
        does not match the policy documents from Git. Returns a dict of all the policies added to the account
        (does not include updated policies)

        Args:
            account (:obj:`Account`): Account to check policies for
            account_policies (`dict` of `str`: `dict`): A dictionary containing all the policies for the specific
            account
            aws_policies (`dict` of `str`: `dict`): A dictionary containing the non-AWS managed policies on the account

        Returns:
            :obj:`dict` of `str`: `str`
        """
        self.log.debug('Fetching policies for {}'.format(account.account_name))
        sess = get_aws_session(account)
        iam = sess.client('iam')
        added = {}

        for policyName, account_policy in account_policies.items():
            # policies pulled from github a likely bytes and need to be converted
            if isinstance(account_policy, bytes):
                account_policy = account_policy.decode('utf-8')

            # Using re.sub instead of format since format breaks on the curly braces of json
            gitpol = json.loads(
                re.sub(r'{AD_Group}', account.ad_group_base
                       or account.account_name, account_policy))

            if policyName in aws_policies:
                pol = aws_policies[policyName]
                awspol = iam.get_policy_version(
                    PolicyArn=pol['Arn'], VersionId=pol['DefaultVersionId']
                )['PolicyVersion']['Document']

                if awspol != gitpol:
                    self.log.warn(
                        'IAM Policy {} on {} does not match Git policy documents, updating'
                        .format(policyName, account.account_name))

                    self.create_policy(account,
                                       iam,
                                       json.dumps(gitpol, indent=4),
                                       policyName,
                                       arn=pol['Arn'])
                else:
                    self.log.debug('IAM Policy {} on {} is up to date'.format(
                        policyName, account.account_name))
            else:
                self.log.warn('IAM Policy {} is missing on {}'.format(
                    policyName, account.account_name))
                response = self.create_policy(account, iam, json.dumps(gitpol),
                                              policyName)
                added[policyName] = response['Policy']

        return added
Пример #6
0
    def __init__(self, account):
        super().__init__()

        if type(account) == str:
            account = AWSAccount.get(account)

        if not isinstance(account, AWSAccount):
            raise InquisitorError('The AWS Collector only supports AWS Accounts, got {}'.format(
                account.__class__.__name__
            ))

        self.account = account
        self.session = get_aws_session(self.account)
Пример #7
0
def process_action(resource, action, resource_type):
    """Process an audit action for a resource, if possible

    Args:
        resource (:obj:`Resource`): A resource object to perform the action on
        action (`str`): Type of action to perform (`kill` or `stop`)
        resource_type (`str`): Type of the resource

    Returns:
        `bool` - Returns the result from the action function
    """
    func_action = action_mapper[resource_type][action]
    if func_action:
        session = get_aws_session(AWSAccount(resource.account))
        client = session.client(
            action_mapper[resource_type]['service_name'],
            region_name=resource.location
        )
        return func_action(client, resource)

    return False
Пример #8
0
    def __init__(self, account, bucket_name, bucket_region, logger):
        self.account = account
        self.bucket_region = bucket_region
        self.bucket_name = bucket_name
        self.log = logger

        # Config settings
        self.global_ct_region = dbconfig.get('global_cloudtrail_region',
                                             self.ns, 'us-west-2')
        self.topic_name = dbconfig.get('sns_topic_name', self.ns,
                                       'cloudtrail-log-notification')
        self.trail_name = dbconfig.get('trail_name', self.ns)

        sqs_queue_name = dbconfig.get('sqs_queue_name', self.ns)
        sqs_queue_region = dbconfig.get('sqs_queue_region', self.ns)
        sqs_account = AWSAccount.get(dbconfig.get('sqs_queue_account',
                                                  self.ns))

        self.sqs_queue = 'arn:aws:sqs:{}:{}:{}'.format(
            sqs_queue_region, sqs_account.account_number, sqs_queue_name)

        self.session = get_aws_session(account)
Пример #9
0
    def run(self):
        """Main entry point for the auditor worker.

        Returns:
            `None`
        """
        # Loop through all accounts that are marked as enabled
        accounts = list(AWSAccount.get_all(include_disabled=False).values())
        for account in accounts:
            self.log.debug('Updating VPC Flow Logs for {}'.format(account))

            self.session = get_aws_session(account)
            role_arn = self.confirm_iam_role(account)
            # region specific
            for aws_region in AWS_REGIONS:
                try:
                    vpc_list = VPC.get_all(account, aws_region).values()
                    need_vpc_flow_logs = [
                        x for x in vpc_list
                        if x.vpc_flow_logs_status != 'ACTIVE'
                    ]

                    for vpc in need_vpc_flow_logs:
                        if self.confirm_cw_log(account, aws_region, vpc.id):
                            self.create_vpc_flow_logs(account, aws_region,
                                                      vpc.id, role_arn)
                        else:
                            self.log.info(
                                'Failed to confirm log group for {}/{}'.format(
                                    account, aws_region))

                except Exception:
                    self.log.exception(
                        'Failed processing VPCs for {}/{}.'.format(
                            account, aws_region))

            db.session.commit()
Пример #10
0
def process_action(resource, action, action_issuer='unknown'):
    """Process an audit action for a resource, if possible

    Args:
        resource (:obj:`Resource`): A resource object to perform the action on
        action (`str`): Type of action to perform (`kill` or `stop`)
        action_issuer (`str`): The issuer of the action
    Returns:
        `ActionStatus`
    """
    func_action = action_mapper[resource.resource_type][action]
    if func_action:
        client = get_aws_session(AWSAccount(resource.account)).client(
            action_mapper[resource.resource_type]['service_name'],
            region_name=resource.location
        )
        try:
            action_status, metrics = func_action(client, resource)
            Enforcement.create(resource.account.account_name, resource.id, action, datetime.now(), metrics)
        except Exception as ex:
            action_status = ActionStatus.FAILED
            logger.error('Failed to apply action {} to {}: {}'.format(action, resource.id, ex))
        finally:
            auditlog(
                event='{}.{}.{}.{}'.format(action_issuer, resource.resource_type, action, action_status),
                actor=action_issuer,
                data={
                    'resource_id': resource.id,
                    'account_name': resource.account.account_name,
                    'location': resource.location
                }
            )
            return action_status
    else:
        logger.error('Failed to apply action {} to {}: Not supported'.format(action, resource.id))
        return ActionStatus.FAILED
Пример #11
0
    def validate_sqs_policy(self, accounts):
        """Given a list of accounts, ensures that the SQS policy allows all the accounts to write to the queue

        Args:
            accounts (`list` of :obj:`Account`): List of accounts

        Returns:
            `None`
        """
        sqs_queue_name = self.dbconfig.get('sqs_queue_name', self.ns)
        sqs_queue_region = self.dbconfig.get('sqs_queue_region', self.ns)
        sqs_account = AWSAccount.get(
            self.dbconfig.get('sqs_queue_account', self.ns))
        session = get_aws_session(sqs_account)

        sqs = session.client('sqs', region_name=sqs_queue_region)
        sqs_queue_url = sqs.get_queue_url(
            QueueName=sqs_queue_name,
            QueueOwnerAWSAccountId=sqs_account.account_number)
        sqs_attribs = sqs.get_queue_attributes(
            QueueUrl=sqs_queue_url['QueueUrl'], AttributeNames=['Policy'])

        policy = json.loads(sqs_attribs['Attributes']['Policy'])

        for account in accounts:
            arn = 'arn:aws:sns:*:{}:{}'.format(account.account_number,
                                               sqs_queue_name)
            if arn not in policy['Statement'][0]['Condition'][
                    'ForAnyValue:ArnEquals']['aws:SourceArn']:
                self.log.warning(
                    'SQS policy is missing condition for ARN {}'.format(arn))
                policy['Statement'][0]['Condition']['ForAnyValue:ArnEquals'][
                    'aws:SourceArn'].append(arn)

        sqs.set_queue_attributes(QueueUrl=sqs_queue_url['QueueUrl'],
                                 Attributes={'Policy': json.dumps(policy)})
Пример #12
0
def aws_get_client(client_type, region=CINQ_TEST_REGION):
    return get_aws_session().client(client_type, region)
Пример #13
0
    def check_roles(self, account, aws_policies, aws_roles):
        """Iterate through the roles of a specific account and create or update the roles if they're missing or
        does not match the roles from Git.

        Args:
            account (:obj:`Account`): The account to check roles on
            aws_policies (:obj:`dict` of `str`: `dict`): A dictionary containing all the policies for the specific
            account
            aws_roles (:obj:`dict` of `str`: `dict`): A dictionary containing all the roles for the specific account

        Returns:
            `None`
        """
        self.log.debug('Checking roles for {}'.format(account.account_name))
        max_session_duration = self.dbconfig.get('role_timeout_in_hours',
                                                 self.ns, 8) * 60 * 60
        sess = get_aws_session(account)
        iam = sess.client('iam')

        # Build a list of default role policies and extra account specific role policies
        account_roles = copy.deepcopy(self.cfg_roles)
        if account.account_name in self.git_policies:
            for role in self.git_policies[account.account_name]:
                if role in account_roles:
                    account_roles[role]['policies'] += list(
                        self.git_policies[account.account_name][role].keys())

        for role_name, data in list(account_roles.items()):
            if role_name not in aws_roles:
                iam.create_role(Path='/',
                                RoleName=role_name,
                                AssumeRolePolicyDocument=json.dumps(
                                    data['trust'], indent=4),
                                MaxSessionDuration=max_session_duration)
                self.log.info('Created role {}/{}'.format(
                    account.account_name, role_name))
            else:
                try:
                    if aws_roles[role_name][
                            'MaxSessionDuration'] != max_session_duration:
                        iam.update_role(
                            RoleName=aws_roles[role_name]['RoleName'],
                            MaxSessionDuration=max_session_duration)
                        self.log.info(
                            'Adjusted MaxSessionDuration for role {} in account {} to {} seconds'
                            .format(role_name, account.account_name,
                                    max_session_duration))
                except ClientError:
                    self.log.exception(
                        'Unable to adjust MaxSessionDuration for role {} in account {}'
                        .format(role_name, account.account_name))

            aws_role_policies = [
                x['PolicyName'] for x in iam.list_attached_role_policies(
                    RoleName=role_name)['AttachedPolicies']
            ]
            aws_role_inline_policies = iam.list_role_policies(
                RoleName=role_name)['PolicyNames']
            cfg_role_policies = data['policies']

            missing_policies = list(
                set(cfg_role_policies) - set(aws_role_policies))
            extra_policies = list(
                set(aws_role_policies) - set(cfg_role_policies))

            if aws_role_inline_policies:
                self.log.info(
                    'IAM Role {} on {} has the following inline policies: {}'.
                    format(role_name, account.account_name,
                           ', '.join(aws_role_inline_policies)))

                if self.dbconfig.get('delete_inline_policies', self.ns,
                                     False) and self.manage_roles:
                    for policy in aws_role_inline_policies:
                        iam.delete_role_policy(RoleName=role_name,
                                               PolicyName=policy)
                        auditlog(
                            event='iam.check_roles.delete_inline_role_policy',
                            actor=self.ns,
                            data={
                                'account': account.account_name,
                                'roleName': role_name,
                                'policy': policy
                            })

            if missing_policies:
                self.log.info(
                    'IAM Role {} on {} is missing the following policies: {}'.
                    format(role_name, account.account_name,
                           ', '.join(missing_policies)))
                if self.manage_roles:
                    for policy in missing_policies:
                        iam.attach_role_policy(
                            RoleName=role_name,
                            PolicyArn=aws_policies[policy]['Arn'])
                        auditlog(event='iam.check_roles.attach_role_policy',
                                 actor=self.ns,
                                 data={
                                     'account': account.account_name,
                                     'roleName': role_name,
                                     'policyArn': aws_policies[policy]['Arn']
                                 })

            if extra_policies:
                self.log.info(
                    'IAM Role {} on {} has the following extra policies applied: {}'
                    .format(role_name, account.account_name,
                            ', '.join(extra_policies)))

                for policy in extra_policies:
                    if policy in aws_policies:
                        polArn = aws_policies[policy]['Arn']
                    elif policy in self.aws_managed_policies:
                        polArn = self.aws_managed_policies[policy]['Arn']
                    else:
                        polArn = None
                        self.log.info(
                            'IAM Role {} on {} has an unknown policy attached: {}'
                            .format(role_name, account.account_name, policy))

                    if self.manage_roles and polArn:
                        iam.detach_role_policy(RoleName=role_name,
                                               PolicyArn=polArn)
                        auditlog(event='iam.check_roles.detach_role_policy',
                                 actor=self.ns,
                                 data={
                                     'account': account.account_name,
                                     'roleName': role_name,
                                     'policyArn': polArn
                                 })
Пример #14
0
    def update_rds_databases(self):
        """Update list of RDS Databases for the account / region

        Returns:
            `None`
        """
        self.log.info('Updating RDS Databases for {} / {}'.format(
            self.account, self.region
        ))
        # All RDS resources are polled via a Lambda collector in a central account
        rds_collector_account = AWSAccount.get(self.rds_collector_account)
        rds_session = get_aws_session(rds_collector_account)
        # Existing RDS resources come from database
        existing_rds_dbs = RDSInstance.get_all(self.account, self.region)

        try:
            # Special session pinned to a single account for Lambda invocation so we
            # don't have to manage lambdas in every account & region
            lambda_client = rds_session.client('lambda', region_name=self.rds_collector_region)

            # The AWS Config Lambda will collect all the non-compliant resources for all regions
            # within the account
            input_payload = json.dumps({"account_id": self.account.account_number,
                                        "region": self.region,
                                        "role": self.rds_role,
                                        "config_rule_name": self.rds_config_rule_name
                                        }).encode('utf-8')
            response = lambda_client.invoke(FunctionName=self.rds_function_name, InvocationType='RequestResponse',
                                            Payload=input_payload
                                            )
            response_payload = json.loads(response['Payload'].read().decode('utf-8'))
            if response_payload['success']:
                rds_dbs = response_payload['data']
                if rds_dbs:
                    for db_instance in rds_dbs:
                        tags = {t['Key']: t['Value'] for t in db_instance['tags'] or {}}
                        properties = {
                            'tags': tags,
                            'metrics': None,
                            'engine': db_instance['engine'],
                            'creation_date': db_instance['creation_date']
                        }
                        if db_instance['resource_name'] in existing_rds_dbs:
                            rds = existing_rds_dbs[db_instance['resource_name']]
                            if rds.update(db_instance, properties):
                                self.log.debug('Change detected for RDS instance {}/{} '
                                               .format(db_instance['resource_name'], properties))
                        else:
                            RDSInstance.create(
                                db_instance['resource_name'],
                                account_id=self.account.account_id,
                                location=db_instance['region'],
                                properties=properties,
                                tags=tags
                            )
                # Removal of RDS instances
                rk = set()
                erk = set()
                for database in rds_dbs:
                    rk.add(database['resource_name'])
                for existing in existing_rds_dbs.keys():
                    erk.add(existing)

                for resource_id in erk - rk:
                    db.session.delete(existing_rds_dbs[resource_id].resource)
                    self.log.debug('Removed RDS instances {}/{}'.format(
                        self.account.account_name,
                        resource_id
                    ))
                db.session.commit()

            else:
                self.log.error('RDS Lambda Execution Failed / {} / {} / {}'.
                                format(self.account.account_name, self.region, response_payload))

        except Exception as e:
            self.log.exception('There was a problem during RDS collection for {}/{}/{}'.format(
                self.account.account_name, self.region, e
            ))
            db.session.rollback()
Пример #15
0
def delete_s3_bucket(client, resource):
    try:
        session = get_aws_session(AWSAccount(resource.account))
        bucket = session.resource('s3', resource.location).Bucket(resource.resource_id)
        days_until_expiry = dbconfig.get('lifecycle_expiration_days', NS_AUDITOR_REQUIRED_TAGS, 3)
        # Separate rule for Object Markers is needed and can't be combined into a single rule per AWS API
        lifecycle_policy = {
            'Rules': [
                {'Status': 'Enabled',
                 'NoncurrentVersionExpiration': {u'NoncurrentDays': days_until_expiry},
                 'Filter': {u'Prefix': ''},
                 'Expiration': {
                     'Date': datetime.utcnow().replace(
                         hour=0, minute=0, second=0, microsecond=0
                     ) + timedelta(days=days_until_expiry)
                 },
                 'AbortIncompleteMultipartUpload': {u'DaysAfterInitiation': days_until_expiry},
                 'ID': 'cinqRemoveObjectsAndVersions'},

                {'Status': 'Enabled',
                 'Filter': {u'Prefix': ''},
                 'Expiration': {
                     'ExpiredObjectDeleteMarker': True
                 },
                 'ID': 'cinqRemoveDeletedExpiredMarkers'}
            ]
        }

        bucket_policy = {
            'Version': '2012-10-17',
            'Id': 'PutObjPolicy',
            'Statement': [
                {'Sid': 'cinqDenyObjectUploads',
                 'Effect': 'Deny',
                 'Principal': '*',
                 'Action': ['s3:PutObject', 's3:GetObject'],
                 'Resource': 'arn:aws:s3:::{}/*'.format(resource.resource_id)
                 }
            ]
        }

        metrics = {'Unavailable': 'Unavailable'}
        for prop in resource.properties:
            if prop.name == "metrics":
                metrics = prop.value

        objects = list(bucket.objects.limit(count=1))
        versions = list(bucket.object_versions.limit(count=1))
        if not objects and not versions:
            bucket.delete()
            logger.info('Deleted s3 bucket {} in {}'.format(resource.resource_id, resource.account))
            Enforcement.create(resource.account_id, resource.resource_id, 'DELETED',
                               datetime.now(), metrics)
            auditlog(
                event='required_tags.s3.terminate',
                actor=NS_AUDITOR_REQUIRED_TAGS,
                data={
                    'resource_id': resource.resource_id,
                    'account_name': resource.account.account_name,
                    'location': resource.location
                }
            )
            return True

        else:
            try:
                rules = bucket.LifecycleConfiguration().rules
                for rule in rules:
                    if rule['ID'] == 'cinqRemoveDeletedExpiredMarkers':
                        rules_exists = True
                        break
                else:
                    rules_exists = False
            except ClientError:
                rules_exists = False

            try:
                current_bucket_policy = bucket.Policy().policy
            except ClientError as error:
                if error.response['Error']['Code'] == 'NoSuchBucketPolicy':
                    current_bucket_policy = 'missing'

            try:
                if not rules_exists:
                    # Grab S3 Metrics before lifecycle policies start removing objects

                    bucket.LifecycleConfiguration().put(LifecycleConfiguration=lifecycle_policy)
                    logger.info('Added policies to delete bucket contents in s3 bucket {} in {}'.format(
                        resource.resource_id,
                        resource.account
                    ))
                    Enforcement.create(resource.account_id, resource.resource_id, 'LIFECYCLE_APPLIED',
                                       datetime.now(), metrics)

                if 'cinqDenyObjectUploads' not in current_bucket_policy:
                    bucket.Policy().put(Policy=json.dumps(bucket_policy))
                    logger.info('Added policy to prevent putObject in s3 bucket {} in {}'.format(
                        resource.resource_id,
                        resource.account
                    ))

            except ClientError as error:
                logger.error(
                    'Problem applying the bucket policy or lifecycle configuration to bucket {} / account {} / {}'
                    .format(resource.resource_id, resource.account_id, error.response['Error']['Code']))

            if rules_exists and 'cinqDenyObjectUploads' in current_bucket_policy:
                # We're waiting for the lifecycle policy to delete data
                raise ResourceActionError({'msg': 'wait_for_deletion'})

    except ResourceActionError as error:
        raise ResourceActionError(error)
    except Exception as error:
        logger.info(
            'Failed to delete s3 bucket {} in {}, error is {}'.format(resource.resource_id, resource.account, error))

        raise ResourceKillError(
            'Failed to delete s3 bucket {} in {}. Reason: {}'.format(resource.resource_id, resource.account, error)
        )
Пример #16
0
def get_aws_regions(service):
    return get_aws_session().get_available_regions(service)