diff --git a/secdep.py b/secdep.py index cbfd73f..a1193ba 100755 --- a/secdep.py +++ b/secdep.py @@ -18,14 +18,9 @@ # from the command line using flags import os -import re import sys import argparse import time -import json -import subprocess -import libcloud.security -import inspect import paramiko import socket from dotenv import load_dotenv @@ -54,13 +49,17 @@ parser = argparse.ArgumentParser( parser.add_argument('-l', '--list', help='List all instances', action='store_true') parser.add_argument('-v', '--values', help='Change credential values', action='store_true') parser.add_argument('-P', '--provider', help='Cloud provider', choices=['gce', 'azure', 'aws']) -parser.add_argument('-a', '--action', help='Action to perform', choices=['create', 'delete', 'start', 'stop', 'reboot']) +# parser.add_argument('-a', '--action', help='Action to perform', choices=['delete', 'start', 'stop', 'reboot']) +parser.add_argument('-a', '--action', help='Action to perform on a single or all instances', choices=['delete', 'start', 'stop', 'reboot', 'deleteall', 'startall', 'stopall', 'rebootall']) parser.add_argument('-c', '--create', help='Create an instance', action='store_true') parser.add_argument('-d', '--delete', help='Delete an instance', action='store_true') parser.add_argument('-da', '--deleteall', help='Delete all instances', action='store_true') -parser.add_argument('-x', '--start', help='Start an instance', action='store_true') -parser.add_argument('-z', '--stop', help='Stop an instance', action='store_true') -parser.add_argument('-r', '--reboot', help='Reboot an instance', action='store_true') +# parser.add_argument('-x', '--start', help='Start an instance', action='store_true') +# parser.add_argument('-xa', '--startall', help='Start all instances', action='store_true') +# parser.add_argument('-z', '--stop', help='Stop an instance', action='store_true') +# parser.add_argument('-za', '--stopall', help='Stop all instances', action='store_true') +# parser.add_argument('-r', '--reboot', help='Reboot an instance', action='store_true') +# parser.add_argument('-ra', '--rebootall', help='Reboot all instances', action='store_true') parser.add_argument('-f', '--file', help='File to run on an instance', type=str, default=None, required=False) parser.add_argument('-I', '--listimages', help='List images', action='store_true') parser.add_argument('-S', '--listsizes', help='List sizes', action='store_true') @@ -70,7 +69,7 @@ parser.add_argument('-s', '--size', help='Size of instance') parser.add_argument('-n', '--name', help='Name of instance') parser.add_argument('-g', '--region', help='Region to use') parser.add_argument('-y', '--yes', help='Do not ask for confirmation', action='store_true') -parser.add_argument('-p', '--print', help='Also print image, location or size', action='store_true') +parser.add_argument('-p', '--print', help='Also print node, image, location or size', action='store_true') args = parser.parse_args() if not os.path.exists(SECDEP_SSH_PUBLIC_KEY) or not os.path.exists(SECDEP_SSH_PRIVATE_KEY): @@ -579,6 +578,7 @@ AZURE_images = { global gce_driver global azure_driver global aws_driver +global providers_quantity # Get GCE driver def get_gce_driver(): @@ -589,7 +589,7 @@ def get_gce_driver(): # Get Azure driver def get_azure_driver(): - if SECDEP_AZURE_TENANT_ID !="" and SECDEP_AZURE_SUB_ID !="" and SECDEP_AZURE_APP_ID !="" and SECDEP_AZURE_PASSWORD !="": + if SECDEP_AZURE_TENANT_ID !="" and SECDEP_AZURE_SUB_ID !="" and SECDEP_AZURE_APP_ID !="" and SECDEP_AZURE_PASSWORD !="" and SECDEP_AZURE_RESOURCE_GROUP !="" and SECDEP_AZURE_VIRTUAL_NETWORK != "": driver = get_driver(Provider.AZURE_ARM) print("Trying to authenticate with azure...\n") return driver(tenant_id=SECDEP_AZURE_TENANT_ID, subscription_id=SECDEP_AZURE_SUB_ID, key=SECDEP_AZURE_APP_ID, secret=SECDEP_AZURE_PASSWORD) @@ -601,6 +601,18 @@ def get_aws_driver(): print("Trying to authenticate with amazon...\n") return driver(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY) +def get_providers_quantity(): + providers_quantity = 0 + if SECDEP_GCE_CLIENT_SECRET !="" and SECDEP_GCE_PROJECT_ID !="" and SECDEP_GCE_CLIENT_ID !="": + providers_quantity +=1 + if SECDEP_AZURE_TENANT_ID !="" and SECDEP_AZURE_SUB_ID !="" and SECDEP_AZURE_APP_ID !="" and SECDEP_AZURE_PASSWORD !="" and SECDEP_AZURE_RESOURCE_GROUP !="" and SECDEP_AZURE_VIRTUAL_NETWORK != "": + providers_quantity +=1 + if SECDEP_AWS_ACCESS_KEY !="" and SECDEP_AWS_SECRET_KEY !="": + providers_quantity +=1 + return providers_quantity + +providers_quantity = get_providers_quantity() + gce_driver = get_gce_driver() azure_driver = get_azure_driver() aws_driver = get_aws_driver() @@ -1088,8 +1100,9 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi print("\nIP: %s\n" % (node.public_ips)) return node -def list_all_nodes(filterOut=None): +def list_all_nodes(filterIn=None): print("Getting all nodes...") + print("Loading 0%...") nodes = [] if SECDEP_GCE_CLIENT_ID != "": print("Getting GCE nodes...") @@ -1098,6 +1111,7 @@ def list_all_nodes(filterOut=None): if len(gceNodes) > 0: for node in gceNodes: nodes.append(node) + print("Loading %s%%..." % (int((1/providers_quantity)*100))) if SECDEP_AZURE_APP_ID != "": print("Getting AZURE nodes...") driver2 = get_corresponding_driver("azure") @@ -1105,6 +1119,7 @@ def list_all_nodes(filterOut=None): if len(azureNodes) > 0: for node in azureNodes: nodes.append(node) + print("Loading %s%%..." % (int((2/providers_quantity)*100))) if SECDEP_AWS_ACCESS_KEY != "": print("Getting AWS nodes...") awsLocations = ["ap-northeast-1", "ap-northeast-2", "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2"] @@ -1115,12 +1130,24 @@ def list_all_nodes(filterOut=None): if len(awsNodes) > 0: for node in awsNodes: nodes.append(node) + print("Loading %s%%..." % (int((3/providers_quantity)*100))) count = 0 if len(nodes) == 0: print("No nodes") exit(0) - if filterOut == "terminated": - nodes = list(filter(lambda x: 'terminated' not in x.state.lower() and 'unknown' not in x.state.lower(), nodes)) + # available states: running, rebooting, terminated, pending, stopped, suspended, paused, erro, unknown + # for delete + if filterIn == "delete": + nodes = list(filter(lambda x: 'running' in x.state.lower() and 'rebooting' in x.state.lower() and 'stopped' in x.state.lower() and 'suspended' in x.state.lower() and 'paused' in x.state.lower(), nodes)) + # for start + if filterIn == "start": + nodes = list(filter(lambda x: 'stopped' in x.state.lower() and 'suspended' in x.state.lower() and 'paused' in x.state.lower(), nodes)) + # for stop + if filterIn == "stop": + nodes = list(filter(lambda x: 'running' in x.state.lower() and 'rebooting' in x.state.lower(), nodes)) + # for reboot + if filterIn == "reboot": + nodes = list(filter(lambda x: 'running' in x.state.lower() and 'stopped' in x.state.lower() and 'suspended' in x.state.lower() and 'paused' in x.state.lower(), nodes)) for node in nodes: count += 1 print("{}) {}\n\nState: {}\nPublic IPs: {}\nPrivate IPs: {}\nDriver: {}\nSize: {}\nImage: {}\nCreation Date: {}\nExtra: {}\n".format(count, node.name, node.state, node.public_ips, node.private_ips, node.driver, node.size, node.image, node.created_at, node.extra)) @@ -1130,8 +1157,216 @@ def get_node(): node = choose_from_list(list_all_nodes(), "node") return node +def node_action(action): + node = choose_from_list(list_all_nodes(action), "node") + if node is None: + print("Nothing was chosen") + exit(0) + providerName = node.name.split("-")[0] + if providerName == "gce": + driver = get_corresponding_driver("gce") + elif providerName == "azure": + driver = get_corresponding_driver("azure") + elif providerName == "aws": + driver = get_corresponding_driver("aws") + assert driver is not None, "Driver is not set up correctly" + region = getAWSRegionFromAmi(node.extra['image_id']) + driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) + match action: + case "reboot": + succeded = driver.reboot_node(node) + case "stop": + succeded = driver.stop_node(node) + case "start": + succeded = driver.start_node(node) + case "delete": + succeded = driver.delete_node(node) + case _: + print("Invalid action command") + exit(0) + if(succeded): + print("%s node %s was successfully" % (providerName.upper(), action)) + else: + print("%s node could not %s" % (providerName.upper(), action)) + if providerName == "azure" and action == "delete": + driver = get_corresponding_driver("azure") + node_location = node.extra['location'] + locations = driver.list_locations() + for loc in locations: + if loc.id == node_location: + location = loc + break + sec_groups = driver.ex_list_network_security_groups(SECDEP_AZURE_RESOURCE_GROUP) + for sec_group in sec_groups: + if sec_group.name == node.name+"-sec_group": + driver.ex_delete_network_security_group(name=sec_group.name, resource_group=SECDEP_AZURE_RESOURCE_GROUP, location=location) + # ips = driver.ex_list_public_ips(SECDEP_AZURE_RESOURCE_GROUP) + # for ip in ips: + # if ip.name == node.name+"-ip": + # driver.ex_delete_public_ip(ip) + +def node_action_all(action): + nodes = list_all_nodes(action) + for node in nodes: + providerName = node.name.split("-")[0] + if providerName == "gce": + driver = get_corresponding_driver("gce") + elif providerName == "azure": + driver = get_corresponding_driver("azure") + elif providerName == "aws": + driver = get_corresponding_driver("aws") + assert driver is not None, "Driver is not set up correctly" + region = getAWSRegionFromAmi(node.extra['image_id']) + driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) + match action: + case "rebootall": + succeded = driver.reboot_node(node) + case "stopall": + succeded = driver.stop_node(node) + case "startall": + succeded = driver.start_node(node) + case "deleteall": + succeded = driver.delete_node(node) + case _: + print("Invalid action command") + exit(0) + if(succeded): + print("%s node %s was successfully" % (node.name, action)) + else: + print("%s node could not %s" % (node.name, action)) + if providerName == "azure" and action == "delete": + driver = get_corresponding_driver("azure") + node_location = node.extra['location'] + locations = driver.list_locations() + for loc in locations: + if loc.id == node_location: + location = loc + break + sec_groups = driver.ex_list_network_security_groups(SECDEP_AZURE_RESOURCE_GROUP) + for sec_group in sec_groups: + if sec_group.name == node.name+"-sec_group": + driver.ex_delete_network_security_group(name=sec_group.name, resource_group=SECDEP_AZURE_RESOURCE_GROUP, location=location) + # ips = driver.ex_list_public_ips(SECDEP_AZURE_RESOURCE_GROUP) + # for ip in ips: + # if ip.name == node.name+"-ip": + # driver.ex_delete_public_ip(ip) + +# def reboot_node(): +# node = choose_from_list(list_all_nodes("reboot"), "node") +# if node is None: +# print("Nothing was chosen") +# exit(0) +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.reboot_node(node)): +# print("%s node rebooted successfully" % (providerName.upper())) +# else: +# print("%s node could not be rebooted" % (providerName.upper())) +# +# def reboot_all_nodes(): +# nodes = list_all_nodes("reboot") +# for node in nodes: +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.reboot_node(node)): +# print("%s node rebooted successfully" % (node.name)) +# else: +# print("%s node could not be rebooted" % (node.name)) +# +# def start_node(): +# node = choose_from_list(list_all_nodes("start"), "node") +# if node is None: +# print("Nothing was chosen") +# exit(0) +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.start_node(node)): +# print("%s node started successfully" % (providerName.upper())) +# else: +# print("%s node could not be started" % (providerName.upper())) +# +# def start_all_nodes(): +# nodes = list_all_nodes("start") +# for node in nodes: +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.start_node(node)): +# print("%s node started successfully" % (node.name)) +# else: +# print("%s node could not be started" % (node.name)) +# +# def stop_node(): +# node = choose_from_list(list_all_nodes("stop"), "node") +# if node is None: +# print("Nothing was chosen") +# exit(0) +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.stop_node(node)): +# print("%s node stopped successfully" % (providerName.upper())) +# else: +# print("%s node could not be stopped" % (providerName.upper())) +# +# def stop_all_nodes(): +# nodes = list_all_nodes("stop") +# for node in nodes: +# providerName = node.name.split("-")[0] +# if providerName == "gce": +# driver = get_corresponding_driver("gce") +# elif providerName == "azure": +# driver = get_corresponding_driver("azure") +# elif providerName == "aws": +# driver = get_corresponding_driver("aws") +# assert driver is not None, "Driver is not set up correctly" +# region = getAWSRegionFromAmi(node.extra['image_id']) +# driver = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region) +# if(driver.stop_node(node)): +# print("%s node stopped successfully" % (node.name)) +# else: +# print("%s node could not be stopped" % (node.name)) + def delete_node(): - node = choose_from_list(list_all_nodes("terminated"), "node") + node = choose_from_list(list_all_nodes("delete"), "node") if node is None: print("Nothing was chosen") exit(0) @@ -1166,9 +1401,8 @@ def delete_node(): # if ip.name == node.name+"-ip": # driver.ex_delete_public_ip(ip) - def delete_all_nodes(): - nodes = list_all_nodes("terminated") + nodes = list_all_nodes("delete") for node in nodes: providerName = node.name.split("-")[0] if providerName == "gce": @@ -1240,15 +1474,43 @@ if args.list: else: list_all_nodes() exit(0) +# If args.action contains the word all execute the node_action_all function, otherwise the node_action function +if args.action: + if(args.action.endswith("all")): + node_action_all(args.action) + else: + node_action(args.action) + exit(0) + if args.delete: delete_node() exit(0) if args.deleteall: delete_all_nodes() exit(0) +# if args.stop: +# stop_node() +# exit(0) +# if args.stopall: +# stop_all_nodes() +# exit(0) +# if args.start: +# start_node() +# exit(0) +# if args.startall: +# start_all_nodes() +# exit(0) +# if args.reboot: +# reboot_node() +# exit(0) +# if args.rebootall: +# reboot_all_nodes() +# exit(0) if args.image or args.size or args.name or args.region or args.yes and not args.create: print("Image, size, name, region and yes parameters only go along with the create flag") exit(0) +if args.print and not args.list or args.listimages or args.listsizes or args.listlocations: + print("The print flag only goes together with the list, list images, list sizes or list locations") # if args.create and not args.provider: # print("Provider must be specified in oder to use the create action") # exit(0)