2026年3月11日水曜日

GPT-5.4の謎の誤字

謎のハングルが含まれる。

admin の依存点を確認します

ダッシュボード API のどこがまだ SurrealDB 依存かを見て、
Cloudflare から取れる情報で置き換えられる部分부터寄せます。



부터

「~から」は韓国語で「부터」という。 

tailscaleで組まれた、複雑なシステムをCloudflareに移植を考える

かなり複雑な構成でtailscaleで組まれている。
ベットサーバとゲームキューを統合しようとすれば可能だが、分けた方が都合がいいことが多い。

・ベットサーバ(rustでカリカリにチューニングされてる、websocket使う)
・Surrealdb
・ゲームキューサーバ + UI(ベットサーバに信号を送り、ゲームステータスや配信サーバを管理)
・配信サーバ + UI(OBSなどをコントロール)
・OBS
・フロント
・管理画面


ベットサーバをCloudflare Durable Objectに、
SurrealdbをD1にしたとして、
他のサーバがDO宛にセキュアに操作したい。


betsrv: Rust + Axum + WebSocket + SurrealDB
game_queue_srv: Bun/Express + WebSocket + SurrealDB
admin: Hono + SurrealDB
client: Svelte フロント



どうやって「private」にするか

ここでいう private は、ネットワーク的に見えないより
認証されていない相手は絶対通さない意味させるのが実務的です。

方式A: Cloudflare Access Service Token

これが第一候補です。

  • ゲームキュー側

    • CF-Access-Client-Id

    • CF-Access-Client-Secret を付けて internal endpoint を呼ぶ

  • Worker 側

    • Access 配下に internal API を置く

良い点

  • サーバー間認証として強い

  • Secret をローテーションしやすい

  • Tailscale の ACL に近い感覚で運用できる

  • 監査しやす

用途

  • ゲーム開始信号

  • ベット開始/停止

  • 配信ステータス通知

  • ーバ内部 webhook

方式B: Worker 側で HMAC 署名検証

これもかなり有効です。

  • ゲームキュー

    • リクエスト本文

    • timestamp

    • nonce

    • 共有秘密鍵 署名を作る

  • Worker が署名検証する

良い

  • Access に依存しなくてもよい

  • アプリイヤで再送防止まで作れる

  • このイベントは本当にゲームキューが送ったか」を検証しやす

ベストプラクティ

  • timestamp を入れる

  • nonce 入れる

  • 5分以上古い要求は拒否

  • 同一 nonce は再利用禁止

方式C: Access + HMAC の両方

一番強いです。

  • Access で「び出し元サービス」を認証

  • HMAC で「この payload が改ざんされていない」ことを検証

内部制御なら、これがかなり堅いです

避けるべき

  • IP 制限だけ

    • Workers 側ではあまり信用しすぎない方がいい

  • 管理者用トークンを共用

    • 内部サーバ全部で同じ bearer token を雑に使うのは弱い

  • クライアント API と同じ経路で管理命令を送る

    • /admin/start_betting みたいなものそのまま公開しない

  • Tailscale の private IP へ Worker から直接行こうとする

    • 基本その発想は捨てた方がいい

あなたのケースでの具体設計

1. Worker に内部専用エンドポイントを作る

:

  • POST /internal/game/start

  • POST /internal/game/open-betting

  • POST /internal/game/close-betting

  • POST /internal/game/result

これらは 一般クライアントからは使わせない

2. Worker は認証 GameDO 転送する

例の流れ:

  • ゲームキュー game_id=20260311_01 に開始命令

  • Worker が認証検証

  • env.GAME_DO.idFromName(game_id)

  • その DO  fetch() か内部メッセージで転送

  • DO が状態を更新し、接続中ユーザーへ配信

3. GameDO はゲーム状態の唯一正本にする

今の betsrv 責務を見る限り、ここに寄せるのが自然です。

  • status

  • betting_end_time

  • race_table

  • pending bets

  • 結果確定

  • ユーザー通知

4. D1 は永続化に使う

  • user

  • bet history

  • race_table

  • settings

Tailscale はどう絡めるか

Tailscale は ゲームキューや配信サーバ同士の内部連携 に残してよいです。
でも Workers との境界はこう切るのがよいです。

text
[Tailscale内]
ゲームキュー ---- 配信サーバ ---- 各内部サービス
|
| HTTPS outbound
v
[Cloudflare]
Internal Worker Endpoint
|
v
GameDO / D1

つまり、

  • Tailscale 内部では private

  • Cloudflare 境界では Access/HMAC で private

  • Worker は Tailscale に直接入らない

です。

さらに安全にするなら

コマンドイベント化する

制御命令を単なる REST ではなく、冪等な command/event として扱うと安全です。

例:

  • command_id

  • game_id

  • action

  • issued_at

を付ける

GameDO 側で

  • 同じ command_id 二重実行しない

  • 順序チェックする

  • 古い command は拒否する

ようにすると、誤再送に強くなります。

権限をサービスごとに分ける

  • ゲームキュー

    • start_game, open_betting, close_betting

  • 結果判定サーバ

    • set_result

  • 管理画面

    • 手動 override のみ

というふうに、同じ secret 全サービスで使い回さない方がよいです。

一番おすすめ

あなたの要件なら、私はこれを勧めます。

推奨アーキテクチャ

  • GameDO

    • 1ゲーム = 1DO

  • D1

    • 続化

  • Internal Control API on Worker

    • /internal/...

  • 認証

    • Cloudflare Access Service Token

    • できれば HMAC 署名も追加

  • Tailscale

    • 内部サーバ間の接続に継続利用

    • Worker との境界には使わない

ひとことで言うと

ゲームキューから betsrv に開始信号を送りたいなら、Worker に内部制御APIを作って、そこから GameDO を叩く。
private は Tailscale 直結ではなく、Access/HMAC で実現する。

これが一番安全で現実的です。


あいうえお