@chris
All of the above? 😄
Seriously: each solution has its space. I agree it could get complicated using each one of them, but you do have to try and test what each one can do for you, and come up with your choices.
Example: Terraform is great for infra provisioning and config, while Ansible is better for VM/service config (post provision), but requires complicated automation for keeping config up to date, while Puppet does it "easier". YMMV.