Tailscale Serve と Funnel: リンクを実際に開けるのは誰か
Serve はサービスを tailnet 内で共有し、Funnel はそれを公開インターネットに露出します。到達できる相手、ID ヘッダー、Funnel が許可するポートを比較します。
どちらのコマンドもローカルサービスを Tailscale の HTTPS 名で公開するため、実行するマシンから見るとほぼ同じに見えます。違いは、その後に URL へ到達できるのが誰かという点にあり、その違いがアプリケーションにまだ必要な制御を決めます。Serve は利用者を tailnet の内側に保ち、Funnel は公開インターネットへ移します。まず利用者を選び、それに合うコマンドを選んでください。
Serve は tailnet の内側の問いに答える
Serve はローカルポートをプロキシするか、tailnet 上のデバイスにローカルコンテンツを配信し、tailnet のアクセスルールはすべてのリクエストに引き続き適用されます。ポート 3000 のダッシュボードは、あなたのデバイスだけが名前解決して接続できる HTTPS 名で到達可能になります。これは、利用者がすでに tailnet によって認証されており公開される面を増やしていないため、内部ツールにとって正しい既定値です。URL は通常のウェブサイトのように見え、まさにそのために人々はそれを普通のサイトと取り違えます。
Serve は転送するリクエストに、tailnet ユーザーを記述する ID ヘッダーを付けることもできます。アプリケーションがそのヘッダーを認証として信頼するなら、バックエンドを localhost に束縛して、ルーティング可能なアドレスで待ち受けるバックエンドがプロキシを一度も通っていないリクエストを受け取らないようにしてください。
Funnel は利用者を公開インターネットに変える
Funnel は選んだサービスを URL を持つ誰にでも公開し、訪問者にはクライアントもアカウントも tailnet への参加も不要です。したがってそのリソースには、あらゆる公開サービスに施す認証、レート制限、パッチが必要です。公開リクエストは Serve の tailnet ID ヘッダーを運ばないため、それに頼っていたアプリケーションは Funnel の下ではユーザー ID をまったく持ちません。別の公開コマンドを選んでも、認証の問いが代わりに答えられるわけではありません。
Funnel には、古いリリースのチュートリアルが触れていない制約もあります。名前のために Tailscale が取得する証明書で TLS を終端し、特定の待ち受けポートしかサポートしません(Funnel のドキュメント が説明しているとおりです)。サービスがそれらのポートの一つで HTTPS 以外のプロトコルを期待しているなら、Funnel は設定のパズルではなく間違った道具です。
モードはポートではなくクライアントから読む
二つのモードは同じローカルポートに対して別の時点で設定できるため、何かを共有する前に現在の状態を確認してください。status コマンドは、実際に何が誰に向けて公開されているかを報告します。URL が応答するという事実から利用者を推測しないでください。
tailscale serve status
tailscale funnel status
tailscale status --json | head -40
コマンドの構文はクライアントのバージョンによって変わっているため、コピーした呼び出しが意図したものと別のモードを選ぶことがあります。実行しているバージョンの文書化された形式を優先し、想定するのではなくクライアントが表示する確認を読んでください。Serve と Funnel の両方の設定がある場合、露出の観点で重要なのは公開側です。意図しなかった設定を重ねるのではなく、リセットしてください。
出力が利用者を示さないなら、立ち止まって status を読み直してください。利用者が明示されていない公開 URL は推測であり、その推測が内部ダッシュボードを公開インターネットに載せてしまいます。
本当に意図した利用者でテストする
サービスを公開したマシンからではなく、tailnet の外側からテストしてください。tailnet のデバイスからのリクエストはプロキシが動くことを証明しますが、部外者が排除されていることは証明しません。Tailscale クライアントがなく、tailnet への経路もないネットワークを使ってください。
curl -sI https://host.tailnet-name.ts.net
curl -sI https://host.tailnet-name.ts.net --resolve host.tailnet-name.ts.net:443:203.0.113.10
内部ダッシュボードなら、外側のリクエストは接続に失敗するか認可に失敗し、内側のリクエストは期待する ID で成功するはずです。公開サービスなら、外側のリクエストは成功し、アプリケーションは自前の資格情報を求めるはずです。URL だけでは分からないため、この 二つの結果のどちらを観察したかを記録してください。結果が意図と逆なら、まず公開設定を削除し、その後に調査してください。
サービスの公開は、外向きトラフィックがどこから出るかを制御する出口ノードの選択と同じ判断ではありません。Serve と Funnel は、あなたが動かすものに誰が到達できるかに答え、出口ノードは、あなた自身の接続がどこから来たように見えるかに答えます。二つの問いを分けておけば、比較は単純なままです。