Claude Code for SRE work

Set up Claude Code so it is useful on infrastructure repos and safe around production, with a CLAUDE.md, tight permissions, a secret filter, headless mode and changes only through merge requests.

Updated 2026-11-11Raw markdown

Strategy sections
On this page

Use this page to configure Claude Code (or a similar coding agent) for SRE repos: IaC, CI templates, runbooks and automation scripts. The agent operating rules are the policy; this page is how to enforce it in the tool.

Use it only on machines and with data your organization has approved for AI tools.

Two ways to use it

Mode Command Good for
Interactive claude in the repo Writing a Terraform module, porting a pipeline, reviewing a diff, drafting a runbook
Headless claude -p "<prompt>" Scheduled, repeatable text jobs: classify tickets, summarise a plan, draft a report

Write a CLAUDE.md in every repo

Claude reads CLAUDE.md at the repo root on start. Keep it short and specific.

# CLAUDE.md

## What this repo is
Terraform for <component> across dev, staging and prod. One state per env under envs/<env>.

## Ground rules
- Read-only by default. Never run terraform apply, aws write calls, git push to main, or force-push.
- Changes are proposed as a branch and a draft MR. A human merges.
- Use the `<account-alias>-ro` AWS profiles only. Always pass --profile and --region.
- Never print or paste secrets, tokens, account IDs, hostnames or customer data.
- When unsure, stop and ask; write the question in the MR description.

## How to check your work
- terraform fmt -recursive && terraform validate
- tflint --recursive
- ./scripts/plan.sh <env>   # read-only plan

## Workflows
### port-pipeline
1. Read the old CI file. 2. Generate the new CI file from templates/. 3. List every TODO. 4. Open a draft MR.

Add personal, machine-specific notes in ~/.claude/CLAUDE.md, not in the repo.

Lock down permissions

Project settings live in .claude/settings.json (shared) and .claude/settings.local.json (yours, git-ignored).

{
  "permissions": {
    "defaultMode": "plan",
    "allow": [
      "Bash(terraform fmt:*)",
      "Bash(terraform validate:*)",
      "Bash(terraform plan:*)",
      "Bash(tflint:*)",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(glab mr view:*)",
      "Bash(glab ci lint:*)"
    ],
    "deny": [
      "Bash(terraform apply:*)",
      "Bash(terraform destroy:*)",
      "Bash(git push --force:*)",
      "Bash(git push -f:*)",
      "Bash(aws secretsmanager get-secret-value:*)",
      "Read(./**/*.tfstate)",
      "Read(./**/.env)",
      "Read(~/.aws/credentials)"
    ]
  }
}
  • plan mode means Claude proposes and you approve each edit or command.
  • The strongest guard is outside the tool: give the session read-only cloud credentials, so even an allowed command cannot write.
  • Never run with the skip-permissions flag on a machine that holds production credentials.

Add a guard hook

A PreToolUse hook runs before every tool call and can block it (exit code 2).

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.claude/hooks/guard.sh" } ] }
    ]
  }
}
#!/usr/bin/env bash
# ~/.claude/hooks/guard.sh: block mutating cloud and git commands
cmd="$(jq -r '.tool_input.command // ""')"
if grep -Eq '(^|[ ;&|])(terraform (apply|destroy)|kubectl (apply|delete)|git push (-f|--force))' <<<"$cmd" \
   || grep -Eq 'aws .* (delete|put|update|create|terminate|modify)-' <<<"$cmd"; then
  echo "blocked by guard.sh: mutating command needs a human" >&2
  exit 2
fi
exit 0

Run headless jobs safely

redact() {
  sed -E \
    -e 's/AKIA[0-9A-Z]{16}/<aws-key-id>/g' \
    -e 's/\b[0-9]{12}\b/<account-id>/g' \
    -e 's/\b[0-9]{13,19}\b/<number>/g' \
    -e 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/<email>/g' \
    -e 's/\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/<ip>/g' \
    -e 's/(token|secret|password|passwd|api[_-]?key)([" :=]+)[^" ,]+/\1\2<redacted>/Ig'
}

redact < tickets.jsonl | claude -p "$(cat prompts/classify.md)" \
  --output-format json \
  --max-turns 1 \
  --disallowedTools Bash Edit Write WebFetch WebSearch \
  | jq -r '.result' > state/classified.json
  • Filter every byte before it reaches the model. Add org-specific patterns (internal domains, project names) from a local, git-ignored file.
  • Disable tools for pure text transforms. The job reads input and writes an answer, nothing more.
  • Validate output: parse the JSON, check labels are from the allowed set, and treat anything else as "needs a human".
  • Cap cost with --max-turns and, where available, --max-budget-usd.

Changes only through merge requests

  • Claude works on a branch, never the default branch.
  • It opens a draft MR (glab mr create --draft) or leaves the branch for you to push.
  • CI runs plan and tests; a human reviews and merges.
  • MR descriptions state that an agent drafted the change.

Pitfalls

  • A long CLAUDE.md nobody maintains. Keep it under a page; link to docs for the rest.
  • Pasting log excerpts with secrets into an interactive session. Redact first, even when it feels urgent.
  • Trusting a plan summary instead of the plan. Read the real terraform plan output.