def create_clidriver(): session = botocore.session.Session(EnvironmentVariables) _set_user_agent_for_session(session) load_plugins(session.full_config.get('plugins', {}), event_hooks=session.get_component('event_emitter')) driver = CLIDriver(session=session) return driver
def get_session(): """# Boto3 MFA session magic""" working_dir = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') session = botocore.session.get_session() provider = session.get_component('credential_provider').get_provider('assume-role') provider.cache = credentials.JSONFileCache(working_dir) return session
def build_aws_client(*args, **kwargs): """Build an AWS client using the awscli credential cache.""" # Create a session with the credential cache session = botocore.session.get_session() provider = session.get_component("credential_provider").get_provider( "assume-role" ) provider.cache = credentials.JSONFileCache(AWS_CREDENTIAL_CACHE_DIR) # Create boto3 client from session return boto3.Session(botocore_session=session).client(*args, **kwargs)
def _shared_example_configs(): session = botocore.session.Session() loader = session.get_component('data_loader') services = loader.list_available_services('examples-1') for service in services: service_model = session.get_service_model(service) example_config = loader.load_service_model(service, 'examples-1', service_model.api_version) examples = example_config.get("examples", {}) for operation, operation_examples in examples.items(): for example in operation_examples: yield operation, example, service_model
def ssm(self): """Lazy loaded to simplify testing""" if self._ssm is None: cli_cache = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') if self.profile: session = botocore.session.Session(profile=self.profile) else: session = botocore.session.get_session() session.get_component('credential_provider').get_provider( 'assume-role').cache = credentials.JSONFileCache(cli_cache) self._ssm = boto3.Session(botocore_session=session).client('ssm') return self._ssm
def _create_server_side_completer(self, session=None): from awsshell.resource import index if session is None: session = botocore.session.Session() loader = session.get_component('data_loader') completions_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'data') loader.search_paths.insert(0, completions_path) client_creator = index.CachedClientCreator(session) describer = index.CompleterDescriberCreator(loader) completer = index.ServerSideCompleter(client_creator, describer) return completer
def test_lint_shared_example_configs(): session = botocore.session.Session() loader = session.get_component('data_loader') services = loader.list_available_services('examples-1') for service in services: service_model = session.get_service_model(service) example_config = loader.load_service_model( service, 'examples-1', service_model.api_version ) examples = example_config.get("examples", {}) for operation, operation_examples in examples.items(): for example in operation_examples: yield _lint_single_example, operation, example, service_model
def _pagination_configs(): session = botocore.session.get_session() loader = session.get_component('data_loader') services = loader.list_available_services('paginators-1') for service_name in services: service_model = session.get_service_model(service_name) page_config = loader.load_service_model(service_name, 'paginators-1', service_model.api_version) for op_name, single_config in page_config['pagination'].items(): yield ( op_name, single_config, service_model )
def _waiter_configs(): session = botocore.session.get_session() validator = Draft4Validator(WAITER_SCHEMA) for service_name in session.get_available_services(): client = session.create_client(service_name, 'us-east-1') try: # We use the loader directly here because we need the entire # json document, not just the portions exposed (either # internally or externally) by the WaiterModel class. loader = session.get_component('data_loader') waiter_model = loader.load_service_model(service_name, 'waiters-2') except UnknownServiceError: # The service doesn't have waiters continue yield validator, waiter_model, client
def test_lint_pagination_configs(): session = botocore.session.get_session() loader = session.get_component('data_loader') services = loader.list_available_services('paginators-1') for service_name in services: service_model = session.get_service_model(service_name) page_config = loader.load_service_model(service_name, 'paginators-1', service_model.api_version) for op_name, single_config in page_config['pagination'].items(): yield ( _lint_single_paginator, op_name, single_config, service_model )
def test_lint_waiter_configs(): session = botocore.session.get_session() validator = Draft4Validator(WAITER_SCHEMA) for service_name in session.get_available_services(): client = session.create_client(service_name, 'us-east-1') service_model = client.meta.service_model try: # We use the loader directly here because we need the entire # json document, not just the portions exposed (either # internally or externally) by the WaiterModel class. loader = session.get_component('data_loader') waiter_model = loader.load_service_model( service_name, 'waiters-2') except UnknownServiceError: # The service doesn't have waiters continue yield _validate_schema, validator, waiter_model for waiter_name in client.waiter_names: yield _lint_single_waiter, client, waiter_name, service_model
def _get_session(self, profile=None, region=None): if self._sessions.get((profile, region)): return self._sessions[(profile, region)] # Construct botocore session with cache # Setup boto to cache STS tokens for MFA # Change the cache path from the default of ~/.aws/boto/cache to the one used by awscli session_vars = {} if profile: session_vars['profile'] = (None, None, profile, None) if region and region != 'global': session_vars['region'] = (None, None, region, None) session = botocore.session.Session(session_vars=session_vars) cli_cache = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') session.get_component('credential_provider').get_provider( 'assume-role').cache = credentials.JSONFileCache(cli_cache) self._sessions[(profile, region)] = session return session
def initialize(region='', profile=''): from botocore import credentials import botocore.session import os cli_cache = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') params = {} if profile: params['profile'] = profile session = botocore.session.Session(**params) session.get_component('credential_provider').get_provider('assume-role').cache = credentials.JSONFileCache( cli_cache) from boto3.session import Session params = {} if region: params['region_name'] = region AWS.__session = Session(botocore_session=session, **params)
def _get_presigned_url(self, cluster_name, role_arn): session = self._session_handler.get_session( self._region_name, role_arn ) if self._region_name is None: self._region_name = session.get_config_variable('region') loader = botocore.loaders.create_loader() data = loader.load_data("endpoints") endpoint_resolver = botocore.regions.EndpointResolver(data) endpoint = endpoint_resolver.construct_endpoint( AUTH_SERVICE, self._region_name ) signer = RequestSigner( ServiceId(AUTH_SERVICE), self._region_name, AUTH_SERVICE, AUTH_SIGNING_VERSION, session.get_credentials(), session.get_component('event_emitter') ) action_params='Action=' + AUTH_COMMAND + '&Version=' + AUTH_API_VERSION params = { 'method': 'GET', 'url': 'https://' + endpoint["hostname"] + '/?' + action_params, 'body': {}, 'headers': {CLUSTER_NAME_HEADER: cluster_name}, 'context': {} } url=signer.generate_presigned_url( params, region_name=endpoint["credentialScope"]["region"], operation_name='', expires_in=URL_TIMEOUT ) return url
# Objective: Wrapper function for boto3 client # Allows shared caching between CLI and boto3 # Enables use of MFA-enforced roles import os import boto3 import botocore.session from botocore import credentials # By default the cache path is ~/.aws/boto/cache cli_cache = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') # Construct botocore session with cache session = botocore.session.get_session() session.get_component('credential_provider').get_provider( 'assume-role').cache = credentials.JSONFileCache(cli_cache) # Create boto3 client from session def boto3_client(service_name): """ Set up a boto3 session with custom botocore credential provider. Boto3 will read from AWS CLI cache and use any cached STS sessions. Enables the use of IAM roles that have been authenticated with MFA via CLI :type service_name: string :param service_name: A valid boto3 service name (eg. ec2, ssm, sqs) :return: Returns an initialized boto3 client for the given service """ return boto3.Session(botocore_session=session).client(service_name)
def get_aws_credentials(profile_name, duration=None): """ Get AWS Credentials for a given profile Why do we get credentials like this and not just create a boto3 session or something? Glad you asked! In the real world, people use AWS profiles because they have _lots_ of AWS accounts, so first and foremost, aws profiles _must_ be handled easily. But that's not the primary concern here. In the real real world, people also use MFA. Why? Well for starters AWS TELLS YOU it's a best practice, and you know what, it really is. Why however don't a lot of people use MFA? Well it's because the people building tools never treat it seriously and do no testing with MFA. Every AWS tools developer should work with MFA set to ON for everything they do, trust me, once you do this, the MFA experience will get fixed real fast. So, with all that in mind, what this approach to getting AWS credentials enables is: 1. Get the MFA process out of the way upfront as the _first_ thing the app prompts you for so you don't have to sit around waiting for a prompt 2. Use the built in ability of Boto3 to cache the MFA credentials so you don't have to go find your token every time you run the tool 3. Support shelling out to AWS aware tools (like the SAM CLI) 4. Also support using the cached credentials when creating Botocore/Boto3 sessions (you have to pass in the keys vs. using a profile_name but that's a small price to pay for awesomeness) Args: profile_name (str): A AWS profile name, as defined in the users .aws/aws_credentials file duration (int): Session duration in seconds, the duration configured in the role policy takes precedence Returns: (dict): """ if not duration: duration = 3600 # Construct low level botocore session with cache, which allows MFA session reuse if profile_name: session = botocore.session.Session(profile=profile_name) mfa_serial = session.full_config['profiles'][profile_name].get( 'mfa_serial') else: session = botocore.session.Session() mfa_serial = None session.get_component('credential_provider').get_provider('assume-role').cache = \ botocore.credentials.JSONFileCache() # this mfa_serial code is _only_ here to deal with boto profiles that _do not_ assume a role # which is required because this PR is still open: https://github.com/boto/botocore/pull/1399 # otherwise MFA is nicely handled automatically by boto. Sadly, these credentials are not cached if mfa_serial and not session.full_config['profiles'][profile_name].get( 'role_arn'): sts = session.create_client('sts') mfa_code = input("Enter MFA code for {}: ".format(mfa_serial)) response = sts.get_session_token(DurationSeconds=duration, SerialNumber=mfa_serial, TokenCode=mfa_code) credentials = response['Credentials'] identity = sts.get_caller_identity() env_vars = { 'AWS_ACCESS_KEY_ID': credentials['AccessKeyId'], 'AWS_SECRET_ACCESS_KEY': credentials['SecretAccessKey'], 'AWS_SESSION_TOKEN': credentials['SessionToken'], 'AWS_ACCOUNT_ID': identity.get('Account') } print('.') else: credentials = session.get_credentials() sts = session.create_client('sts') identity = sts.get_caller_identity() env_vars = { 'AWS_ACCESS_KEY_ID': credentials.access_key, 'AWS_SECRET_ACCESS_KEY': credentials.secret_key, 'AWS_SESSION_TOKEN': credentials.token, 'AWS_ACCOUNT_ID': identity.get('Account') } return env_vars
def session(): session = botocore.session.get_session() cred_chain = session.get_component('credential_provider') provider = cred_chain.get_provider('assume-role') provider.cache = JSONFileCache() return session
import os import sys import json import botocore.session import botocore.credentials session = botocore.session.get_session() if hasattr(botocore.credentials, 'JSONFileCache'): cli_cache = os.path.join(os.path.expanduser('~'), '.aws/cli/cache') try: session.get_component('credential_provider').get_provider('assume-role').cache = botocore.credentials.JSONFileCache(cli_cache) except botocore.exceptions.ProfileNotFound as e: sys.exit(e) else: # workaround old awscli without https://github.com/boto/botocore/pull/1157 from awscli.customizations.assumerole import inject_assume_role_provider_cache from awscli.customizations.scalarparse import add_scalar_parsers inject_assume_role_provider_cache(session) add_scalar_parsers(session) try: credentials = session.get_credentials() if credentials is None: sys.exit('Unable to locate AWS credentials.') frozen_credentials = credentials.get_frozen_credentials() except KeyboardInterrupt as e: sys.exit(e) except botocore.exceptions.ParamValidationError as e: sys.exit(e) except botocore.exceptions.ProfileNotFound as e:
def configure_cache(session): """ Injects caching to the session's credential provider """ cred_chain = session.get_component('credential_provider') provider = cred_chain.get_provider('assume-role') provider.cache = FixedJSONFileCache()
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)
def __init__(self, session=None, region_name=None, api_version=None, use_ssl=None, verify=None, endpoint_url=None, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, config=None, endpoints=None): if session is None: session = botocore.session.get_session() else: if not isinstance(session, botocore.session.Session): try: # Check for a boto3 session-ish object and get the internal botocore session _session = session._session except AttributeError: raise ValueError( 'session must be a botocore or boto3 session') else: session = _session if use_ssl: raise ValueError('SSL/TLS is not supported. Set use_ssl=False.') self._session = session default_client_config = self._session.get_default_client_config() if config is not None and default_client_config is not None: # If a config is provided and a default config is set, then # use the config resulting from merging the two. config = default_client_config.merge(config) elif default_client_config is not None: # If a config was not provided then use the default # client config from the session config = default_client_config self._client_config = config if config is not None else Config( region_name=region_name) # resolve the region name if region_name is None: if config and config.region_name: region_name = config.region_name else: region_name = self._session.get_config_variable('region') self._region_name = region_name # Figure out the verify value base on the various # configuration options. if verify is None: verify = self._session.get_config_variable('ca_bundle') self._verify = verify # Gather endpoints self._endpoints = endpoints or [] if endpoint_url and endpoint_url not in self._endpoints: # If endpoint_url is provided, include it self._endpoints.insert(0, endpoint_url) if not self._endpoints: raise ValueError('No endpoints provided') # Resolve credentials if aws_access_key_id is not None and aws_secret_access_key is not None: self._credentials = Credentials(aws_access_key_id, aws_secret_access_key, aws_session_token) elif self._session._missing_cred_vars(aws_access_key_id, aws_secret_access_key): raise PartialCredentialsError( provider='explicit', cred_var=self._session._missing_cred_vars( aws_access_key_id, aws_secret_access_key)) else: self._credentials = self._session.get_credentials() # Fake out the meta information as much as possible loader = session.get_component('data_loader') json_model = loader.load_service_model('dynamodb', 'service-2', api_version=api_version) service_model = ServiceModel(json_model, service_name='dynamodb') event_emitter = session.get_component('event_emitter') partition = None self.meta = ClientMeta(event_emitter, self._client_config, self._endpoints[0], service_model, self._PY_TO_OP_NAME, partition) # Check signing version if self._client_config.signature_version and self._client_config.signature_version != 'v4': logger.warning( 'DAX only supports SigV4 signing; given signature_version "%s" ignored.', self._client_config.signature_version) # Start cluster connection & background tasks self._cluster = Cluster(self._region_name, self._endpoints, self._credentials, self._client_config.user_agent, self._client_config.user_agent_extra, self._client_config.connect_timeout, self._client_config.read_timeout) self._cluster.start()
# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from botocore import session from dateutil import parser session = session.get_session() # Provide our own botocore json to override (and increase) various timeouts session.get_component('data_loader')._search_paths[1:1] = [os.path.join(os.path.dirname(__file__), "data")] # Force botocore to initialise - this avoids race conditions around # get_component session.create_client("ec2", "eu-west-1") class Session(object): def __init__(self, access_key_id, secret_access_key, session_token, expiration, region): self.access_key_id = access_key_id self.secret_access_key = secret_access_key self.session_token = session_token self.expiration = expiration self.region = region