Start a new estate
For an estate with nothing in it yet, where choudoufu creates every resource.
If AWS already holds resources this configuration should manage, read Migrate an existing estate first. Nothing binds a live resource to your configuration until its markers are on it, so applying against unmarked resources creates a second copy beside them.
Install
Every tagged release carries
prebuilt binaries for macOS, Linux and Windows on amd64 and arm64, plus a
SHA256SUMS file.
os=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
gh release download -R INTENTIUS/choudoufu --pattern "*_${os}_${arch}.tar.gz"
tar xzf choudoufu_*_"${os}"_"${arch}".tar.gz # unpacks ./choudoufu
Or build from a checkout.
go build ./cmd/choudoufu
Until a configuration opts in, the binary behaves as the OpenTofu commit it forked from. Point it at existing work safely.
Turn markers on
Create estate.chdf.hcl beside your configuration and remove any backend or
cloud block.
# estate.chdf.hcl
estate = "my-estate"
The estate name is the unit of ownership. Every resource gets tagged with it, and that tag is how the next plan finds the resource again.
That one file is the whole setup. No .tf changes, so stock terraform validate, tflint and editors keep passing. Reverting means deleting the
file. Record-backed resources, a null_resource or a random_pet, already work:
the estate gets an implied local record store, a .tofu-records directory
beside the module. Add a record_store "s3" here
to put the records in a bucket where a team can share them, and that
bucket is one you create first.
Add .tofu-records/ to your .gitignore before the first run. Nothing
writes that line for you, and the directory holds whatever the state file
would have held, generated secrets included, unless you set
strict { secrets = "refuse" }.
Secrets in the record store has who can
read it, for the local store and for a bucket.
The same content can live as a live block inside terraform.
terraform {
live {
estate = "my-estate"
}
}
Both forms are equivalent. Declaring both at once is an error.
live
block, because live is this fork’s addition to the terraform block schema.
Any tool validating against upstream’s schema does the same. The sidecar file
avoids this, because nothing reads its extension. See
Compatibility reference.A first configuration
Two resources, one from each path identity resolves through.
# AWS assigns the ID here, so ownership recovers only from a tag.
resource "aws_vpc" "main" {
cidr_block = "10.99.0.0/16"
}
# The bucket name is already the identity, so this needs no discovery pass.
resource "aws_s3_bucket" "data" {
bucket = "my-estate-data"
}
A fuller example adding a subnet and security group, a log group, and a
count-expanded pair of EIPs is checked in at live/e2e/estate-block/. It runs
as it stands.
Apply
$ choudoufu init
$ choudoufu apply
The plan carries something a plain OpenTofu plan does not. Beside each resource’s arguments, the diff shows the ownership markers about to be stamped.
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ cidr_block = "10.99.0.0/16"
+ tags = {
+ "tofu-address" = "aws_vpc.main"
+ "tofu-estate" = "my-estate"
}
...
}
Those two tags are the entire ownership contract. live/MARKERS.md is the
normative spec and the surface external tooling can rely on.
Check that the markers carry it
Run choudoufu plan again. It rebuilds prior state by reading the
tofu-estate and tofu-address tags back off the live resources, and reports
no changes. The tags alone were enough.
Repeat that on your own estate. It is the check you can run without trusting this page.
See it prove itself
Before pointing this at your own AWS account, watch the whole thing happen against a local emulator instead: Tutorial: see markers work.
Next
- What you set up by hand for what has to exist before the first plan, per record store backend, and the failure mode each missing piece produces.
- Day-2 operations for renames, removals and working with other people.
- Compatibility reference for the constructs this mode refuses. Read it before the configuration grows.