aws-killswitch

module
v1.12.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: Apache-2.0

README

aws-killswitch

CI Code Quality Security License OpenSSF Scorecard CI carbon

Stop an AWS account spending, without losing anything. Cuts ingress, drains compute, and records exactly how to put it all back.

$ aws-killswitch plan
plan ks-20260802-021500 — account 123456789012, regions eu-west-1

INGRESS — stop the traffic that drives the spend, before draining what serves it
  alb-listener   api-prod:443                     return a fixed 503 instead of forwarding to the target group

COMPUTE — drain compute; EBS is kept, nothing is deleted
  lambda         image-resize                     set reserved concurrency to 0
  ecs-service    checkout-api                     set desired count to 0
  asg            workers-prod                     set min/desired/max to 0

NOT TOUCHED (4)
  ec2-instance   build-cache (i-0a1b2c)           has instance-store volumes, which a stop erases; set allow_instance_store_loss to accept that
  rds-instance   orders-prod                      database: excluded unless include_databases is set
  lambda         cron-billing                     tagged killswitch:protect
  ecs-service    checkout-staging                 Env=staging, scope wants prod

4 resources would change

Nothing has changed. Run `fire --yes` to apply.

Install

macOS, via Homebrew:

brew install fabiocicerchia/tap/aws-killswitch

Linux — a .deb, .rpm, .apk or Arch package from the latest release:

sudo dpkg -i aws-killswitch_*_linux_amd64.deb     # or rpm -i / apk add --allow-untrusted

Or with Go:

go install github.com/fabiocicerchia/aws-killswitch/cmd/aws-killswitch@latest

Or from a checkout:

make build      # -> ./bin/

Use

aws-killswitch plan                        # read-only, safe against production
aws-killswitch fire                        # still a dry run
aws-killswitch fire --yes                  # actually stop it
aws-killswitch status                      # what is stopped, and any deadlines
aws-killswitch restore ks-20260802-021500 --yes
aws-killswitch spend --threshold 500       # exit 3 when month-to-date is over

killswitch.json:

{
  "scope": { "tags": { "Env": "dev" }, "regions": ["eu-west-1"] },
  "state_uri": "s3://my-ops-bucket/killswitch",
  "confirm_above": 25,
  "include_databases": false,
  "delete_nat_gateways": false,
  "allow_instance_store_loss": false
}

Snapshots go to S3 and a local copy, and both must accept the write. S3 is in the never-touch set on purpose: the kill switch must not be able to destroy its own restore record. Turn on bucket versioning for the same reason.

Proving the restore works

A killswitch nobody dares press is worthless, and "the API returned no error" is not evidence that anything stopped. aws-killswitch verify fires, reads the account back, restores, and reads it back again — reporting every place what was planned and what actually happened diverged:

aws-killswitch verify --config killswitch.json --plan-only   # coverage, changes nothing
aws-killswitch verify --config killswitch.json --yes         # the real cycle

The second read is the point. fire succeeding means the calls were accepted; it does not mean the desired count is actually zero, the listener actually blocked, or the concurrency actually pinned. Only reading the account back can tell you that, and only comparing against the pre-fire state can tell you the restore put back what was there rather than merely something different.

Scratch accounts only — it fires for real. examples/scratch-account/ is a Terraform module that seeds one minimal resource of every supported kind, so a run has something to exercise; a kind the account does not hold is reported as NOT EXERCISED, because "no divergence" over a kind that was never present is not evidence of anything.

The report is counts and kinds and nothing else, so it can be pasted into an issue: ARNs, account ids and resource names have nowhere in the report type to live, and a test asserts they cannot reach the output even when they are the subject of a finding.

Verify the download

Every release is signed with cosign, keyless: the identity is the workflow that published it, not a key anybody holds.

cosign verify-blob \
  --bundle checksums.txt.bundle \
  --certificate-identity-regexp 'https://github.com/fabiocicerchia/aws-killswitch' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  checksums.txt
sha256sum --ignore-missing -c checksums.txt

Documentation

Full docs live in docs/. Runnable examples live in examples/.

License

Apache-2.0 — see LICENSE.

Directories

Path Synopsis
cmd
aws-killswitch command
aws-killswitch — stop an account spending, without losing anything.
aws-killswitch — stop an account spending, without losing anything.
killswitch-lambda command
Command killswitch-lambda fires the killswitch from an AWS Budgets action, so the fast trip is driven by the spend signal itself.
Command killswitch-lambda fires the killswitch from an AWS Budgets action, so the fast trip is driven by the spend signal itself.
internal
audit
Package audit is the append-only record of what this tool did.
Package audit is the append-only record of what this tool did.
awsx
Package awsx is everything that talks to AWS: finding what is running, and changing it.
Package awsx is everything that talks to AWS: finding what is running, and changing it.
engine
Package engine executes a plan, and enforces the two rules that make firing one survivable: the restore record is written first, and it is updated after every single change.
Package engine executes a plan, and enforces the two rules that make firing one survivable: the restore record is written first, and it is updated after every single change.
model
Package model is the vocabulary: what can be stopped, what stopping it means, and — the part that matters most — what must never be touched.
Package model is the vocabulary: what can be stopped, what stopping it means, and — the part that matters most — what must never be touched.
plan
Package plan turns a pile of discovered resources into an ordered, reversible sequence of changes — and, just as importantly, a list of everything it will not touch and why.
Package plan turns a pile of discovered resources into an ordered, reversible sequence of changes — and, just as importantly, a list of everything it will not touch and why.
policy
Package policy is what the operator is allowed to hit, decided before the incident rather than during it.
Package policy is what the operator is allowed to hit, decided before the incident rather than during it.
state
Package state persists the snapshot that makes a fire reversible.
Package state persists the snapshot that makes a fire reversible.
trip
Package trip is one discover → plan → fire cycle, with nothing in it that belongs to a particular way of being invoked.
Package trip is one discover → plan → fire cycle, with nothing in it that belongs to a particular way of being invoked.
verify
Package verify runs a full fire/restore cycle and checks the result by reading the account back, twice.
Package verify runs a full fire/restore cycle and checks the result by reading the account back, twice.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL