はじめに
リバースプロキシを介して公開される自己ホスト型サービスは、設定ミス、管理パネル、脆弱なエンドポイントなどを探知する自動スキャナーの標的になりやすい。この記事では、Elastic SecurityとCloudflareを使用して、 Traefikの通常のアクセスログをアクティブな防御制御に変換する方法を紹介します。
私は、 Webサーバーの検出とファジング動作 を特定するために、既製の ES|QL 検出ルールを使用しています。不審なプロービングパターンが検出されると、自動化されたワークフローがCloudflare APIを介して、エッジで問題のある送信元IPアドレスを即座にブロックします。この構成の最大の利点は、拡張が容易な点です。ファジング検出のためにこのレスポンスの仕組みを一度構築することで、SQLインジェクションやファイルインクルージョン試行を捕捉するルールなど、他のElasticsearchルールにも全く同じブロックアクションを適用できます。これにより、基本的なログ記録パイプラインが、高度に適応可能な境界防御システムへと変貌する。
背景と脅威の状況
私のホームラボ環境では、コンテナと仮想マシンにProxmox VEを使用しています。VPNを使わずに外部からのアクセスを可能にするため、認証にAutheliaを使用したTraefikリバースプロキシを使用しています。プロキシが有効になっている場合、CloudflareがDNSを管理します。
この特定のスタックにあまり詳しくない方のために説明すると、Traefikはネットワークの玄関口として機能します。Cloudflare経由でWebリクエストが到着すると、TraefikはSSL証明書を管理して接続を暗号化しながら、トラフィックを適切な内部コンテナに動的にルーティングします。しかし、トラフィックが実際にバックエンドアプリケーションに到達する前に、Autheliaによって傍受されます。Autheliaは、Traefikの前方認証機能を活用することで、シングルサインオンと多要素認証を全面的に適用します。つまり、自動スキャナーや攻撃者は、最初の安全なポータルを経由しない限り、私の内部サービスのログイン画面にすらアクセスできないということです。
可視性とセキュリティを維持するため、公式の統合機能を使用してこれらのTraefikアクセスログをElasticsearchに取り込んでいます。定期的な監視中に、これらのログにおいて、同じ送信元IPアドレスから発信された多数のHTTP 404 レスポンスコードを確認しました。
このパターンは、私のネットワーク上で実際に使用されていないアプリケーションの脆弱性を標的とした、潜在的なWebサーバーへのプロービングまたはファジングトラフィックを示唆しています。これらの対象パスの例としては/wp-includes/mani. 、 /wp-content/plugins/all-in-one-wp-security-and-firewall/templates.php 、 /archive.php 、 /wp-admin/includes/header.phpなどがあります。
設計理念:なぜFail2Banではないのか?
ホームラボコミュニティでよくある質問の一つは、 Fail2BanやCrowdSecといったローカルツールをTraefikサーバー上で直接使用しないのはなぜか、というものです。これらは優れたツールではありますが、Elastic Security を介して対応を調整し、ブロックを Cloudflare にプッシュすることで、2 つの大きな利点が得られます。Cloudflareのエッジで悪意のあるトラフィックを遮断することで、ローカルの帯域幅を節約し、スキャナーがホームネットワークに侵入するのを完全に防ぐことができます。さらに、Elasticを通じて対応を統括することで、すべてのセキュリティ監視を単一の画面で管理できるようになります。
検出戦略と実施戦略
悪意のある偵察活動を効果的に特定するために、当社の戦略はプロキシレベルでのHTTPレスポンスコードの頻度を分析することに基づいています。具体的には、短時間のうちに単一の送信元IPアドレスから大量の 404 (Not Found)エラーが発生しているかどうかを調べています。これは、ディレクトリファジングや脆弱性スキャンの典型的な指標です。
Elastic Securityは、まさにこのシナリオに対応する堅牢な既成の検出ルールを提供していますが、これらのルールが正しく機能するには、適切に正規化されたECS(Elastic Common Schema)データが必要です。したがって、これらのスキャンを検知し、軽減するには、連携のとれた流れが必要となる。これを機能させるには、Traefikのログを取り込み、カスタムパイプラインを使用して不足しているhost.nameフィールドをパッチし、検出ルールをデータに向ける必要があります。
しきい値ロジックとチューニング
私たちの検出戦略は、単純な文字列照合から脱却し、統計的な閾値に依存するものとなっています。このルールは、HTTP 403 および 404 レスポンスコードで表される、拒否されたリソースまたは存在しないリソースを具体的に監視し、このアクティビティを発信元のソース IP ごとに集計します。
この動作は、クエリ内の最後のwhereステートメントによって制御されます。デフォルトでは、ポーリング期間中にソースIPが 250 異なるURIパスにわたって 500 を超えるエラーを生成した場合にのみアラートがトリガーされます。この二層構造のしきい値は、誤検知を排除するように設計されており、単一の破損したアセットによってブロックがトリガーされることを防ぎつつ、ディレクトリのワードリストを循環する自動化されたスクリプトを確実に識別します。
小規模なホームラボや小規模なチーム環境では、これらのデフォルト設定は往々にして緩すぎる。正当な外部トラフィックが私のネットワーク上の存在しない管理パネルにアクセスする理由はないため、より巧妙な偵察活動を早期に検知できるよう感度を調整しました。event_count > 100とurl_original_count_distinct > 50の場合にトリガーされるようにロジックを変更しました。
アプリケーションが必然的に多くのエラーを生成する本番環境では、これらの値を増やすか、既知のリンク切れを除外するためにES|QL where not句を追加することを検討してください。最後に、 where source.ip not in (...)フィルターを使用して、承認されたセキュリティツールや個人用脆弱性スキャナーが自動化されたワークフローによって誤って禁止されないようにします。
Traefikアクセスログの取り込み
Traefikのアクセスログをクラスターに取り込むために、 Traefikのデフォルトの統合機能を使用しました。Elastic AgentはTraefikサーバーからログを収集します。この統合により、取り込まれたログがlogs-traefik.access-defaultデータストリームに書き込まれます。
カスタム取り込みパイプラインの構築
host.nameフィールドは私が使用している検出ルールにとって非常に重要ですが、デフォルトの Traefik 統合ではこのフィールドに値が入力されません。したがって、このフィールドを追加するには、カスタムの取り込みパイプラインが必要です。Traefik統合はTraefikサーバー上のファイルストリームを利用するため、既存のagent.nameフィールドから値をコピーしてhost.nameに入力できます。
私はメインのパイプラインを変更する代わりに、 logs-traefik.access@customパイプラインを意図的に使用しています。エラスティックインテグレーションは、これらの@customパイプラインを処理フローの最後に自動的に取得して実行するように設計されています。さらに重要なことに、統合をアップグレードするたびに、デフォルトのパイプラインが完全に上書きされてしまいます。ロジックをカスタムパイプラインに格納することで、フィールドマッピングが次回の更新後も確実に維持されるようにします。このパイプラインを作成するために必要なAPI呼び出しは、開発者ツールコンソールで実行できます。
PUT _ingest/pipeline/logs-traefik.access@custom
{
"description": "copy the agent.name field to the host.name field",
"processors": [
{
"set": {
"field": "host.name",
"value": "{{{agent.name}}}",
"override": false,
"ignore_empty_value": true,
"ignore_failure": true
}
}
]
}
Cloudflareワークフローによる自動応答
検知から積極的な防御へと移行するために、ElasticアラートとCloudflareエッジ間のギャップを埋めるワークフローを実装します。このロジックは効率性を重視して設計されています。アラートごとに新しいファイアウォールルールを作成すると、Cloudflareのルール制限にすぐに達してしまうため、ワークフローはまず既存のブロックリストを取得します。その後、Cloudflare APIに更新情報を送信する前に、問題のある新しい送信元IPアドレスを動的にリストに追加します。エッジのセキュリティが確保されると、ワークフローはElasticでアラートを確認することで完了し、インシデントに関する処理が事実上完了します。
前提条件とトークンの適用範囲
このプロセスには、Cloudflareの設定に必要なAPIキーとゾーンIDの両方が必要です。ルールを作成するには、APIトークンに「ゾーンWAF編集」権限が付与されている必要があります。Cloudflareダッシュボードでこのトークンを生成する際は、「カスタムトークンの作成」オプションを使用し、権限を厳密にZone -> Zone WAF -> Editに設定してください。
ワークフローが設定されたら、それを「Webサーバー検出またはファジング活動」検出ルールのアクションとして割り当てる必要があります。
前提条件が整ったところで、ワークフローの構築手順を段階的に見ていきましょう。
ワークフローの設定とトリガー
まず、基本的なメタデータを定義します。このワークフローは、Webサーバー検出またはファジング活動のアラートで検出されたIPアドレスをブロックします。ワークフローは有効になっており、APIリクエストのタイムアウトは 30 秒に設定されています。この場合はアラートに基づいて動作するため、セキュリティアラートがトリガーされると自動的に実行されます。
# =========================================================================
# Workflow: Block IP at Cloudflare test
# Category: security/response
# =========================================================================
version: '1'
name: Block IP at Cloudflare
enabled: true
triggers:
- type: alert
定数と認証
このセクションには、認証に必要な変数が格納されています。プレースホルダー文字列を、実際のAPIトークンとゾーンIDに置き換えることを忘れないでください。
consts:
cloudflare_api: "<cloudflare API>"
cloudflare_zone: "<cloudflare ZONE>"
ステップ1:現在のブロックリストを取得する
このシーケンスは、ファイアウォールルールが既に存在するかどうかを確認します。ワークフローは、既存のIPブロックルールを取得するためにHTTP GETリクエストを実行します。
steps:
- name: cloudflare_current_block
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
headers:
Authorization: Bearer {{consts.cloudflare_api}}
method: GET
on-failure:
continue: true
ステップ2:ファイアウォールルールの更新または作成
ルールが存在する場合は、そのルールにIPアドレスが追加され、存在しない場合は、ルールが作成されます。このワークフローは、「ウェブサーバースキャンブロック」の説明が存在するかどうかを識別します。その場合、PUTリクエストを介して、新しいIPアドレスを現在のブロック済みIPアドレスのリストに追加します。そうでない場合は、新しいルールを作成するという手順に戻ります。
- name: cloudflare_block
type: if
condition: 'steps.cloudflare_current_block.output.data.result.rules[0].description == "webserver scanning block"'
steps:
- name: ip-block-cloudflare_add
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
method: PUT
headers:
Authorization: Bearer {{consts.cloudflare_api}}
timeout: 30s
body: '{ "rules": [ { "description": "webserver scanning block", "expression": "{{steps.cloudflare_current_block.output.data.result.rules[0].expression}} or (ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
else:
- name: ip-block-cloudflare_new
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
method: PUT
headers:
Authorization: Bearer {{consts.cloudflare_api}}
timeout: 30s
body: '{ "rules":[ { "description": "webserver scanning block", "expression": "(ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
on-failure:
continue: true
ステップ3:アラートを確認する
その後、アラートが確認されます。この手順では、 kibana.SetAlertsStatusアクションを使用して、Elastic Security のアラートを自動的に閉じます。
- name: update_alert_status
type: kibana.SetAlertsStatus
with:
status: "acknowledged"
signal_ids: ["{{event.alerts[0]._id}}"]
ステップ4:ワークフローをルールに添付する
ワークフローが完全に構築されたら、最後のステップは、それを検出ルールに実際に接続して、自動的に実行されるようにすることです。Elastic Security の「Web サーバーの検出またはファジング活動」ルールの設定で、 「ルールアクション」タブに移動し、新しいアクションを追加します。コネクタのドロップダウンメニューから、先ほど作成したCloudflareワークフローを選択するだけです。
WAF制限に関する注記
このワークフローではorステートメント ( or (ip.src eq <IP>) ) を使用して IP アドレスを連結するため、Cloudflare ではカスタム WAF 式の文字数制限 (通常、標準ティアでは 4096 文字) があることに注意してください。高度に標的化された環境では、この文字列は最終的に限界に達する可能性があります。ホームラボや小規模チームの場合、このWAFルールを時々手動で削除することは、健全なリセットとして役立ちます。
テストと検証
パイプラインがエンドツーエンドで正しく動作していることを確認するために、標準的なファジングツールを使用してノイズを生成することができます。ffufやgobusterのようなファジングツールを使用して、自分のホームラボに対するスキャン攻撃をシミュレートできます。
公開されているTraefikドメイン上の存在しないディレクトリに対して、クイックスキャンを実行してください。
ffuf -u https://your-domain.com/FUZZ -w /path/to/wordlist.txt
シミュレーションが実行されると、自動防御システムが実際に動作する様子を観察できます。 404 エラーはlogs-traefik.access-defaultデータストリームにほぼ即座に現れます。ポーリング間隔内で、ES|QLルールはパターンを識別し、Elastic Security Alertsページに新しいアラートを生成します。そこからはワークフローが引き継ぎ、アラートの状態を「確認済み」に変更し、IPブロックをCloudflare WAFルールに送信することで、スキャナーが偵察を継続する前にエッジで効果的に無効化します。
ブロックが成功したかどうかは、Cloudflare ダッシュボードのSecurity -> WAF -> Custom rulesで確認できます。(注:後でCloudflareのルールから自分のIPアドレスを削除してください。そうしないと、アクセスできなくなってしまいます!)
防御力の拡大
この設定の素晴らしい点は、Cloudflareのワークフローがファジング検出だけに限定されないことです。自動化が構築されたら、疑わしいプロキシトラフィックを検出するElasticsearchのルールにそれを適用できます。例えば、この全く同じ対応アクションを、 WebサーバーのローカルファイルインクルージョンアクティビティやWebサーバーの潜在的なリモートファイルインクルージョンアクティビティなど、特定のアプリケーションの脆弱性を標的とする既成のルールに結び付けることで、攻撃者を即座に排除することができます。また、 Webサーバーエラーログにおける潜在的な急増や異常なWebユーザーエージェントと組み合わせることで、設定ミスのあるスクレイパーや広範なネットワークノイズを検出するのにも最適です。配管工事を一度行えば、敷地全体のシステムが突然スマート化する。
まとめ
TraefikとCloudflareをElastic Securityに連携させることは、基本的なアクセスログを積極的な防御策に変えるための優れた方法です。ホームラボ環境は、容易にアクセスできる情報を探し求める自動スキャナーによって常に攻撃を受けている。この自動化されたワークフローは、攻撃者をエッジで阻止するだけでなく、インシデントを自動的に認識することでアラート疲労も軽減します。これは、セキュリティのオーケストレーションと対応がいかに時間を節約し、同時にセキュリティ体制を大幅に向上させることができるかを示す実践的な例です。