def assume_profile_role(role_profile, session_name="", session_duration=0): """Assume role described by role_profile and return the auth response.""" # Get local profile config config = Session(profile=role_profile).get_scoped_config() # Construct assume role request assert "role_arn" in config, f"{role_profile} does not have role_arn." role_arn = config["role_arn"] rq = { "RoleArn": role_arn, "RoleSessionName": session_name or get_default_session_name(), # "DurationSeconds": 28800 # get_max_duration(role_arn) } # Specify duration if one was given if not session_duration: best_max = get_max_duration(role_arn) dt = timedelta(seconds=best_max) log.debug(f"Using duration of {humanize.naturaldelta(dt)} based on cache.") session_duration = best_max if session_duration: rq["DurationSeconds"] = session_duration else: log.debug(f"No session duration specified, letting AWS choose a default.") # Add MFA token if needed if "mfa_serial" in config: rq["SerialNumber"] = config["mfa_serial"] rq["TokenCode"] = questionary.text("Enter MFA code:").ask() # Log request before making it log.debug(f"Auth request:\n{json.dumps(rq, indent=4)}") # If source_profile is given, we should use it instead of the default profile source_profile = config.get("source_profile") log.info(f"Using source profile: {source_profile}") # Get auth token session = boto3.Session(profile_name=source_profile) sts = session.client("sts") response = sts.assume_role(**rq) # Cache session duration if session_duration: cache_max_duration(role_arn, session_duration) # Log auth token resp_str = json.dumps(response, indent=4, default=lambda o: str(o)) log.debug(f"Auth response:\n{resp_str}") # Log expiration date local_exp = response["Credentials"]["Expiration"].astimezone() remaining = humanize.naturaldelta(local_exp - datetime.now(pytz.utc)) log.info(f"The token will expire after {remaining} on {local_exp}") return response
class BotoConnections(object): """Central Management of boto3 client and resource connection objects.""" def __init__(self, region_name=None, profile_name=None): """ Optionally pass region_name and profile_name. Setup boto3 session. Attach boto3 client and resource connection objects. """ # defaults. self.config = {} self._region_name = self._profile_name = None # trigger region_name.setter self.region_name = region_name # trigger profile_name.setter self.profile_name = profile_name @property def profile_name(self): return self._profile_name @profile_name.setter def profile_name(self, new_name): """set profile_name and refresh_boto_connections""" self._profile_name = new_name if new_name is not None: self.config = Session(profile=new_name).get_scoped_config() self.setup_session_and_refresh_connections() @property def region_name(self): if self._region_name is None: return self.config.get('region', None) return self._region_name @region_name.setter def region_name(self, new_name): """set region_name and refresh_boto_connections""" self._region_name = new_name self.setup_session_and_refresh_connections() def setup_session_and_refresh_connections(self): if self.profile_name and self.region_name: boto3.setup_default_session( profile_name = self.profile_name, region_name = self.region_name, ) elif self.profile_name: boto3.setup_default_session(profile_name = self.profile_name) elif self.region_name: boto3.setup_default_session(region_name = self.region_name) else: return None self.refresh_boto_connections() def refresh_boto_connections(self): """Attach related Boto3 clients and resources.""" self.iam = boto3.resource('iam') self.ec2 = boto3.resource('ec2') self.ec2_client = boto3.client('ec2') self.rds = boto3.client('rds') self.elasticache = boto3.client('elasticache') self.elb = boto3.client('elb') self.autoscaling = boto3.client('autoscaling') self.route53 = boto3.client('route53') @property def azones(self): """Return a list of available AZ names for active AWS profile/region.""" az_filter = make_filter('state', 'available') azs = self.ec2_client.describe_availability_zones(Filters=az_filter) return map(lambda az : az['ZoneName'], azs['AvailabilityZones'])