18 ms·
A more mature take on stateless Terraform
- darkwater 3y agoI remember seeing the original take posted here at some point. I'm glad that the author eventually realized that if a (successful?) piece of software it is like it is, it's because it took some trade-offs at architectural decisions.
- ricardbejarano 3y agoAuthor here, thank you!
- ris 3y ago> Have Terraform plug into your Git history, take the Terraform code from the previous commit, and use that to calculate the old tree This is much much more difficult than it sounds if you want to be able to handle any amount of refactoring or repo reorganization and not be cut off from being able to handle resources from "before" a certain time. How terraform or provider upgrades would work is another minefield. It's not just a matter of having access to the old terraform source, it would need to evaluate it with the same terraform version and providers - so those would have to be acquired and run within the state backend. And then this is still assuming the previous run that you're trying to emulate was applied 100% successfully...
- ricardbejarano 3y agoAuthor here, you're right, provider versions are something I did not account for. Good catch!
- INTPenis 3y agoWhat about sensitive values? I don't want those in git history.
- jamesrom 3y agoIs anyone else distracted by all the emphasis, italics, underlines, and highlighting? When everything stands out, nothing does. Sorry for the off-topic comment, but I do think this is valuable feedback for the author.
- adevopsguy 3y agoYes, I stopped reading because of this.
- nikau 3y agoI think it's to distract you from the vapid stupidity of the article
- ricardbejarano 3y agoAuthor, thank you! I'll tune it down a notch, this is most definitely helpful feedback.
- DylanSp 3y agoI was as well, especially the yellow highlight/underline; I interpreted those as links at first.
- jacurtis 3y agoIs that not what they were? I didn't click any of them, but I assumed they were links the entire time.
- DylanSp 3y agoThe pieces of highlighted text (such as "Terraform should have remained stateless" in the first sentence) aren't links, but I thought they were. The bits with just an underline ("this piece") are links, though. Sidenote: TIL about the <mark> HTML tag.
- Aeolun 3y agoEven if Terraform worked without state, we’d still have a state file because it’d be unbearably slow without, and constantly run into API rate limits.
- Dunedan 3y agoHow would that result in more API calls than Terraform with state? When creating a plan, Terraform does already compare stored resource state and actual resource state, which does require doing API requests for each resource.
- giaour 3y agoTerraform also needs to detect when a resource is removed from a template. Having a state file makes this easy (if something is in the state file and not the template, delete it); otherwise, you have to scan your whole infrastructure (and still risk deleting something that was never managed by terraform in the first place).
- jen20 3y agoIn your inner dev loop, set -refresh=false, it’s a much nicer experience.
- deleted 3y ago[deleted]
- jacurtis 3y agoTerraform already does a three way reconciliation at plan/apply time. It checks declared state (your code), known state (your statefile), and current state (api calls to your providers). If you want to see this, just make a terraform apply. After it completes, go change something directly in your cloud provider and run another plan. The top section of your plan will highlight the changes that Terraform found remotely that don't match existing state. So all this would do is remove known state, so you could do a 2-way reconciliation instead of a 3-way reconciliation. You would compare current-state with declared state. This is how Kubernetes works. But to be fair, Kubernetes actually works in a slightly more controlled environment than Terraform.
- Hnrobert42 3y agoHaving used Ansible to easily mange AWS, I have been horrified by how my new org using Terraform for AWS, precisely because TF maintains state. It is both hard to develop in a team and a security nightmare. They diligently recorded all secrets in AWS Secrets Manager. They used IAM roles and policies to control who can see which environment’s secrets. Great! But then I discovered all the secrets in PLAIN TEXT dumped into the state file?! And this is known behavior that Hashicorp defends as reasonable. They suggest you just encrypt the state file. So the next time there’s a big oil spill, let’s just throw a big blanket over it and call it a day. Terraform’s solution swiftly obliterates all the audit, key rotation, separation of duties built into secrets manager. Indeed, what is the point of using Secrets Manager at all if you use Terraform? Next, they recorded state in a hit repo. So all those secrets are committed to the repo. So now how am I supposed to encrypt the state file? What a disaster. But wait. There’s more. With the team growing, how are we supposed to manage shared resources? Do I have to run tf apply, wait for completion, and then immediately commit and push, and hope I don’t have to manually manage a state file merge conflict? Or should I use some bizarre, self-built mutex? Ugh. Terraform is the worst. I was always unimpressed by its feature set and documentation. Now I hate it. I don’t understand why it is so popular which there are such better alternatives.
- anticristi 3y ago> But wait. There’s more. With the team growing, how are we supposed to manage shared resources? Do I have to run tf apply, wait for completion, and then immediately commit and push, and hope I don’t have to manually manage a state file merge conflict? Or should I use some bizarre, self-built mutex? In one project, we had Terraform run from GitLab CI. The CI was creating a plan. The reviewer had to approve applying that plan. I'm curious about your usage of Ansible for AWS resources. How do you delete them? Do you have a policy of always having 'state: absent' for at least one commit?
- chrisfowles 3y agoWhy on earth is your state in git? The tool has built-in functionality to handle just these kinds of workflows. This reads a lot like hitting your thumb with the hammer and blaming hammers.
- fishnchips 3y agoIf you wanted to store the state in Git, you would probably want to at least encrypt secrets. This is not something that Terraform supports now (theory is that this is to push their commercial offering) but it’s one of the main feature requests for OpenTofu. With this in place, and ideally with allowing folks to define custom backends using the plugin interface (decoupled from core, versioned) this story could make a ton of sense. Disclosure: I’m on the steering committee of OpenTofu.
- leetrout 3y agoIts the biggest gap in TF in my opinion. The fact the Vault provider happily slurps all your secrets into state vs using hashes or similar blows my mind. I am convinced HC just is out of touch at this point because "treat the state as sensitive" is not enough. There are many cases I would accept simple hashes vs client side encryption, too. Everyone is going to have different needs but it makes no sense HC ignored making this better for so long.
- fishnchips 3y agoI agree that the lack of native state and/or secret encryption is a serious limitation. In Terraform’s defense, it’s often the fault of providers and/or APIs.
- jacurtis 3y agoAn easy solution would be to just encrypt the whole statefile. This would work the same as state locking works now. You can apply an extra provider for state encryption/decryption just like you do for state locking/unlocking. It's already been requested (with pull requests) for Terraform for a while now and Hashicorp keeps rejecting it, presumably because it would undermine features of Terraform enterprise. OpenTofu is already considering implementing this feature as a result.
- Longwelwind 3y agoWhy would you want to store the state in Git? This means that if you have a CD pipeline (triggered itself by a commit) that does `terraform deploy`, you'd need to have your CD pipeline do commit _again_ to save the changes to the TF state files. On top of that, you lose the ability to re-run a previous CD pipeline to rollback to a previous version of your infrastructure. The goal of Git is just to store the lifecycle of a piece of software, imo. It's not the reponsibility of the repo to know the state of the deployment.
- Dunedan 3y ago> Have Terraform plug into your Git history, take the Terraform code from the previous commit, and use that to calculate the old tree. So instead of generating state by doing API requests, this would generate state from code in git, which does not necessarily represent the real world state of resources. As much as I'd want Terraform without state I believe using Terraform code in git as state creates more problems than it solves. This approach isn't able to recognize changes made to resources done outside of Terraform. It also assumes the previous version of the Terraform code in git is always the one which got applied last, which isn't necessarily the case.
- ricardbejarano 3y ago> So instead of generating state by doing API requests, this would generate state from code in git, which does not necessarily represent the real world state of resources. What you're talking about here is unrelated to whether the state comes from regular Terraform state or if it's generated using the source code, as the refresh phase should happen during both.
- oneplane 3y agoState is required for a three-way comparison: the desired state, the last known state and the current state. And since not all information about the last known state will be expressed in the source configuration files, you need a secondary source of information: the terraform state. Everything else is indeed optional, but the fact that a useful three-way comparison can be done at every run is why terraform works so well and why other IaC tooling is a failure when it comes to change detection and cleaning up.
- ricardbejarano 3y agoWhy would not all information about the last known state be expressed in the source?
- igetspam 3y agoBecause it's incredibly difficult to do. Look at just something as simple as launching an instance. How do you know the state of the instance ahead of time? The instance ID doesn't exist and you can't do search filters for it because it's not there yet. Yes, you could use some half baked conditional logic to try and search and load values only if your instance exists and create if empty but terraform really isn't good at that. And that's just the very simple case. You could use something like the CDK or pulumi and avoid state but it's still work and it's useful work.
- verdverm 3y agoI think a simpler example is how do you know to delete something. It won't be in the config any more, so won't be queried, unless you have some tag on managed resources for this module, but then you'd need to persist that somewhere
- baby_souffle 3y agoThis is correct. If it helps, you can think of your terraform files as HEAD and the state file as HEAD~1
- hdjjhhvvhga 3y ago> This makes Terraform significantly worse for the majority of its users (users of public cloud providers with APIs whose resources all have such attributes) so the remaining 1% (or less) can use it. I think the author misunderstood the problem (maybe because it's not crystal clear on Hashicorp's website): it's not that not all cloud providers provide tags, the problem is that only certain percentage of resources are taggable. So imagine you are using your stateless TF code based on tags only: you could only deal with those resources that support tags. Whereas now, after configuring the backend on S3 with DynamoDB, it's basically "fire and forget" - you can use practically any resource. Paradoxically, TF supports even more actions on resources on AWS than CloudFormation. So maybe for some simple setups like EC2 with S3 this could work somehow, but for anything more complex the current implementation is far superior.
- orf 3y agoI want to create 3 servers with randomly chosen names from a pool of 10. How can you express this without state? Or more generally, any “random_password”, “random_choice” etc, or even anything that is a “write only” property You can’t. So this is dead in the water.
- dlkmp 3y agoInteresting example. For context, I have only experience with Azure Bicep so "no state" is my default assumption on IAC languages. Do you in practice really use random names? In my experience, I'd just use a loop vm01...vm10 for the names and the passwords aren't needed to identify an instance after the deployment so here randomness isn't an issue.
- orf 3y agoRandom choice of subnet is a better example, random names is definitely not common. Random passwords, write-only attributes (like database master passwords) are the most common. How do you express “create a DB with this strong password, then put it in a s3 object”, then later “actually put it in SSM rather than s3”?
- dlkmp 3y agoWe cannot, okay, I see the point. Up to now, I considered the inability to express modifications on existing resources a limitation of the declarative model but I can see how adding state can help here. With Bicep, we mostly deploy only the initial state and then we either re-deploy the whole thing or, if this isn't possible due to the interruptions this causes, add migration scripts in an imperative language (az cli/ pwsh). Which is admittedly the much less elegant approach.
- deleted 3y ago[deleted]
- danielvaughn 3y agoIn my (very limited) experience with Terraform, the pain isn't so much associated with state, but rather with the declarative nature of the code. I feel like imperative Terraform would be easier to reason about, since it matches up with the non-terraform workflow (i.e. go here add this, then go here and configure that, yadda yadda). When I read HCL, I really struggle in understanding the order of priorities. Like I know that surely some things must be built first, and supposedly it's all handled under the hood. But I'd rather be in control tbh. Then again, as I said, I don't have much experience with Terraform so maybe I'm way off?
- dimitrios1 3y ago> Then again, as I said, I don't have much experience with Terraform so maybe I'm way off? Yes. HCL is the easiest part of terraform. State management / knowing what a particular tf apply is going to do and if it will put your stuff in an irreversible state where you have to go in and manually fix it is the hardest part. For us, we are forever struggling with IAM policies and KMS key aliases, especially if there is also a developer boundary coming into play as well.
- viraptor 3y agoApart from very specific scenarios where you really know you need explicit order, it's not something I ever think about. You've got two options really: 1. One resource depends on another through the attributes, like an autoascaling group depending on a subnet. This is handled automatically by Terraform - updates/ordering will happen in the right way. 2. Dependencies that exist outside of configuration. For example some domain name should be created before some service starts. You can add those explicitly through `depends_on` for the resource that needs it. Going imperative would lose most of what's interesting about Terraform. Imagine you create a service then change some attributes. Now you want another environment that looks the same - how would you do that imperatively? Replay all changes from scratch? Flatten the history and create a new script? With declarative Terraform what you're running is already in your configuration, no changes needed.
- jen20 3y ago
- master_crab 3y agoYou can’t CRUD without state. Just want the “C”, invoke the cloud APIs and skip the hassle. And the author’s mental stretch of claiming git is the state is still a bit of a leap.
- djha-skin 3y agoAt my workplace, managing terraform state has caused outages. It is so very easy to refactor the terraform code and then find yourself deleting a network load balancer and recreating one. Recent versions of terraform have come out with a `moved`[1] block, but it is really unintelligent. It is a step in the right direction, but I can't use variables with it or string interpolation or anything. Trying to get the state to be happy has been very difficult. I prefer ansible for this because it doesn't use state[2], but as my company uses terraform I am left with the unfortunate need to manage state. The best thing that I've been able to find to help in this fight is a little script I created to help automatically make moved blocks[3]. In a refactor you typically want to take resource blocks from the main.tf file and move them into their own module. You first moved the blocks into the module, and then before you edit anything you run that script and it matches up the blocks that were moved using Levenshtein distance. This approach may seem hacky but it works very well. Then I just take the output of the script and append it to my tf file. I found the article refreshing and poignant. I will definitely be hoping for innovations like this to finally improve The state of the art because now that OpenToFu[4] is on the scene features like this that might chew into the bottom line of HashiCorp will start finally start being looked at seriously. 1: https://developer.hashicorp.com/terraform/language/modules/develop/refactoring https://developer.hashicorp.com/terraform/language/modules/d... 2: https://blog.djha.skin/blog/that-does-it-ansible-wins/ https://blog.djha.skin/blog/that-does-it-ansible-wins/ 3: https://gist.github.com/djhaskin987/b856c157bcfce6d2e4ee19f9732e5194 https://gist.github.com/djhaskin987/b856c157bcfce6d2e4ee19f9... 4: https://opentf.org/ https://opentf.org/
- ljm 3y agoI've had similar difficulties and it seems like Terraform is basically a content-addressable system, where the directory tree is part of the addressable content. The addition of `moved` is welcome but I feel like it was a huge mistake to use the FS as the module system such that moving a directory or renaming it is a breaking change, despite the fact that the name of your resource never changed. That design decision has shot even the most experienced engineers in the foot once they see a renamed directory killing a database and spinning a new one up.
- amazingman 3y ago
- abacate 3y agoI read this article and the original one. I don't see any reasoning besides "I think it's not really needed". The reasoning in the original article is shallow at best, and the presented alternatives are not discussed in the depth I was expecting for an article questioning the whole architectural basis of a very popular IaC stack. On the second article, I don't see a self critique of the actual points raised during the original article. The two articles sound much like a collection of statements based on personal opinion. I see the value in an article like this for starting a discussion but not into taking any sort of conclusion.
- xwowsersx 3y agoMissing the word "to" here FYI: > For any given already-existing resource, Terraform needs to know how, in the absence of its code, determine its dependents so they can be destroyed in the right order. should be > how, in the absence of its code, to* determine its dependents so they can be destroyed in the right order.
- jaxxstorm 3y agoEvery single person who has this "you don't need state" take on IaC seems to be missing one key point. They haven't built it, because it's really really hard to do.