AWS コスト・セキュリティ方針


1. コスト前提モデル

項目 値
注文数 5,000件/日(中規模)
ピーク 数十 req/秒(webhook)
同時カート 50
稼働 10時間/日
ロケーション 1(将来複数)
決済 注文の3 webhook/件、在庫2 variation/件

2. サービス別の内訳(中規模)

サービス 用途 概算/月
Lambda API / webhook / 同期 無料枠内〜$1
API Gateway(HTTP API) PWA→API $0.5〜1(webhookはFunction URLで除外)
DynamoDB(オンデマンド) 注文・在庫・カート・冪等 $1〜2
EventBridge(15分間隔) 同期フォールバック $0.02
CloudWatch Logs/アラーム 監視 $0〜0.5
合計 $1.2〜1.8

削減の決定事項

# 施策 効果
1 webhookは Lambda Function URL API GW課金なし
2 terminal.checkout.created は購読しない 無駄な処理を削減
3 冪等キーを既存項目へ統合 書込削減
4 変化なし/古いイベントは書き込まない 書込削減
5 在庫はロケーション単位の1項目に集約 書込削減
6 カートheartbeat 120秒・TTL 5分・可視時のみ・空カート停止 書込大幅減
7 フォールバック同期 15分 起動回数減
8 顧客ポーリング 10秒・Terminal 2秒(非表示時停止) API/Lambda減

規模別試算

規模 注文/日 同時カート 月額目安
小 500 10 $0.3〜1
中 5,000 50 $1.2〜1.8
大 50,000 300 $25〜40

無料枠(要確認・アカウント種別で異なる)

  • Lambda: 100万req / 40万GB-s
  • DynamoDB: 25GB / 25RCU・25WCU(プロビジョンド)
  • CloudFront: 1TB / 1,000万req
  • CloudWatch Logs: 5GB
  • WAF: 無料枠なし(CloudFront定額プランは込み)

予算管理

  • infra/cost-guard.yaml: 月$1予算+異常検知(us-east-1の別スタック)
  • 通知先: .env の ALERT_EMAIL

3. DoS対策の段階計画

Phase 0(採用): $0の防御

対策 内容
署名検証 Square署名を生ボディで検証し、無効は即時棄却(DBアクセスなし)
同時実行上限 webhook専用関数の同時実行を制限(アカウント上限に応じて設定。デモは停止時に0)
ボディ上限 256KB超を413
許可イベントのみ 対象type以外は200で破棄(再送を防ぐ)
ランダムパス断片 /webhooks/square/{32桁}
冪等 event_id(二重処理防止)
アラーム 5分1,000呼び出し超 / 429率5%超 / 5xx率1%超

前提: 攻撃は「標準的(無差別ボット・スキャン程度)」。
性能余力: 同時5〜10で50〜200 req/秒。中規模(ピーク数十req/秒)は余裕。

Phase 1(必要時): CloudFront(webhook専用)+WAF

構成 月額
CloudFront 定額Free(100万req/100GB/5 WAFルール) $0(枠内)
CloudFront 従量+WAF(レート制限1本) 約**$6.5**
CloudFront 定額Pro(1,000万req) $15
  • 原点は AWS_IAM+OAC(Function URLを直接公開しない)
  • WAF: レートベースルール1本(マネージドルールは追加費用)
  • HTTP APIはWAF非対応のため、CloudFrontが必須
  • Shield Standard(L3/L4)は無料

切替トリガー

  • 5分間の呼び出し1,000回超、または429率5%超、または正規webhookの遅延5分超
  • 切替は webhook専用ディストリビューション に限定し、定額Freeの枠(100万req/月)に収める

4. セキュリティ方針

認証・認可

  • 店員: デモはPIN→JWT(HS256)、本番はCognito
  • ロール: staff / admin / terminal
  • レジ・端末はサーバー側で解決(クライアント指定を信用しない)
  • 顧客: 匿名+orderToken(HMAC、注文単位)

Webhook(Square)

  • Square-Signature を生ボディで検証(設定URLと完全一致+timing-safe比較)
  • event_id で冪等化(TTL 30日)
  • 受信から10秒以内に2xx(重い処理は非同期/後続)
  • 順不同・重複を前提に、状態は前進のみ

公開面

  • Function URLは AuthType: NONE(SquareはIAM署名不可)+上記Phase 0対策
  • 将来CloudFront+WAF時は AWS_IAM+OAC に変更
  • API GWはスロットリング(lookup 5回/分など)

秘密管理

  • .env は .gitignore。本番は SSM SecureString(aws/ssmキー=無料)
  • 対象: Squareアクセストークン、Webhook署名キー、JWT秘密鍵、PINハッシュ
  • ローテーション: Squareトークン再発行→SSM更新→Lambda再起動(次回起動で取得)。WebhookキーはSquare Consoleで再生成→SSM更新
  • ログに秘密・カード情報・PIIを出さない(PCIスコープ外)

IAM最小権限

  • DynamoDB: 対象テーブルのみ
  • SSM: 対象パラメータのみ
  • execute-api:ManageConnections(WS通知)
  • ワイルドカード禁止

データ保護

  • 顧客は匿名(氏名・電話を持たない)
  • 注文・在庫のTTL(コード10分、接続2時間、カート5分)
  • 暗号化: DynamoDB既定(AWS所有キー)。必要ならCMK

監査・検知

  • 監査ログ: ペアリング、同期実行、端末解放、手動操作
  • アラーム: 呼び出し急増、429/5xx、同期失敗、キャッシュ鮮度超過

インシデント対応

  1. 不正検知 → webhook購読を一時停止(Square Console)+Function URL同時実行を0に
  2. 秘密漏えい疑い → Squareトークン/JWT秘密鍵をローテーション
  3. データ不整合 → フォールバック同期+予約の再計算ジョブ
  4. 復旧確認 → 少額決済・同期・在庫表示のスモーク

リリース前チェック

  • 署名検証が生ボディで動作
  • .env/秘密がコミットされていない
  • IAMが最小権限
  • アラーム・予算が有効
  • レート制限・同時実行上限が設定済み
  • 監査ログが出る

5. 再計算トリガー

  • 注文数が想定の2倍超
  • ポーリング間隔・カートheartbeat・同時カート数の変更
  • CloudFront/WAFの採用
  • 複数ロケーション化

7. 実装状況(2026-10)

  • webhook は Lambda Function URL(AuthType: NONE)で受信し、app.handler の /webhooks/square で署名検証・イベント冪等・在庫更新を行う。新規アカウントのLambda同時実行上限10を考慮し、常時予約はしない
  • 定期同期は EventBridge rate(15 minutes) の SyncFunction(app.syncHandler)。同期が無効な間も期限切れ引当の掃除を実行
  • 署名キーは SQUARE_WEBHOOK_SIGNATURE_KEY、通知URLは SQUARE_WEBHOOK_URL。Square Console に登録したURLと完全一致させる
  • 未実装(本番前): アラーム、レート制限、CloudFront/WAF、SSM SecureString 連携。現状は環境変数+SAMパラメータ(NoEcho)

8. 参照


9. Cloudflare Pages構成(現行AWSデモ・2026-10)

  • 顧客/店員/Terminal/起動パネルは Cloudflare Pages(静的リクエスト・帯域はFreeで無制限)に配置。S3/CloudFrontは使わない
  • 画面は config.js のapiBaseでAWS API Gatewayへ直接接続。CORSはデモでは*、本番はPagesドメインに限定する
  • WebSocketはAPI Gatewayのwss://へ直接接続。Pages Functionsは使わない(10万req/日上限を回避)
  • ポーリングは顧客10秒・Terminal 2秒に調整。店員の決済中のみ1秒
  • 停止はLambda同時実行0+同期ルール停止で、DynamoDBのデータは保持。DynamoDB 5+5 RCU/WCU×2は無料枠内
  • データはaws-data.ps1でローカルへexport/import/reset可能(DynamoDB直接)
  • Cloudflare Pages Free: 静的リクエスト・帯域無制限、500ビルド/月、20,000ファイル、25MiB/ファイル