TL;DR
Use separate AWS sub-accounts for critical data storage and implement cross-account IAM roles to control access. This prevents accidental deletion of versioned S3 objects even if the main account is compromised or a user makes an error.
Solution Guide: Protecting S3 Versioned Data with Sub-Accounts
- Create Dedicated Sub-Accounts
- For each critical dataset, create a separate AWS sub-account. This isolation is key.
- Name accounts descriptively (e.g., ‘DataArchive-ProjectX’, ‘BackupStorage’).
- Enable Versioning in S3
- Within each sub-account, create an S3 bucket for the relevant data.
- Crucially, enable versioning on these buckets. This is your primary safety net against accidental deletion. You can do this via the AWS Management Console or using the CLI:
- Configure Cross-Account IAM Roles
- In the main account, create an IAM role that grants limited access to the S3 buckets in the sub-accounts. This is how users will interact with the data.
- The policy attached to this role should only allow necessary actions (e.g.,
s3:GetObject,s3:ListBucket). Do not includes3:DeleteObjectors3:DeleteBucket! - Trust Relationship for the IAM Role
- The trust relationship of the IAM role in the main account should allow the sub-account to assume it. This is what enables cross-account access.
- Accessing Data from the Main Account
- Users in the main account assume the IAM role to access data in the sub-accounts. This is typically done using the AWS CLI or SDKs.
- Multi-Factor Authentication (MFA)
- Enforce MFA for all IAM users in the main account, especially those with permissions to assume roles granting access to sensitive data.
- Regular Auditing and Monitoring
- Use AWS CloudTrail to monitor API calls made to S3 buckets in both accounts.
- Set up alerts for any suspicious activity, such as attempts to delete objects or modify bucket policies.
- Implement Bucket Policies (Optional)
- Consider adding explicit deny statements to the sub-account’s bucket policy to further restrict access and prevent accidental deletions from within that account itself. This is a defense in depth measure.
aws s3api put-bucket-versioning --bucket your-bucket-name --versioning-configuration Status=Enabled
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::your-bucket-name/*", "arn:aws:s3:::your-bucket-name" ] } ]}
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::your-sub-account-id:root" }, "Action": "sts:AssumeRole", "Condition": {} } ]}
aws sts assume-role --role-arn arn:aws:iam::your-main-account-id:role/YourCrossAccountRole --role-session-name CrossAccountSession

