Skip to content

QA plan: Bedrock token-spend alarm (#64)

Story: Bedrock token-spend alarm: $5/env via AWS Budgets (#64)
Capability: Cost guardrails and observability (#31)
ADRs: RAG007 — Haiku-class via Bedrock; RAG008 — observability

TypeCoverage
IaC (plan review)Terraform provisions a Bedrock-scoped spend alarm (AWS Budgets filter on Bedrock service, or CloudWatch alarm on Bedrock token metric) per environment
IaC (plan review)Alarm threshold documented per environment ($5/day QA, adjusted for Prod usage pattern)
IaC (plan review)Alarm routes to SNS topic with at least one confirmed subscriber
Integration (manual, QA)After apply: alarm exists in AWS and is in OK state (no current spend breach)
Integration (manual, QA)SNS topic subscription confirmed (email response or test-publish verified)
  • Story #33 (AWS Budgets alarms) complete — this Story adds a Bedrock-specific filter on top of the general budget.
  • #295 complete: the filter dimension is settled, either tag-based (cost allocation tag activated and InvokeModel usage attributable to it) or service-based
  • Story #23 (API module — Lambda + API Gateway HTTP API) deployed so Bedrock service appears in billing
  • Terraform plan shows the Bedrock spend alarm resource for each env
  • Alarm threshold documented in the runbook or cost.md per env
  • Post-apply: alarm exists in OK state; SNS subscriber confirmed
  • Security: threshold is low enough to bound worst-case Bedrock abuse cost (T1/T2 from threat model)

IaC: CI. Integration: manual against QA post-apply.

Terraform, AWS CLI (aws budgets describe-budgets or aws cloudwatch describe-alarms).

Terminal window
# Given the QA Terraform has been applied
# When the Budgets alarms are listed with the Bedrock service filter
aws budgets describe-budgets --account-id "$AWS_ACCOUNT_ID" \
| python3 -c "
import sys, json
budgets = json.load(sys.stdin)['Budgets']
bedrock_budgets = [b for b in budgets if 'bedrock' in b['BudgetName'].lower()]
assert bedrock_budgets, 'No Bedrock budget found'
for b in bedrock_budgets:
limit = float(b['BudgetLimit']['Amount'])
assert limit <= 5.0, f'Bedrock budget limit {limit} exceeds \$5 per-env ceiling'
print('Bedrock alarm verified')
"
# Then at least one Bedrock-scoped alarm exists with a limit at or under $5
  • AWS Budgets has up to 24 h delay before reflecting actual spend; the alarm does not fire in real time. Document this in the runbook and treat the Bedrock alarm as a daily trailing indicator, not an in-request safeguard.
  • The per-key lifetime request quota (RAG009) is the primary per-key cost defense; this alarm is the aggregate fallback. Both must be in place.

Security per-feature requirements (#64): token-spend alarm fires on a defined daily ceiling; threshold documented per environment. Threat model T1/T2 (cost-runaway shape). Exit criteria map directly.