コード例 #1
0
ファイル: views.py プロジェクト: bbhunt-2020/Canivete
class DomainHijackingList(BaseView):
    URLS = ['/api/v1/domainhijacking']
    MENU_ITEMS = [
        MenuItem('reports',
                 'Domain Hijacking',
                 'domainHijacking',
                 'domainHijacking',
                 'HIJACK',
                 order=2,
                 args={
                     'page': 1,
                     'count': 25,
                     'fixed': False
                 })
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=None)
        self.reqparse.add_argument('fixed', type=str, default=False)
        self.reqparse.add_argument('count', type=int, default=25)
        args = self.reqparse.parse_args()

        total, issues = DomainHijackIssue.search(limit=args['count'],
                                                 page=args['page'])
        return self.make_response({
            'message': None,
            'issues': issues,
            'issueCount': total
        })
コード例 #2
0
class InstanceGet(BaseView):
    URLS = ['/api/v1/ec2/instance/<string:instanceId>']
    MENU_ITEMS = [
        MenuItem(
            'browse',
            'EC2 Instances',
            'instance.list',
            'instance',
            args={
                'page': 1,
                'count': 100,
                'accounts': [],
                'regions': [],
                'state': None
            },
            order=1
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self, instanceId):
        instance = EC2Instance.get(instanceId)

        if instance and instance.resource.account_id in session['accounts']:
            return self.make_response({
                'message': None,
                'instance': instance
            })
        else:
            return self.make_response({
                'message': 'Instance not found or no access',
                'instance': None
            }, HTTP.NOT_FOUND)
コード例 #3
0
class DNSZoneList(BaseView):
    URLS = ['/api/v1/dns/zones']
    MENU_ITEMS = [
        MenuItem('browse',
                 'DNS',
                 'dns.zone.list',
                 'dns',
                 order=3,
                 args={
                     'page': 1,
                     'count': 25
                 })
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=1, required=True)
        self.reqparse.add_argument('count', type=int, default=25)
        args = self.reqparse.parse_args()

        total, zones = DNSZone.search(limit=args['count'], page=args['page'])
        return self.make_response({
            'zones': [x.to_json(with_records=False) for x in zones],
            'zoneCount':
            total
        })
コード例 #4
0
class Logs(BaseView):
    URLS = ['/api/v1/logs']
    MENU_ITEMS = [
        MenuItem('admin',
                 'Logs',
                 'log.list',
                 'log',
                 args={
                     'page': 1,
                     'count': 100,
                     'levelno': None
                 },
                 order=90)
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        self.reqparse.add_argument('limit', type=int, default=100)
        self.reqparse.add_argument('page', type=int, default=0)
        self.reqparse.add_argument('levelno', type=int, default=0)
        args = self.reqparse.parse_args()

        if args['levelno'] > 0:
            total_events = db.session.query(func.count(
                LogEvent.log_event_id)).filter(
                    LogEvent.levelno >= args['levelno']).first()[0]

            qry = (LogEvent.query.filter(
                LogEvent.levelno >= args['levelno']).order_by(
                    desc(LogEvent.timestamp)).limit(args['limit']))
        else:
            total_events = db.session.query(func.count(
                LogEvent.log_event_id)).first()[0]
            qry = (LogEvent.query.order_by(desc(LogEvent.timestamp)).limit(
                args['limit']))

        if (args['page'] - 1) > 0:
            offset = (args['page'] - 1) * args['limit']
            qry = qry.offset(offset)

        events = qry.all()
        return self.make_response({
            'logEventCount': total_events,
            'logEvents': events
        })

    @rollback
    @check_auth(ROLE_ADMIN)
    def delete(self):
        self.reqparse.add_argument('maxAge', type=int, default=31)
        args = self.reqparse.parse_args()
        AuditLog.log('logs.prune', session['user'].username, args)

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

        db.session.commit()
コード例 #5
0
ファイル: templates.py プロジェクト: bbhunt-2020/Canivete
class TemplateList(BaseView):
    URLS = ['/api/v1/templates']
    MENU_ITEMS = [
        MenuItem('admin', 'Templates', 'template.list', 'template', order=4)
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        templates = db.Template.all()

        return self.make_response({
            'templates': templates,
            'templateCount': len(templates)
        })

    @rollback
    @check_auth(ROLE_ADMIN)
    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)

    @rollback
    @check_auth(ROLE_ADMIN)
    def put(self):
        """Re-import all templates, overwriting any local changes made"""
        try:
            _import_templates(force=True)
            return self.make_response('Imported templates')
        except:
            self.log.exception('Failed importing templates')
            return self.make_response('Failed importing templates',
                                      HTTP.SERVER_ERROR)
コード例 #6
0
ファイル: emails.py プロジェクト: bbhunt-2020/Canivete
class EmailList(BaseView):
    URLS = ['/api/v1/emails']
    MENU_ITEMS = [
        MenuItem('admin',
                 'Emails',
                 'email.list',
                 'email',
                 args={
                     'page': 1,
                     'count': 100,
                     'subsystem': None
                 },
                 order=70)
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=1)
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('subsystems',
                                   type=str,
                                   default=None,
                                   action='append')

        args = self.reqparse.parse_args()
        total_qry = db.query(func.count(Email.email_id))
        qry = db.Email.order_by(desc(Email.timestamp))

        if args['subsystems']:
            authsystems = [
                x for x in map(lambda x: x.lower(), args['subsystems'])
            ]
            qry = qry.filter(func.lower(Email.subsystem).in_(authsystems))
            total_qry = total_qry.filter(
                func.lower(Email.subsystem).in_(authsystems))

        if (args['page'] - 1) > 0:
            offset = (args['page'] - 1) * args['count']
            qry = qry.offset(offset)

        qry = qry.limit(args['count'])
        emails = qry.all()
        total_emails = total_qry.first()[0]

        return self.make_response({
            'message':
            None,
            'emailCount':
            total_emails,
            'emails':
            emails,
            'subsystems':
            [x[0] for x in db.query(distinct(Email.subsystem)).all()]
        })
コード例 #7
0
ファイル: views.py プロジェクト: gwcmk/cloud-inquisitor
class RequiredInstanceTags(BaseView):
    URLS = ['/api/v1/requiredTags']
    MENU_ITEMS = [
        MenuItem('reports',
                 'Required Tags',
                 'requiredTags.list',
                 'requiredTags',
                 order=1,
                 args={
                     'page': 1,
                     'count': 100,
                     'accounts': None,
                     'regions': None,
                     'requiredTags': None
                 })
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('page', type=int, default=None)
        self.reqparse.add_argument('accounts',
                                   type=str,
                                   default=None,
                                   action='append')
        self.reqparse.add_argument('regions',
                                   type=str,
                                   default=None,
                                   action='append')
        args = self.reqparse.parse_args()

        required_tags = dbconfig.get('required_tags', NS_AUDITOR_REQUIRED_TAGS,
                                     ['owner', 'accounting', 'name']),
        properties = {}

        if args['accounts']:
            properties['account_id'] = [
                Account.get(x).account_id for x in args['accounts']
            ]

        if args['regions']:
            properties['location'] = args['regions']

        total_issues, issues = RequiredTagsIssue.search(limit=args['count'],
                                                        page=args['page'],
                                                        properties=properties)

        return self.make_response({
            'issues': issues,
            'requiredTags': required_tags,
            'issueCount': total_issues
        })
コード例 #8
0
ファイル: auditlog.py プロジェクト: tuxx/cloud-inquisitor
class AuditLogList(BaseView):
    URLS = ['/api/v1/auditlog']
    MENU_ITEMS = [
        MenuItem('admin',
                 'Audit Log',
                 'auditlog.list',
                 'auditlog',
                 args={
                     'page': 1,
                     'count': 100,
                     'events': [],
                     'actors': []
                 },
                 order=80)
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=1)
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('events',
                                   type=str,
                                   action='append',
                                   default=None)
        self.reqparse.add_argument('actors',
                                   type=str,
                                   action='append',
                                   default=None)
        args = self.reqparse.parse_args()

        qry = AuditLog.query.order_by(AuditLog.audit_log_event_id.desc())
        if args['events']:
            qry = qry.filter(AuditLog.event.in_(args['events']))

        if args['actors']:
            qry = qry.filter(AuditLog.actor.in_(args['actors']))

        totalEvents = qry.count()
        qry = qry.limit(args['count'])

        if (args['page'] - 1) > 0:
            offset = (args['page'] - 1) * args['count']
            qry = qry.offset(offset)

        return self.make_response({
            'auditLogEvents':
            qry.all(),
            'auditLogEventCount':
            totalEvents,
            'eventTypes':
            [x[0] for x in db.session.query(distinct(AuditLog.event)).all()]
        })
コード例 #9
0
ファイル: views.py プロジェクト: bbhunt-2020/Canivete
class EBSVolumeAudit(BaseView):
    URLS = ['/api/v1/reports/volumeAudit']
    MENU_ITEMS = [
        MenuItem('reports',
                 'Volume Audit',
                 'volumeAudit',
                 'volumeAudit',
                 order=3,
                 args={
                     'page': 1,
                     'count': 100,
                     'accounts': None,
                     'regions': None
                 })
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('page', type=int, default=None)
        self.reqparse.add_argument('accounts',
                                   type=str,
                                   default=None,
                                   action='append')
        self.reqparse.add_argument('regions',
                                   type=str,
                                   default=None,
                                   action='append')
        args = self.reqparse.parse_args()

        properties = {}

        if args['accounts']:
            properties['account_id'] = [
                Account.get(x).account_id for x in args['accounts']
            ]

        if args['regions']:
            properties['location'] = args['regions']

        total, issues = EBSVolumeAuditIssue.search(limit=args['count'],
                                                   page=args['page'],
                                                   properties=properties)

        return self.make_response({
            'message': None,
            'count': total,
            'issues': issues
        })
コード例 #10
0
class EC2InstanceAge(BaseView):
    URLS = ['/api/v1/reports/instanceAge']
    MENU_ITEMS = [
        MenuItem(
            'reports',
            'Instance Age',
            'instanceAge',
            'instanceAge',
            order=3,
            args={
                'page': 1,
                'count': 100,
                'accounts': None,
                'regions': None,
                'state': None,
                'age': 730
            }
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('page', type=int, default=None)
        self.reqparse.add_argument('accounts', type=str, default=None, action='append')
        self.reqparse.add_argument('regions', type=str, default=None, action='append')
        self.reqparse.add_argument('age', type=int, default=730)
        self.reqparse.add_argument('state', type=str, default=None, choices=(None, '', 'running', 'stopped',))
        args = self.reqparse.parse_args()

        properties = {}

        if args['state']:
            properties['state'] = args['state']

        total, instances = EC2Instance.search_by_age(
            accounts=args['accounts'],
            locations=args['regions'],
            age=args['age'],
            properties=properties
        )

        return self.make_response({
            'message': None,
            'instanceCount': total,
            'instances': instances
        })
コード例 #11
0
ファイル: config.py プロジェクト: tuxx/cloud-inquisitor
class ConfigList(BaseView):
    URLS = ['/api/v1/config']
    MENU_ITEMS = [
        MenuItem(
            'admin',
            'Config',
            'config.list',
            'config',
            order=2
        )
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        """List existing config namespaces and their items"""
        namespaces = ConfigNamespace.query.order_by(
            ConfigNamespace.sort_order,
            ConfigNamespace.name
        ).all()

        return self.make_response({
            'message': None,
            'namespaces': namespaces
        }, HTTP.OK)

    @rollback
    @check_auth(ROLE_ADMIN)
    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()
        AuditLog.log('configItem.create', session['user'].username, 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'])

        return self.make_response('Config item added', HTTP.CREATED)
コード例 #12
0
ファイル: roles.py プロジェクト: bbhunt-2020/Canivete
class RoleList(BaseView):
    URLS = ['/api/v1/roles']
    MENU_ITEMS = [
        MenuItem('admin',
                 'Roles',
                 'role.list',
                 'role',
                 order=4,
                 args={
                     'page': 1,
                     'count': 25
                 })
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        roles = db.Role.all()

        return self.make_response({'roles': roles, 'roleCount': len(roles)})

    @rollback
    @check_auth(ROLE_ADMIN)
    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)
コード例 #13
0
class AccountList(BaseView):
    URLS = ['/api/v1/account']
    MENU_ITEMS = [
        MenuItem('admin', 'Accounts', 'account.list', 'account', order=1)
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        """List all accounts"""
        qry = db.Account.order_by(desc(Account.enabled), Account.account_name)

        if ROLE_ADMIN not in session['user'].roles:
            qry = qry.filter(Account.account_id.in_(
                session['accounts']))  # NOQA

        accounts = qry.all()

        if accounts:
            return self.make_response({
                'message':
                None,
                'accounts': [
                    x.to_json(
                        is_admin=ROLE_ADMIN in session['user'].roles or False)
                    for x in accounts
                ]
            })
        else:
            return self.make_response(
                {
                    'message': 'Unable to find any accounts',
                    'accounts': None
                }, HTTP.NOT_FOUND)

    @rollback
    @check_auth(ROLE_ADMIN)
    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)
コード例 #14
0
ファイル: users.py プロジェクト: Aretusa/cloud-inquisitor
class UserList(BaseView):
    URLS = ['/api/v1/users']
    MENU_ITEMS = [
        MenuItem('admin',
                 'Users',
                 'user.list',
                 'user',
                 order=3,
                 args={
                     'page': 1,
                     'count': 50,
                     'authSystem': None
                 })
    ]

    @rollback
    @check_auth(ROLE_ADMIN)
    def get(self):
        """List all users"""
        self.reqparse.add_argument('page', type=int, default=1, required=True)
        self.reqparse.add_argument('count',
                                   type=int,
                                   default=50,
                                   choices=[25, 50, 100])
        self.reqparse.add_argument('authSystem',
                                   type=str,
                                   default=None,
                                   action='append')
        args = self.reqparse.parse_args()

        qry = db.User.order_by(User.username)
        if args['authSystem']:
            qry = qry.filter(User.auth_system.in_(args['authSystem']))

        total = qry.count()
        qry = qry.limit(args['count'])

        if (args['page'] - 1) > 0:
            offset = (args['page'] - 1) * args['count']
            qry = qry.offset(offset)

        users = qry.all()
        return self.make_response({
            'users': [x.to_dict() for x in users],
            'userCount':
            total,
            'authSystems':
            list(current_app.available_auth_systems.keys()),
            'activeAuthSystem':
            current_app.active_auth_system.name
        })

    @rollback
    @check_auth(ROLE_ADMIN)
    def post(self):
        """Create a new user"""
        self.reqparse.add_argument('username', type=str, required=True)
        self.reqparse.add_argument('authSystem', type=str, required=True)
        self.reqparse.add_argument('password',
                                   type=str,
                                   required=False,
                                   default=None)
        self.reqparse.add_argument('roles',
                                   type=str,
                                   action='append',
                                   default=[])
        args = self.reqparse.parse_args()
        auditlog(event='user.create',
                 actor=session['user'].username,
                 data=args)

        user = db.User.find_one(User.username == args['username'],
                                User.auth_system == args['authSystem'])
        roles = []
        if user:
            return self.make_response('User already exists', HTTP.BAD_REQUEST)

        if args['authSystem'] not in current_app.available_auth_systems:
            return self.make_response(
                'The {} auth system does not allow local edits'.format(
                    args['authSystem']), HTTP.BAD_REQUEST)

        if current_app.available_auth_systems[args['authSystem']].readonly:
            return self.make_response(
                'You cannot create users for the {} auth system as it is handled externally'
                .format(args['authSystem']), HTTP.BAD_REQUEST)

        for roleName in args['roles']:
            role = db.Role.find_one(Role.name == roleName)

            if not role:
                return self.make_response('No such role {}'.format(roleName),
                                          HTTP.BAD_REQUEST)

            if roleName == ROLE_ADMIN and ROLE_ADMIN not in session[
                    'user'].roles:
                self.log.error(
                    'User {} tried to grant admin privileges to {}'.format(
                        session['user'].username, args['username']))

                return self.make_response(
                    'You do not have permission to grant admin privileges',
                    HTTP.FORBIDDEN)

            roles.append(role)

        authSys = current_app.available_auth_systems[args['authSystem']]
        password = args['password'] or generate_password()

        user = User()
        user.username = args['username']
        user.password = hash_password(password)
        user.auth_system = authSys.name
        db.session.add(user)
        db.session.commit()
        db.session.refresh(user)
        User.add_role(user, roles)

        return self.make_response({
            'message':
            'User {}/{} has been created'.format(user.auth_system,
                                                 user.username),
            'user':
            user,
            'password':
            password if not args['password'] else None
        })

    @rollback
    @check_auth(ROLE_ADMIN)
    def options(self):
        """Returns metadata information required for User Creation"""
        roles = db.Role.all()

        return self.make_response({
            'roles':
            roles,
            'authSystems':
            list(current_app.available_auth_systems.keys()),
            'activeAuthSystem':
            current_app.active_auth_system.name
        })
コード例 #15
0
ファイル: elbs.py プロジェクト: bbhunt-2020/Canivete
class ELBList(BaseView):
    URLS = ['/api/v1/elb']
    MENU_ITEMS = [
        MenuItem('browse',
                 'ELBs',
                 'elb.list',
                 'elb',
                 args={
                     'page': 1,
                     'count': 100,
                     'accounts': None,
                     'regions': None,
                     'num_instances': None
                 },
                 order=4)
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=1)
        self.reqparse.add_argument('count',
                                   type=int,
                                   default=100,
                                   choices=[25, 50, 100])
        self.reqparse.add_argument('accounts',
                                   type=str,
                                   default=None,
                                   action='append')
        self.reqparse.add_argument('regions',
                                   type=str,
                                   default=None,
                                   action='append')
        self.reqparse.add_argument('numInstances', type=int, default=None)

        args = self.reqparse.parse_args()
        query = {
            'limit': args['count'],
            'page': args['page'],
            'properties': {}
        }
        if args['accounts']:
            query['accounts'] = args['accounts']
        if args['regions']:
            query['locations'] = args['regions']
        # Javascript camelCase to Python snake_case
        if args['numInstances'] is not None:
            self.log.info('args has numInstances=%s', args['numInstances'])
            query.setdefault('properties',
                             {})['num_instances'] = args['numInstances']

        if (args['page'] - 1) > 0:
            query['page'] = args['page']

        total, elbs = ELB.search(**query)
        elbs = [x.to_json() for x in elbs]
        elb_count = len(elbs)

        response = {'message': None, 'elbCount': total, 'elbs': elbs}
        if elb_count == 0:
            return self.make_response(
                {
                    'message': 'No ELBS found matching criteria',
                    'elbCount': total,
                    'elbs': []
                }, HTTP.NOT_FOUND)
        return self.make_response(response)
コード例 #16
0
class StatsGet(BaseView):
    URLS = ['/api/v1/stats']
    MENU_ITEMS = [
        MenuItem('default', 'Dashboard', 'dashboard', 'dashboard', order=1)
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        rfc26 = []
        accounts = list(AWSAccount.get_all(include_disabled=False).values())
        instances_by_account = self._get_instances_by_account()
        issues_by_account = self._get_issues_by_account()

        for acct in accounts:
            missing_tags = issues_by_account[acct.account_name]
            total_instances = instances_by_account[acct.account_name]
            if missing_tags == 0:
                pct = 0
            else:
                pct = float(missing_tags) / total_instances * 100

            rfc26.append({
                'accountName': acct.account_name,
                'compliantInstances': total_instances - missing_tags,
                'totalInstances': total_instances,
                'percent': 100 - pct
            })

        instances = self._get_instance_counts()
        instances_by_states = self._get_instances_by_state()
        instance_states = {x[0]: x[1] for x in instances_by_states}

        if instances:
            public_ips = float(
                self._get_public_ip_instances()) / instances * 100
        else:
            public_ips = 0

        return self.make_response({
            'message': None,
            'stats': {
                'ec2Instances': {
                    'total': instances,
                    'running': instance_states.get('running', 0),
                    'stopped': instance_states.get('stopped', 0)
                },
                'instancesWithPublicIps': public_ips,
                'rfc26Compliance': rfc26
            }
        })

    def _get_issues_by_account(self):
        acct_alias = aliased(IssueProperty)

        issues = (db.query(func.count(
            Issue.issue_id), Account.account_name).join(
                acct_alias, Issue.issue_id == acct_alias.issue_id).join(
                    Account, acct_alias.value == Account.account_id).filter(
                        Account.account_type_id == aws_account_type_id,
                        Account.enabled == 1,
                        Issue.issue_type_id == reqtag_type_id,
                        acct_alias.name == 'account_id').group_by(
                            Account.account_name).all())

        return defaultdict(int, map(reversed, issues))

    def _get_instances_by_account(self):
        instances = (db.query(func.count(
            Resource.resource_id), Account.account_name).join(
                Account, Resource.account_id == Account.account_id).filter(
                    Resource.resource_type_id == ec2_type_id,
                    Account.account_type_id == aws_account_type_id,
                    Account.enabled == 1).group_by(Account.account_name).all())

        return defaultdict(int, map(reversed, instances))

    def _get_public_ip_instances(self):
        return (db.query(func.count(ResourceProperty.resource_id)).join(
            Resource,
            ResourceProperty.resource_id == Resource.resource_id).join(
                Account, Resource.account_id == Account.account_id).filter(
                    Account.account_id.in_(session['accounts']),
                    Account.enabled == 1,
                    and_(
                        ResourceProperty.name == 'public_ip',
                        not_(func.JSON_CONTAINS(ResourceProperty.value,
                                                'null')))).first()[0])

    def _get_instances_by_state(self):
        return (db.query(
            ResourceProperty.value, func.count(ResourceProperty.value)).join(
                Resource,
                ResourceProperty.resource_id == Resource.resource_id).join(
                    Account, Resource.account_id == Account.account_id).filter(
                        Account.account_id.in_(session['accounts']),
                        Account.enabled == 1,
                        Resource.resource_type_id == ec2_type_id,
                        ResourceProperty.name == 'state').group_by(
                            ResourceProperty.value).all())

    def _get_instance_counts(self):
        return (db.query(func.count(Resource.resource_id)).join(
            Account, Resource.account_id == Account.account_id).filter(
                Account.account_id.in_(session['accounts']),
                Account.enabled == 1,
                Resource.resource_type_id == ec2_type_id).first()[0])
コード例 #17
0
ファイル: accounts.py プロジェクト: Aretusa/cloud-inquisitor
class AccountList(BaseView):
    URLS = ['/api/v1/account']
    MENU_ITEMS = [
        MenuItem(
            'admin',
            'Accounts',
            'account.list',
            'account',
            order=1
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        """List all accounts"""
        _, accounts = BaseAccount.search()

        if ROLE_ADMIN not in session['user'].roles:
            accounts = list(filter(lambda acct: acct.account_id in session['accounts'], accounts))

        if accounts:
            return self.make_response({
                'message': None,
                'accounts': [x.to_dict(is_admin=ROLE_ADMIN in session['user'].roles or False) for x in accounts]
            })
        else:
            return self.make_response({
                'message': 'Unable to find any accounts',
                'accounts': None
            }, HTTP.NOT_FOUND)

    @rollback
    @check_auth(ROLE_ADMIN)
    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)
コード例 #18
0
ファイル: vpcs.py プロジェクト: bbhunt-2020/Canivete
class VPCList(BaseView):
    URLS = ['/api/v1/vpc']
    MENU_ITEMS = [
        MenuItem(
            'browse',
            'VPCs',
            'vpc.list',
            'vpc',
            args={
                'page': 1,
                'count': 100,
                'accounts': None,
                'regions': None,
                'vpcId': None,
                'cidrV4': None,
                'isDefault': None,
                'vpcFlowLogsStatus': None
            },
            order=3
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        try:
            self.reqparse.add_argument('page', type=int, default=1)
            self.reqparse.add_argument('count', type=int, default=100, choices=[25, 50, 100])
            self.reqparse.add_argument('accounts', type=str, default=None, action='append')
            self.reqparse.add_argument('regions', type=str, default=None, action='append')
            self.reqparse.add_argument('vpcId', type=str, default=None, action='append')
            self.reqparse.add_argument('cidrV4', type=str, default=None, action='append')
            self.reqparse.add_argument('isDefault', type=str, default=None, action='append')
            self.reqparse.add_argument('vpcFlowLogsStatus', type=str, default=None, action='append')

            args = self.reqparse.parse_args()
            query = {
                'limit': args['count'],
                'page': args['page'],
                'properties': {}
            }
            if args['accounts']:
                query['accounts'] = args['accounts']

            if args['regions']:
                query['locations'] = args['regions']

            if args['vpcId']:
                query['properties']['vpc_id'] = args['vpcId']

            if args['cidrV4']:
                query['properties']['cidr_v4'] = args['cidrV4']

            if args['isDefault']:
                query['properties']['is_default'] = args['isDefault']

            if args['vpcFlowLogsStatus']:
                query['properties']['vpc_flow_logs_status'] = args['vpcFlowLogsStatus']

            total, vpcs = VPC.search(**query)

            response = {
                'message': None,
                'vpcCount': total,
                'vpcs': vpcs,
            }

            if total == 0:
                return self.make_response({
                    'message': 'No vpcs found matching criteria',
                    'vpcCount': total,
                    'vpcs': []
                }, HTTP.NOT_FOUND)

            return self.make_response(response)

        except Exception as e:
            print('Error calling base class get {}'.format(e))
コード例 #19
0
ファイル: s3.py プロジェクト: bbhunt-2020/Canivete
class S3List(BaseView):
    URLS = ['/api/v1/s3']
    MENU_ITEMS = [
        MenuItem('browse',
                 'S3 Buckets',
                 's3.list',
                 's3',
                 args={
                     'page': 1,
                     'count': 100,
                     'accounts': None,
                     'location': None,
                     'resourceId': None,
                     'websiteEnabled': None,
                 },
                 order=5)
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        try:
            self.reqparse.add_argument('page', type=int, default=1)
            self.reqparse.add_argument('count',
                                       type=int,
                                       default=100,
                                       choices=[25, 50, 100])
            self.reqparse.add_argument('accounts',
                                       type=str,
                                       default=None,
                                       action='append')
            self.reqparse.add_argument('location',
                                       type=str,
                                       default=None,
                                       action='append')
            self.reqparse.add_argument('resourceId',
                                       type=str,
                                       default=None,
                                       action='append')
            self.reqparse.add_argument('websiteEnabled',
                                       type=str,
                                       default=None,
                                       action='append')

            args = self.reqparse.parse_args()
            query = {
                'limit': args['count'],
                'page': args['page'],
                'properties': {}
            }
            if args['accounts']:
                query['accounts'] = args['accounts']

            if args['location']:
                query['properties']['location'] = args['location']

            if args['resourceId']:
                query['resources'] = args['resourceId']

            if args['websiteEnabled']:
                query['properties']['website_enabled'] = args['websiteEnabled']

            total, buckets = S3Bucket.search(**query)

            response = {
                'message': None,
                's3Count': total,
                's3': buckets,
            }

            if total == 0:
                return self.make_response(
                    {
                        'message': 'No buckets found matching criteria',
                        's3Count': total,
                        's3': []
                    }, HTTP.NOT_FOUND)

            return self.make_response(response)

        except Exception as e:
            print('Error calling base class get {}'.format(e))
コード例 #20
0
class Search(BaseView):
    URLS = ['/api/v1/search']
    MENU_ITEMS = [
        MenuItem(
            'browse',
            'Search',
            'search',
            'search',
            args={
                'page': 1,
                'partial': None,
                'keywords': None,
                'accounts': None,
                'regions': None,
                'resourceTypes': None
            },
            order=10
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('keywords', type=str)
        self.reqparse.add_argument('page', type=int, default=1)
        self.reqparse.add_argument('count', type=int, default=100)
        self.reqparse.add_argument('accounts', type=str, default=None, action='append')
        self.reqparse.add_argument('regions', type=str, default=None, action='append')
        self.reqparse.add_argument('partial', type=str)
        self.reqparse.add_argument('resourceTypes', type=int, action='append', default=None)
        args = self.reqparse.parse_args()

        resource_ids = []
        tags = {}
        properties = {}

        if args['keywords']:
            for keyword in shlex.split(args['keywords']):
                if RGX_TAG.match(keyword):
                    groups = RGX_TAG.match(keyword).groupdict()

                    if groups['type'] == 'tag':
                        lx = shlex.shlex(groups['value'])
                        lx.whitespace = ['=']
                        lx.whitespace_split = True
                        key, values = list(lx)

                        vlx = shlex.shlex(re.sub(r'^"|"$', '', values))
                        vlx.whitespace = ['|']
                        vlx.whitespace_split = True
                        values = list(vlx)

                        tags[key] = values

                elif RGX_PROPERTY.match(keyword):
                    groups = RGX_PROPERTY.match(keyword).groupdict()

                    lx = shlex.shlex(groups['value'])
                    lx.whitespace = ['=']
                    lx.whitespace_split = True
                    name, values = list(lx)

                    vlx = shlex.shlex(re.sub(r'^"|"$', '', values))
                    vlx.whitespace = ['|']
                    vlx.whitespace_split = True
                    values = list(vlx)

                    properties[name] = values

                else:
                    resource_ids.append(keyword)

        qry = db.Resource.order_by(Resource.resource_type_id)

        if args['resourceTypes']:
            qry = qry.filter(Resource.resource_type_id.in_(args['resourceTypes']))

        if resource_ids:
            qry = qry.filter(Resource.resource_id.in_(resource_ids))

        if args['accounts']:
            qry = qry.filter(Resource.account_id.in_(args['accounts']))

        if args['regions']:
            qry = qry.filter(Resource.location.in_(args['regions']))

        if tags:
            for key, values in tags.items():
                alias = aliased(Tag)
                tqry = []
                qry = qry.join(alias, Resource.resource_id == alias.resource_id)

                rgx = '|'.join([x.lower() for x in values])
                if not is_truthy(args['partial']):
                    rgx = '^({0})$'.format(rgx)

                tqry.append(
                    and_(
                        func.lower(alias.key) == key.lower(),
                        func.lower(alias.value).op('regexp')(rgx.lower())
                    )
                )

                qry = qry.filter(*tqry)

        if properties:
            for name, values in properties.items():
                alias = aliased(ResourceProperty)
                qry = qry.join(alias, Resource.resource_id == alias.resource_id)
                pqry = []

                if is_truthy(args['partial']):
                    pqry.append(
                        and_(
                            func.lower(alias.name) == name.lower(),
                            or_(*(alias.value.ilike('%{}%'.format(v)) for v in values))
                        )
                    )
                else:
                    pqry.append(
                        and_(
                            func.lower(alias.name) == name.lower(),
                            or_(*(func.JSON_CONTAINS(alias.value, v) for v in values))
                        )
                    )

                qry = qry.filter(*pqry)

        total = qry.count()
        qry = qry.limit(args['count'])

        if (args['page'] - 1) > 0:
            offset = (args['page'] - 1) * args['count']
            qry = qry.offset(offset)

        results = []
        for resource in qry.all():
            cls = current_app.types[resource.resource_type_id]
            data = cls(resource).to_json()
            results.append(data)

        return self.make_response({
            'message': None if results else 'No results found for this query',
            'resourceCount': total,
            'resources': results
        })
コード例 #21
0
class EBSVolumeList(BaseView):
    URLS = ['/api/v1/ebs']
    MENU_ITEMS = [
        MenuItem(
            'browse',
            'EBS Volumes',
            'ebs.list',
            'ebs',
            args={
                'page': 1,
                'count': 100,
                'accounts': None,
                'regions': None,
                'state': None,
                'type': None
            },
            order=2
        )
    ]

    @rollback
    @check_auth(ROLE_USER)
    def get(self):
        self.reqparse.add_argument('page', type=int, default=1)
        self.reqparse.add_argument('count', type=int, default=100, choices=[25, 50, 100])
        self.reqparse.add_argument('accounts', type=str, default=None, action='append')
        self.reqparse.add_argument('regions', type=str, default=None, action='append')
        self.reqparse.add_argument('state', type=str, default=None)
        self.reqparse.add_argument('type', type=str, default=None, action='append')

        args = self.reqparse.parse_args()
        query = {
            'limit': args['count'],
            'page': args['page'],
            'properties': {}
        }
        if args['accounts']:
            query['accounts'] = args['accounts']

        if args['regions']:
            query['locations'] = args['regions']

        if args['state'] and len(args['state']) > 0:
            query['properties']['state'] = args['state']

        if args['type']:
            query['properties']['volume_type'] = args['type']

        total, volumes = EBSVolume.search(**query)
        volume_count = len(volumes)
        volume_types = sorted(('gp2', 'io1', 'st1', 'sc1', 'standard'))
        response = {
            'message': None,
            'volumeCount': total,
            'volumeTypes': volume_types,
            'volumes': volumes
        }

        if volume_count == 0:
            return self.make_response({
                'message': 'No volumes found matching criteria',
                'volumeCount': total,
                'volumeTypes': volume_types,
                'volumes': []
            }, HTTP.NOT_FOUND)

        return self.make_response(response)