マスクしたのにメールアドレスがストレージに残った
目標
同じスパン6個を、プロセッサーの順序とパイプライン構成だけを変えて実際のコレクターに流し、結果のスパン数・残ったメールアドレス・コネクターが数えた値がどう変わるかを確認したうえで、運用向けのパイプライン一式を完成させます。
なぜ重要なのか
コレクターの設定は、文法が合っていても順序が間違っていると、黙って別のことをします。属性を作るプロセッサーよりも、その属性でフィルタリングするプロセッサーが前に立つと、フィルタリングは何もできません。キー名で消した個人情報は別の属性の値に残り、複数のパイプラインにつないだレシーバーは、それぞれにコピーを渡します。個人情報のマスキングとコストのメトリクスがパイプラインのどこにあるかで結果が分かれるため、設定を読む目と、実際に流して確認する習慣の両方が必要です。
用意されている環境
python3 /opt/fixtures/otca_order_lab.py initが、/root/otca-order/にspans.json(スパン6個)、processors.yaml(プロセッサー定義の集まり)、base.yaml(プロセッサーなしの基準設定)を置きます。python3 /opt/fixtures/otca_order_lab.py run 설정.yaml(プレースホルダーは設定ファイル名です)は、lab-k8sイメージのotelcol-contrib 0.116.0を実際に起動してスパンをOTLP/HTTPで送り、fileエクスポーターが書いた結果を要約して/root/otca-order/out/にコピーしたあと、コレクターを停止します。皆さんが別に起動したコレクターと衝突しないように、コピーでレシーバーのポートとfileのパスだけを変えます。プロセッサーと順序はそのままです。採点も、同じ方法で皆さんの設定を再実行します。
ステップ
python3 /opt/fixtures/otca_order_lab.py initで材料を作成してから、python3 /opt/fixtures/otca_order_lab.py run /root/otca-order/base.yamlを実行してください。実際のotelcol-contribが起動し、spans.jsonのスパンを受け取って、fileエクスポーターで書き出します。要約を見て、/root/otca-order/01-baseline.txtに、spans=、spans_with_user_email=、spans_with_any_email=(どの属性値にでもメールアドレスが含まれているスパンの数)を書いてください。/root/otca-order/filter-first.yamlを作成してください。base.yamlに、processors.yamlのfilter/healthとtransform/routeの定義をそのままコピーし、tracesパイプラインのプロセッサーを[filter/health, transform/route]の順にします(fileのパスはout/filter-first.json)。runの結果を、/root/otca-order/02-filter-first.txtにspans=とroutes=(要約のroutesの値そのまま)として書いてください。- 同じ2つの定義で
/root/otca-order/transform-first.yamlを作成し、順序を[transform/route, filter/health]に変えてください(out/transform-first.json)。/root/otca-order/03-transform-first.txtにspans=とroutes=を書き、ステップ2と比較してください。 /root/otca-order/redact.yamlに、ステップ3の順序のうしろにattributes/redactを付けてください([transform/route, filter/health, attributes/redact]、out/redact.json)。/root/otca-order/04-redact.txtに、spans_with_user_email=、spans_with_any_email=、leaked_attribute=(メールアドレスが残った属性のキー)を書いてください。/root/otca-order/mask.yamlに、redact.yamlの3つのプロセッサーの後ろにマスキング用のプロセッサーを1つ追加してください。transformプロセッサーのOTTLのreplace_all_patterns(attributes, "value", 정규식, "***")(プレースホルダーは正規表現です)で、すべての属性値の中にあるメールアドレスの形をマスクします。採点では、スパンが4個残り、どこにもメールアドレスがなく、url.query属性がnotify=より前の部分と一緒に残っているかを確認します。/root/otca-order/fanout.yamlにパイプラインを2つ置いてください。traces/rawはプロセッサーなしでfile/rawへ、traces/cleanはステップ5のプロセッサー4つを経由してfile/cleanへ出力し、どちらも同じotlpレシーバーから受け取ります。/root/otca-order/06-fanout.txtに、raw_spans=、clean_spans=、raw_spans_with_any_email=を書いてください。/root/otca-order/count.yamlで、countコネクターを、tracesパイプライン(プロセッサーは[transform/route, filter/health])のエクスポーターであり、かつmetricsパイプラインのレシーバーとして置いてください。metricsパイプラインは、fileエクスポーター(例:file/metrics)へ出力します。/root/otca-order/07-count.txtに、span_count_metric=(trace.span.countの値)とcounted_after=(tracesパイプラインの最後のプロセッサーの名前)を書いてください。/root/otca-order/final.yamlを書いてください。tracesパイプラインはmemory_limiterで始まりbatchで終わり、その間で、パスの正規化、ヘルスチェックの破棄、user.emailの削除、値の中のメールアドレスのマスキングを、この順に行います。スパンはfileエクスポーター1つへ、countコネクターが数えたtrace.span.countはmetricsパイプラインを経由して別のfileエクスポーターへ出力します。採点では、otelcol-contrib validateと実際の実行で、スパン4個・メールアドレス0個・パスの種類2つ・trace.span.count 4を確認します。
参考
- プロセッサー定義(processors:)の位置ではなく、
service.pipelines.<이름>.processors(プレースホルダーはパイプライン名です)のリストの順序が実行順序です。 - よくある間違い: 正規化よりフィルタリングを前に置くこと、キーの削除だけで個人情報の除去が終わったと考えること、コネクターより前のプロセッサーが数える値に影響することを忘れることです。
- このラボのマスキング用の正規表現は練習用です。実際の個人情報の除去には、フィールドの一覧と検証が別に必要です。
- Collector configuration・Transforming telemetry
プロセッサーなしで流したスパン6個
python3 /opt/fixtures/otca_order_lab.py initで材料を作成してから、python3 /opt/fixtures/otca_order_lab.py run /root/otca-order/base.yamlを実行してください。実際のotelcol-contribが起動し、spans.jsonのスパンを受け取って、fileエクスポーターで書き出します。要約を見て、/root/otca-order/01-baseline.txtに、spans=、spans_with_user_email=、spans_with_any_email=(どの属性値にでもメールアドレスが含まれているスパンの数)を書いてください。
user.emailのキーがなくても、別の属性値にメールアドレスが入っていることがあります。要約の下にあるスパンごとの属性を、1行ずつ読んでみてください。
フィルタリングを先に置くと
/root/otca-order/filter-first.yamlを作成してください。base.yamlに、processors.yamlのfilter/healthとtransform/routeの定義をそのままコピーし、tracesパイプラインのプロセッサーを[filter/health, transform/route]の順にします(fileのパスはout/filter-first.json)。runの結果を、/root/otca-order/02-filter-first.txtにspans=とroutes=(要約のroutesの値そのまま)として書いてください。
filter/healthはhttp.route属性を見ます。その属性は、誰がいつ作るでしょうか。
正規化を先に置くと
同じ2つの定義で/root/otca-order/transform-first.yamlを作成し、順序を[transform/route, filter/health]に変えてください(out/transform-first.json)。/root/otca-order/03-transform-first.txtにspans=とroutes=を書き、ステップ2と比較してください。
パイプラインのprocessorsのリストは、宣言順ではなく実行順です。定義ブロックの位置は関係ありません。
キーを消したのにメールアドレスが残った
/root/otca-order/redact.yamlに、ステップ3の順序のうしろにattributes/redactを付けてください([transform/route, filter/health, attributes/redact]、out/redact.json)。/root/otca-order/04-redact.txtに、spans_with_user_email=、spans_with_any_email=、leaked_attribute=(メールアドレスが残った属性のキー)を書いてください。
attributesプロセッサーのdeleteは、キーの名前で消します。値の中にメールアドレスが混ざっている別のキーは、わかりません。
属性は残して値だけマスクする
/root/otca-order/mask.yamlに、redact.yamlの3つのプロセッサーの後ろにマスキング用のプロセッサーを1つ追加してください。transformプロセッサーのOTTLのreplace_all_patterns(attributes, "value", 정규식, "***")(プレースホルダーは正規表現です)で、すべての属性値の中にあるメールアドレスの形をマスクします。採点では、スパンが4個残り、どこにもメールアドレスがなく、url.query属性がnotify=より前の部分と一緒に残っているかを確認します。
deleteは属性全体を消します。値の一部だけを変えるには、パターン置換の関数が必要です。正規表現はYAMLの文字列の中に入るため、引用符を確認してください。
同じレシーバー、別のパイプライン
/root/otca-order/fanout.yamlにパイプラインを2つ置いてください。traces/rawはプロセッサーなしでfile/rawへ、traces/cleanはステップ5のプロセッサー4つを経由してfile/cleanへ出力し、どちらも同じotlpレシーバーから受け取ります。/root/otca-order/06-fanout.txtに、raw_spans=、clean_spans=、raw_spans_with_any_email=を書いてください。
プロセッサーは、自分が属するパイプラインのデータだけを変更します。レシーバーが複数のパイプラインにつながると、各パイプラインは同じデータを別々に受け取ります。
コネクターは何を数えるのか
/root/otca-order/count.yamlで、countコネクターを、tracesパイプライン(プロセッサーは[transform/route, filter/health])のエクスポーターであり、かつmetricsパイプラインのレシーバーとして置いてください。metricsパイプラインは、fileエクスポーター(例: file/metrics)へ出力します。/root/otca-order/07-count.txtに、span_count_metric=(trace.span.countの値)とcounted_after=(tracesパイプラインの最後のプロセッサーの名前)を書いてください。
コネクターは、あるパイプラインの終わり(エクスポーターの位置)でデータを受け取り、別のパイプラインの始まり(レシーバーの位置)へ渡します。その前のプロセッサーは、すでに通過したあとです。
運用に載せるパイプライン一式
/root/otca-order/final.yamlを書いてください。tracesパイプラインはmemory_limiterで始まりbatchで終わり、その間で、パスの正規化、ヘルスチェックの破棄、user.emailの削除、値の中のメールアドレスのマスキングを、この順に行います。スパンはfileエクスポーター1つへ、countコネクターが数えたtrace.span.countはmetricsパイプラインを経由して別のfileエクスポーターへ出力します。採点では、otelcol-contrib validateと実際の実行で、スパン4個・メールアドレス0個・パスの種類2つ・trace.span.count 4を確認します。
memory_limiterは、負荷が集中したときに最初にデータを拒否してこそ意味があり、batchは、すべての変換が終わった結果を束ねる必要があります。countは、破棄のあとに置いてはじめて、運用メトリクスが正しくなります。