def _create_policy(self, policy_name): """create new IAM policy on AWS""" local_policy_document = os2.parse_json(self._policy_dir / f"{policy_name}.json") policy_description = self._iam_policy_setup[policy_name] self._iam_client.create_policy( PolicyName=policy_name, Path=self._path_prefix, PolicyDocument=json.dumps(local_policy_document), Description=policy_description)
def _validate_iam_policies(config_aws_setup): """validate aws_setup.json reflects contents of iam_policies dir""" policy_dir = consts.AWS_SETUP_DIR / "iam_policies" # Policies described in aws_setup/aws_setup.json setup_policy_list = [ f"{policy}.json" for policy in config_aws_setup['IAM']['Policies'] ] # Actual policy JSON files located in aws_setup/iam_policies/ iam_policy_files = os2.dir_files(policy_dir, ext=".json") # Halt if any IAM policy file contains invalid JSON for iam_policy_file in iam_policy_files: os2.parse_json(policy_dir / iam_policy_file) # Halt if aws_setup.json describes policies not found in iam_policies if not set(setup_policy_list).issubset(set(iam_policy_files)): halt.err( "Following policy(s) not found from aws_setup/iam_policies/:", *[ policy for policy in setup_policy_list if policy not in iam_policy_files ])
def _update_policy(self, policy_name, aws_policies): """update IAM policy that already exists on AWS""" local_policy_document = os2.parse_json(self._policy_dir / f"{policy_name}.json") aws_policy = next(aws_policy for aws_policy in aws_policies if aws_policy['PolicyName'] == policy_name) # Delete beforehand to avoid error of 5 versions already existing self._delete_old_policy_versions(aws_policy['Arn']) self._iam_client.create_policy_version( PolicyArn=aws_policy['Arn'], PolicyDocument=json.dumps(local_policy_document), SetAsDefault=True)
def _delete_user_access_keys(self, user_name): """delete IAM user's access key(s)""" aws_access_keys = self._iam_client.list_access_keys( UserName=user_name)['AccessKeyMetadata'] for access_key in aws_access_keys: self._iam_client.delete_access_key( UserName=user_name, AccessKeyId=access_key['AccessKeyId']) # Remove IAM user's backed up access key from config config_dict = os2.parse_json(consts.CONFIG_JSON) if 'backup_keys' in config_dict: config_dict['backup_keys'].pop(access_key['AccessKeyId'], None) if not config_dict['backup_keys']: del config_dict['backup_keys'] os2.save_json(config_dict, consts.CONFIG_JSON)
def _update_config_dict(new_key, old_key_ids): """remove old access keys and place new one in config""" config_dict = os2.parse_json(consts.CONFIG_JSON) if 'backup_keys' in config_dict: for old_key_id in old_key_ids: config_dict['backup_keys'].pop(old_key_id, None) if not config_dict['backup_keys']: del config_dict['backup_keys'] if next(iter(config_dict['access_key'])) in old_key_ids: config_dict['access_key'] = new_key else: config_dict.setdefault('backup_keys', {}).update(new_key) os2.save_json(config_dict, consts.CONFIG_JSON)
def main(self, cmd_args): """create a new IAM user under an IAM group""" iam_client = aws.iam_client() path_prefix = f"/{consts.NAMESPACE}/" aws.validate_group_exists(path_prefix, cmd_args.group) # IAM user created and added to group (given the name is unique) try: iam_client.create_user(Path=path_prefix, UserName=cmd_args.name) except ClientError as e: if e.response['Error']['Code'] == "EntityAlreadyExists": halt.err(f"IAM user \"{cmd_args.name}\" already exists.") halt.err(str(e)) iam_client.add_user_to_group(GroupName=cmd_args.group, UserName=cmd_args.name) print("") print(f"IAM user \"{cmd_args.name}\" created on AWS.") # IAM user access key generated and saved to dictionary new_key = iam_client.create_access_key( UserName=cmd_args.name)['AccessKey'] new_key = {new_key['AccessKeyId']: new_key['SecretAccessKey']} self._access_key_usable_waiter(new_key) config_dict = os2.parse_json(consts.CONFIG_JSON) if 'backup_keys' not in config_dict: config_dict['backup_keys'] = {} if cmd_args.default: # Modify existing config instead of creating new one config_dict['backup_keys'].update(config_dict['access_key']) config_dict['access_key'] = new_key os2.save_json(config_dict, consts.CONFIG_JSON) print(" User's access key set as default in config.") else: # Back up new IAM user's access key in config file config_dict['backup_keys'].update(new_key) os2.save_json(config_dict, consts.CONFIG_JSON) os2.create_configuration_zip(cmd_args.name, new_key, cmd_args.ssh_key) print(" User's zipped configuration created in config.")
def _switch_access_key(user_name): """set access key stored in backup access keys list as default""" config_dict = os2.parse_json(consts.CONFIG_JSON) if 'backup_keys' not in config_dict: halt.err("No backup access keys stored in config.") for key_id, key_secret in config_dict['backup_keys'].items(): # TODO: Validate access key is active key_owner = aws.access_key_owner(key_id) if key_owner is None: continue if key_owner.lower() == user_name.lower(): # Swap default access key with requested IAM user's in config config_dict['backup_keys'].update(config_dict['access_key']) config_dict['access_key'] = {key_id: key_secret} del config_dict['backup_keys'][key_id] os2.save_json(config_dict, consts.CONFIG_JSON) return key_owner halt.err(f"Backup access key for IAM user \"{user_name}\" not found.")
def main(self, cmd_args): """configure, for example, the default IAM user access key""" # validate_config:main normally does this, but it wasn't called. consts.CONFIG_DIR.mkdir(exist_ok=True) config_dict = {} if consts.CONFIG_JSON.is_file(): schema = os2.get_json_schema("config") config_dict = os2.parse_json(consts.CONFIG_JSON) os2.validate_dict(config_dict, schema, "config.json") if cmd_args.subcommand == "access_key": config_dict = self._set_access_key( config_dict, cmd_args.key_id, cmd_args.key_secret) elif cmd_args.subcommand == "whitelist": self._set_region_whitelist(config_dict, cmd_args.regions) elif cmd_args.subcommand == "use_handler": config_dict['use_handler'] = cmd_args.boolean print(f"IP handler usage set to {str(cmd_args.boolean)}.") os2.save_json(config_dict, consts.CONFIG_JSON)
def _validate_vpc_security_groups(config_aws_setup): """validate aws_setup.json reflects contents of vpc_security_groups dir""" sg_dir = consts.AWS_SETUP_DIR / "vpc_security_groups" # SGs described in aws_setup/aws_setup.json setup_sg_list = [ f"{sg_name}.json" for sg_name in config_aws_setup['VPC']['SecurityGroups'] ] # Actual SG json files located in aws_setup/vpc_security_groups/ vpc_sg_json_files = os2.dir_files(sg_dir, ext=".json") # Halt if aws_setup.json describes SGs not found in sg_dir if not set(setup_sg_list).issubset(set(vpc_sg_json_files)): halt.err( "Following SG(s) not found from aws_setup/vpc_security_groups/:", *[sg for sg in setup_sg_list if sg not in vpc_sg_json_files]) # Halt if any security group missing Ingress key schema = os2.get_json_schema("vpc_security_groups") for sg_file in vpc_sg_json_files: sg_dict = os2.parse_json(sg_dir / sg_file) os2.validate_dict(sg_dict, schema, f"SG {sg_file}")
def _get_json_sg_ingress(sg_name): """retrieve local security group ingress rule(s) dict""" sg_dir = consts.AWS_SETUP_DIR / "vpc_security_groups" return os2.parse_json(sg_dir / f"{sg_name}.json")['Ingress']