working on it
This commit is contained in:
+2
-1
@@ -3,4 +3,5 @@ venv
|
|||||||
deployment*
|
deployment*
|
||||||
config.yml
|
config.yml
|
||||||
logs/
|
logs/
|
||||||
domainhunter/
|
domainhunter/
|
||||||
|
infrastructure_state_*.json
|
||||||
+27
-8
@@ -9,7 +9,7 @@
|
|||||||
- vars.yaml
|
- vars.yaml
|
||||||
vars:
|
vars:
|
||||||
# Default values
|
# Default values
|
||||||
ssh_user: "{{ ssh_user | default('root') }}"
|
ssh_user: "{{ ssh_user | default('kali') }}"
|
||||||
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
|
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
|
||||||
instance_type: "{{ aws_instance_type | default('t2.medium') }}"
|
instance_type: "{{ aws_instance_type | default('t2.medium') }}"
|
||||||
deployment_id: "{{ deployment_id | default('') }}"
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
# Check for shared infrastructure
|
# Check for shared infrastructure
|
||||||
# Only use shared when C2 and redirector are in the same region
|
# Only use shared when C2 and redirector are in the same region
|
||||||
use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}"
|
use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}"
|
||||||
|
# AMI map comes from vars.yaml - add fallback for safety
|
||||||
|
kali_ami_map_fallback:
|
||||||
|
us-east-1: "ami-061b17d332829ab1c"
|
||||||
|
us-east-2: "ami-061b17d332829ab1c" # Fallback to us-east-1 AMI
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Validate AWS credentials
|
- name: Validate AWS credentials
|
||||||
@@ -29,13 +33,13 @@
|
|||||||
# Load shared infrastructure state if available
|
# Load shared infrastructure state if available
|
||||||
- name: Check for shared infrastructure state
|
- name: Check for shared infrastructure state
|
||||||
stat:
|
stat:
|
||||||
path: "infrastructure_state.json"
|
path: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
register: infra_state_file
|
register: infra_state_file
|
||||||
when: use_shared_infra | bool
|
when: use_shared_infra | bool
|
||||||
|
|
||||||
- name: Load shared infrastructure state
|
- name: Load shared infrastructure state
|
||||||
include_vars:
|
include_vars:
|
||||||
file: "infrastructure_state.json"
|
file: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
name: shared_infra
|
name: shared_infra
|
||||||
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
|
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
|
||||||
|
|
||||||
@@ -48,16 +52,31 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
aws_c2_region: "{{ c2_region | default(aws_region) }}"
|
aws_c2_region: "{{ c2_region | default(aws_region) }}"
|
||||||
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
|
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
|
||||||
|
|
||||||
- name: Set AMI ID for selected region
|
- name: Check if ami_map is provided in vars.yaml
|
||||||
|
debug:
|
||||||
|
msg: "ami_map is {{ 'defined' if ami_map is defined else 'NOT defined' }} in vars.yaml"
|
||||||
|
|
||||||
|
- name: Set AMI ID for selected region (from vars.yaml)
|
||||||
set_fact:
|
set_fact:
|
||||||
ami_id: "{{ ami_map[aws_c2_region] }}"
|
ami_id: "{{ ami_map[aws_c2_region] | default(ami_map.us-east-1) }}"
|
||||||
when: ami_map is defined and aws_c2_region in ami_map
|
when: ami_map is defined and ami_map
|
||||||
|
|
||||||
|
- name: Set AMI ID for selected region (fallback)
|
||||||
|
set_fact:
|
||||||
|
ami_id: "{{ kali_ami_map_fallback[aws_c2_region] | default(kali_ami_map_fallback['us-east-1']) }}"
|
||||||
|
when: ami_id is not defined or ami_id == ""
|
||||||
|
|
||||||
|
- name: Ensure we have a valid AMI ID
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ami_id is defined and ami_id != ""
|
||||||
|
fail_msg: "Could not determine a valid AMI ID for region {{ aws_c2_region }}. Please add it to ami_map in vars.yaml."
|
||||||
|
|
||||||
# Add AMI username mapping - improved with better detection
|
# Add AMI username mapping - improved with better detection
|
||||||
- name: Determine correct SSH user for the AMI
|
- name: Determine correct SSH user for the AMI
|
||||||
set_fact:
|
set_fact:
|
||||||
ami_ssh_user: "{{ 'root' if (ami_id is defined and ami_id is search('-root-')) or (ami_id is defined and ami_id == 'ami-061b17d332829ab1c') else 'ubuntu' }}"
|
ami_ssh_user: "{{ 'kali' if (ami_id is defined and ami_id is search('-kali-')) or (ami_id is defined and ami_id == 'ami-061b17d332829ab1c') else 'ubuntu' }}"
|
||||||
|
|
||||||
- name: Display AMI and user information for debugging
|
- name: Display AMI and user information for debugging
|
||||||
debug:
|
debug:
|
||||||
|
|||||||
+419
-295
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
# AWS Cleanup Playbook
|
# AWS Cleanup Playbook - Comprehensive version with robust VPC removal
|
||||||
|
|
||||||
- name: Clean up AWS resources
|
- name: Clean up AWS resources
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
@@ -8,348 +7,473 @@
|
|||||||
vars_files:
|
vars_files:
|
||||||
- vars.yaml
|
- vars.yaml
|
||||||
vars:
|
vars:
|
||||||
delete_results: {}
|
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
|
||||||
vpc_cleanup_list: []
|
confirm_cleanup: "{{ confirm_cleanup | default(true) }}"
|
||||||
aws_detailed_logging: true
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
|
redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}"
|
||||||
|
c2_name: "{{ c2_name | default('s-' + deployment_id) }}"
|
||||||
|
tracker_name: "{{ tracker_name | default('t-' + deployment_id) }}"
|
||||||
|
cleanup_summary: {}
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# Confirmation prompts
|
# Confirmation step (if enabled)
|
||||||
- name: Confirm cleanup
|
- name: Confirm cleanup
|
||||||
pause:
|
pause:
|
||||||
prompt: "This will delete all AWS resources for deployment ID {{ deployment_id }}. Continue? (yes/no)"
|
prompt: "Are you sure you want to delete all AWS resources for deployment ID {{ deployment_id }}? This action cannot be undone. Type 'yes' to confirm"
|
||||||
register: confirm_deletion
|
register: cleanup_confirmation
|
||||||
when: confirm_cleanup | default(true) | bool
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
- name: Check confirmation
|
- name: Check confirmation
|
||||||
assert:
|
assert:
|
||||||
that: confirm_deletion.user_input | default('yes') | lower == 'yes'
|
that:
|
||||||
|
- cleanup_confirmation.user_input | default('yes') == 'yes'
|
||||||
fail_msg: "Cleanup cancelled by user"
|
fail_msg: "Cleanup cancelled by user"
|
||||||
when: confirm_cleanup | default(true) | bool
|
when: confirm_cleanup | bool
|
||||||
|
|
||||||
# Display AWS region being used for cleanup
|
# STEP 1: Find all instances by deployment ID
|
||||||
- name: Display AWS region being used for cleanup
|
- name: Find all EC2 instances for this deployment
|
||||||
debug:
|
amazon.aws.ec2_instance_info:
|
||||||
msg: "Cleaning up resources in region: {{ aws_region }}"
|
|
||||||
when: aws_detailed_logging | bool
|
|
||||||
|
|
||||||
# Check for and load shared infrastructure file
|
|
||||||
- name: Check for shared infrastructure state
|
|
||||||
stat:
|
|
||||||
path: "infrastructure_state.json"
|
|
||||||
register: infra_state_file
|
|
||||||
|
|
||||||
- name: Load shared infrastructure state
|
|
||||||
include_vars:
|
|
||||||
file: "infrastructure_state.json"
|
|
||||||
name: shared_infra
|
|
||||||
when: infra_state_file.stat.exists | default(false)
|
|
||||||
|
|
||||||
# Initialize cleaned resources tracking
|
|
||||||
- name: Initialize cleaned resources tracking
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources:
|
|
||||||
instances: []
|
|
||||||
key_pairs: []
|
|
||||||
security_groups: []
|
|
||||||
network_interfaces: []
|
|
||||||
route_tables: []
|
|
||||||
subnets: []
|
|
||||||
internet_gateways: []
|
|
||||||
vpcs: []
|
|
||||||
|
|
||||||
# EC2 Instance cleanup
|
|
||||||
- name: Terminate C2 instances
|
|
||||||
amazon.aws.ec2_instance:
|
|
||||||
state: absent
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
filters:
|
filters:
|
||||||
"tag:Name": "{{ c2_name }}"
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
register: c2_instances_result
|
register: deployment_instances
|
||||||
when: cleanup_c2 | default(true) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned instances list for C2
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + c2_instances_result.instance_ids}, recursive=true) }}"
|
|
||||||
when: cleanup_c2 | default(true) | bool and c2_instances_result.instance_ids is defined
|
|
||||||
|
|
||||||
- name: Terminate redirector instances
|
- name: Set fact for instances found
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({'instances_found': deployment_instances.instances | length}) }}"
|
||||||
|
|
||||||
|
# STEP 2: Terminate all instances with proper tagging
|
||||||
|
- name: Terminate all instances for this deployment
|
||||||
amazon.aws.ec2_instance:
|
amazon.aws.ec2_instance:
|
||||||
state: absent
|
instance_ids: "{{ item.instance_id }}"
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
filters:
|
|
||||||
"tag:Name": "{{ redirector_name }}"
|
|
||||||
register: redirector_instances_result
|
|
||||||
when: cleanup_redirector | default(true) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned instances list for redirector
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + redirector_instances_result.instance_ids}, recursive=true) }}"
|
|
||||||
when: cleanup_redirector | default(true) | bool and redirector_instances_result.instance_ids is defined
|
|
||||||
|
|
||||||
- name: Terminate tracker instances
|
|
||||||
amazon.aws.ec2_instance:
|
|
||||||
state: absent
|
state: absent
|
||||||
region: "{{ aws_region }}"
|
loop: "{{ deployment_instances.instances }}"
|
||||||
filters:
|
register: terminated_instances
|
||||||
"tag:Name": "{{ tracker_name | default('t-' + deployment_id) }}"
|
when: deployment_instances.instances | length > 0
|
||||||
register: tracker_instances_result
|
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned instances list for tracker
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + tracker_instances_result.instance_ids}, recursive=true) }}"
|
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_instances_result.instance_ids is defined
|
|
||||||
|
|
||||||
# Wait for all instances to terminate before attempting to clean up dependent resources
|
- name: Wait for instances to be terminated
|
||||||
- name: Wait for instances to terminate
|
|
||||||
pause:
|
pause:
|
||||||
seconds: 30
|
seconds: 30
|
||||||
when: (cleanup_c2 | default(true) | bool and c2_instances_result.changed | default(false)) or
|
when: deployment_instances.instances | length > 0
|
||||||
(cleanup_redirector | default(true) | bool and redirector_instances_result.changed | default(false)) or
|
|
||||||
(cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_instances_result.changed | default(false))
|
# STEP 3: Find all security groups by deployment ID
|
||||||
|
- name: Find all security groups for this deployment
|
||||||
# List all key pairs to handle different naming patterns
|
amazon.aws.ec2_security_group_info:
|
||||||
- name: List available EC2 key pairs
|
|
||||||
amazon.aws.ec2_key_info:
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
register: all_key_pairs
|
filters:
|
||||||
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
|
register: deployment_sgs
|
||||||
|
|
||||||
# Delete C2 deployment key with deployment_id pattern
|
# Also find SGs by name pattern
|
||||||
- name: Delete C2 deployment key (deployment_id pattern)
|
- name: Find security groups by name pattern
|
||||||
amazon.aws.ec2_key:
|
amazon.aws.ec2_security_group_info:
|
||||||
name: "c2deploy_{{ deployment_id }}"
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
state: absent
|
register: all_sgs
|
||||||
register: c2_deploy_key_result
|
|
||||||
when: cleanup_c2 | default(true) | bool
|
- name: Filter SGs by name pattern
|
||||||
|
|
||||||
# Delete C2 EC2 key pair (original pattern)
|
|
||||||
- name: Delete C2 EC2 key pair (original pattern)
|
|
||||||
amazon.aws.ec2_key:
|
|
||||||
name: "{{ c2_name }}"
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
state: absent
|
|
||||||
register: c2_key_result
|
|
||||||
when: cleanup_c2 | default(true) | bool
|
|
||||||
|
|
||||||
# Update cleaned key pairs list for C2
|
|
||||||
- name: Update cleaned key pairs list for C2
|
|
||||||
set_fact:
|
set_fact:
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [item]}, recursive=true) }}"
|
named_sgs: "{{ all_sgs.security_groups | selectattr('group_name', 'search', redirector_name + '-sg|' + c2_name + '-sg') | list }}"
|
||||||
with_items:
|
|
||||||
- "c2deploy_{{ deployment_id }}"
|
|
||||||
- "{{ c2_name }}"
|
|
||||||
when: cleanup_c2 | default(true) | bool and (c2_key_result.changed or c2_deploy_key_result.changed)
|
|
||||||
|
|
||||||
# Delete redirector EC2 key pair
|
- name: Combine all security groups to delete
|
||||||
- name: Delete redirector EC2 key pair
|
|
||||||
amazon.aws.ec2_key:
|
|
||||||
name: "{{ redirector_name }}"
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
state: absent
|
|
||||||
register: redirector_key_result
|
|
||||||
when: cleanup_redirector | default(true) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned key pairs list for redirector
|
|
||||||
set_fact:
|
set_fact:
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [redirector_name]}, recursive=true) }}"
|
all_sgs_to_delete: "{{ deployment_sgs.security_groups + named_sgs }}"
|
||||||
when: cleanup_redirector | default(true) | bool and redirector_key_result.changed | default(false)
|
cleanup_summary: "{{ cleanup_summary | combine({'security_groups_found': (deployment_sgs.security_groups + named_sgs) | length}) }}"
|
||||||
|
|
||||||
- name: Delete tracker EC2 key pair
|
# STEP 4: Delete all security groups
|
||||||
amazon.aws.ec2_key:
|
- name: Delete security groups
|
||||||
name: "{{ tracker_name | default('t-' + deployment_id) }}"
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
state: absent
|
|
||||||
register: tracker_key_result
|
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned key pairs list for tracker
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [tracker_name | default('t-' + deployment_id)]}, recursive=true) }}"
|
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_key_result.changed | default(false)
|
|
||||||
|
|
||||||
# Security group cleanup
|
|
||||||
- name: Delete C2 security group
|
|
||||||
amazon.aws.ec2_security_group:
|
amazon.aws.ec2_security_group:
|
||||||
name: "{{ c2_name }}-sg"
|
group_id: "{{ item.group_id }}"
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
state: absent
|
state: absent
|
||||||
register: c2_sg_result
|
loop: "{{ all_sgs_to_delete }}"
|
||||||
|
when: all_sgs_to_delete | length > 0
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
when: cleanup_c2 | default(true) | bool
|
register: deleted_sgs
|
||||||
|
|
||||||
- name: Update cleaned security groups list for C2
|
# STEP 5: Find and delete all ENIs
|
||||||
set_fact:
|
- name: Find network interfaces by tag
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [c2_sg_result.group_id | default('')]}, recursive=true) }}"
|
amazon.aws.ec2_eni_info:
|
||||||
when: cleanup_c2 | default(true) | bool and c2_sg_result.changed | default(false) and c2_sg_result.group_id is defined
|
|
||||||
|
|
||||||
- name: Delete redirector security group
|
|
||||||
amazon.aws.ec2_security_group:
|
|
||||||
name: "{{ redirector_name }}-sg"
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
state: absent
|
filters:
|
||||||
register: redirector_sg_result
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
ignore_errors: yes
|
register: deployment_enis
|
||||||
when: cleanup_redirector | default(true) | bool
|
|
||||||
|
|
||||||
- name: Update cleaned security groups list for redirector
|
- name: Delete ENIs
|
||||||
set_fact:
|
amazon.aws.ec2_eni:
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [redirector_sg_result.group_id | default('')]}, recursive=true) }}"
|
|
||||||
when: cleanup_redirector | default(true) | bool and redirector_sg_result.changed | default(false) and redirector_sg_result.group_id is defined
|
|
||||||
|
|
||||||
- name: Delete tracker security group
|
|
||||||
amazon.aws.ec2_security_group:
|
|
||||||
name: "{{ tracker_name | default('t-' + deployment_id) }}-sg"
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
|
eni_id: "{{ item.id }}"
|
||||||
state: absent
|
state: absent
|
||||||
register: tracker_sg_result
|
force_detach: true
|
||||||
|
loop: "{{ deployment_enis.network_interfaces }}"
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool
|
register: deleted_enis
|
||||||
|
when: deployment_enis.network_interfaces | length > 0
|
||||||
|
|
||||||
- name: Update cleaned security groups list for tracker
|
- name: Set ENIs count in summary
|
||||||
set_fact:
|
set_fact:
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [tracker_sg_result.group_id | default('')]}, recursive=true) }}"
|
cleanup_summary: "{{ cleanup_summary | combine({'enis_found': deployment_enis.network_interfaces | length}) }}"
|
||||||
when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_sg_result.changed | default(false) and tracker_sg_result.group_id is defined
|
|
||||||
|
# STEP 6: Find all VPCs by deployment ID
|
||||||
# Identify VPCs to clean up (by tag and by name pattern)
|
- name: Find all VPCs for this deployment
|
||||||
- name: Get VPCs by deployment tag
|
|
||||||
amazon.aws.ec2_vpc_net_info:
|
amazon.aws.ec2_vpc_net_info:
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
filters:
|
filters:
|
||||||
"tag:deployment_id": "{{ deployment_id }}"
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
register: tagged_vpcs
|
register: deployment_vpcs
|
||||||
|
|
||||||
- name: Add tagged VPCs to cleanup list
|
# STEP 7: Find VPCs by name pattern as fallback
|
||||||
set_fact:
|
- name: Find all VPCs by name pattern
|
||||||
vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}"
|
|
||||||
with_items: "{{ tagged_vpcs.vpcs }}"
|
|
||||||
when: tagged_vpcs.vpcs | length > 0
|
|
||||||
|
|
||||||
# Find VPCs by name pattern
|
|
||||||
- name: Find VPCs by naming pattern for C2
|
|
||||||
amazon.aws.ec2_vpc_net_info:
|
amazon.aws.ec2_vpc_net_info:
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
filters:
|
register: all_vpcs
|
||||||
"tag:Name": "{{ c2_name }}-vpc"
|
|
||||||
register: c2_named_vpcs
|
- name: Filter VPCs by name pattern
|
||||||
when: cleanup_c2 | default(true) | bool
|
|
||||||
|
|
||||||
- name: Add C2-named VPCs to cleanup list
|
|
||||||
set_fact:
|
set_fact:
|
||||||
vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}"
|
named_vpcs: "{{ all_vpcs.vpcs | selectattr('tags', 'defined') | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'search', redirector_name + '-vpc|' + c2_name + '-vpc') | list }}"
|
||||||
with_items: "{{ c2_named_vpcs.vpcs }}"
|
|
||||||
when: cleanup_c2 | default(true) | bool and c2_named_vpcs.vpcs | length > 0
|
- name: Combine all VPCs to delete
|
||||||
|
set_fact:
|
||||||
- name: Find VPCs by naming pattern for redirector
|
all_vpcs_to_delete: "{{ deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id') }}"
|
||||||
amazon.aws.ec2_vpc_net_info:
|
cleanup_summary: "{{ cleanup_summary | combine({'vpcs_found': (deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id')) | length}) }}"
|
||||||
|
|
||||||
|
# STEP 8: Find and delete NAT Gateways for each VPC separately
|
||||||
|
- name: Find NAT gateways in each VPC
|
||||||
|
amazon.aws.ec2_vpc_nat_gateway_info:
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
filters:
|
filters:
|
||||||
"tag:Name": "{{ redirector_name }}-vpc"
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
register: redirector_named_vpcs
|
register: natgw_results
|
||||||
when: cleanup_redirector | default(true) | bool
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
- name: Add redirector-named VPCs to cleanup list
|
- name: Delete NAT gateways
|
||||||
set_fact:
|
amazon.aws.ec2_vpc_nat_gateway:
|
||||||
vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}"
|
region: "{{ aws_region }}"
|
||||||
with_items: "{{ redirector_named_vpcs.vpcs }}"
|
nat_gateway_id: "{{ item.1.nat_gateway_id }}"
|
||||||
when: cleanup_redirector | default(true) | bool and redirector_named_vpcs.vpcs | length > 0
|
|
||||||
|
|
||||||
# Handle shared infrastructure
|
|
||||||
- name: Add shared VPC to cleanup if both C2 and redirector being cleaned
|
|
||||||
set_fact:
|
|
||||||
vpc_cleanup_list: "{{ vpc_cleanup_list + [shared_infra.vpc_id] }}"
|
|
||||||
when: >
|
|
||||||
infra_state_file.stat.exists | default(false) and
|
|
||||||
shared_infra.vpc_id is defined and
|
|
||||||
cleanup_c2 | default(true) | bool and
|
|
||||||
cleanup_redirector | default(true) | bool
|
|
||||||
|
|
||||||
# Make the VPC cleanup list unique
|
|
||||||
- name: Deduplicate VPC cleanup list
|
|
||||||
set_fact:
|
|
||||||
vpc_cleanup_list: "{{ vpc_cleanup_list | unique }}"
|
|
||||||
when: vpc_cleanup_list | length > 0
|
|
||||||
|
|
||||||
# Display VPCs to be cleaned up
|
|
||||||
- name: Display VPCs to be cleaned
|
|
||||||
debug:
|
|
||||||
msg: "VPCs to be cleaned: {{ vpc_cleanup_list }}"
|
|
||||||
when: aws_detailed_logging | bool and vpc_cleanup_list | length > 0
|
|
||||||
|
|
||||||
# Process each VPC
|
|
||||||
- name: Process VPCs for cleanup
|
|
||||||
block:
|
|
||||||
- name: Process each VPC
|
|
||||||
include_tasks: "process_vpc.yml"
|
|
||||||
vars:
|
|
||||||
vpc_id: "{{ item }}"
|
|
||||||
with_items: "{{ vpc_cleanup_list | unique }}"
|
|
||||||
when: vpc_cleanup_list | length > 0
|
|
||||||
|
|
||||||
# Clean up infrastructure state file if both C2 and redirector are being cleaned
|
|
||||||
- name: Remove infrastructure state file if cleaning up shared infrastructure
|
|
||||||
file:
|
|
||||||
path: "infrastructure_state.json"
|
|
||||||
state: absent
|
state: absent
|
||||||
when: >
|
release_eip: true
|
||||||
infra_state_file.stat.exists | default(false) and
|
loop: "{{ natgw_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('nat_gateways', 'defined') | subelements('nat_gateways') }}"
|
||||||
((cleanup_c2 | default(true) | bool and cleanup_redirector | default(true) | bool) or
|
ignore_errors: yes
|
||||||
(cleanup_c2 | default(true) | bool and not cleanup_redirector | default(true) | bool and
|
register: deleted_natgws
|
||||||
c2_region | default(aws_region) == shared_infra.region) or
|
when: natgw_results.results is defined
|
||||||
(cleanup_redirector | default(true) | bool and not cleanup_c2 | default(true) | bool and
|
|
||||||
redirector_region | default(aws_region) == shared_infra.region))
|
- name: Wait after NAT deletion
|
||||||
|
pause:
|
||||||
|
seconds: 15
|
||||||
|
when: deleted_natgws.results is defined and deleted_natgws.results | length > 0
|
||||||
|
|
||||||
|
# STEP 9: Find and delete Internet Gateways
|
||||||
|
- name: Find internet gateways for each VPC
|
||||||
|
amazon.aws.ec2_vpc_igw_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
attachment.vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: igw_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
# Create summary of deleted resources
|
- name: Detach and delete internet gateways
|
||||||
- name: Collect all deleted resources
|
amazon.aws.ec2_vpc_igw:
|
||||||
|
internet_gateway_id: "{{ item.1.internet_gateway_id }}"
|
||||||
|
state: absent
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
loop: "{{ igw_results.results | default([]) | subelements('internet_gateways') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_igws
|
||||||
|
|
||||||
|
- name: Wait after IGW deletion
|
||||||
|
pause:
|
||||||
|
seconds: 15
|
||||||
|
when: deleted_igws.results is defined and deleted_igws.results | length > 0
|
||||||
|
|
||||||
|
# STEP 10: Find and delete Route Tables
|
||||||
|
- name: Find route tables for each VPC
|
||||||
|
amazon.aws.ec2_vpc_route_table_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: rtb_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Delete non-main route tables
|
||||||
|
amazon.aws.ec2_vpc_route_table:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
route_table_id: "{{ item.1.id }}"
|
||||||
|
lookup: id
|
||||||
|
state: absent
|
||||||
|
loop: "{{ rtb_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('route_tables', 'defined') | subelements('route_tables') }}"
|
||||||
|
when: not item.1.associations[0].main | default(false)
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_rtbs
|
||||||
|
|
||||||
|
# Add this after your existing route table deletion
|
||||||
|
- name: Delete main route tables with AWS CLI
|
||||||
|
shell: |
|
||||||
|
for rtb in $(aws ec2 describe-route-tables --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --query 'RouteTables[?Associations[?Main==`true`]].RouteTableId' --output text); do
|
||||||
|
aws ec2 delete-route --route-table-id $rtb --destination-cidr-block 0.0.0.0/0 --region {{ aws_region }} || true
|
||||||
|
done
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# STEP 11: Find and delete Subnets
|
||||||
|
- name: Find subnets for each VPC
|
||||||
|
amazon.aws.ec2_vpc_subnet_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
register: subnet_results
|
||||||
|
|
||||||
|
- name: Delete subnets
|
||||||
|
amazon.aws.ec2_vpc_subnet:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_id: "{{ item.1.vpc_id }}"
|
||||||
|
cidr: "{{ item.1.cidr_block }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ subnet_results.results | default([]) | subelements('subnets') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_subnets
|
||||||
|
when: subnet_results.results is defined
|
||||||
|
|
||||||
|
# STEP 12: Find and delete VPC Endpoints
|
||||||
|
- name: Find VPC endpoints for each VPC
|
||||||
|
amazon.aws.ec2_vpc_endpoint_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
filters:
|
||||||
|
vpc-id: "{{ item.vpc_id }}"
|
||||||
|
register: endpoint_results
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Delete VPC endpoints
|
||||||
|
amazon.aws.ec2_vpc_endpoint:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_endpoint_id: "{{ item.1.vpc_endpoint_id }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ endpoint_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('vpc_endpoints', 'defined') | subelements('vpc_endpoints') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_endpoints
|
||||||
|
when: endpoint_results.results is defined
|
||||||
|
|
||||||
|
# Add before STEP 13
|
||||||
|
- name: Check for remaining VPC dependencies
|
||||||
|
shell: |
|
||||||
|
aws ec2 describe-network-interfaces --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --output json
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
register: remaining_deps
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
- name: Display any remaining dependencies
|
||||||
|
debug:
|
||||||
|
msg: "VPC {{ item.item.vpc_id }} still has dependencies that need to be removed"
|
||||||
|
loop: "{{ remaining_deps.results }}"
|
||||||
|
when: item.stdout | from_json | json_query('NetworkInterfaces') | length > 0
|
||||||
|
|
||||||
|
# Add this before the force delete of network interfaces
|
||||||
|
- name: Detach remaining network interfaces
|
||||||
|
shell: |
|
||||||
|
aws ec2 detach-network-interface --attachment-id $(aws ec2 describe-network-interfaces --network-interface-ids {{ item.1 }} --query 'NetworkInterfaces[0].Attachment.AttachmentId' --output text) --region {{ aws_region }} --force
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') |
|
||||||
|
map('attr', 'stdout') | map('from_json') |
|
||||||
|
map('json_query', 'NetworkInterfaces[?Status==`in-use`].NetworkInterfaceId') |
|
||||||
|
zip(remaining_deps.results | map('attr', 'item')) | list }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: item.0 | length > 0
|
||||||
|
|
||||||
|
- name: Force delete any remaining network interfaces
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-network-interface --network-interface-id {{ item.1 }} --region {{ aws_region }}
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') |
|
||||||
|
map('attr', 'stdout') | map('from_json') |
|
||||||
|
map('json_query', 'NetworkInterfaces[].NetworkInterfaceId') |
|
||||||
|
zip(remaining_deps.results | map('attr', 'item')) | list }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: item.0 | length > 0
|
||||||
|
|
||||||
|
# STEP 13: Final VPC deletion with multiple retries
|
||||||
|
- name: Wait for all dependencies to clear
|
||||||
|
pause:
|
||||||
|
seconds: 20
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# First attempt with normal module - with error display
|
||||||
|
- name: Delete all VPCs (first attempt)
|
||||||
|
amazon.aws.ec2_vpc_net:
|
||||||
|
vpc_id: "{{ item.vpc_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ all_vpcs_to_delete }}"
|
||||||
|
register: vpc_deletion
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display VPC deletion errors
|
||||||
|
debug:
|
||||||
|
msg: "Failed to delete VPC {{ item.item.vpc_id }}: {{ item.msg }}"
|
||||||
|
loop: "{{ vpc_deletion.results | default([]) }}"
|
||||||
|
when: item.failed is defined and item.failed
|
||||||
|
|
||||||
|
# Direct API call for any VPCs that failed
|
||||||
|
- name: Find which VPCs still exist
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
vpc_ids: "{{ all_vpcs_to_delete | map(attribute='vpc_id') | list }}"
|
||||||
|
register: remaining_vpcs
|
||||||
|
when: all_vpcs_to_delete | length > 0
|
||||||
|
|
||||||
|
# Forcibly delete with direct AWS CLI command
|
||||||
|
- name: Force delete remaining VPCs with CLI
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }}
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_vpcs.vpcs }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0
|
||||||
|
register: force_vpc_delete
|
||||||
|
|
||||||
|
# Add after the VPC deletion attempts - more aggressive approach
|
||||||
|
- name: Force delete remaining VPCs with AWS CLI and debug output
|
||||||
|
shell: |
|
||||||
|
aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }} 2>&1 || echo "Failed with: $?"
|
||||||
|
environment:
|
||||||
|
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
|
||||||
|
loop: "{{ remaining_vpcs.vpcs }}"
|
||||||
|
register: force_vpc_delete_debug
|
||||||
|
when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0
|
||||||
|
|
||||||
|
- name: Display debug output from force delete
|
||||||
|
debug:
|
||||||
|
msg: "{{ item.stdout }}"
|
||||||
|
loop: "{{ force_vpc_delete_debug.results | default([]) }}"
|
||||||
|
when: item.stdout is defined and item.stdout | trim != ""
|
||||||
|
|
||||||
|
# Track deleted VPCs in summary
|
||||||
|
- name: Set VPC deletion results in summary
|
||||||
set_fact:
|
set_fact:
|
||||||
resource_summary:
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
ec2_instances:
|
'vpcs_deleted': ((vpc_deletion.results | default([]) | selectattr('failed', 'undefined') | list | length) + (force_vpc_delete.results | default([]) | selectattr('failed', 'undefined') | list | length))}) }}"
|
||||||
c2: "{{ c2_instances_result.instance_ids | default([]) }}"
|
when: all_vpcs_to_delete | length > 0
|
||||||
redirector: "{{ redirector_instances_result.instance_ids | default([]) }}"
|
|
||||||
tracker: "{{ tracker_instances_result.instance_ids | default([]) }}"
|
# Add these tasks to confirm VPC deletion
|
||||||
key_pairs:
|
- name: Verify VPC deletion
|
||||||
c2: "{{ cleaned_resources.key_pairs | default([]) | select('search', 'c2deploy_' + deployment_id) | list + cleaned_resources.key_pairs | default([]) | select('search', c2_name) | list }}"
|
amazon.aws.ec2_vpc_net_info:
|
||||||
redirector: "{{ redirector_key_result.key.name | default('') | ternary([redirector_key_result.key.name], []) }}"
|
region: "{{ aws_region }}"
|
||||||
tracker: "{{ tracker_key_result.key.name | default('') | ternary([tracker_key_result.key.name], []) }}"
|
filters:
|
||||||
security_groups:
|
"tag:deployment_id": "{{ deployment_id }}"
|
||||||
c2: "{{ c2_sg_result.group_id | default('') | ternary([c2_sg_result.group_id], []) }}"
|
register: vpc_check
|
||||||
redirector: "{{ redirector_sg_result.group_id | default('') | ternary([redirector_sg_result.group_id], []) }}"
|
|
||||||
tracker: "{{ tracker_sg_result.group_id | default('') | ternary([tracker_sg_result.group_id], []) }}"
|
|
||||||
vpc_resources:
|
|
||||||
route_tables: "{{ cleaned_resources.route_tables | default([]) }}"
|
|
||||||
internet_gateways: "{{ cleaned_resources.internet_gateways | default([]) }}"
|
|
||||||
subnets: "{{ cleaned_resources.subnets | default([]) }}"
|
|
||||||
network_interfaces: "{{ cleaned_resources.network_interfaces | default([]) }}"
|
|
||||||
vpcs: "{{ cleaned_resources.vpcs | default([]) }}"
|
|
||||||
when: not disable_summary | default(false)
|
|
||||||
|
|
||||||
# Display summary of deleted resources
|
|
||||||
- name: Display cleanup summary
|
- name: Display cleanup summary
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Cleanup Summary:"
|
||||||
|
- "Redirector instance deleted: {{ redirector_deleted | default('N/A') }}"
|
||||||
|
- "C2 instance deleted: {{ c2_deleted | default('N/A') }}"
|
||||||
|
- "VPC resources deleted: {{ vpc_check.vpcs | length == 0 }}"
|
||||||
|
when: not disable_summary | default(false)
|
||||||
|
|
||||||
|
# STEP 14: Delete key pairs
|
||||||
|
- name: Find key pairs by name patterns
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "{{ item }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: present
|
||||||
|
register: keys_check
|
||||||
|
ignore_errors: yes
|
||||||
|
with_items:
|
||||||
|
- "{{ redirector_name }}"
|
||||||
|
- "{{ c2_name }}"
|
||||||
|
- "{{ tracker_name }}"
|
||||||
|
|
||||||
|
- name: Delete key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "{{ item.invocation.module_args.name }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ keys_check.results }}"
|
||||||
|
when: keys_check.results | length > 0 and item.failed is not defined and item.key is defined
|
||||||
|
register: deleted_keys
|
||||||
|
|
||||||
|
- name: Count deleted keys
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
|
'keypairs_deleted': (deleted_keys.results | default([]) | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}"
|
||||||
|
|
||||||
|
# Add this after your existing key pair finding task
|
||||||
|
- name: Find c2deploy key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "c2deploy_{{ deployment_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: present
|
||||||
|
register: c2deploy_key_check
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Delete c2deploy key pairs
|
||||||
|
amazon.aws.ec2_key:
|
||||||
|
name: "c2deploy_{{ deployment_id }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
state: absent
|
||||||
|
when: not c2deploy_key_check.failed | default(true)
|
||||||
|
register: deleted_c2deploy_key
|
||||||
|
|
||||||
|
# STEP 15: Delete SSH key files
|
||||||
|
- name: Delete SSH key files
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- "~/.ssh/{{ redirector_name }}.pem"
|
||||||
|
- "~/.ssh/{{ c2_name }}.pem"
|
||||||
|
- "~/.ssh/{{ tracker_name }}.pem"
|
||||||
|
- "~/.ssh/c2deploy_{{ deployment_id }}.pem" # Fix: add .pem extension
|
||||||
|
- "~/.ssh/c2deploy_{{ deployment_id }}.pub"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: deleted_ssh_files
|
||||||
|
|
||||||
|
- name: Count deleted SSH files
|
||||||
|
set_fact:
|
||||||
|
cleanup_summary: "{{ cleanup_summary | combine({
|
||||||
|
'ssh_files_deleted': (deleted_ssh_files.results | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}"
|
||||||
|
|
||||||
|
# Remove infrastructure state file - fix path to include deployment_id
|
||||||
|
- name: Remove infrastructure state file
|
||||||
|
file:
|
||||||
|
path: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
register: infra_file
|
||||||
|
|
||||||
|
# STEP 16: Enhanced and Accurate Cleanup Summary
|
||||||
|
- name: Enhanced cleanup summary
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "=========================================================="
|
- "=========================================================="
|
||||||
- "CLEANUP SUMMARY FOR DEPLOYMENT ID: {{ deployment_id }}"
|
- " AWS CLEANUP SUMMARY: {{ deployment_id }} "
|
||||||
- "=========================================================="
|
- "=========================================================="
|
||||||
- "EC2 INSTANCES DELETED:"
|
- "EC2 Instances: {{ cleanup_summary.instances_found | default(0) }} found, {{ terminated_instances.results | default([]) | length }} terminated"
|
||||||
- " C2: {{ resource_summary.ec2_instances.c2 }}"
|
- "Security Groups: {{ cleanup_summary.security_groups_found | default(0) }} found, {{ deleted_sgs.results | default([]) | length }} deleted"
|
||||||
- " Redirector: {{ resource_summary.ec2_instances.redirector }}"
|
- "Network Interfaces: {{ cleanup_summary.enis_found | default(0) }} found, {{ deleted_enis.results | default([]) | length }} deleted"
|
||||||
- " Tracker: {{ resource_summary.ec2_instances.tracker }}"
|
- "VPCs: {{ cleanup_summary.vpcs_found | default(0) }} found, {{ cleanup_summary.vpcs_deleted | default(0) }} deleted"
|
||||||
- ""
|
- "Key Pairs: {{ cleanup_summary.keypairs_deleted | default(0) }} deleted"
|
||||||
- "KEY PAIRS DELETED:"
|
- "SSH Key Files: {{ cleanup_summary.ssh_files_deleted | default(0) }} deleted"
|
||||||
- " C2: {{ resource_summary.key_pairs.c2 }}"
|
- "Infrastructure file: {{ 'Removed' if infra_file.changed else 'Not found' }}"
|
||||||
- " Redirector: {{ resource_summary.key_pairs.redirector }}"
|
|
||||||
- " Tracker: {{ resource_summary.key_pairs.tracker }}"
|
|
||||||
- ""
|
|
||||||
- "SECURITY GROUPS DELETED:"
|
|
||||||
- " C2: {{ resource_summary.security_groups.c2 }}"
|
|
||||||
- " Redirector: {{ resource_summary.security_groups.redirector }}"
|
|
||||||
- " Tracker: {{ resource_summary.security_groups.tracker }}"
|
|
||||||
- ""
|
|
||||||
- "VPC RESOURCES DELETED:"
|
|
||||||
- " Route Tables: {{ resource_summary.vpc_resources.route_tables }}"
|
|
||||||
- " Internet Gateways: {{ resource_summary.vpc_resources.internet_gateways }}"
|
|
||||||
- " Subnets: {{ resource_summary.vpc_resources.subnets }}"
|
|
||||||
- " Network Interfaces: {{ resource_summary.vpc_resources.network_interfaces }}"
|
|
||||||
- " VPCs: {{ resource_summary.vpc_resources.vpcs }}"
|
|
||||||
- "=========================================================="
|
- "=========================================================="
|
||||||
when: not disable_summary | default(false)
|
- "CLEANUP {{ 'COMPLETED' if (cleanup_summary.vpcs_deleted | default(0) == cleanup_summary.vpcs_found | default(0)) else 'PARTIAL - SOME RESOURCES MAY REMAIN' }}"
|
||||||
|
- "========================================================="
|
||||||
+8
-198
@@ -1,204 +1,14 @@
|
|||||||
---
|
---
|
||||||
# VPC Cleanup Process with enhanced dependency handling
|
# VPC Cleanup Process with enhanced dependency handling
|
||||||
# Step 1: Network Interfaces
|
# Removed detailed cleanup tasks for ENIs, RTs, IGWs, NATs, subnets, SGs to simplify deletion
|
||||||
- name: Find network interfaces in VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_eni_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
filters:
|
|
||||||
vpc-id: "{{ vpc_id }}"
|
|
||||||
register: eni_info
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Delete network interfaces
|
# Step X: Delete VPC directly
|
||||||
amazon.aws.ec2_eni:
|
- name: Delete VPC {{ vpc_id }}
|
||||||
region: "{{ aws_region }}"
|
amazon.aws.ec2_vpc_net:
|
||||||
eni_id: "{{ item.id }}"
|
|
||||||
state: absent
|
|
||||||
force_detach: true
|
|
||||||
loop: "{{ eni_info.network_interfaces }}"
|
|
||||||
register: eni_deleted
|
|
||||||
ignore_errors: yes
|
|
||||||
when: eni_info.network_interfaces | length > 0
|
|
||||||
|
|
||||||
- name: Wait after deleting network interfaces
|
|
||||||
pause:
|
|
||||||
seconds: 10
|
|
||||||
when: eni_info.network_interfaces | length > 0
|
|
||||||
|
|
||||||
# Step 2: Route Tables
|
|
||||||
- name: Find all route tables for VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_vpc_route_table_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
filters:
|
|
||||||
vpc-id: "{{ vpc_id }}"
|
|
||||||
register: rt_info
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Process route tables
|
|
||||||
when: rt_info.route_tables | length > 0
|
|
||||||
block:
|
|
||||||
- name: Delete non-main route tables
|
|
||||||
amazon.aws.ec2_vpc_route_table:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
vpc_id: "{{ vpc_id }}"
|
|
||||||
route_table_id: "{{ item.id }}"
|
|
||||||
state: absent
|
|
||||||
loop: "{{ rt_info.route_tables }}"
|
|
||||||
when: not item.associations or not item.associations[0].main | default(false)
|
|
||||||
register: deleted_rts
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Update cleaned route tables
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'route_tables': cleaned_resources.route_tables + [item.id]}, recursive=True) }}"
|
|
||||||
with_items: "{{ rt_info.route_tables }}"
|
|
||||||
when: not item.associations or not item.associations[0].main | default(false)
|
|
||||||
|
|
||||||
- name: Wait after deleting route tables
|
|
||||||
pause:
|
|
||||||
seconds: 10
|
|
||||||
when: rt_info.route_tables | length > 0
|
|
||||||
|
|
||||||
# Step 3: Internet Gateways
|
|
||||||
- name: Find internet gateways for VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_vpc_igw_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
filters:
|
|
||||||
attachment.vpc-id: "{{ vpc_id }}"
|
|
||||||
register: igw_info
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Process internet gateways
|
|
||||||
when: igw_info.internet_gateways | length > 0
|
|
||||||
block:
|
|
||||||
- name: Detach internet gateways
|
|
||||||
amazon.aws.ec2_vpc_igw:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
vpc_id: "{{ vpc_id }}"
|
|
||||||
state: absent
|
|
||||||
register: igw_detached
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Wait after detaching IGW
|
|
||||||
pause:
|
|
||||||
seconds: 15
|
|
||||||
when: igw_detached is changed
|
|
||||||
|
|
||||||
- name: Delete internet gateways
|
|
||||||
amazon.aws.ec2_vpc_igw:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
igw_id: "{{ item.id }}"
|
|
||||||
state: absent
|
|
||||||
loop: "{{ igw_info.internet_gateways }}"
|
|
||||||
register: deleted_igws
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Update cleaned internet gateways
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'internet_gateways': cleaned_resources.internet_gateways + [item.id]}, recursive=True) }}"
|
|
||||||
with_items: "{{ igw_info.internet_gateways }}"
|
|
||||||
|
|
||||||
# Step 4: Subnets
|
|
||||||
- name: Find subnets for VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_vpc_subnet_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
filters:
|
|
||||||
vpc-id: "{{ vpc_id }}"
|
|
||||||
register: subnet_info
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Delete subnets
|
|
||||||
amazon.aws.ec2_vpc_subnet:
|
|
||||||
region: "{{ aws_region }}"
|
region: "{{ aws_region }}"
|
||||||
vpc_id: "{{ vpc_id }}"
|
vpc_id: "{{ vpc_id }}"
|
||||||
cidr: "{{ item.cidr_block }}"
|
|
||||||
state: absent
|
state: absent
|
||||||
loop: "{{ subnet_info.subnets }}"
|
retries: 5
|
||||||
register: deleted_subnets
|
delay: 15
|
||||||
ignore_errors: true
|
register: vpc_delete_result
|
||||||
when: subnet_info.subnets | length > 0
|
until: vpc_delete_result is success
|
||||||
|
|
||||||
- name: Update cleaned subnets
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'subnets': cleaned_resources.subnets + [item.id]}, recursive=True) }}"
|
|
||||||
with_items: "{{ subnet_info.subnets }}"
|
|
||||||
when: subnet_info.subnets | length > 0
|
|
||||||
|
|
||||||
- name: Wait after deleting subnets
|
|
||||||
pause:
|
|
||||||
seconds: 15
|
|
||||||
when: subnet_info.subnets | length > 0
|
|
||||||
|
|
||||||
# Step 5: Security Groups (except default)
|
|
||||||
- name: Find non-default security groups for VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_security_group_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
filters:
|
|
||||||
vpc-id: "{{ vpc_id }}"
|
|
||||||
register: sg_info
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Delete non-default security groups
|
|
||||||
amazon.aws.ec2_security_group:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
group_id: "{{ item.group_id }}"
|
|
||||||
state: absent
|
|
||||||
loop: "{{ sg_info.security_groups }}"
|
|
||||||
when: item.group_name != 'default'
|
|
||||||
register: deleted_sgs
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Update cleaned security groups
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [item.group_id]}, recursive=True) }}"
|
|
||||||
with_items: "{{ sg_info.security_groups }}"
|
|
||||||
when: item.group_name != 'default'
|
|
||||||
|
|
||||||
- name: Wait after deleting security groups
|
|
||||||
pause:
|
|
||||||
seconds: 15
|
|
||||||
when: sg_info.security_groups | length > 0
|
|
||||||
|
|
||||||
# Step 6: Delete VPC with proper dependencies and retries
|
|
||||||
- name: Wait longer before trying to delete VPC
|
|
||||||
pause:
|
|
||||||
seconds: 30
|
|
||||||
|
|
||||||
- name: Delete VPC with retries
|
|
||||||
block:
|
|
||||||
- name: Delete VPC {{ vpc_id }}
|
|
||||||
amazon.aws.ec2_vpc_net:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
vpc_id: "{{ vpc_id }}"
|
|
||||||
state: absent
|
|
||||||
register: vpc_delete_result
|
|
||||||
retries: 5
|
|
||||||
delay: 15
|
|
||||||
until: vpc_delete_result is success
|
|
||||||
rescue:
|
|
||||||
- name: Force check dependencies again if VPC deletion failed
|
|
||||||
amazon.aws.ec2_vpc_net_info:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
vpc_ids:
|
|
||||||
- "{{ vpc_id }}"
|
|
||||||
register: vpc_check
|
|
||||||
|
|
||||||
- name: Final attempt to delete VPC if it still exists
|
|
||||||
amazon.aws.ec2_vpc_net:
|
|
||||||
region: "{{ aws_region }}"
|
|
||||||
vpc_id: "{{ vpc_id }}"
|
|
||||||
state: absent
|
|
||||||
when: vpc_check.vpcs | length > 0
|
|
||||||
ignore_errors: true
|
|
||||||
register: final_vpc_delete
|
|
||||||
|
|
||||||
- name: Update cleaned VPCs
|
|
||||||
set_fact:
|
|
||||||
cleaned_resources: "{{ cleaned_resources | combine({'vpcs': cleaned_resources.vpcs + [vpc_id]}, recursive=True) }}"
|
|
||||||
when: (vpc_delete_result is defined and vpc_delete_result is success) or
|
|
||||||
(final_vpc_delete is defined and final_vpc_delete is success)
|
|
||||||
+51
-11
@@ -14,7 +14,8 @@
|
|||||||
instance_type: "{{ aws_instance_type | default('t2.micro') }}"
|
instance_type: "{{ aws_instance_type | default('t2.micro') }}"
|
||||||
deployment_id: "{{ deployment_id | default('') }}"
|
deployment_id: "{{ deployment_id | default('') }}"
|
||||||
redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}"
|
redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}"
|
||||||
shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}"
|
# Calculate effective port: use shell_handler_port from vars or default to 8083
|
||||||
|
effective_listen_port: "{{ shell_handler_port | default(8083) }}"
|
||||||
# Check for shared infrastructure
|
# Check for shared infrastructure
|
||||||
# Only use shared when C2 and redirector are in the same region
|
# Only use shared when C2 and redirector are in the same region
|
||||||
use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}"
|
use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}"
|
||||||
@@ -43,16 +44,37 @@
|
|||||||
# Load shared infrastructure state if available
|
# Load shared infrastructure state if available
|
||||||
- name: Check for shared infrastructure state
|
- name: Check for shared infrastructure state
|
||||||
stat:
|
stat:
|
||||||
path: "infrastructure_state.json"
|
path: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
register: infra_state_file
|
register: infra_state_file
|
||||||
when: use_shared_infra | bool
|
when: use_shared_infra | bool
|
||||||
|
|
||||||
- name: Load shared infrastructure state
|
- name: Load shared infrastructure state
|
||||||
include_vars:
|
include_vars:
|
||||||
file: "infrastructure_state.json"
|
file: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
name: shared_infra
|
name: shared_infra
|
||||||
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
|
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
|
||||||
|
|
||||||
|
# After loading shared infrastructure state
|
||||||
|
- name: Validate shared VPC exists
|
||||||
|
amazon.aws.ec2_vpc_net_info:
|
||||||
|
region: "{{ shared_infra.region }}"
|
||||||
|
vpc_ids:
|
||||||
|
- "{{ shared_infra.vpc_id }}"
|
||||||
|
register: vpc_check
|
||||||
|
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Delete stale infrastructure state file
|
||||||
|
file:
|
||||||
|
path: "infrastructure_state.json"
|
||||||
|
state: absent
|
||||||
|
when: use_shared_infra | bool and vpc_check.vpcs is defined and vpc_check.vpcs | length == 0
|
||||||
|
|
||||||
|
- name: Disable shared infrastructure when VPC doesn't exist
|
||||||
|
set_fact:
|
||||||
|
use_shared_infra: false
|
||||||
|
when: use_shared_infra | bool and vpc_check.vpcs is defined and vpc_check.vpcs | length == 0
|
||||||
|
|
||||||
- name: Set region for redirector from shared infra
|
- name: Set region for redirector from shared infra
|
||||||
set_fact:
|
set_fact:
|
||||||
aws_redirector_region: "{{ shared_infra.region | default(aws_region) }}"
|
aws_redirector_region: "{{ shared_infra.region | default(aws_region) }}"
|
||||||
@@ -148,12 +170,6 @@
|
|||||||
redirector_vpc_id: "{{ vpc_result.vpc.id }}" # Store for cleanup reference
|
redirector_vpc_id: "{{ vpc_result.vpc.id }}" # Store for cleanup reference
|
||||||
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
|
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
|
||||||
|
|
||||||
# Set a random shell handler port if not defined
|
|
||||||
- name: Set random shell handler port if not defined
|
|
||||||
set_fact:
|
|
||||||
shell_handler_port: "{{ 4000 + 59000 | random }}"
|
|
||||||
when: shell_handler_port is not defined
|
|
||||||
|
|
||||||
# Create security group
|
# Create security group
|
||||||
- name: Create security group
|
- name: Create security group
|
||||||
amazon.aws.ec2_security_group:
|
amazon.aws.ec2_security_group:
|
||||||
@@ -167,7 +183,7 @@
|
|||||||
- 22
|
- 22
|
||||||
- 80
|
- 80
|
||||||
- 443
|
- 443
|
||||||
- "{{ shell_handler_port }}"
|
- "{{ effective_listen_port }}"
|
||||||
cidr_ip: 0.0.0.0/0
|
cidr_ip: 0.0.0.0/0
|
||||||
rules_egress:
|
rules_egress:
|
||||||
- proto: -1
|
- proto: -1
|
||||||
@@ -175,6 +191,20 @@
|
|||||||
state: present
|
state: present
|
||||||
register: security_group
|
register: security_group
|
||||||
|
|
||||||
|
# Save infrastructure state for reuse
|
||||||
|
- name: Save infrastructure state for reuse
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
{
|
||||||
|
"vpc_id": "{{ vpc_id }}",
|
||||||
|
"subnet_id": "{{ subnet_id }}",
|
||||||
|
"security_group_id": "{{ security_group.group_id }}",
|
||||||
|
"region": "{{ aws_redirector_region }}",
|
||||||
|
"deployment_id": "{{ deployment_id }}"
|
||||||
|
}
|
||||||
|
dest: "infrastructure_state_{{ deployment_id }}.json"
|
||||||
|
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
|
||||||
|
|
||||||
# Launch the redirector
|
# Launch the redirector
|
||||||
- name: Launch redirector instance
|
- name: Launch redirector instance
|
||||||
amazon.aws.ec2_instance:
|
amazon.aws.ec2_instance:
|
||||||
@@ -215,6 +245,7 @@
|
|||||||
ansible_ssh_private_key_file: "~/.ssh/{{ redirector_name }}.pem"
|
ansible_ssh_private_key_file: "~/.ssh/{{ redirector_name }}.pem"
|
||||||
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes"
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes"
|
||||||
ansible_python_interpreter: "/usr/bin/python3"
|
ansible_python_interpreter: "/usr/bin/python3"
|
||||||
|
shell_handler_port: "{{ effective_listen_port }}"
|
||||||
|
|
||||||
# Rest of the playbook for configuring the redirector
|
# Rest of the playbook for configuring the redirector
|
||||||
- name: Configure redirector
|
- name: Configure redirector
|
||||||
@@ -225,12 +256,21 @@
|
|||||||
- vars.yaml
|
- vars.yaml
|
||||||
vars:
|
vars:
|
||||||
c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}"
|
c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}"
|
||||||
|
shell_handler_port: "{{ hostvars['localhost']['effective_listen_port'] }}"
|
||||||
|
|
||||||
# Include the rest of your redirector configuration tasks here
|
# Include the rest of your redirector configuration tasks here
|
||||||
tasks:
|
tasks:
|
||||||
- name: Include common redirector configuration tasks
|
- name: Include common redirector configuration tasks
|
||||||
include_tasks: "../tasks/configure_redirector.yml"
|
include_tasks: "../tasks/configure_redirector.yml"
|
||||||
|
|
||||||
|
- name: Configure shell handler script with listening port
|
||||||
|
template:
|
||||||
|
src: "../files/havoc_shell_handler.sh"
|
||||||
|
dest: "/root/Tools/shell_handler.sh"
|
||||||
|
mode: 0755
|
||||||
|
vars:
|
||||||
|
listen_port: "{{ effective_listen_port }}"
|
||||||
|
|
||||||
- name: Print deployment summary
|
- name: Print deployment summary
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
|
|||||||
@@ -128,5 +128,4 @@
|
|||||||
- "-------------------------------"
|
- "-------------------------------"
|
||||||
- "Redirector IP: {{ ansible_host }}"
|
- "Redirector IP: {{ ansible_host }}"
|
||||||
- "Redirector Domain: {{ redirector_subdomain }}.{{ domain }} (Update DNS A record)"
|
- "Redirector Domain: {{ redirector_subdomain }}.{{ domain }} (Update DNS A record)"
|
||||||
- "Shell Handler Port: {{ shell_handler_port }}"
|
|
||||||
when: not disable_summary | default(false)
|
when: not disable_summary | default(false)
|
||||||
@@ -21,7 +21,7 @@ deployment_id = None
|
|||||||
# Constants for providers
|
# Constants for providers
|
||||||
PROVIDERS = ["aws", "linode", "flokinet"]
|
PROVIDERS = ["aws", "linode", "flokinet"]
|
||||||
DEFAULT_SSH_USER = {
|
DEFAULT_SSH_USER = {
|
||||||
"aws": "root",
|
"aws": "kali",
|
||||||
"linode": "root",
|
"linode": "root",
|
||||||
"flokinet": "root"
|
"flokinet": "root"
|
||||||
}
|
}
|
||||||
@@ -375,7 +375,7 @@ def gather_common_parameters():
|
|||||||
config['zero_logs'] = input("Enable zero-logs configuration? (y/n) [default: y]: ").lower() != 'n'
|
config['zero_logs'] = input("Enable zero-logs configuration? (y/n) [default: y]: ").lower() != 'n'
|
||||||
|
|
||||||
# Add SSH option that was missing
|
# Add SSH option that was missing
|
||||||
config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: n]: ").lower() == 'y'
|
config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: y]: ").lower() == 'y'
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
@@ -519,6 +519,14 @@ def execute_deployment(config):
|
|||||||
print(f"\n{COLORS['RED']}Deployment failed.{COLORS['RESET']}")
|
print(f"\n{COLORS['RED']}Deployment failed.{COLORS['RESET']}")
|
||||||
|
|
||||||
input("\nPress Enter to return to menu...")
|
input("\nPress Enter to return to menu...")
|
||||||
|
# Clean up shared infrastructure state file if present
|
||||||
|
try:
|
||||||
|
state_file = os.path.join(os.getcwd(), 'infrastructure_state.json')
|
||||||
|
if os.path.exists(state_file):
|
||||||
|
os.remove(state_file)
|
||||||
|
logging.info('Removed shared infrastructure state file')
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f'Failed to remove infra state file: {e}')
|
||||||
|
|
||||||
def generate_random_string(length=8):
|
def generate_random_string(length=8):
|
||||||
"""Generate a random string of letters and digits."""
|
"""Generate a random string of letters and digits."""
|
||||||
@@ -526,8 +534,11 @@ def generate_random_string(length=8):
|
|||||||
|
|
||||||
def generate_deployment_id():
|
def generate_deployment_id():
|
||||||
"""Generate a consistent deployment ID for all resources in this deployment"""
|
"""Generate a consistent deployment ID for all resources in this deployment"""
|
||||||
rand_suffix = generate_random_string(6)
|
global deployment_id
|
||||||
return f"{rand_suffix}"
|
if not deployment_id:
|
||||||
|
rand_suffix = generate_random_string(6)
|
||||||
|
deployment_id = f"{rand_suffix}"
|
||||||
|
return deployment_id
|
||||||
|
|
||||||
def setup_logging(deployment_id=None):
|
def setup_logging(deployment_id=None):
|
||||||
"""Set up logging for the deployment"""
|
"""Set up logging for the deployment"""
|
||||||
@@ -864,7 +875,7 @@ def interactive_setup(deployment_id=None):
|
|||||||
config['tracker_create_pixel'] = input("Create tracking pixel? (y/n) [default: y]: ").lower() != 'n'
|
config['tracker_create_pixel'] = input("Create tracking pixel? (y/n) [default: y]: ").lower() != 'n'
|
||||||
|
|
||||||
# Post-deployment options
|
# Post-deployment options
|
||||||
config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: n]: ").lower() == 'y'
|
config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: y]: ").lower() == 'y'
|
||||||
|
|
||||||
# Debug mode
|
# Debug mode
|
||||||
config['debug'] = input("Enable debug mode? (y/n) [default: n]: ").lower() == 'y'
|
config['debug'] = input("Enable debug mode? (y/n) [default: n]: ").lower() == 'y'
|
||||||
@@ -1326,6 +1337,8 @@ def deploy_infrastructure(config):
|
|||||||
logging.error(f"{provider} redirector deployment failed")
|
logging.error(f"{provider} redirector deployment failed")
|
||||||
if redirector_config.get('debug'):
|
if redirector_config.get('debug'):
|
||||||
logging.error(f"Ansible stderr: {stderr}")
|
logging.error(f"Ansible stderr: {stderr}")
|
||||||
|
# Run cleanup before returning
|
||||||
|
cleanup_resources(config, interactive=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Extract and save redirector IP for C2 configuration
|
# Extract and save redirector IP for C2 configuration
|
||||||
@@ -1353,6 +1366,8 @@ def deploy_infrastructure(config):
|
|||||||
logging.error(f"{provider} C2 server deployment failed")
|
logging.error(f"{provider} C2 server deployment failed")
|
||||||
if c2_config.get('debug'):
|
if c2_config.get('debug'):
|
||||||
logging.error(f"Ansible stderr: {stderr}")
|
logging.error(f"Ansible stderr: {stderr}")
|
||||||
|
# Run cleanup before returning
|
||||||
|
cleanup_resources(config, interactive=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Extract and save C2 IP for reference
|
# Extract and save C2 IP for reference
|
||||||
@@ -1367,7 +1382,8 @@ def deploy_infrastructure(config):
|
|||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
|
|
||||||
# Clean up any partial resources that were created
|
# Clean up any partial resources that were created
|
||||||
cleanup_resources(config, interactive=True)
|
# Force interactive to False to ensure cleanup runs without prompting when there's an exception
|
||||||
|
cleanup_resources(config, interactive=False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def deploy_flokinet_redirector(config):
|
def deploy_flokinet_redirector(config):
|
||||||
@@ -2212,7 +2228,7 @@ def main():
|
|||||||
if args.provider == "linode":
|
if args.provider == "linode":
|
||||||
config['ssh_user'] = "root"
|
config['ssh_user'] = "root"
|
||||||
elif args.provider == "aws":
|
elif args.provider == "aws":
|
||||||
config['ssh_user'] = "root"
|
config['ssh_user'] = "kali"
|
||||||
else:
|
else:
|
||||||
if hasattr(args, 'ssh_user'):
|
if hasattr(args, 'ssh_user'):
|
||||||
config['ssh_user'] = args.ssh_user or vars_data.get('ssh_user') or DEFAULT_SSH_USER.get(args.provider)
|
config['ssh_user'] = args.ssh_user or vars_data.get('ssh_user') or DEFAULT_SSH_USER.get(args.provider)
|
||||||
|
|||||||
@@ -97,10 +97,12 @@
|
|||||||
replace: 'C2_HOST="{{ c2_ip }}"'
|
replace: 'C2_HOST="{{ c2_ip }}"'
|
||||||
|
|
||||||
- name: Configure shell handler script with listening port
|
- name: Configure shell handler script with listening port
|
||||||
replace:
|
template:
|
||||||
path: /root/Tools/shell-handler/persistent-listener.sh
|
src: "../files/havoc_shell_handler.sh"
|
||||||
regexp: 'LISTEN_PORT=4444'
|
dest: "/root/Tools/shell_handler.sh"
|
||||||
replace: 'LISTEN_PORT={{ shell_handler_port }}'
|
mode: 0755
|
||||||
|
vars:
|
||||||
|
listen_port: "{{ shell_handler_port | default(8083) }}"
|
||||||
|
|
||||||
- name: Create shell handler service
|
- name: Create shell handler service
|
||||||
template:
|
template:
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"vpc_id": "{{ infra_state.vpc_id }}",
|
||||||
|
"subnet_id": "{{ infra_state.subnet_id }}",
|
||||||
|
"security_group_id": "{{ infra_state.security_group_id }}",
|
||||||
|
"region": "{{ infra_state.region }}"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user