TT Lab
はじめる
学ぶ 学習パス コース

FDE総合演習:倉庫に同じ注文が3回届いた

プロキシを有効にしたら社内 API が落ちた

TT Labで続きを見る

目標

顧客の社内プロキシの設定で、curl・Python urllib・requestsが、それぞれどの経路に行くのかを、記録するダミーのプロキシで直接測り、3つのツールがすべて同じ経路に行く設定・連携ツール・判定ツールを作ります。

なぜ重要なのか

プロキシの環境変数は、標準ではなく慣習なので、ツールごとに解釈が違います。そのため、顧客の設定を入れたあと、curlのヘルスチェックは緑なのに、Pythonの収集ツールだけが、社内APIから403を受け取ることが起きます。推測で設定を直すと、1つのツールを生かして別のツールを殺しやすくなります。このラボは、「そのリクエストがプロキシに届いたか」を、記録で確認する習慣を作ります。

用意するもの: /opt/lab/p1a-proxy/。corpnet.py(ダミーのプロキシ・社内API)、customer.env(顧客の設定)、cases.tsv(ケース18個)、connector.py(問題のある連携ツール)です。インターネットはありません。127.0.0.2・127.0.0.3も、このPod自身(ループバック)で、corp.example・saascorp.exampleのような名前は解決されません。直接行こうとしたリクエストは、名前解決で失敗しますが、プロキシの記録にないこと自体が、「直接行った」という証拠です。

想定所要時間は60分です。セッションが終わると、/root/proxyは消えるので、必要なファイルは別に保管してください。

ステップ

  1. python3 /opt/lab/p1a-proxy/corpnet.py upで、社内ネットワークの模擬を立ち上げ、customer.envを適用した状態で、http://127.0.0.2:8080/healthを、curl・urllib・requestsで1回ずつリクエストします。応答本文のserved_byとidを見て、도구<TAB>PROXY|DIRECT<TAB>idの形で、3行を記録します(プレースホルダーはツール名です。ファイル: /root/proxy/repro.tsv)。
  2. cases.tsvのステップ2のケース(c01..c05、大文字・小文字、スキームごとの変数)を、3つのツールで実行して、case<TAB>curl<TAB>urllib<TAB>requestsの形で記録します(ファイル: /root/proxy/matrix.tsv)。
  3. ステップ3のケース(c06..c10、サフィックス・先頭のドット・アスタリスク付きのドメイン)を測って、matrix.tsvに追加します。
  4. ステップ4のケース(c11..c14、IP・CIDR・ポート)を測って、matrix.tsvに追加します。
  5. ステップ5のケース(c15..c18、アスタリスク1文字と、小文字・大文字の優先順位)を測って、matrix.tsvに追加します。
  6. 3つのツールがすべて、社内の4か所(127.0.0.2:8080、127.0.0.3:8080、localhost:8081、api.corp.example:8080)は直接、外部の3か所(httpとhttpsのsaascorp.example、updates.vendor.example)は、プロキシhttp://127.0.0.1:3128経由で行くようにする設定を作ります(ファイル: /root/proxy/fixed.env)。
  7. connector.pyをコピーして直します(コピー先: /root/proxy/connector.py)。CONNECTOR_PROXYは引き続き使いますが、NO_PROXYに該当するURLは直接行き、環境のHTTP_PROXY・HTTPS_PROXYは使ってはいけません。
  8. 探針を作ります(ファイル: /root/proxy/route_probe.py)。python3 route_probe.py <env파일> URL...が、設定ファイルのプロキシのアドレスを、ローカルのセンチネルに差し替えて、3つのツールを実際に実行し(プレースホルダーはenvファイルのパスです)、URLごとにurl<TAB>curl<TAB>urllib<TAB>requestsを出力し、判定が分かれたら終了コード3、すべて同じなら0で終わる必要があります。

参考

顧客の設定で障害を再現して、証拠を残す

corpnetを立ち上げ、customer.envで、3つのツールのリクエストを1回ずつ送ったあと、ツール・経路・idを記録してください(ファイル: /root/proxy/repro.tsv)。

応答本文のserved_byがcorp-proxyなら、プロキシを通ったということです。idは、logsの記録の行と対応している必要があり、記録のUser-Agentで、どのツールが送ったかを、クロスチェックされます。customer.envは、set -aで、サブシェルでだけexportしてください。

大文字のHTTP_PROXYとALL_PROXYを測る

cases.tsvのc01..c05を、3つのツールで実行して、PROXY/DIRECTで記録してください(ファイル: /root/proxy/matrix.tsv)。

ケースごとに、env -iで、きれいな環境を作り、リクエストの前後で、proxy.jsonlの行数が増えたかを見てください。curlのマニュアルのENVIRONMENTの節で、http_proxyにだけ付いた例外を探してみてください。

サフィックス・先頭のドット・アスタリスク付きのドメイン

c06..c10を測って、追加してください(ファイル: /root/proxy/matrix.tsv。前のケースの行は消さないでください)。

直接行こうとしたリクエストは、名前解決で失敗します。失敗したかどうかではなく、プロキシの記録に届いたかどうかで判定してください。saascorp.exampleは、corp.exampleで終わる、別の会社の名前です。

CIDRとポートを書いたNO_PROXY

c11..c14を測って、追加してください(ファイル: /root/proxy/matrix.tsv)。

CIDRのサポートは、curlのマニュアルの--noproxyの説明に、バージョンとともに出てきます。urllibのドキュメントは、no_proxyの項目にポートを付けられると書いています。ドキュメントが何も言っていないツールは、測ってみないとわかりません。

アスタリスク1文字と、小文字の優先

c15..c18を測って、追加してください(ファイル: /root/proxy/matrix.tsv)。

アスタリスクが、リストの中の1つの項目のときと、リスト全体のときを、比べてください。空文字列の小文字の変数が、「設定されていない」と読まれるのか、「空のリスト」と読まれるのかも、ツールごとに違います。

3つのツールの共通項で設定を書き直す

社内の4か所は直接、外部の3か所はプロキシ(http://127.0.0.1:3128)経由になる設定を作ってください(ファイル: /root/proxy/fixed.env)。

前に埋めた表で、3つのツールがすべて同じ答えを出した表記だけを選んでください。大文字・小文字、ドメインの前のドット、CIDRの代わりに使うもの、ポートを付けるかどうか、の4つを決める必要があります。

proxies引数を使う連携ツールを直す

/opt/lab/p1a-proxy/connector.pyをコピーして、NO_PROXYを守るように直してください(コピー先: /root/proxy/connector.py)。

requests.utilsに、URLとno_proxyの文字列で、迂回するかどうかを教えてくれる関数があります。セッションのtrust_envは、環境変数のプロキシを使うかどうかを決めます。社内のIPをコードに埋め込むと、別のNO_PROXYで採点するときに不合格になります。

どんな設定でも、ツールごとの経路を測る探針

探針を作ってください(ファイル: /root/proxy/route_probe.py)。envファイルとURLを受け取って、3つのツールの経路を実際の実行で判定してTSVで出力し、分かれたら3、同じなら0で終わります。

顧客のプロキシのアドレスは、このPodから届きません。判断の規則(no_proxy)はそのままにして、プロキシの値だけを、ローカルのセンチネルのアドレスに差し替えれば、センチネルが接続を受けたかどうかで判定できます。採点ツールは、ランダムなドメインとプロキシのアドレスで試験します。