def get_service_principal(service, endpoint_host, session=None):
    suffix, region = _get_suffix_and_region_from_endpoint_host(endpoint_host)
    if session is None:
        session = botocore.session.Session()

    if service == EMR_AUTOSCALING_SERVICE_NAME:
        if region not in session.get_available_regions('emr', 'aws-cn'):
            return EMR_AUTOSCALING_SERVICE_PRINCIPAL

    return service + '.' + suffix
def get_client(profile, region, service):
    """Returns a new or cached botocore service client for the AWS profile, region, and service.

    Warns when a service is not available for a region, which means we
    need to update botocore or skip that call for that region.
    """
    session = get_session(profile)

    if region not in session.get_available_regions(service):
        warnings.warn("service {} not available in {}".format(service, region))

    return session.create_client(service, region_name=region)
  def from_url(remote_url):
    """
    Parses repository information from a git url, filling in additional
    attributes we need from our AWS profile.

    Our remote helper accepts one type of urls...

    * cvm://<role>@<account_name>/<repository>

    :param str remote_url: git remote url to parse

    :returns: **Context** with our CodeCommit repository information

    :raises:
      * **FormatError** if the url is malformed
      * **ProfileNotFound** if the url references a profile that doesn't exist
      * **RegionNotFound** if the url references a region that doesn't exist
      * **RegionNotAvailable** if the url references a region that is not available
    """

    url = urlparse(remote_url)
    event_handler = botocore.hooks.HierarchicalEmitter()
    profile = 'default'

    if not url.scheme or not url.netloc or not url.path or '@' not in url.netloc:
      raise FormatError('The following URL is malformed: {}. A URL must be in the following format: cvm://<role>@<account_name>/<repository>'.format(remote_url))

    repository = url.path[1:]
    role_name, account_name = url.netloc.split('@', 1)

    session = botocore.session.Session(event_hooks = event_handler)
    available_regions = [
        region
            for partition in session.get_available_partitions()
            for region in session.get_available_regions('codecommit', partition)
    ]
    region = session.get_config_variable('region')
    if not region or region not in available_regions:
      raise RegionNotFound('Please set the AWS_DEFAULT_REGION environment variable to a valid AWS region.')

    r = subprocess.run(
      f'cvm creds --account-name {account_name} --role-name {role_name}'.split(' '),
      stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    data = json.loads(r.stdout.decode('utf-8'))
    credentials = ReadOnlyCredentials(
      data['Credentials']['AccessKeyId'],
      data['Credentials']['SecretAccessKey'],
      data['Credentials']['SessionToken']
    )

    return Context(session, repository, 'v1', region, credentials)
Exemple #4
0
def get_client(profile: str, region: str, service: str) -> botocore.client.BaseClient:
    """Returns a new or cached botocore service client for the AWS profile, region, and service.

    Warns when a service is not available for a region, which means we
    need to update botocore or skip that call for that region.
    """
    session = get_session(profile)

    if (
        region not in session.get_available_regions(service)
        and service not in SERVICES_WITHOUT_REGIONS
    ):
        warnings.warn("service {} not available in {}".format(service, region))

    return session.create_client(service, region_name=region)
Exemple #5
0
def get_regions_to_search(
        session: botocore.session.Session,
        service_name: str,
        region_allow_list: Optional[List[str]] = None,
        region_deny_list: Optional[List[str]] = None) -> List[str]:
    """Using a botocore Session object, the name of a service, and either an allow-list or a deny-list (but not both),
    return a list of regions to be used during the gathering process. This uses the botocore Session object's
    get_available_regions method as the base list.

    If the allow-list is specified, the returned list is the union of the base list and the allow-list. No error is
    thrown if a region is specified in the allow-list but not included in the base list.

    If the deny-list is specified, the returned list is the base list minus the elements of the deny-list. No error is
    thrown if a region is specified inthe deny-list but not included in the base list.

    A ValueError is thrown if the allow-list AND deny-list are both not None.
    """

    if region_allow_list is not None and region_deny_list is not None:
        raise ValueError(
            'This function allows only either the allow-list or the deny-list, but NOT both.'
        )

    base_list = session.get_available_regions(service_name)

    result = []

    if region_allow_list is not None:
        for element in base_list:
            if element in region_allow_list:
                result.append(element)
    elif region_deny_list is not None:
        for element in base_list:
            if element not in region_deny_list:
                result.append(element)
    else:
        result = base_list

    logger.debug('Final list of regions for {}: {}'.format(
        service_name, result))

    return result
Exemple #6
0
  def from_url(remote_url):
    """
    Parses repository information from a git url, filling in additional
    attributes we need from our AWS profile.

    Our remote helper accepts two distinct types of urls...

    * codecommit://<profile>@<repository>
    * codecommit::<region>://<profile>@<repository>

    If provided the former we get the whole url, but if the later git will
    truncate the proceeding 'codecommit::' prefix for us.

    The '<profile>@' url is optional, using the aws sessions present profile
    if not provided.

    :param str remote_url: git remote url to parse

    :returns: **Context** with our CodeCommit repository information

    :raises:
      * **FormatError** if the url is malformed
      * **ProfileNotFound** if the url references a profile that doesn't exist
      * **RegionNotFound** if the url references a region that doesn't exist
      * **RegionNotAvailable** if the url references a region that is not available
    """

    url = urlparse(remote_url)
    event_handler = botocore.hooks.HierarchicalEmitter()
    profile = 'default'
    repository = url.netloc
    if not url.scheme or not url.netloc:
      raise FormatError('The following URL is malformed: {}. A URL must be in one of the two following formats: codecommit://<profile>@<repository> or codecommit::<region>://<profile>@<repository>'.format(remote_url))

    if '@' in url.netloc:
      profile, repository = url.netloc.split('@', 1)
      session = botocore.session.Session(profile = profile, event_hooks = event_handler)

      if profile not in session.available_profiles:
        raise ProfileNotFound('The following profile was not found: {}. Available profiles are: {}. Either use one of the available profiles, or create an AWS CLI profile to use and then try again. For more information, see Configure an AWS CLI Profile in the AWS CLI User Guide.'.format(profile, ', '.join(session.available_profiles)))
    else:
      session = botocore.session.Session(event_hooks = event_handler)

    session.get_component('credential_provider').get_provider('assume-role').cache = JSONFileCache()

    try:
      # when the aws cli is available support plugin authentication

      import awscli.plugin

      awscli.plugin.load_plugins(
          session.full_config.get('plugins', {}),
          event_hooks = event_handler,
          include_builtins = False,
      )

      session.emit_first_non_none_response('session-initialized', session = session)
    except ImportError:
      pass

    available_regions = [region for partition in session.get_available_partitions() for region in session.get_available_regions('codecommit', partition)]

    if url.scheme == 'codecommit':
      region = session.get_config_variable('region')

      if not region:
        raise RegionNotFound('The following profile does not have an AWS Region: {}. You must set an AWS Region for this profile. For more information, see Configure An AWS CLI Profile in the AWS CLI User Guide.'.format(profile))

      if region not in available_regions:
        raise RegionNotAvailable('The following AWS Region is not available for use with AWS CodeCommit: {}. For more information about CodeCommit\'s availability in AWS Regions, see the AWS CodeCommit User Guide. If an AWS Region is listed as supported but you receive this error, try updating your version of the AWS CLI or the AWS SDKs.'.format(region))

    elif re.match(r"^[a-z]{2}-\w*.*-\d{1}", url.scheme):
      if url.scheme in available_regions:
        region = url.scheme

      else:
        raise RegionNotAvailable('The following AWS Region is not available for use with AWS CodeCommit: {}. For more information about CodeCommit\'s availability in AWS Regions, see the AWS CodeCommit User Guide. If an AWS Region is listed as supported but you receive this error, try updating your version of the AWS CLI or the AWS SDKs.'.format(url.scheme))

    else:
      raise FormatError('The following URL is malformed: {}. A URL must be in one of the two following formats: codecommit://<profile>@<repository> or codecommit::<region>://<profile>@<repository>'.format(remote_url))
    credentials = session.get_credentials()

    if not credentials:
      raise CredentialsNotFound('The following profile does not have credentials configured: {}. You must configure the access key and secret key for the profile. For more information, see Configure an AWS CLI Profile in the AWS CLI User Guide.'.format(profile))

    return Context(session, repository, 'v1', region, credentials)