aws
β€’ Markdown

Generic CT Shutdown

Complete AWS Control Tower + CDK Teardown Guide

⚠️ WARNING: This will permanently delete all resources, data, and accounts. Make sure you have backups of any important data before proceeding.

Phase 1: Destroy CDK Applications (CRITICAL - Do This First!)

1.1 Quick CDK Resource Cleanup

# Navigate to your project directory
cd simple-control-tower-cdk

# Load environment variables (if available)
source .env 2>/dev/null || echo "No .env file found"

# Destroy all CDK stacks in reverse order (prod β†’ dev)
cdk destroy HelloWorld-prod --force
cdk destroy HelloWorld-shared --force
cdk destroy HelloWorld-staging --force
cdk destroy HelloWorld-dev --force

# Alternative: Destroy all stacks at once
cdk destroy --all --force

1.2 Automated Teardown Script

Create and run this script for complete CDK cleanup:

#!/bin/bash
# File: scripts/teardown-all.sh

echo "πŸ”₯ Starting Complete AWS Control Tower Teardown"
echo "==============================================="

# Load environment variables
source .env 2>/dev/null || echo "⚠️ No .env file found"

# Function to destroy stack with retry
destroy_stack() {
    local stack_name="$1"
    local account_id="$2"

    echo "πŸ—‘οΈ Destroying $stack_name..."

    # Try to destroy with specific account context
    if [ ! -z "$account_id" ]; then
        cdk destroy $stack_name \
            --context accountId=$account_id \
            --force \
            --require-approval never
    else
        cdk destroy $stack_name --force --require-approval never
    fi

    if [ $? -eq 0 ]; then
        echo "βœ… $stack_name destroyed successfully"
    else
        echo "⚠️ Failed to destroy $stack_name (may not exist)"
    fi
}

# Destroy application stacks
destroy_stack "HelloWorld-prod" "$PROD_ACCOUNT_ID"
destroy_stack "HelloWorld-shared" "$SHARED_ACCOUNT_ID"
destroy_stack "HelloWorld-staging" "$STAGING_ACCOUNT_ID"
destroy_stack "HelloWorld-dev" "$DEV_ACCOUNT_ID"

# Clean up any remaining CDK bootstrap stacks (optional)
echo "🧹 Cleaning up CDK Bootstrap stacks..."
echo "⚠️ Only run this if you're not using CDK for other projects:"
echo "cdk destroy CDKToolkit --force"

echo "βœ… CDK teardown complete!"
# Make script executable and run
chmod +x scripts/teardown-all.sh
./scripts/teardown-all.sh

Phase 2: Manual CloudFormation Cleanup

2.1 Check for Remaining Stacks

# List all CloudFormation stacks in your region
aws cloudformation list-stacks \
    --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
    --query 'StackSummaries[?contains(StackName, `HelloWorld`) || contains(StackName, `CDK`)].{Name:StackName,Status:StackStatus}'

# πŸ‡ΈπŸ‡¬ Singapore users:
# aws cloudformation list-stacks --region ap-southeast-1 \
#     --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
#     --query 'StackSummaries[?contains(StackName, `HelloWorld`) || contains(StackName, `CDK`)].{Name:StackName,Status:StackStatus}'

2.2 Force Delete Remaining Stacks

# Delete any remaining HelloWorld stacks
aws cloudformation delete-stack --stack-name HelloWorld-prod
aws cloudformation delete-stack --stack-name HelloWorld-staging
aws cloudformation delete-stack --stack-name HelloWorld-dev
aws cloudformation delete-stack --stack-name HelloWorld-shared

# Wait for deletion to complete
aws cloudformation wait stack-delete-complete --stack-name HelloWorld-prod
aws cloudformation wait stack-delete-complete --stack-name HelloWorld-staging
aws cloudformation wait stack-delete-complete --stack-name HelloWorld-dev
aws cloudformation wait stack-delete-complete --stack-name HelloWorld-shared

# If needed, delete CDK bootstrap stack (ONLY if not used elsewhere)
# aws cloudformation delete-stack --stack-name CDKToolkit

Phase 3: Account-by-Account Resource Cleanup

3.1 Switch to Each Account and Clean Up

For each workload account (dev, staging, prod, shared), you need to:

# Method 1: If you have cross-account roles set up
aws sts assume-role \
    --role-arn "arn:aws:iam::ACCOUNT-ID:role/OrganizationAccountAccessRole" \
    --role-session-name "cleanup-session"

# Method 2: Use separate AWS profiles for each account
aws configure set profile.dev.region us-east-1  # or ap-southeast-1 for Singapore
aws configure set profile.dev.account ACCOUNT-ID

# For each account, check for remaining resources:
aws --profile dev lambda list-functions
aws --profile dev apigatewayv2 get-apis
aws --profile dev logs describe-log-groups
aws --profile dev cloudformation list-stacks

3.2 Manual Resource Cleanup (If CDK Destroy Failed)

# Clean up Lambda functions
aws lambda list-functions --query 'Functions[?contains(FunctionName, `HelloWorld`) || contains(FunctionName, `Health`)].FunctionName' --output text | xargs -r -n1 aws lambda delete-function --function-name

# Clean up API Gateways
aws apigatewayv2 get-apis --query 'Items[?contains(Name, `Hello World`)].ApiId' --output text | xargs -r -n1 aws apigatewayv2 delete-api --api-id

# Clean up Log Groups
aws logs describe-log-groups --query 'logGroups[?contains(logGroupName, `hello-world`)].logGroupName' --output text | xargs -r -n1 aws logs delete-log-group --log-group-name

# Clean up IAM roles (created by CDK)
aws iam list-roles --query 'Roles[?contains(RoleName, `HelloWorld`)].RoleName' --output text | xargs -r -n1 aws iam delete-role --role-name

Phase 4: Control Tower Teardown

4.1 Decommission Landing Zone

⚠️ CRITICAL: This will delete ALL accounts created by Control Tower!

# Check Control Tower status first
aws controltower list-landing-zones

# Get the landing zone identifier
LANDING_ZONE_ID=$(aws controltower list-landing-zones --query 'landingZones[0].arn' --output text)

echo "Found Landing Zone: $LANDING_ZONE_ID"

# Initiate landing zone deletion (THIS IS IRREVERSIBLE!)
aws controltower delete-landing-zone --landing-zone-identifier $LANDING_ZONE_ID

# Monitor deletion progress
aws controltower get-landing-zone-operation --operation-identifier OPERATION-ID

4.2 Manual Control Tower Teardown (Alternative)

If CLI method fails, use AWS Console:

  1. Go to Control Tower Console

  2. Navigate to Landing Zone Settings

    • Click "Landing zone settings" in left sidebar
    • Click "Delete landing zone"
  3. Confirm Deletion

    • Type "delete" to confirm
    • Wait 30-60 minutes for complete deletion

Phase 5: Account Cleanup

5.1 Handle Created Accounts

Control Tower created these accounts that need manual closure:

  • Development account (your-email+dev@gmail.com)
  • Staging account (your-email+staging@gmail.com)
  • Production account (your-email+prod@gmail.com)
  • Shared Services account (your-email+shared@gmail.com)
  • Audit account (your-email+audit@gmail.com)
  • Log Archive account (your-email+logs@gmail.com)

5.2 Close AWS Accounts

For each created account:

  1. Sign in to each account separately

    • Use the email address for that account
    • Reset password if needed
  2. Close the account

  3. Alternative: Remove from Organization

    # From your management account
    aws organizations list-accounts
    aws organizations remove-account-from-organization --account-id ACCOUNT-ID
    

Phase 6: Final Cleanup

6.1 Clean Up Management Account

# Remove any remaining CloudFormation stacks
aws cloudformation list-stacks --query 'StackSummaries[?StackStatus!=`DELETE_COMPLETE`].StackName' --output text

# Clean up Service Catalog (if Control Tower used it)
aws servicecatalog list-portfolios
aws servicecatalog list-products

# Clean up Config rules (created by Control Tower)
aws configservice describe-configuration-recorders
aws configservice describe-delivery-channels

# Clean up CloudTrail (created by Control Tower)
aws cloudtrail describe-trails

6.2 Clean Up Local Environment

# Remove project directory
cd ..
rm -rf simple-control-tower-cdk

# Clean up AWS credentials (optional)
aws configure list-profiles
# Remove specific profiles if needed:
# aws configure --profile dev remove region
# aws configure --profile staging remove region
# etc.

# Clean up CDK global installation (optional)
npm uninstall -g aws-cdk

Phase 7: Verification

7.1 Verify Complete Cleanup

# Check for any remaining resources
aws cloudformation list-stacks --query 'StackSummaries[?StackStatus!=`DELETE_COMPLETE`]'
aws lambda list-functions
aws apigatewayv2 get-apis
aws logs describe-log-groups --query 'logGroups[?contains(logGroupName, `hello-world`)]'

# Check Control Tower status
aws controltower list-landing-zones

# Check organizations
aws organizations list-accounts

7.2 Cost Verification

  1. Check AWS Cost Explorer

  2. Check each account's billing

    • Sign into each account before closure
    • Verify $0 balance
    • Download final invoices if needed

Emergency: If Something Goes Wrong

Force Delete Everything

#!/bin/bash
# Nuclear option - use with extreme caution

echo "🚨 EMERGENCY FORCE CLEANUP - THIS WILL DELETE EVERYTHING!"
read -p "Are you sure? Type 'DESTROY EVERYTHING' to continue: " confirm

if [ "$confirm" = "DESTROY EVERYTHING" ]; then
    # Force delete all CloudFormation stacks
    aws cloudformation list-stacks --query 'StackSummaries[?StackStatus!=`DELETE_COMPLETE`].StackName' --output text | xargs -r -n1 aws cloudformation delete-stack --stack-name

    # Force delete all Lambda functions
    aws lambda list-functions --query 'Functions[].FunctionName' --output text | xargs -r -n1 aws lambda delete-function --function-name

    # Force delete all API Gateways
    aws apigatewayv2 get-apis --query 'Items[].ApiId' --output text | xargs -r -n1 aws apigatewayv2 delete-api --api-id

    # Force delete log groups
    aws logs describe-log-groups --query 'logGroups[].logGroupName' --output text | xargs -r -n1 aws logs delete-log-group --log-group-name

    echo "πŸ”₯ Emergency cleanup complete!"
else
    echo "❌ Emergency cleanup cancelled"
fi

Summary Checklist

  • CDK Stacks Destroyed (cdk destroy --all --force)
  • CloudFormation Stacks Deleted (Manual verification)
  • Resources Cleaned Per Account (Lambda, API Gateway, Logs)
  • Control Tower Landing Zone Deleted (Console or CLI)
  • AWS Accounts Closed (6 created accounts)
  • Management Account Cleaned (Config, CloudTrail, etc.)
  • Local Project Removed (rm -rf simple-control-tower-cdk)
  • Costs Verified ($0 across all accounts)
  • Profiles Cleaned (Optional AWS CLI cleanup)

Total Estimated Time: 2-4 hours (including account closure waiting periods)

πŸ’° Final Cost Check: After 24-48 hours, verify $0 charges across all accounts.


⚠️ Remember: Account closure has a 90-day cooling period. You may see the accounts in a "suspended" state during this time, but they won't incur charges.