DEV Community

Rakan Nimer
Rakan Nimer

Posted on

Emptying and Deleting Multiple S3 Buckets with the AWS JS SDK

At the time of writing, to empty and delete an S3 bucket from the AWS console you would have to click through 2 confirmations and type the name of the bucket to confirm that you know you are doing a non-reversible operation.

I have a lot of buckets in my S3 (4 pages worth) and needed to delete most of them. Instead of doing that manually from the console, I opted to do it programmatically. This post walks the reader through the steps needed to write a helper node scripts with the AWS SDK.

Permissions Setup

  1. Download/Update your AWS CLI here : https://aws.amazon.com/cli/

  2. Tell the cli about the AWS credentials that you want to use.

You can do this in several ways but the quickest way is to use the aws configure command.

# You can omit the --profile s3 part 
# and configure the default usser
$ aws configure --profile s3
AWS Access Key ID: foo
AWS Secret Access Key: bar
Default region name [us-west-2]: us-west-2
Default output format [None]: json

To get an access key and a secret access key, go to the user section of IAM from your AWS console and then add a new user with programmatic access to S3 with full read and write permissions.

Set user details :

Set user details

Set user permissions :

Set user permissions

You can now click on next until the user is created and an access key and secret access key are shown.

View user IAM keys

We can use those keys with the configure command above to finish configuration

Using the AWS JS SDK

To do the operations we will be using the AWS JS SDK with NodeJS.

We want the tool to :

  1. List all buckets.
  2. Allow the user to pick the buckets they would like to delete.
  3. On submit it would iterate through the selected buckets and delete them one by one.

If you'd like to use the tool without caring about how it's done, you can use this one-liner:

git clone https://github.com/rakannimer/s3-bucket-deleter && cd s3-bucket-deleter && npm i && npm run start

For the rest of us, let's start by creating a project :

mkdir s3-deleter
cd s3-deleter
npm init -y
# aws-sdk3 is in developer preview at time of writing 
# fixing it to version 2 is used to future-proof this article 
# in case it's not updated when aws-sdk@3 is released
npm install aws-sdk@2
# to display a nice looking prompt
npm install enquirer
touch s3.js
code s3.js

In package.json we'll add a start script that will run the code in s3.js

{
  "name": "s3-deleter",
  "version": "1.0.0",
  "description": "Empty and delete multiple S3 buckets",
  "main": "s3.js",
  "scripts": {
    "start": "node s3.js"
  },
  "dependencies": {
    "aws-sdk": "^2.649.0",
    "enquirer": "^2.3.4"
  }
}

And the main code with npm start :

// These 3 lines are not necessary if you're using the default aws profile
const AWS = require("aws-sdk");
var credentials = new AWS.SharedIniFileCredentials({ profile: "s3" });
AWS.config.credentials = credentials;

const S3 = require("aws-sdk/clients/s3");
const s3 = new S3();

const { MultiSelect } = require("enquirer");

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

const deleteBucket = async Bucket => {
  try {
    console.log(`Deleting ${Bucket}`);
    // We can't delete a bucket before emptying its contents
    const { Contents } = await s3.listObjects({ Bucket }).promise();
    if (Contents.length > 0) {
      await s3
        .deleteObjects({
          Bucket,
          Delete: {
            Objects: Contents.map(({ Key }) => ({ Key }))
          }
        })
        .promise();
    }
    await s3.deleteBucket({ Bucket }).promise();
    return true;
  } catch (err) {
    console.log("\n", err, "\n");
    return false;
  }
};

const main = async () => {
  const { Buckets } = await s3.listBuckets().promise();
  const choices = Buckets.map(({ Name }) => ({ name: Name, value: Name }));
  const prompt = new MultiSelect({
    name: "value",
    message: "Select the buckets you would like to delete",
    choices
  });

  const bucketsToDelete = await prompt.run();
  let deletedBuckets = 0;
  for (let bucket of bucketsToDelete) {
    await delay(200);
    const isDeleted = await deleteBucket(bucket);
    deletedBuckets += isDeleted ? 1 : 0;
  }
  console.log(
    `\nDeleted ${deletedBuckets}/${bucketsToDelete.length} buckets.\n`
  );
};

main();

And we're ready to run it :
Demo part 1
Demo part 2

👋

Discussion (0)