Disclaimer: Sorry, still not related to my home network infrastructure, although I have one or two posts I want to write about later..

I have been thinking recently about how to deal with some personal resources I have in the cloud - mainly in Oracle Cloud thanks to their generous free tier. So far I’ve dealt with them manually doing click-ops in their GUI, but I have been trying to up my personal infra game so I started to think about how to make this not manual.

In work life, Terraform by HashiCorp has been quite good tool for it for number of years, but the licensing change last year to BSL ( Business Source License 1.1) left a sour taste in my mouth about the whole tool. While making money from open source development is laudable goal (and I have been involved in that in more than one company), creating an open ecosystem and then locking out the commercial users out of it (unless they pay to stay in it) is not ethical business model from my point of view.

I am also not huge fan of domain specific languages, but given the large ecosystem around Terraform it seems like no-brainer for many things unless you want to write provisioning from scratch, or lock yourself in to something cloud provider specific.

However, this blog post isn’t really about the licensing or rant about evils of DSLs, but instead brief overview of how to handle Terraform data securely.

Terraform data consists of:

  • configuration for infrastructure
  • secrets to configure the infrastructure (used in configuration)
  • state file which indicates current state of the infrastructure (which sadly includes some secrets every now and then too)

Usually it is not good idea to store any secrets in version control, and due to that usually only storing configuration in version control is an option (see e.g. Managing Terraform State - Best Practices & Examples for how to handle state correctly).

What to do with normal secrets?

There’s large number of different tools that can be used to store short secrets locally or in shared way, with reasonable API, e.g. chamber: CLI for managing secrets if you like AWS, Pass: The Standard Unix Password Manager if you like gpg and want to do things locally, and 1Password if you want subscription service for that.

Due to that, it is not that interesting how they are stored, just that they are available as environment variables. And those can be passed along to the terraform commands which need them.

Currently I am mostly using pass for hobby stuff which is needed in automation, and BitWarden/VaultWarden for other things (as some of my hobby infra as code also manages my VaultWarden, it would be awkward if it was required for setting it up). I used to use 1Password for many years - as long as they had ‘buy to own’ model - but I don’t really like ‘rent to use’ ( subscription model ) they offer now with 1Password 8.

What about the elephant.. or state file.. in the room?

State files grow quite a lot, and initially the suggestion was to store the state file in version control alongside the configuration files. Unfortunately more and more providers started sneaking in secrets there, and due to that that strategy became bad practise.

After that the suggestion has been just to use ‘remote’ state provider of some kind, which stores the state somewhere in hopefully encrypted format. I am using hopefully intentionally here, as the assumption is usually that e.g. ‘you store it in S3 bucket with encryption, so it is encrypted’ and NOT that the client encrypts it, and then someone may encrypt it more if they want to.

This difference is quite crucial, as the assumption in the ‘cloudy encryption’ is that you

  • you trust the storage provider (and transitively, their security), and
  • you have nothing in the middle screwing around with transmission of from/to storage provider (e.g. TLS man-in-the-middle attack)

If either of those assumptions does not hold, your secrets are wide open for an active attacker and due to that I would not recommend any solution without client-side encryption for personal or business use.

State encryption in Terraform

I am not alone in my thinking, it seems - there has been an issue in the Terraform project since 2016 to add support for client-side encryption of the state. Unfortunately, it has not moved anywhere in the 8 years since it was created.

Today when I was looking for solutions to this problem (some of them quite nasty, e.g. storing state in git using encryption and decryption as needed), I found OpenTofu proposal to add state encryption ( OpenTofu is open source licensed fork of the Terraform code before BSL license change ). Much to my joy, this feature actually shipped in April 2024 when 1.7.0 came out ( see OpenTofu 1.7.0 is out with State Encryption, Dynamic Provider-Defined Functions, and more ).

My conclusion? If you want encrypted state, and you should, use OpenTofu and not Terraform. And OpenTofu also has still open license as bonus 🙃