def __init__(self, fabric_config_dict): if fabric_config_dict.has_key("fabric"): for key in self.required_keys: if not fabric_config_dict['fabric'].has_key(key): util.log_error_and_exit( "Fabric configuration file is missing " + key) try: self.edge_facing_capacity = int( fabric_config_dict["fabric"]["edge_facing_capacity"]) except ValueError: util.log_error_and_exit( "Invalid value found for total edge facing capacity in provided fabric configuration" ) for rack in fabric_config_dict['fabric']['racks']: rack['rack_id'] = self.rack_id self.total_racks += rack['rack_count'] self.racks.append(Rack(rack)) self.rack_facing_capacity += self.racks[ self. rack_id].total_required_fabric_network_capacity * self.racks[ self.rack_id].rack_count self.rack_id += 1 self.network_addressing = Network_addressing( fabric_config_dict['fabric']['addressing']) print "Total rack facing capacity required: " + str( self.rack_facing_capacity) print "Total edge facing capacity required: " + str( self.edge_facing_capacity)
def __init__(self, sku_dict): ports = None for key in self.required_keys: if not sku_dict.has_key(key): util.log_error_and_exit("SKU data is missing "+key+" for SKU: "+str(sku['sku'])) for key, value in sku_dict.items(): setattr(self, key, value) self.ports = Ports(self.network_interfaces)
def get_config(aws_creds_path): config = configparser.RawConfigParser() try: config.read(aws_creds_path) except configparser.ParsingError: e = sys.exc_info()[1] log_error_and_exit( logger, "There was a problem reading or parsing " "your credentials file: %s" % (e.args[0], )) return config
def __init__(self, ports_list): self.ports_list = [] self.count = 0 for port in ports_list: for key in self.required_sku_keys: if not port.has_key(key): util.log_error_and_exit("Platform SKU network interfaces definition is missing key "+key) for port in ports_list: port['in_use'] = False self.ports_list.append(port) self.count += 1
def generate_tor_links(self, tor, rack): tor_links = [] required_ports = rack.host_ports.count rport_list = rack.host_ports.ports_list for rport in rport_list: for sport in tor.sku.ports.ports_list: if sport['in_use'] is False and util.is_form_factor_compatible( sport['form_factor'], rport['form_factor']): if util.is_intersect(rport['speeds'], sport['speeds']): speed = rport['speeds'][0] sport['in_use'] = True tor_links.append( Link(tor.name, sport['name'], sport['form_factor'], speed)) tor_links[len(tor_links) - 1].set_remote_vars( "host", "host_port", sport['form_factor'], speed) required_ports -= 1 break required_ports = rack.fabric_ports.count rport_list = rack.fabric_ports.ports_list for rport in rport_list: for sport in tor.sku.ports.ports_list: if sport['in_use'] is False and util.is_form_factor_compatible( sport['form_factor'], rport['form_factor']): if util.is_intersect(rport['speeds'], sport['speeds']): speed = rport['speeds'][0] sport['in_use'] = True tor_links.append( Link(tor.name, sport['name'], sport['form_factor'], speed)) tor_links[len(tor_links) - 1].set_remote_vars( "next_stage", "next_stage", sport['form_factor'], speed) required_ports -= 1 break ###Reset in_use flag for sport in tor.sku.ports.ports_list: sport['in_use'] = False if required_ports > 0: util.log_error_and_exit( "generate_tor_links() failed to generate links for TOR " + tor_name) else: return tor_links
def initial_setup(logger, config, config_path): console_input = prompter() profile_name = console_input('Profile name to [%s]: ' % ("default")) if profile_name is None or profile_name == "": profile_name = "default" profile_name = "{}-long-term".format(profile_name) aws_access_key_id = getpass.getpass('aws_access_key_id: ') if aws_access_key_id is None or aws_access_key_id == "": log_error_and_exit(logger, "You must supply aws_access_key_id") aws_secret_access_key = getpass.getpass('aws_secret_access_key: ') if aws_secret_access_key is None or aws_secret_access_key == "": log_error_and_exit(logger, "You must supply aws_secret_access_key") config.add_section(profile_name) config.set(profile_name, 'aws_access_key_id', aws_access_key_id) config.set(profile_name, 'aws_secret_access_key', aws_secret_access_key) with open(config_path, 'w') as configfile: config.write(configfile)
def __init__(self, ports_list): self.ports_list = [] self.count = 0 for port in ports_list: for key in self.required_rack_keys: if not port.has_key(key): util.log_error_and_exit( "Rack SKU host_network_interfaces definition is missing key " + key) for port in ports_list: for count in range(0, int(port['count'])): port_definition = { 'name': self.count, 'form_factor': port['form_factor'], 'speeds': [port['speed']], 'breakouts': [], 'port_group': self.count, 'in_use': False } self.ports_list.append(port_definition) self.count += 1
def __init__(self, network_interfaces_list, rack_name): for key in self.supported_form_factors: self.host_interfaces_total[key] = 0 for nic in network_interfaces_list: for key in self.required_keys: if not nic.has_key(key): util.log_error_and_exit("Missing key of "+str(key)+" from configuration for rack "+str(rack_name)) if nic['speed'] not in self.supported_speeds: util.log_error_and_exit("Network interface speed of "+str(nic['speed'])+" is not supported") if nic['form_factor'] not in self.supported_form_factors: util.log_error_and_exit("Network interface form_factor of "+str(nic['optic'])+" is not supported") self.host_interfaces_total[nic['form_factor']] += 1 * nic['count']
def __init__(self, rack_dict): for attribute in self.required_attributes: if not rack_dict.has_key(attribute): util.log_error_and_exit( attribute + " is a mandatory variable and is missing from the provided configuration file" ) for key, value in rack_dict.items(): setattr(self, key, value) try: self.rack_count = int(rack_dict["rack_count"]) except ValueError: util.log_error_and_exit( "Invalid value found for rack count for rack " + str(self.name) + " in provided fabric configuration") for nic in self.host_network_interfaces: ###Sum the total required host network capacity in the rack self.total_required_host_network_capacity += nic['speed'] * nic[ 'count'] ###Determine the fastest host facing interface speed in the rack if nic['speed'] > self.largest_potential_flow_size: self.largest_potential_flow_size = nic['speed'] self.total_required_fabric_network_capacity = math.ceil( util.calculate_sub_ratio(self.subscription_ratio_to_fabric) * self.total_required_host_network_capacity) if (self.total_required_fabric_network_capacity < 0): util.log_error_and_exit("Oversubscription ratio for rack " + str(self.name) + " of " + str(self.subscription_ratio_to_fabric) + " is invalid") self.host_ports = Host_ports(self.host_network_interfaces) self.fabric_ports = Fabric_ports( self.total_required_fabric_network_capacity, self.largest_potential_flow_size)
def __init__(self, platform_data_dict): if not platform_data_dict.has_key('platforms'): util.log_error_and_exit( "Platform data is missing high level 'platform' key") for sku in platform_data_dict['platforms']: self.sku_list.append(Sku(sku))
def __init__(self, addressing_config_dict): for key in self.required_keys: if not addressing_config_dict.has_key(key): util.log_error_and_exit("Addressing configuration is missing "+key) ###Populate lists of available subnets and addresses ###FIXME: Add IPv6 support self.network_point_to_point_network = ipaddress.IPv4Network(unicode(addressing_config_dict['network_point_to_points']['range']),strict=True) self.network_point_to_point_subnets = list(self.network_point_to_point_network.subnets(new_prefix=31)) if addressing_config_dict['network_point_to_points'].has_key('exclude'): for addr in addressing_config_dict['network_point_to_points']['exclude']: if not util.is_ip_address(addr): if not util.is_ip_network(addr): util.log_error_and_exit("Excluded address "+addr+" is not a valid IP address or network") self.network_point_to_point_exclude.append(ipaddress.IPv4Network(unicode(addr))) ###Remove any subnets that contain excluded addresses ###FIXME: I'm lazy and not doing LPM for addr in self.network_point_to_point_exclude: for subnet in self.network_point_to_point_subnets: if subnet.overlaps(addr): print "Excluding subnet: "+str(subnet) self.network_point_to_point_subnets.remove(subnet) ###Populate lists of available subnets and addresses ###FIXME: Add IPv6 support self.loopbacks_network = ipaddress.IPv4Network(unicode(addressing_config_dict['loopbacks']['range']),strict=True) self.loopbacks_subnets = list(self.loopbacks_network.subnets(new_prefix=32)) if addressing_config_dict['loopbacks'].has_key('exclude'): for addr in addressing_config_dict['loopbacks']['exclude']: if not util.is_ip_address(addr): if not util.is_ip_network(addr): util.log_error_and_exit("Excluded address "+addr+" is not a valid IP address or network") self.loopbacks_exclude.append(ipaddress.IPv4Network(unicode(addr))) ###Remove any subnets that contain excluded addresses ###FIXME: I'm lazy and not doing LPM for addr in self.loopbacks_exclude: for subnet in self.loopbacks_subnets: if subnet.overlaps(addr): print "Excluding subnet: "+str(subnet) self.loopbacks_subnets.remove(subnet) ###Populate lists of available subnets and addresses ###FIXME: Add IPv6 support self.management_network_network = ipaddress.IPv4Network(unicode(addressing_config_dict['management_network']['range']),strict=True) self.management_network_subnets = list(self.management_network_network.subnets(new_prefix=32)) if addressing_config_dict['management_network'].has_key('exclude'): for addr in addressing_config_dict['management_network']['exclude']: if not util.is_ip_address(addr): if not util.is_ip_network(addr): util.log_error_and_exit("Excluded address "+addr+" is not a valid IP address or network") self.management_network_exclude.append(ipaddress.IPv4Network(unicode(addr))) ###Remove any subnets that contain excluded addresses ###FIXME: I'm lazy and not doing LPM for addr in self.management_network_exclude: for subnet in self.management_network_subnets: if subnet.overlaps(addr): print "Excluding subnet: "+str(subnet) self.management_network_subnets.remove(subnet)
def get_credentials(short_term_name, lt_key_id, lt_access_key, args, config): console_input = prompter() mfa_token = console_input('Enter AWS MFA code for device [%s] ' '(renewing for %s seconds):' % (args.device, args.duration)) client = boto3.client('sts', aws_access_key_id=lt_key_id, aws_secret_access_key=lt_access_key) if args.assume_role: logger.info("Assuming Role - Profile: %s, Role: %s, Duration: %s", short_term_name, args.assume_role, args.duration) if args.role_session_name is None: log_error_and_exit( logger, "You must specify a role session name " "via --role-session-name") try: response = client.assume_role( RoleArn=args.assume_role, RoleSessionName=args.role_session_name, DurationSeconds=args.duration, SerialNumber=args.device, TokenCode=mfa_token) except ClientError as e: log_error_and_exit( logger, "An error occured while calling " "assume role: {}".format(e)) except ParamValidationError: log_error_and_exit(logger, "Token must be six digits") config.set( short_term_name, 'assumed_role', 'True', ) config.set( short_term_name, 'assumed_role_arn', args.assume_role, ) else: logger.info("Fetching Credentials - Profile: %s, Duration: %s", short_term_name, args.duration) try: response = client.get_session_token(DurationSeconds=args.duration, SerialNumber=args.device, TokenCode=mfa_token) except ClientError as e: log_error_and_exit( logger, "An error occured while calling assume role: {}".format(e)) except ParamValidationError: log_error_and_exit(logger, "Token must be six digits") config.set( short_term_name, 'assumed_role', 'False', ) config.remove_option(short_term_name, 'assumed_role_arn') # aws_session_token and aws_security_token are both added # to support boto and boto3 options = [ ('aws_access_key_id', 'AccessKeyId'), ('aws_secret_access_key', 'SecretAccessKey'), ('aws_session_token', 'SessionToken'), ('aws_security_token', 'SessionToken'), ] for option, value in options: config.set(short_term_name, option, response['Credentials'][value]) # Save expiration individiually, so it can be manipulated config.set( short_term_name, 'expiration', response['Credentials']['Expiration'].strftime('%Y-%m-%d %H:%M:%S')) with open(AWS_CREDS_PATH, 'w') as configfile: config.write(configfile) logger.info("Success! Your credentials will expire in %s seconds at: %s" % (args.duration, response['Credentials']['Expiration'])) sys.exit(0)
def main(): parser = argparse.ArgumentParser() parser.add_argument('--device', required=False, metavar='arn:aws:iam::123456788990:mfa/dudeman', help="The MFA Device ARN. This value can also be " "provided via the environment variable 'MFA_DEVICE' or" " the ~/.aws/credentials variable 'aws_mfa_device'.") parser.add_argument('--duration', type=int, help="The duration, in seconds, that the temporary " "credentials should remain valid. Minimum value: " "900 (15 minutes). Maximum: 129600 (36 hours). " "Defaults to 43200 (12 hours), or 3600 (one " "hour) when using '--assume-role'. This value " "can also be provided via the environment " "variable 'MFA_STS_DURATION'. ") parser.add_argument('--profile', help="If using profiles, specify the name here. The " "default profile name is 'default'. The value can " "also be provided via the environment variable " "'AWS_PROFILE'.", required=False) parser.add_argument('--long-term-suffix', '--long-suffix', help="The suffix appended to the profile name to" "identify the long term credential section", required=False) parser.add_argument('--short-term-suffix', '--short-suffix', help="The suffix appended to the profile name to" "identify the short term credential section", required=False) parser.add_argument('--assume-role', '--assume', metavar='arn:aws:iam::123456788990:role/RoleName', help="The ARN of the AWS IAM Role you would like to " "assume, if specified. This value can also be provided" " via the environment variable 'MFA_ASSUME_ROLE'", required=False) parser.add_argument('--role-session-name', help="Friendly session name required when using " "--assume-role", default=getpass.getuser(), required=False) parser.add_argument('--force', help="Refresh credentials even if currently valid.", action="store_true", required=False) parser.add_argument( '--log-level', help="Set log level", choices=['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET'], required=False, default='DEBUG') parser.add_argument('--setup', help="Setup a new log term credentials section", action="store_true", required=False) args = parser.parse_args() level = getattr(logging, args.log_level) setup_logger(level) if not os.path.isfile(AWS_CREDS_PATH): console_input = prompter() create = console_input("Could not locate credentials file at {}, " "would you like to create one? " "[y/n]".format(AWS_CREDS_PATH)) if create.lower() == "y": with open(AWS_CREDS_PATH, 'a'): pass else: log_error_and_exit( logger, 'Could not locate credentials file at ' '%s' % (AWS_CREDS_PATH, )) config = get_config(AWS_CREDS_PATH) if args.setup: initial_setup(logger, config, AWS_CREDS_PATH) return validate(args, config)
def validate(args, config): if not args.profile: if os.environ.get('AWS_PROFILE'): args.profile = os.environ.get('AWS_PROFILE') else: args.profile = 'default' if not args.long_term_suffix: long_term_name = '%s-long-term' % (args.profile, ) elif args.long_term_suffix.lower() == 'none': long_term_name = args.profile else: long_term_name = '%s-%s' % (args.profile, args.long_term_suffix) if not args.short_term_suffix or args.short_term_suffix.lower() == 'none': short_term_name = args.profile else: short_term_name = '%s-%s' % (args.profile, args.short_term_suffix) if long_term_name == short_term_name: log_error_and_exit( logger, "The value for '--long-term-suffix' cannot " "be equal to the value for '--short-term-suffix'") if args.assume_role: role_msg = "with assumed role: %s" % (args.assume_role, ) elif config.has_option(args.profile, 'assumed_role_arn'): role_msg = "with assumed role: %s" % (config.get( args.profile, 'assumed_role_arn')) else: role_msg = "" logger.info('Validating credentials for profile: %s %s' % (short_term_name, role_msg)) reup_message = "Obtaining credentials for a new role or profile." try: key_id = config.get(long_term_name, 'aws_access_key_id') access_key = config.get(long_term_name, 'aws_secret_access_key') except NoSectionError: log_error_and_exit( logger, "Long term credentials session '[%s]' is missing. " "You must add this section to your credentials file " "along with your long term 'aws_access_key_id' and " "'aws_secret_access_key'" % (long_term_name, )) except NoOptionError as e: log_error_and_exit(logger, e) # get device from param, env var or config if not args.device: if os.environ.get('MFA_DEVICE'): args.device = os.environ.get('MFA_DEVICE') elif config.has_option(long_term_name, 'aws_mfa_device'): args.device = config.get(long_term_name, 'aws_mfa_device') else: log_error_and_exit( logger, 'You must provide --device or MFA_DEVICE or set ' '"aws_mfa_device" in ".aws/credentials"') # get assume_role from param or env var if not args.assume_role: if os.environ.get('MFA_ASSUME_ROLE'): args.assume_role = os.environ.get('MFA_ASSUME_ROLE') elif config.has_option(long_term_name, 'assume_role'): args.assume_role = config.get(long_term_name, 'assume_role') # get duration from param, env var or set default if not args.duration: if os.environ.get('MFA_STS_DURATION'): args.duration = int(os.environ.get('MFA_STS_DURATION')) else: args.duration = 3600 if args.assume_role else 43200 # If this is False, only refresh credentials if expired. Otherwise # always refresh. force_refresh = False # Validate presence of short-term section if not config.has_section(short_term_name): logger.info("Short term credentials section %s is missing, " "obtaining new credentials." % (short_term_name, )) if short_term_name == 'default': try: config.add_section(short_term_name) # a hack for creating a section named "default" except ValueError: configparser.DEFAULTSECT = short_term_name config.set(short_term_name, 'CREATE', 'TEST') config.remove_option(short_term_name, 'CREATE') else: config.add_section(short_term_name) force_refresh = True # Validate option integrity of short-term section else: required_options = [ 'assumed_role', 'aws_access_key_id', 'aws_secret_access_key', 'aws_session_token', 'aws_security_token', 'expiration' ] try: short_term = {} for option in required_options: short_term[option] = config.get(short_term_name, option) except NoOptionError: logger.warn("Your existing credentials are missing or invalid, " "obtaining new credentials.") force_refresh = True try: current_role = config.get(short_term_name, 'assumed_role_arn') except NoOptionError: current_role = None if args.force: logger.info("Forcing refresh of credentials.") force_refresh = True # There are not credentials for an assumed role, # but the user is trying to assume one elif current_role is None and args.assume_role: logger.info(reup_message) force_refresh = True # There are current credentials for a role and # the role arn being provided is the same. elif (current_role is not None and args.assume_role and current_role == args.assume_role): pass # There are credentials for a current role and the role # that is attempting to be assumed is different elif (current_role is not None and args.assume_role and current_role != args.assume_role): logger.info(reup_message) force_refresh = True # There are credentials for a current role and no role arn is # being supplied elif current_role is not None and args.assume_role is None: logger.info(reup_message) force_refresh = True should_refresh = True # Unless we're forcing a refresh, check expiration. if not force_refresh: exp = datetime.datetime.strptime( config.get(short_term_name, 'expiration'), '%Y-%m-%d %H:%M:%S') diff = exp - datetime.datetime.utcnow() if diff.total_seconds() <= 0: logger.info("Your credentials have expired, renewing.") else: should_refresh = False logger.info("Your credentials are still valid for %s seconds" " they will expire at %s" % (diff.total_seconds(), exp)) if should_refresh: get_credentials(short_term_name, key_id, access_key, args, config)