2026-08-04 · 7 min · Pavel Hegler

Claude Code as your DevOps engineer: AWS, Terraform, Cloudflare

CloudWatch woke me up this morning with a certificate warning. Seven days to expiry, auto-renewal not happening. I was in the middle of something else, so I gave the problem to Claude Code — identify what needs to be done, then make a plan — and went back to what I was doing.

The certificate CloudWatch was upset about turned out to be a red herring. It was attached to nothing; it could expire and no one would notice. But while listing certificates the agent found a second one with the same expiry date, and that one was live on our load balancer, with its renewal stuck in PENDING_VALIDATION. ACM renews certificates by checking for a DNS validation record, and the record was gone. dig returned nothing.

Then it got interesting. The agent created the record in our DNS provider, queried the authoritative nameserver to confirm, and got no answer back. Instead of declaring success — the API had said success — it looked at why, and found that this particular subdomain is delegated to a different DNS provider than the rest of the zone. The record it had just created could never be served from where it put it. So it moved the record to the zone that actually owns the name, watched dig come back with the right answer, deleted its first attempt, and left a background watcher polling ACM until the renewal goes through.

That was my morning of DevOps: an alert pointing at the wrong certificate, a root cause two layers under it, a fix spanning two DNS providers. My total contribution was two sentences and one browser tap.

People keep asking what it takes to set this up. Less than you'd think. Three access grants, a memory, and a short file of rules.

AWS: a named profile, not your keys

Claude Code runs shell commands, so it uses the same AWS CLI you do, and the whole access question collapses into one you already know how to answer: what is this profile allowed to do?

Create a dedicated profile in ~/.aws/config backed by an IAM identity you scope deliberately, and have the agent put it on every command:

AWS_PROFILE=agent aws acm list-certificates --region eu-central-1

Every call is visible in the transcript, attributable in CloudTrail, revocable in one place.

Start with ReadOnlyAccess. I expected this to be limiting and it mostly isn't, because diagnosis is read-only. This morning's session was about forty read calls — list-certificates, describe-certificate, list-hosted-zones, a lot of dig — and exactly one write, the record change. Grant writes per service, when reads stop being enough. The write list stays short.

Terraform: the plan is the review

Terraform already splits into the two halves you want. terraform plan is safe to run unattended, and its output is the honest version of "here is what I intend to do" — not a summary the model wrote about its own changes, but the computed diff against real infrastructure. Let the agent plan freely. terraform apply goes through you, and in Claude Code that costs nothing to enforce: the permission system asks before unfamiliar commands, and you simply never put apply on the allowlist.

Cloudflare: scopes you tap, not tokens you paste

The lazy move is pasting an API token into an environment variable. Cloudflare's MCP server is better: the first time the agent needs the API, a consent page opens in your browser, you pick the scopes — read-only template, full access, or per-permission — and tap approve. The token lives with the tool, never lands in a dotfile, and can be killed from the dashboard. That tap was the only moment today that needed my hands, and I think it's exactly the right moment to need them. For Workers there's already wrangler, which manages its own login.

Memory: not paying for the same lesson twice

The delegation surprise cost most of this morning's wall-clock time. Claude Code alone would pay that cost again at the next renewal, because it starts every session blank. Ours won't, because the session ended with the agent writing what it verified to backant-memory, our local-first memory MCP: recall before acting, write after learning. Today's entry says, roughly — the validation records for this subdomain live in the delegated zone, not the apex, and they are never to be deleted. Next time, the session starts from that sentence instead of from dig.

Full disclosure, because it's funny: memory was this morning's second patient. A disk-fill event last week had quietly killed the embedding runtime it depends on, so the agent's first recall attempt failed — and it diagnosed and restarted its own memory service before using it. Draw whatever conclusion about self-hosted tooling you like.

The CLAUDE.md file, honestly

Every guide says to write a CLAUDE.md full of rules, and we have one. I'll be straight with you: I can't measure how much it mattered today. The parts I can trace are unglamorous — it's where the agent learned which AWS profile to use without asking, and it's where the recall-then-write memory discipline is spelled out. The ask-before-deleting behavior it largely has anyway; the file makes it explicit, which counts for something when you're trusting a pattern instead of a promise.

Rather than describe it, here's the file itself — save it as CLAUDE.md in your repo root and change the profile name. You'll notice some lines read like they were learned the hard way. They were, and two of them were learned today: verify DNS changes against the authoritative nameserver, and never delete validation records. When the agent drifts, you edit the file, and the correction applies to every session after.

What to expect

It will ask before anything destructive or outward-facing, and you should keep it that way. After a good week the temptation is to widen the allowlist until nothing asks anymore. Resist that. After a while, the prompts you still see are precisely the ones you want to see.

It will also be wrong sometimes, in ordinary ways — today it put a DNS record in the provider any reasonable engineer would have guessed first. What made the session work is that it checked, found its own change not serving, and went looking for the reason instead of reporting done. When you evaluate an agent for infrastructure work, don't score the first guess. Score what happens after a wrong one.

And the factual privacy note: this is Claude Code, so commands and their outputs go to Anthropic like in any session. What stays on your machine is the memory. If your log lines are sensitive, scope what the agent can read with the same care you scope what it can write.

Start here

  1. aws configure --profile agent against a fresh IAM identity with ReadOnlyAccess. Widen per service, per need.
  2. Terraform: allowlist plan, never apply.
  3. Add Cloudflare's MCP server; approve scopes in the browser on first use.
  4. Install backant-memory so the next incident starts where the last one ended.
  5. Take our CLAUDE.md as a base and make it yours.

Then hand the agent your next alarm, and read everything it does.

If you'd rather this ran as an unattended loop than a conversation, that's Kairos — but that's a different post. The certificate renews itself now.