Esempio n. 1
0
    def connect(self):
        """
        Connect to an AWS API via boto3 low-level client and set ``self.conn``
        to the `boto3.client <https://boto3.readthed
        ocs.org/en/latest/reference/core/boto3.html#boto3.client>`_ object
        (a ``botocore.client.*`` instance). If ``self.conn`` is not None,
        do nothing. This connects to the API name given by ``self.api_name``.

        :returns: None
        """
        if self.conn is not None:
            return

        default_config = Config(retries={'mode': 'adaptive'})
        kwargs = dict(self._boto3_connection_kwargs)
        kwargs['config'] = default_config

        if self._max_retries_config is not None:
            kwargs['config'] = default_config.merge(self._max_retries_config)
        self.conn = boto3.client(self.api_name, **kwargs)
        logger.info("Connected to %s in region %s", self.api_name,
                    self.conn._client_config.region_name)
Esempio n. 2
0
class AWSClient:
    def __init__(self, aws_default_region, aws_role_arn, aws_role_session_name,
                 aws_role_session_duration, aws_role_policy, aws_access_key_id,
                 aws_secret_access_key, verify_certificate, timeout, retries):
        self.aws_default_region = aws_default_region
        self.aws_role_arn = aws_role_arn
        self.aws_role_session_name = aws_role_session_name
        self.aws_role_session_duration = aws_role_session_duration
        self.aws_role_policy = aws_role_policy
        self.aws_access_key_id = aws_access_key_id
        self.aws_secret_access_key = aws_secret_access_key
        self.verify_certificate = verify_certificate

        proxies = handle_proxy(proxy_param_name='proxy',
                               checkbox_default_value=False)
        (read_timeout, connect_timeout) = AWSClient.get_timeout(timeout)
        if int(retries) > 10:
            retries = 10
        self.config = Config(connect_timeout=connect_timeout,
                             read_timeout=read_timeout,
                             retries=dict(max_attempts=int(retries)),
                             proxies=proxies)

    def update_config(self):
        command_config = {}
        retries = demisto.getArg(
            'retries'
        )  # Supports retries and timeout parameters on the command execution level
        if retries is not None:
            command_config['retries'] = dict(max_attempts=int(retries))
        timeout = demisto.getArg('timeout')
        if timeout is not None:
            (read_timeout, connect_timeout) = AWSClient.get_timeout(timeout)
            command_config['read_timeout'] = read_timeout
            command_config['connect_timeout'] = connect_timeout
        if retries or timeout:
            demisto.debug(
                'Merging client config settings: {}'.format(command_config))
            self.config = self.config.merge(Config(**command_config))

    def aws_session(self,
                    service,
                    region=None,
                    role_arn=None,
                    role_session_name=None,
                    role_session_duration=None,
                    role_policy=None):
        kwargs = {}

        self.update_config()

        if role_arn and role_session_name is not None:
            kwargs.update({
                'RoleArn': role_arn,
                'RoleSessionName': role_session_name,
            })
        elif self.aws_role_arn and self.aws_role_session_name is not None:
            kwargs.update({
                'RoleArn': self.aws_role_arn,
                'RoleSessionName': self.aws_role_session_name,
            })

        if role_session_duration is not None:
            kwargs.update({'DurationSeconds': int(role_session_duration)})
        elif self.aws_role_session_duration is not None:
            kwargs.update(
                {'DurationSeconds': int(self.aws_role_session_duration)})

        if role_policy is not None:
            kwargs.update({'Policy': role_policy})
        elif self.aws_role_policy is not None:
            kwargs.update({'Policy': self.aws_role_policy})

        if kwargs and not self.aws_access_key_id:  # login with Role ARN

            if not self.aws_access_key_id:
                sts_client = boto3.client('sts',
                                          config=self.config,
                                          verify=self.verify_certificate,
                                          region_name=self.aws_default_region)
                sts_response = sts_client.assume_role(**kwargs)
                client = boto3.client(
                    service_name=service,
                    region_name=region if region else self.aws_default_region,
                    aws_access_key_id=sts_response['Credentials']
                    ['AccessKeyId'],
                    aws_secret_access_key=sts_response['Credentials']
                    ['SecretAccessKey'],
                    aws_session_token=sts_response['Credentials']
                    ['SessionToken'],
                    verify=self.verify_certificate,
                    config=self.config)
        elif self.aws_access_key_id and self.aws_role_arn:  # login with Access Key ID and Role ARN
            sts_client = boto3.client(
                service_name='sts',
                aws_access_key_id=self.aws_access_key_id,
                aws_secret_access_key=self.aws_secret_access_key,
                verify=self.verify_certificate,
                config=self.config)
            kwargs.update({
                'RoleArn': self.aws_role_arn,
                'RoleSessionName': self.aws_role_session_name,
            })
            sts_response = sts_client.assume_role(**kwargs)
            client = boto3.client(
                service_name=service,
                region_name=self.aws_default_region,
                aws_access_key_id=sts_response['Credentials']['AccessKeyId'],
                aws_secret_access_key=sts_response['Credentials']
                ['SecretAccessKey'],
                aws_session_token=sts_response['Credentials']['SessionToken'],
                verify=self.verify_certificate,
                config=self.config)
        elif self.aws_access_key_id and not self.aws_role_arn:  # login with access key id
            client = boto3.client(
                service_name=service,
                region_name=region if region else self.aws_default_region,
                aws_access_key_id=self.aws_access_key_id,
                aws_secret_access_key=self.aws_secret_access_key,
                verify=self.verify_certificate,
                config=self.config)
        else:  # login with default permissions, permissions pulled from the ec2 metadata
            client = boto3.client(
                service_name=service,
                region_name=region if region else self.aws_default_region)

        return client

    @staticmethod
    def get_timeout(timeout):
        if not timeout:
            timeout = "60,10"  # default values
        try:
            timeout_vals = timeout.split(',')
            read_timeout = int(timeout_vals[0])
        except ValueError:
            raise DemistoException(
                "You can specify just the read timeout (for example 60) or also the connect "
                "timeout followed after a comma (for example 60,10). If a connect timeout is not "
                "specified, a default of 10 second will be used.")
        connect_timeout = 10 if len(timeout_vals) == 1 else int(
            timeout_vals[1])
        return read_timeout, connect_timeout
Esempio n. 3
0
def boto3_cached_conn(service,
                      service_type='client',
                      future_expiration_minutes=15,
                      account_number=None,
                      assume_role=None,
                      session_name='cloudaux',
                      region='us-east-1',
                      return_credentials=False,
                      external_id=None,
                      arn_partition='aws',
                      read_only=False,
                      retry_max_attempts=10,
                      config=None,
                      sts_client_kwargs=None,
                      client_kwargs=None):
    """
    Used to obtain a boto3 client or resource connection.
    For cross account, provide both account_number and assume_role.

    :usage:

    # Same Account:
    client = boto3_cached_conn('iam')
    resource = boto3_cached_conn('iam', service_type='resource')

    # Cross Account Client:
    client = boto3_cached_conn('iam', account_number='000000000000', assume_role='role_name')

    # Cross Account Resource:
    resource = boto3_cached_conn('iam', service_type='resource', account_number='000000000000', assume_role='role_name')

    :param service: AWS service (i.e. 'iam', 'ec2', 'kms')
    :param service_type: 'client' or 'resource'
    :param future_expiration_minutes: Connections will expire from the cache
        when their expiration is within this many minutes of the present time. [Default 15]
    :param account_number: Required if assume_role is provided.
    :param assume_role:  Name of the role to assume into for account described by account_number.
    :param session_name: Session name to attach to requests. [Default 'cloudaux']
    :param region: Region name for connection. [Default us-east-1]
    :param return_credentials: Indicates if the STS credentials should be returned with the client [Default False]
    :param external_id: Optional external id to pass to sts:AssumeRole.
        See https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html
    :param arn_partition: Optional parameter to specify other aws partitions such as aws-us-gov for aws govcloud
    :param read_only: Optional parameter to specify the built in ReadOnlyAccess AWS policy
    :param retry_max_attempts: An integer representing the maximum number of retry attempts that will be made on a
        single request
    :param config: Optional botocore.client.Config
    :param sts_client_kwargs: Optional arguments to pass during STS client creation
    :return: boto3 client or resource connection
    """
    key = (account_number, assume_role, session_name, external_id, region,
           service_type, service, arn_partition, read_only)
    client_config = Config(retries=dict(max_attempts=retry_max_attempts))
    if not client_kwargs:
        client_kwargs = {}
    if config:
        client_config = client_config.merge(config)

    if key in CACHE:
        retval = _get_cached_creds(key, service, service_type, region,
                                   future_expiration_minutes,
                                   return_credentials, client_config,
                                   client_kwargs)
        if retval:
            return retval

    role = None
    if assume_role:
        sts_client_kwargs = sts_client_kwargs or {}
        sts = boto3.session.Session().client('sts', **sts_client_kwargs)

        # prevent malformed ARN
        if not all([account_number, assume_role]):
            raise ValueError(
                "Account number and role to assume are both required")

        arn = 'arn:{partition}:iam::{0}:role/{1}'.format(
            account_number, assume_role, partition=arn_partition)

        assume_role_kwargs = {'RoleArn': arn, 'RoleSessionName': session_name}

        if read_only:
            assume_role_kwargs['PolicyArns'] = [
                {
                    'arn': 'arn:aws:iam::aws:policy/ReadOnlyAccess'
                },
            ]

        if external_id:
            assume_role_kwargs['ExternalId'] = external_id

        role = sts.assume_role(**assume_role_kwargs)

    if service_type == 'client':
        conn = _client(service, region, role, client_config, client_kwargs)
    elif service_type == 'resource':
        conn = _resource(service, region, role, client_config, client_kwargs)

    if role:
        CACHE[key] = role

    if return_credentials:
        return conn, role['Credentials']

    return conn