---
title: "Writing · Ruslan Akchurin"
canonical_url: https://ruslanakchurin.dev/blog
description: "Infrastructure decisions that are easy to hand-wave and hard to live with later"
---

# Writing · Ruslan Akchurin

Infrastructure decisions that are easy to hand-wave and hard to live with later

## Making IaC boring

https://ruslanakchurin.dev/blog/making-iac-boring

- Part 1 — [Start with the shape](https://ruslanakchurin.dev/blog/making-iac-boring/01-shape) — By the time anyone reviews an IaC codebase, its shape is already decided.
- Part 2 — [Resolve by contract](https://ruslanakchurin.dev/blog/making-iac-boring/02-contract) — Cross-stack dependencies make another stack's outputs a public interface. A typed contract on a producer namespace and key is the alternative.
- Part 3 — [Define tier membership](https://ruslanakchurin.dev/blog/making-iac-boring/03-membership) — Environment boundaries blur when workload-specific members (service accounts, IAM bindings, DNS records) accumulate in the shared environment tier.
- Part 4 — [Fail before apply](https://ruslanakchurin.dev/blog/making-iac-boring/04-fail-before-apply) — An IaC contract holds only if the release path enforces it: a resolver checks type and context, then refuses invalid composition before apply.
- Part 5 — [Re-cut the system](https://ruslanakchurin.dev/blog/making-iac-boring/05-re-cut-the-system) — Refactoring a live IaC system toward a new architecture: freeze the old boundary, publish the new contract beside it, delete only after consumers move.
- [Appendix A: The shape, runnable](https://ruslanakchurin.dev/blog/making-iac-boring/appendix-a) — A companion repository makes the series architecture executable: four tiers, typed cross-tier contracts, and resolver probes that refuse bad composition before any provider call.
- [Appendix B: The contract, end to end](https://ruslanakchurin.dev/blog/making-iac-boring/appendix-b) — One self-contained file implements the cross-tier contract: a producer publishes a typed value, a consumer names producer, key, context, and type, and a resolver returns the bound value or refuses by name.

## Where secrets go

https://ruslanakchurin.dev/blog/where-secrets-go

- Part 1 — [A secret has to arrive](https://ruslanakchurin.dev/blog/where-secrets-go/01-a-secret-has-to-arrive) — Secret storage gives a value somewhere to rest; secret delivery records the route, authority, wiring, and proof that get it there.
- Part 2 — [Delivery is a transaction](https://ruslanakchurin.dev/blog/where-secrets-go/02-delivery-is-a-transaction) — Secret delivery breaks when writes, wiring, and receipts are separate chores; the transaction is the unit that keeps partial success and proof limits visible.
- Part 3 — [The bundle is the competitor](https://ruslanakchurin.dev/blog/where-secrets-go/03-the-bundle-is-the-competitor) — The working bundle around a secret store can deliver a value; rotation, revocation, and honest proof limits are what test whether it delivers one verifiable transaction or evidence held together by convention.

## Standalone

- [A library is not an architecture](https://ruslanakchurin.dev/blog/library-not-architecture) — The Pulumi component library I built made infrastructure easier to create before ownership, tiers, contracts, and release boundaries were explicit.
- [The green placebo](https://ruslanakchurin.dev/blog/green-placebo) — An autonomous coding agent ran a ratified security plan on a secrets manager and twice recommended the less-secure option, every fact correct. The green test suite certified a defence that did nothing. Here is what actually held the line, and why the human could not be removed from it.
