diff options
Diffstat (limited to 'tuffy')
| -rw-r--r-- | tuffy/tuffycommand1.py | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/tuffy/tuffycommand1.py b/tuffy/tuffycommand1.py new file mode 100644 index 0000000..5b069ea --- /dev/null +++ b/tuffy/tuffycommand1.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +import argparse +import os +import io +import os +import shutil +import fileinput +import subprocess +#import paramiko #install pip3, paramiko, zip +import sys +import time + +""" +External dependencies: +https://api.ipify.org + to get the pubic facing ip address of this server + + NOTES + -before deploying, make sure template files are present and pub keys installed + -at each step of the process, describe what you want to do + + next steps + -hardcode aws and terraform installation and their credentials for ease of testing on new servers + -can test exfil and infil + - + +""" +#global variables +working_user="ubuntu" +working_directory=f"/home/{working_user}/tuffycommand1" + +def deploy(args): + #print(f"Hello {args.name}!") + #print(f"{args.name}, {args.cloudcomputeprovider}, {args.location}, {args.serverid}, {args.clients}!") + + #prerequisite for this code block to run is to have the lowpriv pub in the user dir, rest works + #this is to initialise the low priv user to put files in. + #store the variable 'username' and install ssh keys if they don't exist for remote user login + lpusername = "lowpriv" + pubkey_file = f"{working_directory}/pubkey/lowpriv.pub" + + file_names = [f"{pubkey_file}", + f"{working_directory}/server_exec-template/comp208.pub", + f"{working_directory}/server_exec-template/exfil.sh", + f"{working_directory}/server_exec-template/init.sh", + f"{working_directory}/server_exec-template/lowpriv", + f"{working_directory}/server_provisioning-template/template.tf", + f"{working_directory}/server_provisioning-template/tf-start.sh", + f"{working_directory}/server_provisioning-template/tf-end.sh"] + for file_name in file_names: + if os.path.exists(file_name): + continue + else: + print("one of the prerequisite files isn't present.") + print("exiting program") + sys.exit() + + if os.system("grep -q '^" + lpusername + ":' /etc/passwd") == 0: + print("user already exist, pub key is assumed to be installed") + else: + print("user does not exist, creating...") + #create the new user with low-privileges!! + subprocess.run(["useradd", "-m", "-s", "/bin/bash", lpusername]) + subprocess.run(["mkdir", "-p", f"/home/{lpusername}/.ssh"]) + subprocess.run(["chmod", "700", f"/home/{lpusername}/.ssh"]) + subprocess.run(["touch", f"/home/{lpusername}/.ssh/authorized_keys"]) + subprocess.run(["chmod", "600", f"/home/{lpusername}/.ssh/authorized_keys"]) + subprocess.run(["chown", "-R", f"{lpusername}:{lpusername}", f"/home/{lpusername}/.ssh"]) + with open(pubkey_file, "r") as f: + pubkey_file = f.read() + with open(f"/home/{lpusername}/.ssh/authorized_keys", "a") as auth_file: + auth_file.write(pubkey_file) + print(f"User '{lpusername}' has been created with the provided public key") + + cmd = "curl ifconfig.me" + result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True) + local_public_ip = result.stdout.decode().strip() + print(local_public_ip) + + + #you need these 3 variables and serverid to configure the template for terraform! + location_aws="" + ami="" + ccp="" + if args.location == "London": + location_aws = "eu-west-2" + ami="ami-038d76c4d28805c09" + ccp="aws" + elif args.location == "Paris": + location_aws = "eu-west-3" + ami="ami-0dfb6769e523bf035" + ccp="aws" + else: + print("Error: invalid cloud compute location. Allowed locations are 'London' and 'Paris'") + print("exiting program") + sys.exit() + + #create unique directory + path = os.path.join(working_directory,"instances", args.name, ccp, args.location, args.serverid) + print(f"unique server path is {path}") + if os.path.exists(os.path.expanduser(path)): + print("Error: Directory already exists, nothing will happen, program will continue to run") + else: + os.makedirs(os.path.expanduser(path)) + print("hi new directory will be made") + + # copy file from source to destination directory + source_dir = f"{working_directory}/server_provisioning-template/" + dest_dir = f"{path}/server_provisioning/" + if not os.path.exists(dest_dir): + #if directory does not exist, create it + os.makedirs(dest_dir) + for filename in os.listdir(source_dir): + src_file = os.path.join(source_dir, filename) + dest_file = os.path.join(dest_dir, filename) + #overwrite the file if it already exists + shutil.copy(src_file, dest_file) + + + # Replace string in template.tf file + filename_template = os.path.join(path, "server_provisioning/template.tf") + with fileinput.FileInput(os.path.join(path, filename_template), inplace=True, backup="", mode="r") as file: + #these strings are already in the template + old_string_location = "LOCATION-TEMPLATE" + old_string_ami = "AMI-TEMPLATE" + old_string_serverid = "SERVERID-TEMPLATE" + #do note the below 3 commands do not work on mac due to a bug in sed + #verified it works in linux + subprocess.run(f"sed -i 's/{old_string_location}/{location_aws}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's/{old_string_ami}/{ami}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's/{old_string_serverid}/{args.serverid}/g' {filename_template}", shell=True) + print("template change success") + + #commands to execute in the particular instance's directory + print("path changed to the server path") + path_server_provisioning=os.path.join(f"{path}","server_provisioning/") + os.chdir(path_server_provisioning) + commands = [ + f"chmod +x {path_server_provisioning}tf-start.sh", + f"chmod +x {path_server_provisioning}tf-end.sh", + f"sudo {path_server_provisioning}tf-start.sh" + ] + + + # Iterate over the commands and execute them + for command in commands: + # Build the full SSH command to execute + #full_command = f"{ssh_command} '{command}'" + # Start the subprocess and capture the output + process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # Print the output as it is generated + while True: + # Read a line of output from the process's stdout stream + output = process.stdout.readline() + # If there is no more output, break out of the loop + if not output: + break + # Decode the output and print it to the console + print(output.decode().strip()) + # Print any error messages that were generated + stderr_output = process.stderr.read().decode() + if stderr_output: + print(f"Error: {stderr_output.strip()}") + # Wait for the process to finish + process.wait() + subprocess.run(f"mv terraform-output.txt ../", shell=True) + os.chdir(working_directory) + + + #after tf-start.sh is executed, output.txt is produced + #store each variable of "output.txt" + filename_output = os.path.join(path, "terraform-output.txt") + instance_id="" + instance_public_ip="" + instance_labelled_serverid="" + with open(filename_output) as file: + lines = [line.strip() for line in file.readlines()] + instance_id=lines[0] + instance_public_ip=lines[1] + instance_labelled_serverid=lines[2] + #check if the created server id, labelled in terraform is the same as the one given as input. it should be the same. + if args.serverid == instance_labelled_serverid: + pass + print("server initialisation success!!") + else: + print('ERROR! \nThe instance you created does not have the same server id as the one you assigned it.\n(The problem is due to a mistake made by the programmer)') + + + print("\nserver initialisation success! now we are going to configure and install the vpn on the server\n") + + #set source and destination directory + source_dir = "server_exec-template/" + dest_dir = os.path.join(path, "server_exec") + if not os.path.exists(dest_dir): + #if directory does not exist, create it + os.makedirs(dest_dir) + #copy all files from the source destination + for filename in os.listdir(source_dir): + src_file = os.path.join(source_dir, filename) + dest_file = os.path.join(dest_dir, filename) + #overwrite the file if it already exists + shutil.copy(src_file, dest_file) + + + + + #now make the .sh file to be executed in the user environment + + #create edited input file, line seperated + with io.open(os.path.expanduser(f"{path}/server-info-all.txt"), "w", encoding="utf-8") as f: + f.write(f"{args.name}\n") + f.write(f"{ccp}\n") + f.write(f"{args.location}\n") + f.write(f"{args.clients}\n") + f.write(f"{args.serverid}\n") + f.write(f"{location_aws}\n") + f.write(f"{ami}\n") + f.write(f"\n") + f.write(f"{local_public_ip}\n") + f.write(f"{instance_public_ip}\n") + f.write(f"{lpusername}\n") + f.write(f"{pubkey_file}\n") + + + + #generate a list of client names + clients = [f'client{i}' for i in range(1, args.clients+1)] + #concatenate the client names into a comma-separated string + client_string = ','.join(clients) + print(f"client string is {client_string}") + + + filename_template = os.path.join(f"{path}","server_exec", "exfil.sh") + #subprocess.run(f"cat {filename_template}", shell=True) + with fileinput.FileInput(os.path.join(path, filename_template), inplace=True, backup="", mode="r") as file: + #these strings are already in the template + old_string_iip = "instance_ip_TEMPLATE" + old_string_clientstring = "allclients_TEMPLATE" + old_string_lpusername = "lowpriv_TEMPLATE" + old_string_serverip = "exfil_ip_TEMPLATE" + lowpriv_serverdir=f"/home/lowpriv{path}" + old_string_serverdir = "exfil_dir_TEMPLATE" + #do note the below 3 commands do not work on mac due to a bug in sed + #verified it works in linux + subprocess.run(f"sed -i 's/{old_string_iip}/{instance_public_ip}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's/{old_string_clientstring}/{client_string}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's/{old_string_lpusername}/{lpusername}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's/{old_string_serverip}/{local_public_ip}/g' {filename_template}", shell=True) + subprocess.run(f"sed -i 's+{old_string_serverdir}+{lowpriv_serverdir}+g' {filename_template}", shell=True) + + + #instance_public_ip="10.211.55.18" + print("sleeping 10") + time.sleep(10) + #if not, ssh will fail, aws needs a bit of time for their ssh to work + username='ubuntu' + key_filename='/home/ubuntu/awscomp208.pem' + print(instance_public_ip) + + # make the zipped file from the folder that already contains the preconfigured files first + local_folder_name = os.path.join(path, "server_exec") + local_zipped_file = f'{local_folder_name}.zip' + path_to_zipped_file = os.path.join(path,local_zipped_file) + #print("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii") + #print(path_to_zipped_file) + print("zipping local configured initialisation files for transfer") + subprocess.run(f"cp {path}/server-info-all.txt {local_folder_name}/", shell=True) + subprocess.run(f"zip -r {local_folder_name}.zip {local_folder_name}/", shell=True) + print("") + + time.sleep(1) + print("transferring zipped file over to the other(vpn) server") + #EDIT SSH AUTH FILE AND USERNAME HERE + print(local_zipped_file) + print(instance_public_ip) + subprocess.run(f"scp -i /home/ubuntu/awscomp208.pem -o StrictHostKeyChecking=no {local_zipped_file} ubuntu@{instance_public_ip}:/home/ubuntu/", shell=True) + subprocess.run(f"scp -i /home/ubuntu/awscomp208.pem -o StrictHostKeyChecking=no {path}/server_exec/init.sh ubuntu@{instance_public_ip}:/home/ubuntu/", shell=True) + # unzip file on remote server + + remote_folder_name = local_folder_name[1:] + + # Define the SSH command to use + ssh_command = f"ssh -i {key_filename} {username}@{instance_public_ip}" + + # Define the commands to execute + commands = [ + #f"sudo apt-get update", + #f"echo 'update completed, sleeping for 20 seconds'", + #f"sleep 20", + #f"sudo apt-get install zip unzip tree tmux vim htop mlocate mosh net-tools -y", + f"sudo rm -rf /var/lib/apt/lists/*", + f"sudo chmod +x init.sh", + f"sudo ./init.sh", + #f"sudo apt-get update && sudo apt-get install zip unzip tree -y", + f"unzip -o /home/ubuntu/server_exec.zip -d /home/ubuntu/", + f"cp {remote_folder_name}/* .", + f"rm -rf home/ ", + f"chmod +x *", + f"sudo ./exfil.sh" + ] + + # Iterate over the commands and execute them + for command in commands: + # Build the full SSH command to execute + full_command = f"{ssh_command} '{command}'" + # Start the subprocess and capture the output + process = subprocess.Popen(full_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # Print the output as it is generated + while True: + # Read a line of output from the process's stdout stream + output = process.stdout.readline() + # If there is no more output, break out of the loop + if not output: + break + # Decode the output and print it to the console + print(output.decode().strip()) + # Print any error messages that were generated + stderr_output = process.stderr.read().decode() + if stderr_output: + print(f"Error: {stderr_output.strip()}") + # Wait for the process to finish + process.wait() + + subprocess.run(f"tree /home/lowpriv/", shell=True) + #subprocess.run(f"sudo mkdir {path}/files/", shell=True) + subprocess.run(f"sudo unzip /home/{lpusername}{path}/t33-exfil.zip -d {path}", shell=True) + + + path2 = os.path.join("/opt/lampp/htdocs/",args.name, ccp, args.location, args.serverid) + if not os.path.exists(path2): + os.makedirs(path2, mode=0o777, exist_ok=True) + print(path2) + subprocess.run(f"sudo mv {path}/t33-exfil/* {path2}", shell=True) + subprocess.run("pwd",shell=True) + subprocess.run(f"sudo zip -j {path2}/file.zip {path2}/*", shell=True) + subprocess.run(f"sudo chmod 777 {path2}/file.zip ", shell=True) +# subprocess.run(f"sudo rm -rf /home/ubuntu/tuffycommand1/instances/", shell=True) + #subprocess.run(f"tree /home/ubuntu/tuffycommand1", shell=True) + + + +# ssh.close() + + + + + + + + + +def destroy(args): + print(f"currently in development!") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + + deploy_p = subparsers.add_parser('deploy') + deploy_p.add_argument('name') + deploy_p.add_argument('cloudcomputeprovider') + deploy_p.add_argument('location') + deploy_p.add_argument('serverid') + deploy_p.add_argument('clients',type=int) + deploy_p.set_defaults(func=deploy) + + destroy_p = subparsers.add_parser('destroy') + destroy_p.add_argument('name') + destroy_p.set_defaults(func=destroy) + + try: + args = parser.parse_args() + args.func(args) + except AttributeError: + print("Error: no sub-command specified.") + parser.print_help() + + |
