---
title: "Protect resources that hold data · Agent Wranglers"
url: https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code/protect-stateful-resources
updated: 2026-10-20
licence: "All rights reserved"
---

# Protect resources that hold data

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Infrastructure as code](https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code)
- Rule: Turn on deletion protection for every database, bucket and disk that holds data. Stop any plan that deletes or replaces one until a second person approves.
- How: Set the provider's own protection, such as `deletion_protection` on databases, and `prevent_destroy` in the code. A renamed resource or a changed setting can mean "destroy and create", which loses the data. Read the plan as JSON in CI, and fail it when a protected type has `delete` among its actions. Backups are a separate safety net, as in the [operations playbook](https://agentwranglers.se/playbook/operations/disaster-recovery/off-site-backups).
- Check: Change a database's name in a branch. The CI plan step fails and names the resource. In the cloud, a delete call on the production database is refused.

Example:

```hcl
resource "aws_db_instance" "orders" {
  identifier          = "shop-orders"
  deletion_protection = true
  lifecycle {
    prevent_destroy = true
  }
}
```

```js
// node check-plan.mjs plan.json, after: tofu show -json release.tfplan > plan.json
import { readFileSync } from 'node:fs';

const PROTECTED_TYPES = new Set(['aws_db_instance', 'aws_s3_bucket', 'aws_ebs_volume']);
const plan = JSON.parse(readFileSync(process.argv[2], 'utf8'));
const losses = plan.resource_changes.filter(change => PROTECTED_TYPES.has(change.type) && change.change.actions.includes('delete'));
for (const change of losses) console.error(`Would delete ${change.address}`);
process.exit(losses.length ? 1 : 0);
```

```python
# python check_plan.py plan.json
import json, sys

PROTECTED_TYPES = {"aws_db_instance", "aws_s3_bucket", "aws_ebs_volume"}
plan = json.load(open(sys.argv[1]))
losses = [c for c in plan["resource_changes"] if c["type"] in PROTECTED_TYPES and "delete" in c["change"]["actions"]]
for change in losses:
    print(f"Would delete {change['address']}", file=sys.stderr)
sys.exit(1 if losses else 0)
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code/protect-stateful-resources`.

- Previous: [Detect drift every day](https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code/drift-detection)
- Next: [Bring hand-made resources under code](https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code/import-existing-resources)
- [Infrastructure as code](https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code)
