Skip to content

Instantly share code, notes, and snippets.

@breser
Last active February 19, 2021 02:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save breser/db04b5653685801011906ee801a528d0 to your computer and use it in GitHub Desktop.
Save breser/db04b5653685801011906ee801a528d0 to your computer and use it in GitHub Desktop.
remove_unused_default_vpcs.sh
#!/bin/bash
# Delete Default VPCs
# Deletes Default VPCs across an entire organization if there are no ENIs in
# the default VPC.
#
# Assumes that ~/.aws/credentials has credentials to the root account for the
# AWS Organization. Assumes that the user/role you're logged into in the
# root account has permissions to assume the OrganizationAccountAccessRole in
# each member account. Requires jq and aws cli be installed on the path.
# Copyright (c) 2020 Vibes Media LLC
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
function assume_role {
local role="$1"
local results=$(aws sts assume-role --role-arn "$role" \
--role-session-name "rmunusedvpcs-$(date +%Y%m%d%H%M%S)")
if [ $? -ne 0 ]; then
printf "%s\n" "$results" >&2
exit 1
fi
export AWS_SECRET_ACCESS_KEY=$(printf "%s" "$results" | \
jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(printf "%s" "$results" | \
jq -r '.Credentials.SessionToken')
export AWS_ACCESS_KEY_ID=$(printf "%s" "$results" | \
jq -r '.Credentials.AccessKeyId')
}
function drop_role {
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN
unset AWS_ACCESS_KEY_ID
}
# Find the account id for the organization account
org_account_id=$(aws sts get-caller-identity --query Account --output text)
if [ $? -ne 0 ]; then
printf "%s\n" "$master_account_id" >&2
exit 1
fi
# Find all the account ids in the organization while handling pagination
account_ids=''
next=''
while true; do
results=$(aws organizations list-accounts $next)
if [ $? -ne 0 ]; then
printf "%s\n" "$results" >&2
exit 1
fi
next_token=$(printf "%s" "$results" | jq -r '.NextToken')
account_ids="${account_ids} $(printf "%s" "$results" | jq -r '.Accounts[].Id')"
if [ "$next_token" != "null" ]; then
printf -v next -- "--starting-token %q" "$next_token"
else
break
fi
done
for account_id in $account_ids; do
printf "AccountId %s\n" "$account_id"
# only assume_role for an account different than our starting account
if [ "$account_id" != "$org_account_id" ]; then
assume_role "arn:aws:iam::${account_id}:role/OrganizationAccountAccessRole"
fi
# find the account alias which we will use for account name
account_name=$(aws iam list-account-aliases --query AccountAliases[0] --output text)
if [ $? -ne 0 ]; then
printf "%s\n" "$account_name" >&2
exit 1
fi
printf "AccountName %s\n" "$account_name"
# Determine the regions available in the account
regions=$(aws ec2 describe-regions --query 'Regions[*].RegionName' \
--output text)
if [ $? -ne 0 ]; then
printf "%s\n" "$regions" >&2
exit 1
fi
for region in $regions; do
printf "Region: %s\n" "${region}"
default_vpc=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query 'Vpcs[*].VpcId' --output text --region "${region}")
if [ -z "${default_vpc}" ]; then
printf "No Default VPC found\n"
continue
fi
printf "DefaultVpcId %s\n" "$default_vpc"
enis=$(aws ec2 describe-network-interfaces --filters "Name=vpc-id,Values=${default_vpc}" --query NetworkInterfaces --region "${region}")
if [ "${enis}" == '[]' ]; then
# No ENIs so VPC is unused
igw=$(aws ec2 describe-internet-gateways --filter "Name=attachment.vpc-id,Values=${default_vpc}" --query InternetGateways[0].InternetGatewayId --output text --region "${region}")
if [ "${igw}" != "None" ]; then
aws ec2 detach-internet-gateway --internet-gateway-id "${igw}" --vpc-id "${default_vpc}" --region "${region}"
aws ec2 delete-internet-gateway --internet-gateway-id "${igw}" --region "${region}"
fi
subnets=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=${default_vpc}" --query Subnets[*].SubnetId --output text --region "${region}")
for subnet in ${subnets}; do
aws ec2 delete-subnet --subnet-id "${subnet}" --region "${region}"
done
aws ec2 delete-vpc --vpc-id "${default_vpc}" --region "${region}"
else
printf "ENIs found, DefaultVpc appears to be in use\n"
fi
done
drop_role
printf "\n"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment