Recovering Deleted S3 Files: A Step-by-Step Guide Using S3 Versioning
Accidentally deleting a critical file from S3 is a common operational nightmare — but if you had S3 Versioning enabled on the bucket, that file is not gone. It's hidden behind a Delete Marker, and recovery is a deterministic, reversible operation.
TL;DR
| Step | Action | Tool |
|---|---|---|
| 1 | Confirm versioning is enabled on the bucket | Console / CLI |
| 2 | List all versions to find the Delete Marker | CLI / Console |
| 3 | Identify the last valid version ID before deletion | CLI / Console |
| 4 | Delete the Delete Marker to restore the object | CLI / Console |
| 5 | Verify the object is accessible again | CLI / Console |
How S3 Versioning Works Under the Hood
When versioning is enabled, S3 never truly overwrites or deletes an object. Every PUT creates a new version. A DELETE request (without specifying a version ID) does not remove any data — it inserts a special object called a Delete Marker as the current version. This marker causes S3 to return a 404 Not Found for standard GET requests, making the object appear deleted to applications.
Analogy: Think of S3 Versioning like a filing cabinet where you never throw away documents — you just place a red "REMOVED" sticky note on top of the stack. The file is still there; you just need to peel off the sticky note to see it again.
Architecture: What Happens During a Delete and Restore
- Normal GET: The client requests the object. S3 serves the current (latest) version.
- Unversioned DELETE: The client sends a
DELETEwithout a version ID. S3 inserts a Delete Marker as the new current version. No data is removed. - GET after DELETE: S3 sees the Delete Marker as the current version and returns
404 Not Foundto the client. - Restore (Delete the Delete Marker): The operator explicitly deletes the Delete Marker by specifying its version ID. S3 removes the marker, promoting the previous real version back to current.
- GET after Restore: S3 now serves the restored object version successfully.
Step-by-Step Recovery Guide
Step 1: Confirm Versioning Is Enabled
Before anything else, verify the bucket has versioning in an Enabled state (not Suspended).
aws s3api get-bucket-versioning \
--bucket your-bucket-name
Expected output:
{
"Status": "Enabled"
}
If the output is empty or shows Suspended, versioning was not active when the delete occurred, and the data is unrecoverable via this method.
Step 2: List All Versions of the Deleted Object
Use list-object-versions to see every version and every Delete Marker for the specific key.
aws s3api list-object-versions \
--bucket your-bucket-name \
--prefix "path/to/your-file.txt"
🔽 [Click to expand] — Example output
{
"Versions": [
{
"ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
"Size": 1024,
"StorageClass": "STANDARD",
"Key": "path/to/your-file.txt",
"VersionId": "abc123XYZ_previous_version",
"IsLatest": false,
"LastModified": "2024-01-10T10:00:00.000Z"
}
],
"DeleteMarkers": [
{
"Owner": { "DisplayName": "your-account" },
"Key": "path/to/your-file.txt",
"VersionId": "def456UVW_delete_marker",
"IsLatest": true,
"LastModified": "2024-01-15T14:30:00.000Z"
}
]
}
From this output, identify two critical values:
- Delete Marker Version ID (
IsLatest: trueinDeleteMarkers):def456UVW_delete_marker - Last Valid Version ID (
IsLatest: falseinVersions):abc123XYZ_previous_version
Step 3: Restore by Deleting the Delete Marker
To restore the object, you must permanently delete the Delete Marker by specifying its exact VersionId. This is a permanent action on the marker itself.
aws s3api delete-object \
--bucket your-bucket-name \
--key "path/to/your-file.txt" \
--version-id "def456UVW_delete_marker"
A successful response returns the version ID of the deleted marker and a DeleteMarker: true flag, confirming you removed a marker (not actual data).
Step 4: Verify the Object Is Restored
aws s3api head-object \
--bucket your-bucket-name \
--key "path/to/your-file.txt"
A 200 OK response with object metadata confirms the file is accessible again. The previous version is now the current version.
Alternative: Restore a Specific Older Version
If you need to restore a version that is not the most recent one (e.g., you want to roll back two versions), copy that specific version over itself. This creates a new current version with the content of the old one.
aws s3api copy-object \
--bucket your-bucket-name \
--copy-source "your-bucket-name/path/to/your-file.txt?versionId=abc123XYZ_previous_version" \
--key "path/to/your-file.txt"
This is the safest restore pattern — it is non-destructive and creates an auditable version history.
Doing This in the AWS Console
- Navigate to your S3 bucket in the AWS Console.
- Browse to the folder containing the deleted file.
- Toggle "Show versions" in the top-right of the object list. Delete Markers will appear with a "Delete marker" badge.
- Select the Delete Marker for your file and click Delete.
- Confirm the permanent deletion of the marker. The object is now restored.
IAM Permissions Required
The operator performing the restore needs the following minimum permissions. Note that deleting a specific version (including a Delete Marker) requires s3:DeleteObjectVersion, which is a separate and more privileged action than s3:DeleteObject.
🔽 [Click to expand] — Least-privilege IAM policy for S3 restore
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3VersionRestore",
"Effect": "Allow",
"Action": [
"s3:ListBucketVersions",
"s3:GetBucketVersioning",
"s3:GetObjectVersion",
"s3:DeleteObjectVersion",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}
Prevention: Best Practices Going Forward
- Enable MFA Delete: Requires multi-factor authentication to permanently delete object versions or change versioning state. This prevents accidental or malicious permanent deletions.
- S3 Object Lock: For compliance-critical data, use Object Lock in GOVERNANCE or COMPLIANCE mode to make objects immutable for a defined retention period.
- S3 Lifecycle Policies: Configure lifecycle rules to automatically expire old versions after a defined period to manage storage costs from accumulated versions.
- Bucket Policies: Restrict
s3:DeleteObjectVersionto a break-glass IAM role to minimize the blast radius of accidental permanent deletions.
Glossary
| Term | Definition |
|---|---|
| Delete Marker | A placeholder object inserted by S3 when a versioned object is deleted without specifying a version ID. It has no data and causes GET requests to return 404. |
| Version ID | A unique string assigned by S3 to each version of an object when versioning is enabled. |
| MFA Delete | An S3 bucket feature that requires MFA authentication to permanently delete object versions or suspend versioning. |
| S3 Object Lock | A feature that prevents object versions from being deleted or overwritten for a fixed amount of time or indefinitely. |
| IsLatest | A boolean field in the list-object-versions API response indicating whether a version is the current (most recent) version of an object. |
Next Steps
Enable versioning on all production S3 buckets today — it is a zero-cost configuration change that provides a critical safety net. Review the official AWS documentation for S3 Versioning and MFA Delete to harden your data protection posture further.
Comments
Post a Comment