From 70bd785d68d05bc1f72ae3f1fe2f21a15ac2963a Mon Sep 17 00:00:00 2001 From: konsthol Date: Sat, 11 Mar 2023 19:22:53 +0200 Subject: [PATCH] Does this work --- secdep.py | 89 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/secdep.py b/secdep.py index f126b7c..d3109e7 100755 --- a/secdep.py +++ b/secdep.py @@ -26,11 +26,12 @@ import subprocess import libcloud.security import inspect import paramiko +import socket from dotenv import load_dotenv from libcloud.compute.types import Provider from libcloud.compute.providers import get_driver from libcloud.compute.base import NodeAuthSSHKey -from libcloud.compute.deployment import ScriptDeployment +from libcloud.compute.deployment import ScriptDeployment, SSHKeyDeployment, MultiStepDeployment # Disable SSL certificate verification # Disable SHA-2 variants of RSA key verification algorithm for backward compatibility reasons @@ -76,10 +77,12 @@ if not os.path.exists(SECDEP_SSH_PUBLIC_KEY) or not os.path.exists(SECDEP_SSH_PR # The public key is stored in the current directory and named secdep.pub # The passphrase is an empty string # The key is a 4096 bit RSA key + # The key's comment is secdep@hostname + key = paramiko.RSAKey.generate(4096) key.write_private_key_file(SECDEP_SSH_PRIVATE_KEY) with open(SECDEP_SSH_PUBLIC_KEY, 'w') as f: - f.write("%s %s" % (key.get_name(), key.get_base64())) + f.write("%s %s secdep@%s" % (key.get_name(), key.get_base64(), socket.gethostname())) # We first check if it exists already in order to avoid overwriting it # and if it doesn't exist, we create it by inserting an empty string @@ -715,8 +718,8 @@ def choose_from_list(listFromlistFunction,listName): printFormat = "{}) {}\n\n{}\n" printstring = "print(printFormat.format(count, item.name, item.extra['description']))" elif listName == "node": - printFormat = "{}) {}\n\nState: {}\nPublic IPs: {}\nPrivate IPs: {}\nDriver: {}\nSize: {}\nImage: {}\nCreation Date: {}\n" - printstring = "print(printFormat.format(count, item.name, item.state, item.public_ips, item.private_ips, item.driver, item.size, item.image, item.created_at))" + printFormat = "{}) {}\n\nState: {}\nPublic IPs: {}\nPrivate IPs: {}\nDriver: {}\nSize: {}\nImage: {}\nCreation Date: {}\nExtra: {}\n" + printstring = "print(printFormat.format(count, item.name, item.state, item.public_ips, item.private_ips, item.driver, item.size, item.image, item.created_at, item.extra))" compiled_code = compile(printstring,"","exec") print("Choosing 0 will exit") @@ -801,17 +804,19 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi # Get public ssh key value with open(SECDEP_SSH_PUBLIC_KEY, 'r') as f: pubkey = f.read() - if provider != "gce": + if provider == "azure": auth = NodeAuthSSHKey(pubkey) # Check if name was given and if not prompt the user to give one if name is None: name = input("Enter the name of the node: ") assert name != "", "Name is empty" - name = "provider_"+name + name = provider+"_"+name + else: + name = provider+"_"+name # In the case of aws location has to be None because it is actually derived from the ami (image) if provider == "aws": location = None - print("in aws you first have to choose an image before the location") + # print("in aws you first have to choose an image before the location") else: # In other cases # Check if location was given and if not prompt the user to choose @@ -859,6 +864,12 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi if image is None: image = get_provider_image(provider) assert image is not None, "Image is None" + if provider == "aws": + ami = image.id + region = getAWSRegionFromAmi(ami) + dr = get_corresponding_driver(provider) + assert dr is not None, "Driver is not set up correctly" + image = get_driver(Provider.EC2)(SECDEP_AWS_ACCESS_KEY, SECDEP_AWS_SECRET_KEY,region=region).get_image(ami) else: blockPrint() # If provider was aws we must get the list of amis @@ -939,8 +950,20 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi # step = ScriptDeployment(SCRIPT) node = driver.create_node(name=name, image=image, size=size, location=location, ex_service_accounts=sa_scopes, ex_metadata=metadata) # node = driver.deploy_node(name=name, image=image, size=size, location=location, deploy=step, ex_service_accounts=sa_scopes, ex_metadata=metadata, ssh_key=SECDEP_SSH_PRIVATE_KEY) - else: + elif provider == "azure": node = driver.create_node(name, size, image, location, auth=auth) + else: + # driver.import_key_pair_from_string("secdep@"+socket.gethostname(), pubkey) + SCRIPT = '''#!/usr/bin/env bash + useradd -G sudo -m secdep + echo "secdep:secdeppass" | chpasswd + echo "%sudo ALL=(ALL:ALL) ALL" >> /etc/sudoers + mkdir -p /home/secdep/.ssh + cp /root/.ssh/authorized_keys /home/secdep/.ssh/authorized_keys''' + step_1 = SSHKeyDeployment(pubkey) + step_2 = ScriptDeployment(SCRIPT) + msd = MultiStepDeployment([step_1, step_2]) + node = driver.deploy_node(name=name, image=image, size=size, deploy=msd, ssh_key=SECDEP_SSH_PRIVATE_KEY) else: # When the -y or --yes parameter is passed we go straight to the node creation if provider == "gce": @@ -952,14 +975,43 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi # step = ScriptDeployment(SCRIPT) node = driver.create_node(name=name, image=image, size=size, location=location, ex_service_accounts=sa_scopes, ex_metadata=metadata) # node = driver.deploy_node(name=name, image=image, size=size, location=location, deploy=step, ex_service_accounts=sa_scopes, ex_metadata=metadata, ssh_key=SECDEP_SSH_PRIVATE_KEY) - else: + # if provider == "aws": + # SCRIPT = '''#!/usr/bin/env bash + # useradd -G sudo -m secdep + # echo "secdep:secdeppass" | chpasswd + # echo "%sudo ALL=(ALL:ALL) ALL" >> /etc/sudoers + # mkdir -p /home/secdep/.ssh''' + # step = ScriptDeployment(SCRIPT) + # + elif provider == "azure": node = driver.create_node(name, size, image, location, auth=auth) + else: + # driver.import_key_pair_from_string("secdep@"+socket.gethostname(), pubkey) + SCRIPT = '''#!/usr/bin/env bash + useradd -G sudo -m secdep + echo "secdep:secdeppass" | chpasswd + echo "%sudo ALL=(ALL:ALL) ALL" >> /etc/sudoers + mkdir -p /home/secdep/.ssh + cp /root/.ssh/authorized_keys /home/secdep/.ssh/authorized_keys''' + step_1 = SSHKeyDeployment(pubkey) + step_2 = ScriptDeployment(SCRIPT) + msd = MultiStepDeployment([step_1, step_2]) + node = driver.deploy_node(name=name, image=image, size=size, deploy=msd, ssh_key=SECDEP_SSH_PRIVATE_KEY) + print('stdout: %s' % (step_1.stdout)) + print('stderr: %s' % (step_1.stderr)) + print('exit_code: %s' % (step_1.exit_status)) + print('stdout: %s' % (step_2.stdout)) + print('stderr: %s' % (step_2.stderr)) + print('exit_code: %s' % (step_2.exit_status)) print(node.name + " created successfully") + print("Node is initializing") + time.sleep(30) print("ip to connect to") - print(node.public_ips) + print("\nIP: %s\n" % (node.public_ips)) return node +## aws node does not return ip -def list_all_nodes(): +def list_all_nodes(filterOut=None): print("Getting all nodes...") nodes = [] if SECDEP_GCE_CLIENT_ID != "": @@ -987,9 +1039,11 @@ def list_all_nodes(): if len(nodes) == 0: print("No nodes") exit(0) + if filterOut == "terminated": + nodes = list(filter(lambda x: 'terminated' not in x.state.lower(), nodes)) for node in nodes: count += 1 - print("{}) {}\n\nState: {}\nPublic IPs: {}\nPrivate IPs: {}\nDriver: {}\nSize: {}\nImage: {}\nCreation Date: {}\n".format(count, node.name, node.state, node.public_ips, node.private_ips, node.driver, node.size, node.image, node.created_at)) + 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)) return nodes def get_node(): @@ -997,7 +1051,7 @@ def get_node(): return node def delete_node(): - node = choose_from_list(list_all_nodes(), "node") + node = choose_from_list(list_all_nodes("terminated"), "node") providerName = node.name.split("_")[0] if providerName == "gce": driver = get_corresponding_driver("gce") @@ -1005,10 +1059,15 @@ def delete_node(): 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.destroy_node(node)): - print("% node deleted successfully" % (providerName.upper())) + print("%s node deleted successfully" % (providerName.upper())) else: - print("% node could not be deleted" % (providerName.upper())) + print("%s node could not be deleted" % (providerName.upper())) + +#elif node.state == "running": # def get_provider_features(provider): # driver = get_corresponding_driver(provider);