working on it

This commit is contained in:
n0mad1k
2025-05-10 15:14:10 -04:00
parent f4e24edf9b
commit ce5d7c4fb7
9 changed files with 542 additions and 525 deletions
+27 -8
View File
@@ -9,7 +9,7 @@
- vars.yaml
vars:
# Default values
ssh_user: "{{ ssh_user | default('root') }}"
ssh_user: "{{ ssh_user | default('kali') }}"
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
instance_type: "{{ aws_instance_type | default('t2.medium') }}"
deployment_id: "{{ deployment_id | default('') }}"
@@ -17,6 +17,10 @@
# Check for shared infrastructure
# 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 }}"
# 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:
- name: Validate AWS credentials
@@ -29,13 +33,13 @@
# Load shared infrastructure state if available
- name: Check for shared infrastructure state
stat:
path: "infrastructure_state.json"
path: "infrastructure_state_{{ deployment_id }}.json"
register: infra_state_file
when: use_shared_infra | bool
- name: Load shared infrastructure state
include_vars:
file: "infrastructure_state.json"
file: "infrastructure_state_{{ deployment_id }}.json"
name: shared_infra
when: use_shared_infra | bool and infra_state_file.stat.exists | default(false)
@@ -48,16 +52,31 @@
set_fact:
aws_c2_region: "{{ c2_region | default(aws_region) }}"
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:
ami_id: "{{ ami_map[aws_c2_region] }}"
when: ami_map is defined and aws_c2_region in ami_map
ami_id: "{{ ami_map[aws_c2_region] | default(ami_map.us-east-1) }}"
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
- name: Determine correct SSH user for the AMI
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
debug:
+419 -295
View File
@@ -1,6 +1,5 @@
---
# AWS Cleanup Playbook
# AWS Cleanup Playbook - Comprehensive version with robust VPC removal
- name: Clean up AWS resources
hosts: localhost
gather_facts: false
@@ -8,348 +7,473 @@
vars_files:
- vars.yaml
vars:
delete_results: {}
vpc_cleanup_list: []
aws_detailed_logging: true
aws_region: "{{ aws_region | default(aws_region_choices | random) }}"
confirm_cleanup: "{{ confirm_cleanup | default(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:
# Confirmation prompts
# Confirmation step (if enabled)
- name: Confirm cleanup
pause:
prompt: "This will delete all AWS resources for deployment ID {{ deployment_id }}. Continue? (yes/no)"
register: confirm_deletion
when: confirm_cleanup | default(true) | bool
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: cleanup_confirmation
when: confirm_cleanup | bool
- name: Check confirmation
assert:
that: confirm_deletion.user_input | default('yes') | lower == 'yes'
that:
- cleanup_confirmation.user_input | default('yes') == 'yes'
fail_msg: "Cleanup cancelled by user"
when: confirm_cleanup | default(true) | bool
# Display AWS region being used for cleanup
- name: Display AWS region being used for cleanup
debug:
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
when: confirm_cleanup | bool
# STEP 1: Find all instances by deployment ID
- name: Find all EC2 instances for this deployment
amazon.aws.ec2_instance_info:
region: "{{ aws_region }}"
filters:
"tag:Name": "{{ c2_name }}"
register: c2_instances_result
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
"tag:deployment_id": "{{ deployment_id }}"
register: deployment_instances
- 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:
state: absent
instance_ids: "{{ item.instance_id }}"
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
region: "{{ aws_region }}"
filters:
"tag:Name": "{{ tracker_name | default('t-' + deployment_id) }}"
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
loop: "{{ deployment_instances.instances }}"
register: terminated_instances
when: deployment_instances.instances | length > 0
# Wait for all instances to terminate before attempting to clean up dependent resources
- name: Wait for instances to terminate
- name: Wait for instances to be terminated
pause:
seconds: 30
when: (cleanup_c2 | default(true) | bool and c2_instances_result.changed | default(false)) or
(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))
# List all key pairs to handle different naming patterns
- name: List available EC2 key pairs
amazon.aws.ec2_key_info:
when: deployment_instances.instances | length > 0
# STEP 3: Find all security groups by deployment ID
- name: Find all security groups for this deployment
amazon.aws.ec2_security_group_info:
region: "{{ aws_region }}"
register: all_key_pairs
filters:
"tag:deployment_id": "{{ deployment_id }}"
register: deployment_sgs
# Delete C2 deployment key with deployment_id pattern
- name: Delete C2 deployment key (deployment_id pattern)
amazon.aws.ec2_key:
name: "c2deploy_{{ deployment_id }}"
# Also find SGs by name pattern
- name: Find security groups by name pattern
amazon.aws.ec2_security_group_info:
region: "{{ aws_region }}"
state: absent
register: c2_deploy_key_result
when: cleanup_c2 | default(true) | bool
# 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
register: all_sgs
- name: Filter SGs by name pattern
set_fact:
cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [item]}, recursive=true) }}"
with_items:
- "c2deploy_{{ deployment_id }}"
- "{{ c2_name }}"
when: cleanup_c2 | default(true) | bool and (c2_key_result.changed or c2_deploy_key_result.changed)
named_sgs: "{{ all_sgs.security_groups | selectattr('group_name', 'search', redirector_name + '-sg|' + c2_name + '-sg') | list }}"
# Delete redirector EC2 key pair
- 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
- name: Combine all security groups to delete
set_fact:
cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [redirector_name]}, recursive=true) }}"
when: cleanup_redirector | default(true) | bool and redirector_key_result.changed | default(false)
- name: Delete tracker EC2 key pair
amazon.aws.ec2_key:
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
all_sgs_to_delete: "{{ deployment_sgs.security_groups + named_sgs }}"
cleanup_summary: "{{ cleanup_summary | combine({'security_groups_found': (deployment_sgs.security_groups + named_sgs) | length}) }}"
# STEP 4: Delete all security groups
- name: Delete security groups
amazon.aws.ec2_security_group:
name: "{{ c2_name }}-sg"
group_id: "{{ item.group_id }}"
region: "{{ aws_region }}"
state: absent
register: c2_sg_result
loop: "{{ all_sgs_to_delete }}"
when: all_sgs_to_delete | length > 0
ignore_errors: yes
when: cleanup_c2 | default(true) | bool
- name: Update cleaned security groups list for C2
set_fact:
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [c2_sg_result.group_id | default('')]}, recursive=true) }}"
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"
register: deleted_sgs
# STEP 5: Find and delete all ENIs
- name: Find network interfaces by tag
amazon.aws.ec2_eni_info:
region: "{{ aws_region }}"
state: absent
register: redirector_sg_result
ignore_errors: yes
when: cleanup_redirector | default(true) | bool
filters:
"tag:deployment_id": "{{ deployment_id }}"
register: deployment_enis
- name: Update cleaned security groups list for redirector
set_fact:
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"
- name: Delete ENIs
amazon.aws.ec2_eni:
region: "{{ aws_region }}"
eni_id: "{{ item.id }}"
state: absent
register: tracker_sg_result
force_detach: true
loop: "{{ deployment_enis.network_interfaces }}"
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:
cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [tracker_sg_result.group_id | default('')]}, recursive=true) }}"
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
# Identify VPCs to clean up (by tag and by name pattern)
- name: Get VPCs by deployment tag
cleanup_summary: "{{ cleanup_summary | combine({'enis_found': deployment_enis.network_interfaces | length}) }}"
# STEP 6: Find all VPCs by deployment ID
- name: Find all VPCs for this deployment
amazon.aws.ec2_vpc_net_info:
region: "{{ aws_region }}"
filters:
"tag:deployment_id": "{{ deployment_id }}"
register: tagged_vpcs
register: deployment_vpcs
- name: Add tagged VPCs to cleanup list
set_fact:
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
# STEP 7: Find VPCs by name pattern as fallback
- name: Find all VPCs by name pattern
amazon.aws.ec2_vpc_net_info:
region: "{{ aws_region }}"
filters:
"tag:Name": "{{ c2_name }}-vpc"
register: c2_named_vpcs
when: cleanup_c2 | default(true) | bool
- name: Add C2-named VPCs to cleanup list
register: all_vpcs
- name: Filter VPCs by name pattern
set_fact:
vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}"
with_items: "{{ c2_named_vpcs.vpcs }}"
when: cleanup_c2 | default(true) | bool and c2_named_vpcs.vpcs | length > 0
- name: Find VPCs by naming pattern for redirector
amazon.aws.ec2_vpc_net_info:
named_vpcs: "{{ all_vpcs.vpcs | selectattr('tags', 'defined') | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'search', redirector_name + '-vpc|' + c2_name + '-vpc') | list }}"
- name: Combine all VPCs to delete
set_fact:
all_vpcs_to_delete: "{{ deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id') }}"
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 }}"
filters:
"tag:Name": "{{ redirector_name }}-vpc"
register: redirector_named_vpcs
when: cleanup_redirector | default(true) | bool
vpc-id: "{{ item.vpc_id }}"
register: natgw_results
loop: "{{ all_vpcs_to_delete }}"
when: all_vpcs_to_delete | length > 0
- name: Add redirector-named VPCs to cleanup list
set_fact:
vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}"
with_items: "{{ redirector_named_vpcs.vpcs }}"
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"
- name: Delete NAT gateways
amazon.aws.ec2_vpc_nat_gateway:
region: "{{ aws_region }}"
nat_gateway_id: "{{ item.1.nat_gateway_id }}"
state: absent
when: >
infra_state_file.stat.exists | default(false) and
((cleanup_c2 | default(true) | bool and cleanup_redirector | default(true) | bool) or
(cleanup_c2 | default(true) | bool and not cleanup_redirector | default(true) | bool and
c2_region | default(aws_region) == shared_infra.region) or
(cleanup_redirector | default(true) | bool and not cleanup_c2 | default(true) | bool and
redirector_region | default(aws_region) == shared_infra.region))
release_eip: true
loop: "{{ natgw_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('nat_gateways', 'defined') | subelements('nat_gateways') }}"
ignore_errors: yes
register: deleted_natgws
when: natgw_results.results is defined
- 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: Collect all deleted resources
- name: Detach and delete internet gateways
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:
resource_summary:
ec2_instances:
c2: "{{ c2_instances_result.instance_ids | default([]) }}"
redirector: "{{ redirector_instances_result.instance_ids | default([]) }}"
tracker: "{{ tracker_instances_result.instance_ids | default([]) }}"
key_pairs:
c2: "{{ cleaned_resources.key_pairs | default([]) | select('search', 'c2deploy_' + deployment_id) | list + cleaned_resources.key_pairs | default([]) | select('search', c2_name) | list }}"
redirector: "{{ redirector_key_result.key.name | default('') | ternary([redirector_key_result.key.name], []) }}"
tracker: "{{ tracker_key_result.key.name | default('') | ternary([tracker_key_result.key.name], []) }}"
security_groups:
c2: "{{ c2_sg_result.group_id | default('') | ternary([c2_sg_result.group_id], []) }}"
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
cleanup_summary: "{{ cleanup_summary | combine({
'vpcs_deleted': ((vpc_deletion.results | default([]) | selectattr('failed', 'undefined') | list | length) + (force_vpc_delete.results | default([]) | selectattr('failed', 'undefined') | list | length))}) }}"
when: all_vpcs_to_delete | length > 0
# Add these tasks to confirm VPC deletion
- name: Verify VPC deletion
amazon.aws.ec2_vpc_net_info:
region: "{{ aws_region }}"
filters:
"tag:deployment_id": "{{ deployment_id }}"
register: vpc_check
- 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:
msg:
- "=========================================================="
- "CLEANUP SUMMARY FOR DEPLOYMENT ID: {{ deployment_id }}"
- " AWS CLEANUP SUMMARY: {{ deployment_id }} "
- "=========================================================="
- "EC2 INSTANCES DELETED:"
- " C2: {{ resource_summary.ec2_instances.c2 }}"
- " Redirector: {{ resource_summary.ec2_instances.redirector }}"
- " Tracker: {{ resource_summary.ec2_instances.tracker }}"
- ""
- "KEY PAIRS DELETED:"
- " C2: {{ resource_summary.key_pairs.c2 }}"
- " 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 }}"
- "EC2 Instances: {{ cleanup_summary.instances_found | default(0) }} found, {{ terminated_instances.results | default([]) | length }} terminated"
- "Security Groups: {{ cleanup_summary.security_groups_found | default(0) }} found, {{ deleted_sgs.results | default([]) | length }} deleted"
- "Network Interfaces: {{ cleanup_summary.enis_found | default(0) }} found, {{ deleted_enis.results | default([]) | length }} deleted"
- "VPCs: {{ cleanup_summary.vpcs_found | default(0) }} found, {{ cleanup_summary.vpcs_deleted | default(0) }} deleted"
- "Key Pairs: {{ cleanup_summary.keypairs_deleted | default(0) }} deleted"
- "SSH Key Files: {{ cleanup_summary.ssh_files_deleted | default(0) }} deleted"
- "Infrastructure file: {{ 'Removed' if infra_file.changed else 'Not found' }}"
- "=========================================================="
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
View File
@@ -1,204 +1,14 @@
---
# VPC Cleanup Process with enhanced dependency handling
# Step 1: Network Interfaces
- 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
# Removed detailed cleanup tasks for ENIs, RTs, IGWs, NATs, subnets, SGs to simplify deletion
- name: Delete network interfaces
amazon.aws.ec2_eni:
region: "{{ aws_region }}"
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:
# Step X: Delete VPC directly
- name: Delete VPC {{ vpc_id }}
amazon.aws.ec2_vpc_net:
region: "{{ aws_region }}"
vpc_id: "{{ vpc_id }}"
cidr: "{{ item.cidr_block }}"
state: absent
loop: "{{ subnet_info.subnets }}"
register: deleted_subnets
ignore_errors: true
when: subnet_info.subnets | length > 0
- 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)
retries: 5
delay: 15
register: vpc_delete_result
until: vpc_delete_result is success
+51 -11
View File
@@ -14,7 +14,8 @@
instance_type: "{{ aws_instance_type | default('t2.micro') }}"
deployment_id: "{{ deployment_id | default('') }}"
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
# 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 }}"
@@ -43,16 +44,37 @@
# Load shared infrastructure state if available
- name: Check for shared infrastructure state
stat:
path: "infrastructure_state.json"
path: "infrastructure_state_{{ deployment_id }}.json"
register: infra_state_file
when: use_shared_infra | bool
- name: Load shared infrastructure state
include_vars:
file: "infrastructure_state.json"
file: "infrastructure_state_{{ deployment_id }}.json"
name: shared_infra
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
set_fact:
aws_redirector_region: "{{ shared_infra.region | default(aws_region) }}"
@@ -148,12 +170,6 @@
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))
# 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
- name: Create security group
amazon.aws.ec2_security_group:
@@ -167,7 +183,7 @@
- 22
- 80
- 443
- "{{ shell_handler_port }}"
- "{{ effective_listen_port }}"
cidr_ip: 0.0.0.0/0
rules_egress:
- proto: -1
@@ -175,6 +191,20 @@
state: present
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
- name: Launch redirector instance
amazon.aws.ec2_instance:
@@ -215,6 +245,7 @@
ansible_ssh_private_key_file: "~/.ssh/{{ redirector_name }}.pem"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes"
ansible_python_interpreter: "/usr/bin/python3"
shell_handler_port: "{{ effective_listen_port }}"
# Rest of the playbook for configuring the redirector
- name: Configure redirector
@@ -225,12 +256,21 @@
- vars.yaml
vars:
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
tasks:
- name: Include common redirector configuration tasks
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
debug:
msg: