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、同期失敗、キャッシュ鮮度超過
インシデント対応
- 不正検知 → webhook購読を一時停止(Square Console)+Function URL同時実行を0に
- 秘密漏えい疑い → Squareトークン/JWT秘密鍵をローテーション
- データ不整合 → フォールバック同期+予約の再計算ジョブ
- 復旧確認 → 少額決済・同期・在庫表示のスモーク
リリース前チェック
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/ファイル