Amazon S3 — MFA Delete

Alvin Lucillo
Nullify
Published in
4 min readMay 17, 2023

In managing files on S3, it is important to know how to prevent accidental and malicious deletions, especially since there are a lot of ways it can happen, manually (console/CLI) or programmatically (SDK). Let’s say you have a bucket where every member of your team can upload sensitive, audit-related files but can’t permanently delete them. You want to achieve two things: prevent yourself from accidentally deleting files permanently and protect the files in case someone gets hold of your credentials. You can use the MFA Delete feature of S3 as it ensures that you, the bucket owner, can only delete “versions” of the files.

In S3, when you upload a file with the same name as the existing object on the bucket, a new version is created. The same happens when you delete an object; a new version of type Delete marker is created. The object is not permanently deleted and can be recovered by deleting the Deleting marker. But what if you deleted the only version of your object? Then, you can’t recover the object anymore. Note that versioning is only possible if Bucket Versioning is enabled on your bucket.

MFA Delete In Action

Let’s see this feature in action. So, we have test-bucket-personal-1 as our example bucket. Running the CLI command below tells us that its bucket versioning and MFA delete features are enabled.

Note: I have configured the CLI to use the root account.

aws s3api get-bucket-versioning — bucket test-bucket-personal-1

{
"Status": "Enabled",
"MFADelete": "Enabled"
}

The CLI command below shows us the different versions of the terraform.json object

aws s3api list-object-versions — bucket test-bucket-personal-1 — prefix terraform.json

{
"Versions": [
{
"ETag": "\"cb16cbfe7709d5076427e97e099a1148\"",
"Size": 26304,
"StorageClass": "STANDARD",
"Key": "terraform.json",
"VersionId": "hTgoFm143hwc7jEgiJrKdTp6z0RMjtus",
"IsLatest": false,
"LastModified": "2023-05-17T11:24:16+00:00"
},
{
"ETag": "\"cb16cbfe7709d5076427e97e099a1148\"",
"Size": 26304,
"StorageClass": "STANDARD",
"Key": "terraform.json",
"VersionId": "0XcD655XhcLPxbPfeFxcVzXgMLhiSG.5",
"IsLatest": false,
"LastModified": "2023-05-17T05:41:28+00:00"
}
],
"DeleteMarkers": [
{
"Key": "terraform.json",
"VersionId": "9o9PZMX9DFHbqC9871NtitMOKYg6qtwe",
"IsLatest": true,
"LastModified": "2023-05-17T11:24:35+00:00"
}
]
}

The delete marker is the latest version. In an MFA-enabled bucket, let’s try to delete the original version, hTgoFm143hwc7jEgiJrKdTp6z0RMjtus.

aws s3api delete-object — bucket test-bucket-personal-1 — version-id hTgoFm143hwc7jEgiJrKdTp6z0RMjtus — key terraform.json

An error occurred (AccessDenied) when calling the DeleteObject operation: Mfa Authentication must be used for this request

Deleting a version requires MFA authentication. Now, this is where the feature helps not only with accidental deletion but also prevention of malicious deletion with another security layer.

How about with unauthorized users? Let’s use a different account (i.e., non-bucket owner, non-root).

An error occurred (AccessDenied) when calling the DeleteObject operation: Mfa Authentication must be used for this request

It showed the same error. Let’s try to add the MFA code generated for this account.

aws s3api delete-object — bucket test-bucket-personal-1 — version-id hTgoFm143hwc7jEgiJrKdTp6z0RMjtus — key terraform.json — mfa “arn:aws:iam::000000001234:mfa/non-root-acct-device 400001”

An error occurred (AccessDenied) when calling the DeleteObject operation: This operation may only be performed by the bucket owner

Now, it tells us that it requires the bucket owner to do the operation. Notice that we used the — mfaparameter to provide the MFA code. Since the account is not the bucket owner, the operation can’t proceed. How do we check the bucket owner of a bucket?

aws s3api get-bucket-acl — bucket test-bucket-personal-1

{
"Owner": {
"DisplayName": "[redacted]",
"ID": "[redacted]"
},
"Grants": [
{
"Grantee": {
"DisplayName": "[redacted]",
"ID": "[redacted]",
"Type": "CanonicalUser"
},
"Permission": "FULL_CONTROL"
}
]
}

That tells us who can delete an object’s version of an MFA-enabled bucket.

Using the bucket owner’s account, deleting the version should be successful.

aws s3api delete-object — bucket test-bucket-personal-1 -version-id hTgoFm143hwc7jEgiJrKdTp6z0RMjtus — key terraform.json -mfa “arn:aws:iam::000000001234:mfa/root-account-device 983519”

{
"VersionId": "hTgoFm143hwc7jEgiJrKdTp6z0RMjtus"
}

The version deletion is successful if it returns the same version ID it attempts to delete.

Enabling MFA Delete

aws s3api put-bucket-versioning — bucket test-bucket-personal-1 — versioning-configuration Status=Enabled,MFADelete=Enabled — mfa “arn:aws:iam::000000001234:mfa/root-account-device 050748”

Note that only the bucket owner can enable or disable the MFA Delete feature, and use the MFA device’s ARN on the CLI command found on the IAM page.

--

--

Alvin Lucillo
Nullify
Editor for

Software engineer, writer, self-taught pianist, and a lifelong learner