Ejemplo n.º 1
0
    def create_cloudtrail(self, region):
        """Creates a new CloudTrail Trail

        Args:
            region (str): Name of the AWS region

        Returns:
            `None`
        """
        ct = self.session.client('cloudtrail', region_name=region)

        # Creating the sns topic for the trail prior to creation
        self.create_sns_topic(region)

        ct.create_trail(Name=self.trail_name,
                        S3BucketName=self.bucket_name,
                        S3KeyPrefix=self.account.account_name,
                        IsMultiRegionTrail=True,
                        IncludeGlobalServiceEvents=True,
                        SnsTopicName=self.topic_name)
        self.subscribe_sns_topic_to_sqs(region)

        auditlog(event='cloudtrail.create_cloudtrail',
                 actor=self.ns,
                 data={
                     'account': self.account.account_name,
                     'region': region
                 })
        self.log.info('Created CloudTrail for {} in {} ({})'.format(
            self.account, region, self.bucket_name))
Ejemplo n.º 2
0
    def create_sns_topic(self, region):
        """Creates an SNS topic if needed. Returns the ARN if the created SNS topic

        Args:
            region (str): Region name

        Returns:
            `str`
        """
        sns = self.session.client('sns', region_name=region)

        self.log.info('Creating SNS topic for {}/{}'.format(
            self.account, region))
        # Create the topic
        res = sns.create_topic(Name=self.topic_name)
        arn = res['TopicArn']

        # Allow CloudTrail to publish messages with a policy update
        tmpl = get_template('cloudtrail_sns_policy.json')
        policy = tmpl.render(region=region,
                             account_id=self.account.account_number,
                             topic_name=self.topic_name)
        sns.set_topic_attributes(TopicArn=arn,
                                 AttributeName='Policy',
                                 AttributeValue=policy)

        auditlog(event='cloudtrail.create_sns_topic',
                 actor=self.ns,
                 data={
                     'account': self.account.account_name,
                     'region': region
                 })

        return arn
Ejemplo n.º 3
0
    def put(self, template_name):
        """Update a template"""
        self.reqparse.add_argument('template', type=str, required=True)
        args = self.reqparse.parse_args()

        template = db.Template.find_one(template_name=template_name)

        if not template:
            return self.make_response('No such template found', HTTP.NOT_FOUND)

        changes = diff(template.template, args['template'])
        template.template = args['template']
        template.is_modified = True

        db.session.add(template)
        db.session.commit()
        auditlog(event='template.update',
                 actor=session['user'].username,
                 data={
                     'template_name': template_name,
                     'template_changes': changes
                 })

        return self.make_response(
            'Template {} has been updated'.format(template_name))
Ejemplo n.º 4
0
def _import_templates(force=False):
    """Import templates from disk into database

    Reads all templates from disk and adds them to the database. By default, any template that has been modified by
    the user will not be updated. This can however be changed by setting `force` to `True`, which causes all templates
    to be imported regardless of status

    Args:
        force (`bool`): Force overwrite any templates with local changes made. Default: `False`

    Returns:
        `None`
    """
    tmplpath = os.path.join(resource_filename('cloud_inquisitor', 'data'),
                            'templates')
    disk_templates = {
        f: os.path.join(root, f)
        for root, directory, files in os.walk(tmplpath) for f in files
    }
    db_templates = {tmpl.template_name: tmpl for tmpl in db.Template.find()}

    for name, template_file in disk_templates.items():
        with open(template_file, 'r') as f:
            body = f.read()
        disk_hash = get_hash(body)

        if name not in db_templates:
            template = Template()
            template.template_name = name
            template.template = body

            db.session.add(template)
            auditlog(event='template.import',
                     actor='init',
                     data={
                         'template_name': name,
                         'template': body
                     })
            logger.info('Imported template {}'.format(name))
        else:
            template = db_templates[name]
            db_hash = get_hash(template.template)

            if db_hash != disk_hash:
                if force or not db_templates[name].is_modified:
                    template.template = body

                    db.session.add(template)
                    auditlog(event='template.update',
                             actor='init',
                             data={
                                 'template_name': name,
                                 'template_diff': diff(template.template, body)
                             })
                    logger.info('Updated template {}'.format(name))
                else:
                    logger.warning(
                        'Updated template available for {}. Will not import as it would'
                        ' overwrite user edited content and force is not enabled'
                        .format(name))
Ejemplo n.º 5
0
    def post(self):
        """Create a new configuration namespace"""
        self.reqparse.add_argument('namespacePrefix', type=str, required=True)
        self.reqparse.add_argument('name', type=str, required=True)
        self.reqparse.add_argument('sortOrder', type=int, required=True)
        args = self.reqparse.parse_args()

        if self.dbconfig.namespace_exists(args['namespacePrefix']):
            return self.make_response(
                'Namespace {} already exists'.format(args['namespacePrefix']),
                HTTP.CONFLICT)

        ns = ConfigNamespace()

        ns.namespace_prefix = args['namespacePrefix']
        ns.name = args['name']
        ns.sort_order = args['sortOrder']

        db.session.add(ns)
        db.session.commit()

        self.dbconfig.reload_data()
        auditlog(event='configNamespace.create',
                 actor=session['user'].username,
                 data=args)

        return self.make_response('Namespace created', HTTP.CREATED)
Ejemplo n.º 6
0
    def delete(self, user_id):
        """Delete a user"""
        auditlog(event='user.delete',
                 actor=session['user'].username,
                 data={'userId': user_id})
        if session['user'].user_id == user_id:
            return self.make_response(
                'You cannot delete the user you are currently logged in as',
                HTTP.FORBIDDEN)

        user = db.User.find_one(User.user_id == user_id)
        if not user:
            return self.make_response(
                'No such user id found: {}'.format(user_id), HTTP.UNAUTHORIZED)

        if user.username == 'admin' and user.auth_system == 'builtin':
            return self.make_response(
                'You cannot delete the built-in admin user', HTTP.FORBIDDEN)

        username = user.username
        auth_system = user.auth_system
        db.session.delete(user)
        db.session.commit()

        return self.make_response(
            'User {}/{} has been deleted'.format(auth_system, username),
            HTTP.OK)
Ejemplo n.º 7
0
    def put(self, user_id):
        self.reqparse.add_argument('password', type=str, required=False)
        args = self.reqparse.parse_args()
        auditlog(event='user.passwordReset', actor=session['user'].username, data=args)

        user = db.User.find_one(User.user_id == user_id)
        if not user:
            return self.make_response('User not found', HTTP.NOT_FOUND)

        if ROLE_ADMIN not in session['user'].roles and user_id != session['user'].user_id:
            self.log.warning('{} tried to change the password for another user'.format(session['user'].user_id))
            return self.make_response('You cannot change other users passwords', HTTP.FORBIDDEN)

        authsys = current_app.available_auth_systems[user.auth_system]
        if authsys.readonly:
            return self.make_response(
                'You cannot reset passwords for the {} based users'.format(authsys.name),
                HTTP.FORBIDDEN
            )

        new_pass = args['password'] or generate_password()

        user.password = hash_password(new_pass)
        db.session.add(user)
        db.session.commit()

        return self.make_response({
            'user': user.to_json(),
            'newPassword': new_pass if not args['password'] else None
        }, HTTP.OK)
Ejemplo n.º 8
0
    def post(self):
        """Create a new template"""
        self.reqparse.add_argument('templateName', type=str, required=True)
        self.reqparse.add_argument('template', type=str, required=True)
        args = self.reqparse.parse_args()

        template = db.Template.find_one(template_name=args['templateName'])
        if template:
            return self.make_response(
                'Template already exists, update the existing template instead',
                HTTP.CONFLICT)

        template = Template()
        template.template_name = args['templateName']
        template.template = args['template']

        db.session.add(template)
        db.session.commit()
        auditlog(event='template.create',
                 actor=session['user'].username,
                 data=args)

        return self.make_response(
            'Template {} has been created'.format(template.template_name),
            HTTP.CREATED)
Ejemplo n.º 9
0
    def put(self, emailId):
        email = db.Email.find_one(Email.email_id == emailId)
        if not email:
            return self.make_response(
                {
                    'message': 'Email not found',
                    'email': None
                }, HTTP.NOT_FOUND)

        try:
            send_notification(subsystem=email.subsystem,
                              recipients=[
                                  NotificationContact('email', x)
                                  for x in email.recipients
                              ],
                              subject=email.subject,
                              body_html=email.message_html,
                              body_text=email.message_text)

            auditlog(event='email.resend',
                     actor=session['user'].username,
                     data={'emailId': emailId})
            return self.make_response('Email resent successfully')

        except EmailSendError as ex:
            self.log.exception('Failed resending email {0}: {1}'.format(
                email.email_id, ex))
            return self.make_response(
                'Failed resending the email: {0}'.format(ex), HTTP.UNAVAILABLE)
Ejemplo n.º 10
0
    def put(self, user_id):
        """Update a user object"""
        self.reqparse.add_argument('roles', type=str, action='append')
        args = self.reqparse.parse_args()
        auditlog(event='user.create',
                 actor=session['user'].username,
                 data=args)

        user = db.User.find_one(User.user_id == user_id)
        roles = db.Role.find(Role.name.in_(args['roles']))
        if not user:
            return self.make_response('No such user found: {}'.format(user_id),
                                      HTTP.NOT_FOUND)

        if user.username == 'admin' and user.auth_system == 'builtin':
            return self.make_response(
                'You cannot modify the built-in admin user', HTTP.FORBIDDEN)

        user.roles = []
        for role in roles:
            if role in args['roles']:
                user.roles.append(role)

        db.session.add(user)
        db.session.commit()

        return self.make_response({'message': 'User roles updated'}, HTTP.OK)
Ejemplo n.º 11
0
    def post(self):
        """Create a new config item"""
        self.reqparse.add_argument('namespacePrefix', type=str, required=True)
        self.reqparse.add_argument('description', type=str, required=True)
        self.reqparse.add_argument('key', type=str, required=True)
        self.reqparse.add_argument('value', required=True)
        self.reqparse.add_argument('type', type=str, required=True)
        args = self.reqparse.parse_args()

        if not self.dbconfig.namespace_exists(args['namespacePrefix']):
            return self.make_response('The namespace doesnt exist',
                                      HTTP.NOT_FOUND)

        if self.dbconfig.key_exists(args['namespacePrefix'], args['key']):
            return self.make_response('This config item already exists',
                                      HTTP.CONFLICT)

        self.dbconfig.set(args['namespacePrefix'],
                          args['key'],
                          _to_dbc_class(args),
                          description=args['description'])
        auditlog(event='configItem.create',
                 actor=session['user'].username,
                 data=args)

        return self.make_response('Config item added', HTTP.CREATED)
Ejemplo n.º 12
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
Ejemplo n.º 13
0
    def get(self):
        out = [ns.to_dict() for ns in db.ConfigNamespace.find()]

        auditlog(event='config.export',
                 actor=session['user'].username,
                 data={})
        return Response(response=b64encode(
            bytes(json.dumps(out, cls=InquisitorJSONEncoder), 'utf-8')),
                        status=HTTP.OK)
Ejemplo n.º 14
0
    def get(self):
        out = [ns.to_json(is_admin=True) for ns in db.Account.find()]

        auditlog(event='account.export',
                 actor=session['user'].username,
                 data={})
        return Response(response=b64encode(
            bytes(json.dumps(out, cls=InquisitorJSONEncoder), 'utf-8')),
                        status=HTTP.OK)
Ejemplo n.º 15
0
def terminate_ec2_instance(client, resource):
    """Terminate an EC2 Instance

    This function will terminate an EC2 Instance. Returns `True` if succesful, or raises an exception if not

    Args:
        client (:obj:`boto3.session.Session.client`): A boto3 client object
        resource (:obj:`Resource`): The resource object to terminate

    Returns:
        `bool` - True if the instance was terminated. Will raise an exception if failed
    """
    try:
        # Gather instance metrics before termination
        instance_type = "Not Found"
        public_ip = "Not Found"
        for prop in resource.properties:
            if prop.name == "instance_type":
                instance_type = prop.value
            if prop.name == "public_ip":
                public_ip = prop.value

        metrics = {"instance_type": instance_type, "public_ip": public_ip}

        client.modify_instance_attribute(InstanceId=resource.resource_id, Attribute='disableApiTermination', Value='False')
        client.terminate_instances(InstanceIds=[resource.resource_id])
        logger.info('Terminated instance {}/{}/{}'.format(
            resource.account,
            resource.location,
            resource.resource_id
        ))
        Enforcement.create(resource.account_id, resource.resource_id, 'TERMINATE',
                           datetime.now(), metrics)
        auditlog(
            event='required_tags.ec2.terminate',
            actor=NS_AUDITOR_REQUIRED_TAGS,
            data={
                'resource_id': resource.resource_id,
                'account_name': resource.account.account_name,
                'location': resource.location
            }
        )
        return True

    except Exception as error:
        logger.info('Failed to kill instance {}/{}/{}: {}'.format(
            resource.account.account_name,
            resource.location,
            resource.resource_id,
            error
        ))
        raise ResourceKillError('Failed to kill instance {}/{}/{}: {}'.format(
            resource.account.account_name,
            resource.location,
            resource.resource_id,
            error
        ))
Ejemplo n.º 16
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))
Ejemplo n.º 17
0
    def delete(self, accountId):
        """Delete an account"""
        acct = BaseAccount.get(accountId)
        if not acct:
            raise Exception('No such account found')

        acct.delete()
        auditlog(event='account.delete', actor=session['user'].username, data={'accountId': accountId})

        return self.make_response('Account deleted')
Ejemplo n.º 18
0
    def post(self):
        """Create a new account"""
        self.reqparse.add_argument('accountName', type=str, required=True)
        self.reqparse.add_argument('accountNumber', type=str, required=True)
        self.reqparse.add_argument('contacts',
                                   type=dict,
                                   required=True,
                                   action='append')
        self.reqparse.add_argument('enabled',
                                   type=int,
                                   required=True,
                                   choices=(0, 1))
        self.reqparse.add_argument('requiredGroups',
                                   type=str,
                                   action='append',
                                   default=())
        self.reqparse.add_argument('adGroupBase', type=str, default=None)
        args = self.reqparse.parse_args()

        validate_contacts(args['contacts'])

        for key in ('accountName', 'accountNumber', 'contacts', 'enabled'):
            value = args[key]
            if type(value) == str:
                value = value.strip()

            if type(value) in (int, tuple, list, str):
                if not value:
                    raise Exception('{} cannot be empty'.format(
                        key.replace('_', ' ').title()))
            else:
                raise ValueError(
                    'Invalid type: {} for value {} for argument {}'.format(
                        type(value), value, key))

        if db.Account.filter_by(account_name=args['accountName']).count() > 0:
            raise Exception('Account already exists')

        acct = Account(args['accountName'], args['accountNumber'].zfill(12),
                       args['contacts'], args['enabled'], args['adGroupBase'])
        acct.required_groups = json.dumps(args['requiredGroups'])
        db.session.add(acct)
        db.session.commit()

        # Add the newly created account to the session so we can see it right away
        session['accounts'].append(acct.account_id)
        auditlog(event='account.create',
                 actor=session['user'].username,
                 data=args)

        return self.make_response(
            {
                'message': 'Account created',
                'accountId': acct.account_id
            }, HTTP.CREATED)
Ejemplo n.º 19
0
def stop_ec2_instance(client, resource):
    """Stop an EC2 Instance

    This function will attempt to stop a running instance. If the instance is already stopped the function will return
    False, else True.

    Args:
        client (:obj:`boto3.session.Session.client`): A boto3 client object
        resource (:obj:`Resource`): The resource object to stop

    Returns:
        `bool`
    """
    try:
        instance = EC2Instance.get(resource.resource_id)
        if instance.state not in ('stopped', 'terminated'):
            instance_type = "Not Found"
            public_ip = "Not Found"
            for prop in resource.properties:
                if prop.name == "instance_type":
                    instance_type = prop.value
                if prop.name == "public_ip":
                    public_ip = prop.value

            metrics = {"instance_type": instance_type, "public_ip": public_ip}

            client.stop_instances(InstanceIds=[resource.resource_id])
            logger.debug('Stopped instance {}/{}'.format(resource.account.account_name, resource.resource_id))
            Enforcement.create(resource.account_id, resource.resource_id, 'STOP',
                               datetime.now(), metrics)
            auditlog(
                event='required_tags.ec2.stop',
                actor=NS_AUDITOR_REQUIRED_TAGS,
                data={
                    'resource_id': resource.resource_id,
                    'account_name': resource.account.account_name,
                    'location': resource.location
                }
            )

            return True
        else:
            return False
    except Exception as error:
        logger.info('Failed to stop instance {}/{}: {}'.format(
            resource.account.account_name,
            resource.resource_id,
            error
        ))
        raise ResourceStopError('Failed to stop instance {}/{}: {}'.format(
            resource.account,
            resource.resource_id,
            error
        ))
Ejemplo n.º 20
0
    def log(cls, event=None, actor=None, data=None):
        """Generate and insert a new event

        Args:
            event (str): Action performed
            actor (str): Actor (user or subsystem) triggering the event
            data (dict): Any extra data necessary for describing the event

        Returns:
            `None`
        """
        from cloud_inquisitor.log import auditlog

        auditlog(event=event, actor=actor, data=data)
Ejemplo n.º 21
0
    def delete(self):
        self.reqparse.add_argument('maxAge', type=int, default=31)
        args = self.reqparse.parse_args()

        db.LogEvent.filter(
            func.datesub(
                LogEvent.timestamp < datetime.now() - timedelta(days=args['maxAge'])
            )
        ).delete()

        db.session.commit()
        auditlog(event='logs.prune', actor=session['user'].username, data=args)

        return self.make_response('Pruned logs older than {} days'.format(args['maxAge']))
Ejemplo n.º 22
0
    def delete(self, namespace, key):
        """Delete a specific configuration item"""
        if not self.dbconfig.key_exists(namespace, key):
            return self.make_response(
                'No such config entry exists: {}/{}'.format(namespace, key),
                HTTP.BAD_REQUEST)

        self.dbconfig.delete(namespace, key)
        auditlog(event='configItem.delete',
                 actor=session['user'].username,
                 data={
                     'namespace': namespace,
                     'key': key
                 })
        return self.make_response('Config entry deleted')
Ejemplo n.º 23
0
    def post(self):
        self.reqparse.add_argument('config', type=str, required=True)
        args = self.reqparse.parse_args()

        try:
            config = json.loads(args['config'], cls=InquisitorJSONDecoder)
            for nsdata in config:
                ns = ConfigNamespace.get(nsdata['namespacePrefix'])

                # Update existing namespace
                if ns:
                    ns.namespace_prefix = nsdata['namespacePrefix']
                    ns.name = nsdata['name']
                    ns.sort_order = nsdata['sortOrder']

                else:
                    ns = ConfigNamespace()
                    ns.namespace_prefix = nsdata['namespacePrefix']
                    ns.name = nsdata['name']
                    ns.sort_order = nsdata['sortOrder']
                db.session.add(ns)

                for itmdata in nsdata['configItems']:
                    itm = ConfigItem.get(ns.namespace_prefix, itmdata['key'])

                    if itm:
                        itm.value = itmdata['value']
                        itm.type = itmdata['type']
                        itm.description = itmdata['description']
                    else:
                        itm = ConfigItem()
                        itm.namespace_prefix = ns.namespace_prefix
                        itm.key = itmdata['key']
                        itm.value = itmdata['value']
                        itm.description = itmdata['description']

                    db.session.add(itm)

            db.session.commit()
            auditlog(event='config.import',
                     actor=session['user'].username,
                     data=config)
            return self.make_response('Configuration imported')
        except Exception as ex:
            self.log.exception('Failed importing configuration data')
            return self.make_response(
                'Error importing configuration data: {}'.format(ex),
                HTTP.SERVER_ERROR)
Ejemplo n.º 24
0
    def delete(self, template_name):
        """Delete a template"""
        template = db.Template.find_one(template_name=template_name)
        if not template:
            return self.make_response('No such template found', HTTP.NOT_FOUND)

        db.session.delete(template)
        db.session.commit()
        auditlog(event='template.delete',
                 actor=session['user'].username,
                 data={'template_name': template_name})

        return self.make_response({
            'message': 'Template has been deleted',
            'templateName': template_name
        })
Ejemplo n.º 25
0
    def post(self):
        self.reqparse.add_argument('config', type=str, required=True)
        args = self.reqparse.parse_args()

        try:
            config = json.loads(args['config'], cls=InquisitorJSONDecoder)
            apply_config(config)
            auditlog(event='config.import',
                     actor=session['user'].username,
                     data=config)
            return self.make_response('Configuration imported')
        except Exception as ex:
            self.log.exception('Failed importing configuration data')
            return self.make_response(
                'Error importing configuration data: {}'.format(ex),
                HTTP.SERVER_ERROR)
Ejemplo n.º 26
0
    def post(self):
        """Create a new account"""
        self.reqparse.add_argument('accountName', type=str, required=True)
        self.reqparse.add_argument('accountType', type=str, required=True)
        self.reqparse.add_argument('contacts', type=dict, required=True, action='append')
        self.reqparse.add_argument('enabled', type=int, required=True, choices=(0, 1))
        self.reqparse.add_argument('requiredGroups', type=str, action='append', default=())
        self.reqparse.add_argument('properties', type=dict, required=True)
        args = self.reqparse.parse_args()

        account_class = get_plugin_by_name(PLUGIN_NAMESPACES['accounts'], args['accountType'])
        if not account_class:
            raise InquisitorError('Invalid account type: {}'.format(args['accountType']))

        validate_contacts(args['contacts'])

        for key in ('accountName', 'accountType', 'contacts', 'enabled'):
            value = args[key]
            if type(value) == str:
                value = value.strip()

            if type(value) in (int, tuple, list, str):
                if not value:
                    raise Exception('{} cannot be empty'.format(key.replace('_', ' ').title()))
            else:
                raise ValueError('Invalid type: {} for value {} for argument {}'.format(type(value), value, key))

        class_properties = {from_camelcase(key): value for key, value in args['properties'].items()}
        for prop in account_class.class_properties:
            if prop['key'] not in class_properties:
                raise InquisitorError('Missing required property {}'.format(prop))

        acct = account_class.create(
            account_name=args['accountName'],
            contacts=args['contacts'],
            enabled=args['enabled'],
            required_roles=args['requiredGroups'],
            properties=class_properties,
            auto_commit=False
        )
        db.session.commit()

        # Add the newly created account to the session so we can see it right away
        session['accounts'].append(acct.account_id)
        auditlog(event='account.create', actor=session['user'].username, data=args)

        return self.make_response({'message': 'Account created', 'accountId': acct.account_id}, HTTP.CREATED)
Ejemplo n.º 27
0
    def confirm_cw_log(self, account, region, vpcname):
        """Create a new CloudWatch log group based on the VPC Name if none exists. Returns `True` if succesful

        Args:
            account (:obj:`Account`): Account to create the log group in
            region (`str`): Region to create the log group in
            vpcname (`str`): Name of the VPC the log group is fow

        Returns:
            `bool`
        """
        try:
            cw = self.session.client('logs', region)
            token = None
            log_groups = []
            while True:
                result = cw.describe_log_groups(
                ) if not token else cw.describe_log_groups(nextToken=token)
                token = result.get('nextToken')
                log_groups.extend(
                    [x['logGroupName'] for x in result.get('logGroups', [])])

                if not token:
                    break

            if vpcname not in log_groups:
                cw.create_log_group(logGroupName=vpcname)

                cw_vpc = VPC.get(vpcname)
                cw_vpc.set_property('vpc_flow_logs_log_group', vpcname)

                self.log.info('Created log group {}/{}/{}'.format(
                    account.account_name, region, vpcname))
                auditlog(event='vpc_flow_logs.create_cw_log_group',
                         actor=self.ns,
                         data={
                             'account': account.account_name,
                             'region': region,
                             'log_group_name': vpcname,
                             'vpc': vpcname
                         })
            return True

        except Exception:
            self.log.exception(
                'Failed creating log group for {}/{}/{}.'.format(
                    account, region, vpcname))
Ejemplo n.º 28
0
    def delete(self, roleId):
        """Delete a user role"""
        role = db.Role.find_one(Role.role_id == roleId)
        if not role:
            return self.make_response('No such role found', HTTP.NOT_FOUND)

        if role.name in ('User', 'Admin'):
            return self.make_response('Cannot delete the built-in roles',
                                      HTTP.BAD_REQUEST)

        db.session.delete(role)
        db.session.commit()
        auditlog(event='role.delete',
                 actor=session['user'].username,
                 data={'roleId': roleId})

        return self.make_response('Role has been deleted')
Ejemplo n.º 29
0
    def delete(self, namespacePrefix):
        """Delete a specific configuration namespace"""
        ns = db.ConfigNamespace.find_one(
            ConfigNamespace.namespace_prefix == namespacePrefix)
        if not ns:
            return self.make_response(
                'No such namespace: {}'.format(namespacePrefix),
                HTTP.NOT_FOUND)

        db.session.delete(ns)
        db.session.commit()

        self.dbconfig.reload_data()
        auditlog(event='configNamespace.delete',
                 actor=session['user'].username,
                 data={'namespacePrefix': namespacePrefix})
        return self.make_response('Namespace deleted')
Ejemplo n.º 30
0
    def post(self):
        """Create a new role"""
        self.reqparse.add_argument('name', type=str, required=True)
        self.reqparse.add_argument('color', type=str, required=True)
        args = self.reqparse.parse_args()

        role = Role()
        role.name = args['name']
        role.color = args['color']

        db.session.add(role)
        db.session.commit()
        auditlog(event='role.create',
                 actor=session['user'].username,
                 data=args)

        return self.make_response(
            'Role {} has been created'.format(role.role_id), HTTP.CREATED)