行ストリーム処理で複数行パターンを一致させる(begin/end マーカーのバッファリング)
一言まとめ
行単位で即フラッシュするストリーム処理に PEM 秘密鍵のような複数行ブロックの検出を足すには、開始マーカーを見た行からバッファリングに入り、終了マーカーか安全上限(100 行 / 64KB)で抜ける。上限超過時は無加工でフラッシュする(fail-open)。単一行パターンの遅延は変わらない。
目次 6 sections
調査時点: 2026-04。公開 OSS の mask-pipe(github.com/c12o-dev/mask-pipe)が PEM(秘密鍵や証明書を開始・終了マーカー付きのテキストで表す形式) 秘密鍵のマスクを足したときの ADR から。
問題
ストリーミング用のフィルタは「入力 1 行ごとに出力をフラッシュする」ことを保証したい(tail -f | filter が EOF まで止まらないため)。一方、PEM 秘密鍵のブロックは 20〜50 行にまたがり、ブロック全体を見ないとマスクするか決められない。99% 以上の行は複数行の秘密情報を含まないので、それらの遅延を増やさないことが制約になる。
決定: begin/end マーカーによる条件付きバッファリング
- パターン定義に省略可能な
Multiline bool/BeginMarker/EndMarkerを足す。 - エンジンが
BeginMarkerに一致する行を見たらバッファリングモードに入り、行を溜める。 EndMarkerに一致するか、安全上限(100 行または 64KB の早いほう)を超えるまで続ける。EndMarkerで抜けたら、溜めたブロックを結合して本来の正規表現を適用し、一致すれば置換文字列(例:[REDACTED PRIVATE KEY])に置き換える。- 安全上限で抜けたら、溜めた行を無加工でフラッシュし(fail-open)、stderr に警告を書く。入力が壊れていてもデータは失わない。
- 単一行パターン(既定)は一切影響を受けない。
結果
- PEM ブロック内の行だけ、ブロック全体を読む時間ぶんの遅延が乗る(2KB の鍵で 10ms 未満)。
BEGINだけあってENDが来ない入力では、最大 100 行ぶん遅れてからフラッシュされる。- 同じ仕組みで、後から YAML の秘密ブロックや複数行 JSON にも対応できる。
- パターン構造体に、大半のパターンでは nil / false のフィールドが 3 つ増える。
採らなかった案
| 案 | 棄却理由 |
|---|---|
| 入力全体をメモリに溜めてから一致 | ストリーミング保証が壊れる。tail -f が EOF まで出力しない |
| N 行のスライディングウィンドウ | PEM ブロックの長さはばらつく(RSA-2048 で約 27 行、RSA-4096 で約 52 行)。固定幅は大きい鍵を取りこぼすか、全行でメモリを無駄にする |
| 複数行パターンを見送る | PEM 鍵は明示的なマーカーがあり偽陽性ゼロで、最も漏れやすい秘密情報の 1 つ。外すと価値が落ちる |
関連
更新履歴
- 2026-04-17: 初版(mask-pipe ADR-0004)
- 2026-10-17: Wiki へ移植、概念ページとして再構成