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

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

顧客はログを外に送れないと言った

TT Labで続きを見る

目標

顧客のサーバーで、顧客の担当者が自分で実行するサポートバンドルの収集ツールを作ります。許可リストで集め、秘密をマスクし、manifestとサイズの上限を設け、同じ入力なら同じバイト列になるtar.gzにまとめます。

なぜ重要なのか

ログを外に送れない顧客からバンドルを受け取るには、顧客のセキュリティ担当者の承認が必要です。何が入ったのか、何を何件マスクしたのか、受け取ったファイルが確認したそのファイルなのかを示せなければ、バンドルは外に出せません。毎回人がファイルを選ぶと、秘密が漏れたり、役に立たないバンドルができたりします。

用意するもの: /opt/lab/p1a-bundle/site(顧客サーバーのコピー。VERSION、etc、logs、run/environ、data)、/opt/lab/p1a-bundle/rules.tsv(顧客のセキュリティチームの追加のマスキングルール)。 作業ディレクトリは/root/bundleです。想定所要時間は60分で、セッションが終わると、/root/bundleは消えます。

収集のルール(このラボの約束):

ステップ

  1. 用意するもののsiteから、収集のルールに合うファイルの相対パスを、1行に1つずつ記録します(ファイル: /root/bundle/scope.txt)。
  2. 標準入力をマスクして標準出力へ出し、標準エラー出力にredactions=Nを出力するスクリプトを作ります(ファイル: /root/bundle/redact.py)。
  3. python3 collect.py SRC OUTが、OUT/stageに、許可リストのファイルをマスクして置くスクリプトを作ります(ファイル: /root/bundle/collect.py)。
  4. collect.pyが、manifestを作るようにします(files配列: path・size・sha256・redactions・truncated、path順に並べ替え、total_redactions。ファイル: OUT/stage/manifest.json)。
  5. ログファイルに65536バイトの上限を適用し、manifestのtruncated・redactionsを実際に合わせます。
  6. collect.pyが、バンドルを作るようにします(ファイル: OUT/support-bundle.tar.gz)。項目は、support-bundle/の下で名前順にし、同じ入力なら、いつどこでまとめても、sha256が同じでなければなりません。
  7. --rules FILEを受け取って、kind<TAB>정규식のルール(プレースホルダーは正規表現です)を、デフォルトのルールのあとに適用し、[REDACTED:kind]でマスクするようにします。
  8. 用意するもののsiteとrules.tsvから、受け渡し用のバンドル、SHA256SUMS、REDACTION-REPORT.tsvを作ります(保存先: /root/bundle/delivery/support-bundle.tar.gz、SHA256SUMS、REDACTION-REPORT.tsv)。

参考

何を入れるかを、許可リストで決める

用意するもののsiteから、収集のルールに合うファイルの相対パスを、1行に1つずつ記録してください(ファイル: /root/bundle/scope.txt)。

siteの全体を、まずfindで見渡してみてください。ルールに名前で書かれているものだけを入れ、ローテーションされたログ、下位ディレクトリのログ、顧客データ、pidファイルは、ルールにないので外れます。パスは、siteを基準にした相対パスです。

狭く正確なマスクのフィルター

標準入力をマスクして標準出力へ出し、標準エラー出力にredactions=Nを出力するスクリプトを作ってください(ファイル: /root/bundle/redact.py)。

正規表現は、形で決めます。秘密鍵は複数行なので、行のルールより先に、re.Sでブロックごと置き換えてください。キー名は、passwordが「含まれる」ものではなく、「終わる」ものでなければ、password_min_lengthが生き残りません。値は、引用符で囲まれていることも、&や空白で終わることもあります。

許可リストだけを集めて、マスクしたstageを作る

python3 /root/bundle/collect.py SRC OUTが、OUT/stageに、許可リストのファイルをマスクして置くスクリプトを作ってください(ファイル: /root/bundle/collect.py)。

redact.pyを同じディレクトリでimportすれば、ルールを2回書かずに済みます。etcの下をたどるときは、os.path.islinkでリンクを除き、run/environはNULで分割してから並べ替えて、env.txtとして置きます。もう一度動かしたとき、前のstageのファイルが残らないようにしてください。

確認する人が照合するmanifest

collect.pyが、manifestを作るようにしてください(files: path・size・sha256・redactions・truncated、path順、total_redactions。ファイル: OUT/stage/manifest.json)。

sha256とsizeは、マスクしたあとで、stageに実際に書いたバイト列から計算します。redactionsは、そのファイルでマスクした件数です。このファイルに生成時刻を入れると、ステップ6で何が問題になるかを、先に考えてみてください。

大きなログは、マスクしてから最近の行だけ

logsのファイルごとに65536バイトの上限を適用し、manifestのtruncated・redactionsを、切り詰めた結果に合わせてください。

マスクした結果の末尾から65536バイトを切り取ったあと、その窓の最初の行が完全でなければ捨てます。窓の直前のバイトが改行かどうかを見れば、判断できます。件数は、切り落とした部分を除いて、残った部分で数え直す必要があります。

同じ入力なら同じバイト列

collect.pyが、バンドルを作るようにしてください(ファイル: OUT/support-bundle.tar.gz)。項目は、support-bundle/の下で名前順にし、別の時刻・別のOUTでまとめても、sha256が同じでなければなりません。

tarには、更新時刻・所有者・権限・順序が入り、gzipのヘッダーには、時刻がもう1回入ります。Pythonなら、TarInfoを自分で作って値を固定し、GzipFileのmtimeを決めてください。GNU tarでまとめるなら、reproducible-buildsのドキュメントのオプションを見てください。

顧客のセキュリティチームの追加ルールをファイルで受け取る

collect.pyが、--rules FILE(kind正規表現)を受け取って、デフォルトのルールのあとに適用し、件数をmanifestにまとめるようにしてください。

コメント(#)と空行は飛ばします。ルールは、コードに埋め込まず、ファイルから読んでください。採点ツールは、毎回異なる種類名と正規表現を渡し、ルールなしで動かしたとき、その値が残るかも見ます。

受け渡し用のバンドルと、確認用の報告書

用意するもののsiteとrules.tsvから、受け渡し用のバンドル、SHA256SUMS、REDACTION-REPORT.tsvを作ってください(保存先: /root/bundle/delivery/support-bundle.tar.gz、/root/bundle/delivery/SHA256SUMS、/root/bundle/delivery/REDACTION-REPORT.tsv)。

SHA256SUMSは、受け取る側が、sha256sum -cで確認できる形式です。報告書の件数は、manifestを写さずに、バンドルの中のファイルのマーカーを、種類ごとに数えて書いてください。採点ツールは、いまのcollect.pyで、用意するものからもう一度まとめて、受け渡し用のものとバイト列が同じかを見ます。