diff --git a/Linode/c2.yml b/Linode/c2.yml index c63e091..7bbd2a2 100644 --- a/Linode/c2.yml +++ b/Linode/c2.yml @@ -77,7 +77,7 @@ name: "c2" groups: "c2servers" ansible_host: "{{ c2_ip }}" - ansible_user: "{{ ssh_user }}" + ansible_user: "root" # Hard-coded instead of using ssh_user ansible_ssh_private_key_file: "{{ ssh_key_path | replace('.pub', '') }}" ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" diff --git a/Linode/cleanup.yml b/Linode/cleanup.yml index 37460e7..2ea1b00 100644 --- a/Linode/cleanup.yml +++ b/Linode/cleanup.yml @@ -1,5 +1,5 @@ -# Linode/cleanup.yml --- +# Linode/cleanup.yml - name: Clean up Linode infrastructure hosts: localhost connection: local @@ -22,23 +22,52 @@ debug: msg: | =============================================== - CLEANUP CONFIRMATION REQUIRED + CLEANUP OPERATION =============================================== - The following resources will be PERMANENTLY DELETED: - {% if cleanup_redirector %} + The following resources will be DELETED PERMANENTLY: + {% if cleanup_redirector and redirector_name is defined %} - Redirector instance: {{ redirector_name }} {% endif %} - {% if cleanup_c2 %} + {% if cleanup_c2 and c2_name is defined %} - C2 instance: {{ c2_name }} {% endif %} when: confirm_cleanup | bool - - name: Confirm cleanup + - name: Confirm cleanup operation pause: - prompt: "Type 'yes' to confirm deletion or 'no' to abort" + prompt: "\n>>> Type 'yes' to confirm deletion or press Ctrl+C to abort <<<" register: confirmation when: confirm_cleanup | bool - - - name: Exit if not confirmed + + - name: Skip cleanup if not confirmed meta: end_play - when: confirm_cleanup | bool and confirmation.user_input != 'yes' \ No newline at end of file + when: confirm_cleanup | bool and (confirmation.user_input | default('')) != 'yes' + + - name: Delete redirector instance + community.general.linode_v4: + access_token: "{{ linode_token }}" + label: "{{ redirector_name }}" + state: absent + when: cleanup_redirector and redirector_name is defined and redirector_name != "" + register: redirector_deletion + ignore_errors: yes + + - name: Delete C2 instance + community.general.linode_v4: + access_token: "{{ linode_token }}" + label: "{{ c2_name }}" + state: absent + when: cleanup_c2 and c2_name is defined and c2_name != "" + register: c2_deletion + ignore_errors: yes + + - name: Report cleanup status + debug: + msg: | + Cleanup results: + {% if redirector_deletion is defined %} + - Redirector {{ redirector_name }}: {{ redirector_deletion.changed | ternary('Deleted', 'Not found/Could not delete') }} + {% endif %} + {% if c2_deletion is defined %} + - C2 {{ c2_name }}: {{ c2_deletion.changed | ternary('Deleted', 'Not found/Could not delete') }} + {% endif %} \ No newline at end of file diff --git a/deploy.py b/deploy.py index ff31c5a..8ae25be 100644 --- a/deploy.py +++ b/deploy.py @@ -565,63 +565,114 @@ def deploy_infrastructure(config): if not config.get('region'): config['region'] = select_random_region(config) - # Determine which components to deploy - success = True - - # Use the correct case for provider directory - provider_dir = provider.capitalize() if provider != "aws" else provider.upper() - - # Redirector deployment - if not config.get('c2_only'): - playbook = f"{provider_dir}/redirector.yml" - inventory_path = create_inventory_file(config, "local") + # Set different instance sizes for redirector vs. C2 + if provider == "linode": + # Store the original plan + original_plan = config.get('plan', 'g6-standard-2') - logging.info(f"Deploying redirector using {playbook}") - redirector_success, stdout, stderr = run_ansible_playbook( - playbook, inventory_path, config, config.get('debug', False) - ) - - # Log Ansible output - if config.get('debug', False): - logging.debug(f"Ansible stdout: {stdout}") - if stderr: - logging.debug(f"Ansible stderr: {stderr}") - else: - # Always log at least a summary even without debug mode - logging.info(f"Redirector deployment {'succeeded' if redirector_success else 'failed'}") - - if os.path.exists(inventory_path): - os.unlink(inventory_path) + # For redirector, use smaller instance size regardless of what was specified + if not config.get('c2_only'): + redirector_config = config.copy() + redirector_config['plan'] = 'g6-nanode-1' # Smallest viable Linode plan - if not redirector_success: - logging.error("Redirector deployment failed") - return False - - # C2 deployment - if not config.get('redirector_only'): - playbook = f"{provider_dir}/c2.yml" - inventory_path = create_inventory_file(config, "local") - - logging.info(f"Deploying C2 server using {playbook}") - c2_success, stdout, stderr = run_ansible_playbook( - playbook, inventory_path, config, config.get('debug', False) - ) - - # Log Ansible output - if config.get('debug', False): - logging.debug(f"Ansible stdout: {stdout}") - if stderr: - logging.debug(f"Ansible stderr: {stderr}") - else: - # Always log at least a summary even without debug mode - logging.info(f"C2 server deployment {'succeeded' if c2_success else 'failed'}") - - if os.path.exists(inventory_path): - os.unlink(inventory_path) + # Use the correct case for provider directory + provider_dir = "Linode" + playbook = f"{provider_dir}/redirector.yml" + inventory_path = create_inventory_file(redirector_config, "local") - if not c2_success: - logging.error("C2 server deployment failed") - return False + logging.info(f"Deploying redirector using {playbook} with plan: g6-nanode-1") + redirector_success, stdout, stderr = run_ansible_playbook( + playbook, inventory_path, redirector_config, redirector_config.get('debug', False) + ) + + # Log Ansible output + if redirector_config.get('debug', False): + logging.debug(f"Ansible stdout: {stdout}") + if stderr: + logging.debug(f"Ansible stderr: {stderr}") + + if os.path.exists(inventory_path): + os.unlink(inventory_path) + + if not redirector_success: + logging.error("Redirector deployment failed") + return False + + # For C2, use the original plan + if not config.get('redirector_only'): + # Restore original plan for C2 + config['plan'] = original_plan + + provider_dir = "Linode" + playbook = f"{provider_dir}/c2.yml" + inventory_path = create_inventory_file(config, "local") + + logging.info(f"Deploying C2 server using {playbook} with plan: {config['plan']}") + c2_success, stdout, stderr = run_ansible_playbook( + playbook, inventory_path, config, config.get('debug', False) + ) + + # Log Ansible output + if config.get('debug', False): + logging.debug(f"Ansible stdout: {stdout}") + if stderr: + logging.debug(f"Ansible stderr: {stderr}") + + if os.path.exists(inventory_path): + os.unlink(inventory_path) + + if not c2_success: + logging.error("C2 server deployment failed") + return False + else: + # For AWS and other providers, follow the same pattern but with their directory names + provider_dir = "AWS" if provider == "aws" else provider.capitalize() + + # Redirector deployment + if not config.get('c2_only'): + playbook = f"{provider_dir}/redirector.yml" + inventory_path = create_inventory_file(config, "local") + + logging.info(f"Deploying redirector using {playbook}") + redirector_success, stdout, stderr = run_ansible_playbook( + playbook, inventory_path, config, config.get('debug', False) + ) + + # Log Ansible output + if config.get('debug', False): + logging.debug(f"Ansible stdout: {stdout}") + if stderr: + logging.debug(f"Ansible stderr: {stderr}") + + if os.path.exists(inventory_path): + os.unlink(inventory_path) + + if not redirector_success: + logging.error("Redirector deployment failed") + return False + + # C2 deployment + if not config.get('redirector_only'): + playbook = f"{provider_dir}/c2.yml" + inventory_path = create_inventory_file(config, "local") + + logging.info(f"Deploying C2 server using {playbook}") + c2_success, stdout, stderr = run_ansible_playbook( + playbook, inventory_path, config, config.get('debug', False) + ) + + # Log Ansible output + if config.get('debug', False): + logging.debug(f"Ansible stdout: {stdout}") + if stderr: + logging.debug(f"Ansible stderr: {stderr}") + + if os.path.exists(inventory_path): + os.unlink(inventory_path) + + if not c2_success: + logging.error("C2 server deployment failed") + return False return True @@ -815,15 +866,39 @@ def cleanup_resources(config): logging.info(f"Cleaning up {provider} resources...") # Use the correct case for provider directory - provider_dir = provider.capitalize() if provider != "aws" else provider.upper() + provider_dir = "AWS" if provider == "aws" else provider.capitalize() + + # Use Ansible for cleanup with confirmation set to false + extra_vars = { + "confirm_cleanup": False, # Skip confirmation prompt + "redirector_name": config.get('redirector_name'), + "c2_name": config.get('c2_name'), + "cleanup_redirector": True, + "cleanup_c2": True + } - # Use Ansible for cleanup playbook = f"{provider_dir}/cleanup.yml" if os.path.exists(playbook): logging.info(f"Running cleanup playbook: {playbook}") inventory_path = create_inventory_file(config, "local") + + # Add extra vars to config for cleanup + cleanup_config = config.copy() + cleanup_config.update(extra_vars) + try: - run_ansible_playbook(playbook, inventory_path, config) + success, stdout, stderr = run_ansible_playbook( + playbook, inventory_path, cleanup_config, + cleanup_config.get('debug', False) + ) + + if not success: + logging.error(f"Cleanup playbook failed: {stderr}") + + # Log what we attempted to clean up + logging.error(f"Failed to clean up resources: redirector={config.get('redirector_name')}, c2={config.get('c2_name')}") + else: + logging.info("Cleanup completed successfully") except Exception as e: logging.error(f"Cleanup playbook failed: {e}") finally: