robert@notes: ~ — zsh
➜ robert@notes ~ git:(master) cat ~/.motd
Robert's notes - Notes on Go, Kubernetes, Terraform/OpenTofu, AWS and DevOps culture.
➜ robert@notes ~ git:(master) ls ~
➜ robert@notes ~ git:(master) ls -t posts/ | head -n 5 | xargs head -n 3

Blocking egress from Lambda: the sequel to the EKS post

After the EKS egress post the first question I got was “and what about Lambda?”. Fair. A lot of the Python glue I write runs as Lambda functions, those functions call third-party APIs, and the supply-chain argument is identical: a compromised dependency in a function has the same unrestricted internet access as one in a pod. The answer is mostly the same tool, Route 53 Resolver DNS Firewall, with one big catch that changes the economics.

read more →

Testing an OpenTofu module without an AWS account: tofu test and mock_provider

In July I published a DNS Firewall module and admitted that “tested” meant “applied it once and looked”. That is how most infrastructure modules are tested, and it is why module refactors are scary. OpenTofu has had tofu test since 1.6 and provider mocking since 1.8, which together let you assert what a module does - how many rules it creates, that the action is BLOCK, that the wildcard gets added - without credentials, without a VPC, in a few seconds, in CI. Here is that module with real tests.

read more →

State surgery without the CLI: import, moved and removed blocks with for_each

For about eight years, changing what is in the state meant typing terraform state mv and terraform import by hand, one resource at a time, in the right order, hoping nobody else ran an apply in between. Those commands still exist, but you should mostly stop using them. There are three declarative blocks - import, moved, removed - that do the same thing from code, show up in the plan, go through code review, and since they accept for_each they handle fifty resources as easily as one. This is in both OpenTofu and Terraform (since 1.7 on both sides), so unlike my last two posts this is not a “Tofu only” trick - it is a “most people still don’t use it” trick.

read more →

OpenTofu state encryption: encrypt an existing state and rotate the key without downtime

Your state file has your database password in it. Not a hash, not a reference, the password. Also every secret the AWS provider ever returned, every private key you generated with the tls provider, every random_password. S3 bucket encryption does not help here, because anyone who can read the bucket gets the plaintext back from S3. OpenTofu 1.7 added client-side state encryption: the state is encrypted before it leaves your machine and S3 only ever sees ciphertext. This post is the practical part - turning it on for an existing project, and then rotating the key - because the docs explain the blocks but not the sequence.

read more →

GitHub Actions beyond the basics: containers, services, your own runners, dynamic matrices and summaries

Most workflows I see are a list of run: steps on ubuntu-latest, and for most repos that is correct. This post is about the five features you reach for when that stops being enough: running a job inside a container image, starting a database next to your tests, bringing your own runners, building the job matrix at run time, and getting plan output into the PR instead of into a log nobody opens. Each one is a few lines of YAML once you know it exists, and each one took me longer to find than it should have.

read more →
➜ robert@notes ~ git:(master) ls -t posts/ | sed -n