Exemple #1
0
    def create(cls, *, account_name, contacts, enabled, required_roles=list(), properties=None, auto_commit=True):
        if cls.get(account_name):
            raise AccountException('Account {} already exists'.format(account_name))

        for prop in cls.class_properties:
            if prop['required'] and (prop['key'] not in properties or not properties[prop['key']]):
                raise InquisitorError('Missing required property {}'.format(prop['name'], cls.__name__))

        res = Account()
        res.account_name = account_name
        res.contacts = contacts
        res.enabled = enabled
        res.required_roles = required_roles
        res.account_type_id = AccountType.get(cls.account_type).account_type_id

        if properties:
            for name, value in properties.items():
                prop = AccountProperty()
                prop.account_id = res.account_id
                prop.name = name
                prop.value = value.isoformat() if type(value) == datetime else value
                res.properties.append(prop)
                db.session.add(prop)

        db.session.add(res)
        if auto_commit:
            db.session.commit()

        return res
Exemple #2
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)
Exemple #3
0
    def put(self, accountId):
        """Update an 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('requiredRoles', 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'])

        if not args['accountName'].strip():
            raise Exception('You must provide an account name')

        if not args['contacts']:
            raise Exception('You must provide at least one contact')

        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))

        account = account_class.get(accountId)
        if account.account_type != args['accountType']:
            raise InquisitorError('You cannot change the type of an account')

        account.account_name = args['accountName']
        account.contacts = args['contacts']
        account.enabled = args['enabled']
        account.required_roles = args['requiredRoles']
        account.update(**args['properties'])
        account.save()

        auditlog(event='account.update', actor=session['user'].username, data=args)

        return self.make_response({'message': 'Object updated', 'account': account.to_dict(is_admin=True)})
Exemple #4
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)
Exemple #5
0
def get_aws_session(account):
    """Function to return a boto3 Session based on the account passed in the first argument.

    Args:
        account (:obj:`Account`): Account to create the session object for

    Returns:
        :obj:`boto3:boto3.session.Session`
    """
    from cloud_inquisitor.config import dbconfig
    from cloud_inquisitor.plugins.types.accounts import AWSAccount

    if not isinstance(account, AWSAccount):
        raise InquisitorError('Non AWSAccount  passed to get_aws_session, got {}'.format(account.__class__.__name__))

    # If no keys are on supplied for the account, use sts.assume_role instead
    session = get_local_aws_session()
    if session.get_credentials().method == 'iam-role':
        sts = session.client('sts')
    else:
        # If we are not running on an EC2 instance, assume the instance role
        # first, then assume the remote role
        temp_sts = session.client('sts')

        audit_sts_role = temp_sts.assume_role(
            RoleArn=app_config.aws_api.instance_role_arn,
            RoleSessionName='inquisitor'
        )
        sts = boto3.session.Session(
            audit_sts_role['Credentials']['AccessKeyId'],
            audit_sts_role['Credentials']['SecretAccessKey'],
            audit_sts_role['Credentials']['SessionToken']
        ).client('sts')

    role = sts.assume_role(
        RoleArn='arn:aws:iam::{}:role/{}'.format(
            account.account_number,
            dbconfig.get('role_name', default='cinq_role')
        ),
        RoleSessionName='inquisitor'
    )

    sess = boto3.session.Session(
        role['Credentials']['AccessKeyId'],
        role['Credentials']['SecretAccessKey'],
        role['Credentials']['SessionToken']
    )

    return sess
def get_template(template):
    """Return a Jinja2 template by filename

    Args:
        template (str): Name of the template to return

    Returns:
        A Jinja2 Template object
    """
    from cloud_inquisitor.database import db

    tmpl = db.Template.find_one(template_name=template)
    if not tmpl:
        raise InquisitorError('No such template found: {}'.format(template))

    tmplenv = Environment(loader=BaseLoader, autoescape=True)
    tmplenv.filters['json_loads'] = json.loads
    tmplenv.filters['slack_quote_join'] = lambda data: ', '.join('`{}`'.format(x) for x in data)

    return tmplenv.from_string(tmpl.template)
Exemple #7
0
    def get_all(cls, include_disabled=True):
        """Returns a list of all accounts of a given type

        Args:
            include_disabled (`bool`): Include disabled accounts. Default: `True`

        Returns:
            list of account objects
        """
        if cls == BaseAccount:
            raise InquisitorError('get_all on BaseAccount is not supported')

        account_type_id = db.AccountType.find_one(account_type=cls.account_type).account_type_id
        qry = db.Account.order_by(desc(Account.enabled), Account.account_type_id, Account.account_name)

        if not include_disabled:
            qry = qry.filter(Account.enabled == 1)

        accounts = qry.find(Account.account_type_id == account_type_id)

        return {res.account_id: cls(res) for res in accounts}
Exemple #8
0
    def update(self, **kwargs):
        """Updates the object information based on live data, if there were any changes made. Any changes will be
        automatically applied to the object, but will not be automatically persisted. You must manually call
        `db.session.add(object)` on the object.

        Args:
            **kwargs (:obj:): AWS API Resource object fetched from AWS API

        Returns:
            `bool`
        """
        updated = False

        for prop in self.class_properties:
            key = prop['key']
            kwarg_key = to_camelcase(key)
            if kwarg_key in kwargs:
                if prop['required'] and not kwargs[kwarg_key]:
                    raise InquisitorError('Missing required property {}'.format(prop['name']))

                updated |= self.set_property(key, kwargs[kwarg_key])

        return updated