複数の人やプロジェクトが1つのプロキシアカウントを使うようになると、決まって同じ疑問が出てくる。チーム全体で1つの認証情報を共有するのをどうやって止めるか。どのクライアントがどれだけのギガバイトを消費したのかをどう把握するか。他の全員に影響を与えずに契約者のアクセスをどう遮断するか。この業界では、こうした疑問はたいてい「サブユーザー」という言葉で答えられるが、その言葉の意味は販売元によって異なる。
サブユーザーとは実際に何を指すのか、レジデンシャルプロキシ製品が提供するものと提供しないもの、そしてどちらにせよ根底にある3つの問題をどう解決するかを説明する。
この市場でサブユーザーが意味するもの
プロバイダーがサブユーザーを提供している場合、それは親アカウントの下で発行される2次的なプロキシ認証情報のセットを指す。通常は独自の帯域上限を持たせることができ、場合によっては独自のターゲティング制限も持たせられ、親アカウントに影響を与えずに無効化できる。これはトラフィックそのものに紐づいたアクセス制御機能である。
チームがサブユーザーを求める理由は3つあり、それぞれ解決策が異なるため分けて考える価値がある。
分離。 異なる人物やプロジェクトが1つの認証情報を共有するべきではない。それにより、漏洩や離脱が発生した際の影響範囲を抑えられる。
帰属の特定。 通常は請求や利益計算のために、どのクライアント、チーム、プロジェクトが帯域のどの部分を使用したかを誰かが把握する必要がある。
上限管理。 1つのプロジェクトが、誤ってあるいは暴走したジョブによってプラン全体を消費してしまうことがあってはならない。
レジデンシャルプロキシ製品が提供するもの
はっきり言うと、Shifterのレジデンシャルプロキシにはサブユーザーごとのプロキシ認証情報は存在しない。認証は1つのユーザー名とパスワードで行い、ターゲティングやセッションのオプションはユーザー名の中に表現される。詳細はゲートウェイと認証に記載されている。独自の帯域上限を持つ2つ目のプロキシ認証情報を発行する仕組みはない。
実際に存在するのは2つの仕組みに分かれており、それらを組み合わせることで上記の3つの問題をカバーしている。
Team Workspacesはアカウントへのアクセスを管理する。メールで人を招待し、役割を割り当てる。Viewerはメンバーシップ、トラフィック、請求書を読み取り専用で閲覧できる役割、Billingはそれに加えて資金投入や購入ができる役割、Adminは完全なメンバーシップとチーム管理ができる役割だ。役割はグローバルではなくワークスペースごとに設定され、削除は即時に反映され既存のセッションも終了する。1人が複数のワークスペースに所属し、1回のログインで切り替えることもできる。詳細な仕様はTeam Workspacesの発表にある。
セッション識別子はトラフィックの区分を管理する。すべてのリクエストに任意に選んだセッションIDを付与できるため、別々の認証情報を使わずにクライアントごと、プロジェクトごとの帰属特定が可能になる。
押さえておくべき区別はこうだ。ワークスペースはアカウントを管理できる人を制御し、セッション識別子はトラフィックが何をしているかを整理する。他社に存在するサブユーザーは、この2つを1つに混ぜ合わせてしまっている。
サブユーザーなしで分離を実現する
1つの認証情報がすべてに使われるため、分離の作業はその認証情報をどのように保存し、どのように公開するかに移る。
認証情報はコードや設定、共有ドキュメントに置くのではなく、シークレットマネージャーに保管し、アプリケーションが実行時に環境から読み取るようにする。人がプロキシの認証情報そのものを必要とすることは業務上ないはずで、必要なのはシステムの方だ。テストが必要なエンジニアには、値そのものではなく、それを利用するサービスへのアクセスを与えればよい。
本当に影響範囲を分離する必要がある場合は、独自のプランを持つ別々のワークスペースを用意すれば、プランがワークスペースを越えて共有されないため、実質的に別々の認証情報を得られる。これはサブユーザーより重い仕組みであり、請求も別になるため、単に整理整頓したいという場合よりも、クライアントや事業部門がそもそも自分自身のアカウントを持つべき場合に適している。
そして、必要になる前にローテーションの計画を立てておく。1つの認証情報が共有されているため、ローテーションを行うとすべてに一度に影響が及ぶ。そのためこれをデプロイと同じように扱い、シークレットストアを更新し、すべてのクライアントに反映し、その後で古い値を無効化する。この順序を省略すると、その認証情報がどれだけ多くの場所で使われているかをチームが思い知る最も典型的な事態、つまりすべての場所が同時に407エラーを返し始めるという事態を招く。
システムではなく人に関しては、オフボーディングはワークスペースの役割を通じて行う。メンバーを削除すれば、そのパネルへのアクセスは開いているセッションも含めて即座に終了する。これは契約者のケースをカバーしており、実際に問われていることの大半はこれに当たる。
サブユーザーなしで帰属特定を実現する
ここでセッション識別子が役割を果たす。最初から意図的に構造化しておく価値がある。
セッションIDにテナントを埋め込めば、すべてのリクエストが誰のためのものかを追跡できる。IDは任意に選べる文字列なので、構造化された命名規則を採用するコストはゼロであり、帰属特定は自分たちのログを解析する作業になる。
def proxy_for(client, job, country, ttl=600):
sid = f"{client}-{job}" # e.g. acme-prices-0827
user = f"customer-USERNAME-country-{country}-sid-{sid}-ttl-{ttl}"
url = f"http://{user}:PASSWORD@p.shifter.io:443"
return {"http": url, "https": url}
次に、リクエストごとのバイト数をクライアントに対して記録する。プロバイダーからの請求書はアカウント全体の単一の合計値であり、内訳を教えてくれないからだ。テナントごとにレスポンスサイズを合計すれば、請求やマージン計算に使える利用量が得られる。そして定期的に合計値を請求書と照合することで正確性を保てる。というのも、再試行や失敗したリクエスト、接続オーバーヘッドはすべて帯域を消費するが、単純なボディサイズのカウントではそれらを見落としてしまうからだ。テナントごとに注視すべき指標は「1レコードあたりのバイト数」であり、これはプロキシのKPIで扱われている、帰属特定をコストの議論に変える数値だ。
セッションはここでも本来の目的を果たす。クライアントごとに異なる識別子を使うことで、2つのクライアントのフローが同じセッション上で衝突するのを防げる。これは複数のジョブが同時に実行されるようになった瞬間から重要になる。詳しい仕組みはスティッキーとローテーティングにある。
サブユーザーなしで上限管理を実現する
プロバイダー側にテナントごとの上限は存在しないため、上限は自分たちのスケジューラー側に持たせる必要がある。そして、本来そこにあるべきものでもある。クライアントが何をどこまで利用できるかを知っているのは自分たちのシステムであり、プロキシ側ではない。
各テナントに期間ごとの帯域予算を設定し、すでに記録している利用状況に対してそれを適用する。予算が尽きたら、共有の割り当てを食いつぶすのではなく、そのテナントのジョブを停止またはキューに入れる。アラートは上限に達した時点ではなく、その手前で出す。これに加えて、テナントごとの同時実行数の割り当てを組み合わせることで、1つの大規模な夜間バッチが4つの小さな時間制約のあるジョブを飢餓状態にすることを防ぎ、テナントごとのリトライ予算を組み合わせることで、1つのクライアントの失敗し続けるターゲットが共有プールを圧迫することを防ぐ。これはリトライとバックオフとレート制限で述べられている抑制の考え方だ。
これらすべてを収める自然な場所は、すでにすべてのリクエストを見ているコンポーネントである。だからこそ、テナントの予算や同時実行数の割り当て、帰属特定をジョブごとに分散させるのではなく、プロキシマネージャーにまとめて置くのが正しい。
1つのアカウントか複数のワークスペースかを選ぶ
この判断は見た目より単純なことが多く、結局は商取引上の関係を誰が持つかに帰着する。
サービスを提供していて、ベンダーがサプライチェーンの一部である場合は、論理的なテナントを持つ1つのアカウントで運用する。帯域を購入するのは自分たちであり、クライアントはプロバイダーを目にすることがなく、区分は自分たちのコード内の命名規則にすぎない。これはエージェンシー型のよくある形だ。
クライアントが自分自身のプランと請求書を持つべき場合は、クライアントごとのワークスペースを運用し、自分たちのチームをAdminとして追加する。請求は本当に別々になり、プランがワークスペースを越えないためトラフィックが混ざることもなく、契約が終了した場合にはクライアントがきれいに引き継ぐことができる。
初日からテナント識別子を軸に設計しておけば、これらの間を移動するのは設定変更で済み、作り直しにはならない。
結論
サブユーザーは3つの独立したニーズに対する1つの実装であり、唯一の実装ではない。レジデンシャルプロキシ製品には1つのプロキシ認証情報しか存在しないため、分離はシークレット管理から、そして絶対的な分離が必要な場合は独自のプランを持つ別々のワークスペースから得られる。人に対するアクセス制御は即時無効化が可能なワークスペースの役割から得られる。帰属特定は構造化されたセッション識別子と、自分たち自身によるテナントごとのバイト計測から得られる。これは請求書が単一の合計値だからだ。そして上限管理は、各テナントが何をどこまで利用できるかを知る唯一の場所であるスケジューラー内の予算から得られる。最初からテナント識別子を軸に構築すれば、この3つすべてが手に入り、後になって収集用のコードに手を加えずにクライアントを自分専用のワークスペースへ移すという選択肢も残せる。
その基盤にあるのはレジデンシャルプロキシだ。1つのゲートウェイで、国、都市、セッション、TTLをすべてリクエストごとに指定できる。まさにこれによって、テナントごとの区分が製品上の制約ではなく命名規則になる。そしてGB単位の価格設定により、社内で帰属させる利用量は、実際に請求される単位と同じ単位で計測される。