Drift-aware change sets are a newer CloudFormation feature that solves a quiet but serious problem: **traditional change sets compare templates, not reality**. If someone made an out-of-band change to a resource (incident response, a console fix), a normal change set won't see it — and on execute, it silently reverts the live change.
## Two-way vs three-way comparison
**Traditional change sets** (two-way): `previous template` ↔ `new template`. Drift is invisible.
**Drift-aware change sets** (three-way): `actual live state` ↔ `previous deployment state` ↔ `new desired state`. CFN reads each resource's live config via the underlying service APIs at change set creation time.
## What this enables
| Capability | Traditional | Drift-aware |
|------------|-------------|-------------|
| See what the deployment will overwrite | Template diff only | Live-resource diff |
| Reset drift without modifying resource | No | Yes — update template to match actual, drift status clears |
| Rollback target on failure | Previous template state | **Actual pre-deployment state** |
| Preserve out-of-band incident fixes | No | Yes (when appropriate) |
| Three-way visibility on all properties | No | Yes |
The rollback-target shift is the biggest operational win. Traditional change sets, on failure, roll back to whatever the *template* said before — overwriting any in-flight live changes. Drift-aware preserves what was actually there.
## How CFN classifies "out-of-band" changes
Not all drift is bad. Drift-aware change sets distinguish:
- **AWS-managed properties** — left alone if you didn't touch them in the template
- `AWS::RDS::DBInstance` `EngineVersion` (when AutoMinorVersionUpgrade is on)
- `AWS::ApplicationAutoScaling::ScalableTarget` (DynamoDB capacity, ECS desired count)
- `AWS::AutoScaling::ScalingPolicy` settings
- **Write-only properties** (passwords, secrets) — compared against previous deployment, not live (live values aren't returned by services)
- **External tag keys** — preserved if not specified in template (protects ABAC systems)
## CLI invocation
```bash
aws cloudformation create-change-set \
--stack-name my-stack \
--change-set-name my-drift-aware-changeset \
--template-body file://updated-template.yaml \
--deployment-mode REVERT_DRIFT \
--capabilities CAPABILITY_IAM
```
The `--deployment-mode REVERT_DRIFT` flag is the toggle. Without it, you get a traditional change set.
## Reading the output
`describe-change-set` adds these fields:
- `StackDriftStatus`: `DRIFTED` / `IN_SYNC` / `NOT_CHECKED` / `UNKNOWN`
- `ResourceDriftStatus`: per resource — `DELETED` / `MODIFIED` / `IN_SYNC` / `NOT_CHECKED`
- `BeforeValueFrom`: `ACTUAL_STATE` or `PREVIOUS_DEPLOYMENT_STATE` — tells you whether the "before" value in a property diff comes from live config or last template
- `Drift`: object with `PreviousValue`, `ActualValue`, `DriftDetectionTimestamp`
- `ResourceDriftIgnoredProperties`: properties where drift is intentionally not reverted, with reasons (AWS-managed, ABAC tag, etc.)
## Limitations
- Resource-type support is broad but not universal; unsupported types fall back to two-way comparison
- Immutable properties (those that require replacement) cannot be drift-reconciled — replacement is the only path
- Cross-stack attachments (an `IAM::Policy` in stack A modifying an `IAM::Role` in stack B) are detected as drift in B and may be reverted
## When to default to drift-aware
For any production stack with any non-trivial operational history. The cost is one extra CLI flag; the benefit is never silently overwriting an incident fix.
## Related
- [[CFN Change Sets Preview-Execute]]
- [[CFN Drift Detection Mechanics and Limits]]
- [[CFN Failure Rollback Behavior]]