Auto-Reconcile Policy
An auto-reconcile policy automatically enforces a stack's declared state at regular intervals. When attached to a stack, formae periodically re-applies the last reconciled configuration, undoing any out-of-band changes or patches made since the last reconciliation.
How It Works
When you attach an auto-reconcile policy to a stack:
- formae records the declared state after each successful reconcile
- At the configured interval, it compares the current state to the last reconciled state
- If these deviate is detected, formae automatically applies a reconcile command to restore the declared state
The interval timer starts after each reconcile completes, ensuring consistent spacing between reconciliations regardless of how long each one takes.
Configuration
An auto-reconcile policy has one setting:
| Property | Type | Description |
|---|---|---|
interval |
Duration | How often to reconcile (e.g., 5.min, 1.h) |
Out-of-band And Incremental Changes and Auto-Reconcile
formae detects changes to your infrastructure through synchronization. These are changes made through the cloud console or other tools (out-of-band changes) or through formae patches (incremental changes).
Without auto-reconcile, you control what happens to these changes on your next apply:
- Keep the changes: Accept the out-of-band and incremental changes and update your infrastructure code
- Overwrite them: Revert to your declared state
With auto-reconcile, such changes are automatically undone at the configured interval. This is useful when you want to enforce strict compliance with your declared configuration.
Tip: Auto-reconcile works well for production stacks where configuration consistency is critical. For development environments where you want flexibility for experimentation, consider not using auto-reconcile.
Examples
Inline Auto-Reconcile Policy
Define the policy directly in the stack:
amends "@formae/forma.pkl"
import "@formae/formae.pkl"
import "@aws/aws.pkl"
import "@aws/ec2/securitygroup.pkl"
local prodTarget = new formae.Target {
label = "prod-target"
config = new aws.Config {
region = "us-east-1"
}
}
forma {
prodTarget
new formae.Stack {
label = "production-networking"
description = "Production network security - auto-enforced"
policies = new Listing {
new formae.AutoReconcilePolicy {
interval = 5.min // Re-enforce every 5 minutes
}
}
}
new securitygroup.SecurityGroup {
label = "api-sg"
stack = "production-networking"
target = prodTarget.res
groupDescription = "API security group - managed by formae"
securityGroupIngress = new Listing {
new {
ipProtocol = "tcp"
fromPort = 443
toPort = 443
cidrIp = "0.0.0.0/0"
}
}
}
}
Reusable Auto-Reconcile Policy
Share the same reconciliation interval across multiple production stacks:
amends "@formae/forma.pkl"
import "@formae/formae.pkl"
import "@aws/aws.pkl"
import "@aws/s3/bucket.pkl"
// Reusable policy for all production stacks
local prodReconcile = new formae.AutoReconcilePolicy {
label = "prod-reconcile-5m"
interval = 5.min
}
local prodTarget = new formae.Target {
label = "prod-target"
config = new aws.Config {
region = "us-east-1"
}
}
forma {
prodReconcile
prodTarget
new formae.Stack {
label = "prod-storage"
description = "Production storage infrastructure"
policies = new Listing { prodReconcile.res }
}
new bucket.Bucket {
label = "prod-data"
stack = "prod-storage"
target = prodTarget.res
bucketName = "company-prod-data"
}
new formae.Stack {
label = "prod-logging"
description = "Production logging infrastructure"
policies = new Listing { prodReconcile.res }
}
new bucket.Bucket {
label = "prod-logs"
stack = "prod-logging"
target = prodTarget.res
bucketName = "company-prod-logs"
}
}
Combining TTL and Auto-Reconcile
Use both policies together for controlled, consistent environments:
amends "@formae/forma.pkl"
import "@formae/formae.pkl"
import "@aws/aws.pkl"
import "@aws/logs/loggroup.pkl"
local stagingTarget = new formae.Target {
label = "staging-target"
config = new aws.Config {
region = "us-east-1"
}
}
forma {
stagingTarget
new formae.Stack {
label = "staging-environment"
description = "Staging env - auto-reconciled, expires in 7 days"
policies = new Listing {
// Auto-reconcile every hour
new formae.AutoReconcilePolicy {
interval = 1.h
}
// Auto-destroy after 7 days
new formae.TTLPolicy {
ttl = 7.d
onDependents = "cascade"
}
}
}
new loggroup.LogGroup {
label = "staging-logs"
stack = "staging-environment"
target = stagingTarget.res
logGroupName = "/staging/logs"
retentionInDays = 7
}
}
Use Cases
Security compliance: Ensure security groups and IAM policies always match declared configuration, automatically reverting unauthorized changes.
Production stability: Enforce desired state in critical infrastructure.
Multi-team environments: When multiple teams access the same infrastructure, auto-reconcile ensures changes made outside of version-controlled IaC are reverted.
Audit and compliance: Maintain consistent, auditable infrastructure by automatically correcting deviations from approved configurations.
Monitoring Auto-Reconcile
View auto-reconcile commands in the status output:
# List recent auto-reconcile commands
formae status --query "source:policy:auto-reconcile"
Check which stacks have auto-reconcile policies:
formae inventory stacks
Considerations
Interval selection: Choose an interval that balances responsiveness with API rate limits. Very short intervals (< 1 minute) may trigger rate limiting from cloud providers.
Emergency changes: If you need to make an emergency change that should persist, either temporarily remove the auto-reconcile policy or update your infrastructure code before the next reconciliation.
Interaction with patches: Patch mode changes are reverted by auto-reconcile. If you apply a patch for an urgent fix, the auto-reconciler will revert it on the next cycle unless you also update the declared state.