導入
SSHはクラウドサーバーに接続するための事実上の方法です。それは耐久性があり、拡張性があります – 新しい暗号化基準が開発されると、それらを使用して新しいSSHキーを生成することができ、基本プロトコルが安全であることを保証します。しかし、どんなプロトコルやソフトウェアスタックも完全に防御的ではなく、インターネット全体に広く展開されているSSHは非常に予測可能な攻撃表面または攻撃ベクトルを表しています。攻撃表面または攻撃ベクトル。
ネットワークに公開されているサービスはこのような方法で潜在的な標的です。広く使用されているサーバーで実行されているSSHサービスのログを確認すると、ユーザーやボットによる繰り返されたシステマティックなログイン試行が頻繁に見られます。これらの攻撃がほぼゼロに近い成功確率であるようにするために、SSHキーを利用したパスワード認証の無効化などのSSHサービスの最適化を行うことができますが、それでも少なくとも軽微な継続的な負担を引き起こす可能性があります。パスワード認証の代わりにSSHキーを利用した無効化。
大規模なプロダクション展開では、この責任が完全に受け入れられない場合、通常、WireGuardなどのVPNを実装して、デフォルトのSSHポート22に直接インターネットから接続することが不可能になります。追加のソフトウェア抽象化やゲートウェイなしに。これらのVPNソリューションは広く信頼されていますが、複雑さを増し、一部の自動化やその他の小さなソフトウェアフックを壊す可能性があります。
完全なVPNセットアップへのコミットメントの前または追加として、Fail2banというツールを実装することができます。Fail2banは、特定のIPアドレスを一定回数の失敗したログイン試行後に自動的にファイアウォール構成を変更してブロックするルールを作成することで、総当たり攻撃を大幅に緩和することができます。これにより、サーバーはあなたの介入なしにこれらのアクセス試行に対して自己を強化できます。
別のチュートリアルでは、Fail2banでSSHを保護する方法について説明しました。このガイドでは、Fail2banが実際にどのように機能し、このサービスの動作を変更または拡張するためにこの知識をどのように活用できるかについて詳しく説明します。
Fail2banの基本
Fail2banの目的は、一般的なサービスのログを監視して認証の失敗のパターンを見つけることです。
fail2banがサービスのログを監視するように設定されている場合、そのサービスに特化した設定がされたフィルタを見ます。フィルタは、その特定のサービスの認証失敗を複雑な正規表現を使用して識別するように設計されています。正規表現はパターンマッチングに使用される一般的なテンプレート言語です。これらの正規表現パターンはfailregex
という内部変数に定義されます。
デフォルトでは、Fail2banには一般的なサービスのためのフィルタファイルが含まれています。ウェブサーバーなどの任意のサービスのログが、そのフィルタ内のfailregex
に一致すると、そのサービスに対して事前定義されたアクションが実行されます。アクションは、管理者の設定に応じてさまざまなことを行うように設定できる変数です。
デフォルトのアクションは、ローカルのファイアウォールルールを変更して侵害者のホスト/IPアドレスを禁止することです。このアクションを、たとえばシステム管理者に電子メールを送信するように拡張することができます。
デフォルトでは、認証失敗が10分間に3回検出された場合に、アクションが実行され、デフォルトの禁止時間は10分です。これは設定可能です。
デフォルトのiptables
ファイアウォールを使用する場合、fail2ban
はサービスが開始されると新しいファイアウォールルール、またはチェーンを作成します。ポート22に向けられたすべてのTCPトラフィックを新しいチェーンに送信するINPUTチェーンに新しいルールを追加します。新しいチェーンには、INPUTチェーンに戻る単一のルールが挿入されます。Fail2banサービスが停止されると、チェーンと関連するルールが削除されます。
Fail2banサービス設定の探索
Fail2banは、/etc/fail2ban/
ディレクトリの階層内にある複数のファイルを通じて構成されています。
fail2ban.conf
ファイルは、デーモンが情報をログに記録する方法や、使用するソケットやPIDファイルなど、一部の操作設定を構成します。ただし、メインの構成は、アプリケーションごとの”jails”を定義するファイルで指定されています。
デフォルトでは、fail2banにはjail.conf
ファイルが付属しています。ただし、これは更新時に上書きされる可能性があるため、このファイルをjail.local
ファイルにコピーしてそこで調整する必要があります。
すでにjail.local
ファイルを持っている場合は、nano
やお気に入りのテキストエディタを使用して開きます:
すでにjail.local
ファイルが存在しない場合、または開いたファイルが空白の場合は、jail.conf
ファイルをコピーしてから新しいファイルを開きます:
ここで利用可能なオプションを見て、このファイルがシステム上の他の構成ファイルとどのように相互作用するかを見てみましょう。
デフォルトセクション
ファイルの最初の部分は、fail2ban ポリシーのデフォルトを定義します。これらのオプションは、各個別のサービスの設定セクションで上書きできます。
コメントを除去した場合、デフォルトセクション全体は次のようになります。
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 10m
findtime = 10m
maxretry = 3
backend = auto
usedns = warn
destemail = root@localhost
sendername = Fail2Ban
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s", sendername="%(sendername)s"]
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"]
action = %(action_)s
これが何を意味するかを見てみましょう:
- ignoreip: このパラメーターは、禁止システムによって無視されるIPアドレスを識別します。デフォルトでは、これはマシン自体からのトラフィックを無視するように設定されています。これにより、自分自身のログを埋めたり、自分自身をロックアウトしたりしないようにします。
- bantime: このパラメーターは、禁止の長さ(秒単位)を設定します。デフォルトは10分です。
- findtime: このパラメーターは、Fail2ban が繰り返し失敗した認証試行を探すときに注目するウィンドウを設定します。デフォルトは10分で、ソフトウェアは直近の10分間に失敗した試行の数をカウントします。
- maxretry: これは、禁止が実施される前に
findtime
ウィンドウ内で許容される失敗した試行の数を設定します。 - backend: このエントリは、Fail2ban がログファイルを監視する方法を指定します。
auto
の設定は、fail2ban がpyinotify
、次にgamin
、そして利用可能なものに基づいてポーリングアルゴリズムを試すことを意味します。inotify
は、ファイルがアクセスされたときのトラッキングを行うための組み込みのLinuxカーネル機能であり、pyinotify
はFail2ban で使用されるinotify
のPythonインタフェースです。 - usedns: これは、逆DNSが禁止を実装するのに役立つかどうかを定義します。これを「no」に設定すると、IP自体が禁止され、ドメインホスト名は禁止されません。
warn
設定は、ホスト名を検索して禁止することを試みますが、その活動をログに記録して確認します。 - destemail: これは、アラートメールを送信する場合に通知メールが送信されるアドレスです。
- sendername: これは、生成された通知メールのメールからフィールドに使用されます。
- banaction: これは、しきい値が達成されたときに使用されるアクションを設定します。実際には、
/etc/fail2ban/action.d/
にあるファイルへのパスであり、iptables-multiport.conf
と呼ばれます。これは、IPアドレスを禁止するための実際のiptables
ファイアウォール操作を処理します。これについては後で説明します。 - mta: これは、通知メールを送信するために使用されるメール転送エージェントです。
- protocol: これは、IP禁止が実装されたときにドロップされるトラフィックのタイプです。これはまた、新しいiptablesチェーンに送信されるトラフィックのタイプでもあります。
- chain: これは、トラフィックをfail2banファンネルに送信するジャンプルールで構成されるチェーンです。
残りのパラメータは、指定されたさまざまなアクションを定義します。これらは、次のようにテキスト文字列内で変数の置換を使用して、上記で定義したパラメータの一部を渡します:
%(var_name)s
上記の行は、var_name
の内容に置き換えられます。これにより、action
変数がデフォルトでaction_
定義に設定されていることがわかります(禁止のみ、メールアラートはありません)。
これにより、バンを実行するために必要なパラメーター(サービス名、ポート、プロトコル、およびチェーン)のリストを使用して、iptables-multiport
アクションが呼び出されるように構成されます。 __name__
は、以下のセクションヘッダーで指定されたサービス名で置換されます。
サービス固有のセクション
デフォルトセクションの下に、デフォルト設定をオーバーライドするために使用できる特定のサービスのセクションがあります。これは、通常の値と異なるパラメーターのみを変更する慣習に従います(設定より慣習)。
各セクションヘッダーは次のように指定されます:
[service_name]
行 enabled = true
を含むセクションは読み取られ、有効になります。
各セクション内では、フィルタファイル(ファイル拡張子を除く)を解析するために使用するべきフィルタファイルと、ログファイル自体の場所を含むパラメーターが構成されます。
これを考慮すると、SSHサービスのアクションを指定するセクションは次のようになります:
[SSH]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
これにより、このセクションが有効になり、ポートがデフォルトの「ssh」ポート(ポート22)に設定されます。これは、Fail2banにこのセクションのログを/var/log/auth.log
で見るよう指示し、ログを/etc/fail2ban/filters.d
ディレクトリ内のsshd.conf
というファイルで定義されたフィルタリングメカニズムを使用して解析するように伝えます。
それが必要とする他のすべての情報は、[DEFAULT]
セクションで定義されたパラメータから取得されます。たとえば、アクションはaction_
に設定され、これはiptables-multiport
banactionを使用して攻撃元のIPアドレスを禁止します。これは/etc/fail2ban/action.d
で見つかるiptables-multiport.conf
というファイルを参照します。
ご覧のように、[DEFAULT]
セクションのアクションは一般的で柔軟である必要があります。パラメータの置換を使用して、適切なデフォルト値を提供するパラメータと共に定義を上書きできるようにすると便利です。
フィルタファイルの検査
構成内で何が起こっているかを理解するためには、作業の大部分を行うフィルタとアクションファイルを理解する必要があります。
フィルターファイルは、fail2banがログファイル内で違反の特徴を特定するために探す行を決定します。 アクションファイルは、サービスの開始時にファイアウォール構造を構築し、ルールを追加および削除し、サービスが停止したときにファイアウォール構造を解体するために必要なすべてのアクションを実装します。
上記の設定でSSHサービスが要求したフィルターファイルを見てみましょう:
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from <HOST>( via \S+)?\s*$
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$
^%(__prefix_line)sFailed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s(, client user ".*", client host ".*")?))?\s*$
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because listed in DenyUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not in any group\s*$
^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
ignoreregex =
[INCLUDES]
セクションヘッダーは、このファイルの前または後に読み込まれる他のフィルターファイルを指定します。 この例では、common.conf
ファイルが読み込まれ、このファイルの他の行の前に配置されます。 これにより、設定で使用するいくつかのパラメータがセットアップされます。
次に、実際のフィルター一致のルールを定義する[Definition]
セクションがあります。 最初に、_daemon
パラメータを使用して監視しているデーモンの名前を設定します。
その後、実際のfailregex
定義を行います。 これは、ログファイル内の一致する行が見つかったときにトリガーされるパターンを設定します。 これらは、ユーザーが正しく認証されなかったときにスローされるさまざまなエラーや失敗に基づいてマッチする正規表現です。
%(__prefix_line)s
などの行の一部は、ソースとなるcommon.conf
ファイルでセットアップされたパラメータの値で置換されます。 これは、標準的な方法を使用してオペレーティングシステムがログファイルに書き込むさまざまな先行情報に一致するために使用されます。 たとえば、/var/log/auth.log
からのいくつかの行は次のようになります:
May 6 18:18:52 localhost sshd[3534]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=101.79.130.213
May 6 18:18:54 localhost sshd[3534]: Failed password for invalid user phil from 101.79.130.213 port 38354 ssh2
May 6 18:18:54 localhost sshd[3534]: Received disconnect from 101.79.130.213: 11: Bye Bye [preauth]
ハイライトされた部分は、オペレーティングシステムがより多くのコンテキストを提供するために挿入する標準的なパターンです。その後、iptablesファイアウォールサービスがログに失敗した試行を書き込むさまざまな方法があります。
上記の最初の2行で2つの別々の失敗が見られます(PAM認証エラーとパスワードエラー)。フィルタで定義された正規表現は、可能なすべての失敗行と一致するように設計されています。これらの行のいずれも調整する必要はありませんが、自分でフィルタファイルを作成する必要がある場合は、保護しようとしているアプリケーションの許可されていない使用エラーを示すすべてのログエントリをキャッチする必要があることを認識してください。
最後に、現在空白のignoreregex
パラメータがあります。これは、特定のシナリオでfail2banの失敗トリガーを否定したい場合に、通常失敗条件に一致するより具体的なパターンを除外するために使用できます。これは調整しません。
ファイルの検討が終了したら、保存して閉じます。
アクションファイルの検討
次に、アクションファイルを見てみましょう。このファイルは、悪意のあるホストを禁止するための構造を備え、それらのホストを必要に応じて追加および削除するようにファイアウォールを設定する責任があります。
私たちのSSHサービスが呼び出すアクションはiptables-multiport
と呼ばれます。関連するファイルを開きます:
コメントを削除した場合、このファイルは次のようになります:
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
actionstart = iptables -N fail2ban-<name>
iptables -A fail2ban-<name> -j RETURN
iptables -I <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actioncheck = iptables -n -L <chain> | grep -a 'fail2ban-<name>[ \t]'
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j <blocktype>
actionunban = iptables -D fail2ban-<name> -s <ip> -j <blocktype>
[Init]
name = default
port = ssh
protocol = tcp
chain = INPUT
ファイルは、iptables-blocktype.conf
という別のアクションファイルをソースとして開始します。このファイルはblocktype
パラメータを定義し、クライアントが禁止されたときに設定される制限を構成します。デフォルトではblocktype
はパケットを拒否し、禁止されたクライアントから送信されたpingに対してポートが到達不能であるという拒否メッセージを返信します。これを以下の禁止ルールで使用します。
次に、ルール定義に移ります。 actionstart
アクションは、fail2banサービスが開始されるときにiptablesファイアウォールを設定します。新しいチェーンを作成し、そのチェーンに戻り元のチェーンに戻るルールを追加し、INPUTチェーンの先頭に新しいチェーンに一致するトラフィックを渡すルールを挿入します。
これは、jail.local
ファイルで定義したaction
で渡した値を使用して行います。 name
は各サービスのセクションヘッダーから取得されます。 chain
、protocol
、およびport
は、そのファイル内のaction
行自体から取得されます。
ここでは、他のファイルで設定されたすべてのパラメータが、パラメータ名を角かっこで囲んで参照されています:
<param_name>
伴うactionstop
定義に移動すると、ファイアウォールコマンドがactionstart
コマンドの逆を実装していることがわかります。Fail2banサービスが停止すると、追加されたファイアウォールルールがきれいに削除されます。
別のアクションであるactioncheck
は、適切なチェーンが作成されてから禁止ルールの追加を試みることを確認します。
次に、実際の禁止ルールであるactionban
に移ります。このルールは、作成したチェーンに新しいルールを追加することで機能します。このルールは、攻撃しているクライアントのソースIPアドレスに一致します – このパラメータは、maxretry
制限が達成されたときに認証ログから読み取られます。これは、ファイルの先頭にある[INCLUDE]
セクションでソースとなるblocktype
パラメータで定義されたブロックを実行します。
actionunban
ルールはこのルールを削除します。これは、ban時間が経過したときにfail2banによって自動的に行われます。
最後に、[Init]
セクションに移ります。これは、適切な値をすべて渡さずにアクションファイルが呼び出された場合に、いくつかのデフォルト値を提供するだけです。
Fail2banサービスが設定ファイルを処理して禁止を実行する方法
具体的な内容を見てきましたので、fail2banが起動するときに行われるプロセスについて説明します。
初期設定ファイルの読み込み
まず、メインのfail2ban.conf
ファイルが読み取られ、メインプロセスが動作する条件が決定されます。必要に応じてソケット、pid、およびログファイルが作成され、それらを使用し始めます。
次に、fail2banは構成の詳細を把握するためにjail.conf
ファイルを読み取ります。その後、jail.d
ディレクトリにある.conf
で終わるファイルをアルファベット順に読み取ります。これらのファイルに見つかった設定を内部の構成に追加し、jail.conf
ファイルで説明されている値よりも新しい値が優先されます。
その後、jail.local
ファイルを検索し、このプロセスを繰り返し、新しい値に適応します。最後に、jail.d
ディレクトリを再度検索し、.local
で終わるファイルをアルファベット順に読み込みます。
私たちの場合、jail.conf
ファイルとjail.local
ファイルしかありません。 jail.local
ファイルでは、jail.conf
ファイルと異なる値を定義する必要があります。これで、fail2banプロセスには、見つかったすべてのファイルの組み合わせを表すメモリに読み込まれたディレクティブセットがあります。
それは各セクションを調べ、enabled = true
ディレクティブを検索します。見つかった場合、そのセクションで定義されたパラメータを使用してポリシーを構築し、必要なアクションを決定します。サービスのセクションに見つからないパラメータは、[DEFAULT]
セクションで定義されたパラメータを使用します。
開始アクションを決定するためのアクションファイルの解析
Fail2banは、禁止/解除ポリシーを実装するために呼び出すアクションスクリプトを特定するためにaction
ディレクティブを探します。見つからない場合、上記で決定されたデフォルトのアクションにフォールバックします。
アクションディレクティブは、読み取られるアクションファイルの名前と、それらのファイルで必要なパラメータを渡すキー値辞書で構成されています。これらの値は、サービスのセクションで構成された設定を参照してパラメータ置換の形式を取ることがよくあります。通常、”name”キーには、セクションのヘッダーの値に設定される特別な__name__
変数の値が渡されます。
その後、Fail2banはこの情報を使用して、action.d
ディレクトリ内の関連ファイルを見つけます。最初に、関連するアクションファイルが.conf
で終わるファイルを検索し、次に、action.d
ディレクトリ内にも見つかる.local
ファイルに含まれる設定とともに、そこで見つかった情報を修正します。
それらのファイルを解析して、実行する必要のあるアクションを決定します。 環境を設定するために取るべきアクションを見るためにactionstart
値を読み取ります。 これには、将来の禁止規則に対応するためのファイアウォール構造を作成することが含まれることがよくあります。
このファイルで定義されたアクションは、action
指令から渡されたパラメーターを使用します。 これらの値を使用して、適切なルールを動的に作成します。 特定の変数が設定されていない場合、アクションファイルで設定されているデフォルト値を参照して、空白を埋めることができます。
フィルタリングルールを決定するためのフィルタファイルの解析
jail.*
ファイルのサービスのパラメータには、ログファイルの場所だけでなく、ファイルをチェックするために使用するポーリングメカニズム(これはbackend
パラメータで定義されます)も含まれます。 失敗を表すログの行を決定するために使用するフィルタも含まれます。
Fail2banは、マッチングするフィルタファイルを探すためにfilter.d
ディレクトリを調べます。 それは、侵害行にマッチするために使用できるパターンを定義するためにこのファイルを読み取ります。 次に、マッチングするフィルタファイルが.local
で終わることを確認して、デフォルトのパラメータが上書きされているかどうかを確認します。
これは、サービスのログファイルを読み取りながら定義された正規表現を使用します。それは、サービスのログファイルに書き込まれたすべての新しい行に対してfilter.d
ファイルで定義された各failregex
行を試みます。
正規表現が一致する場合、行をignoreregex
で定義された正規表現と照合します。これも一致する場合、fail2banはそれを無視します。行がfailregex
の式に一致するが、ignoreregex
の式に一致しない場合、クライアントが行を引き起こした内部カウンタが増加し、イベントの関連付けられたタイムスタンプが作成されます。
jail.*
ファイル内のfindtime
パラメータで設定された時間ウィンドウが到達すると(イベントのタイムスタンプによって決定される)、内部カウンタは再度減算され、イベントはもはや禁止ポリシーに関連付けられません。
時間の経過とともに、追加の認証失敗が記録されると、各試行がカウンタを増やします。設定された時間ウィンドウ内でmaxretry
パラメータで設定された値にカウンタが到達すると、fail2banは、サービスのaction.d/
ファイルで定義されたアクションとしてactioncheck
アクションを呼び出して禁止を実施します。これは、actionstart
アクションが必要な構造を設定したかどうかを判断するためです。その後、actionban
アクションを呼び出して、問題のあるクライアントを禁止します。これにもイベントのタイムスタンプが設定されます。
bantime
パラメータで指定された経過時間が経過すると、fail2banはactionunban
アクションを呼び出してクライアントの禁止を解除します。
結論
今では、fail2banの動作原理にかなり深く理解しているはずです。標準の設定から逸脱する場合、fail2banの動作を理解し、予測可能な方法でその動作を操作することが役立ちます。
他のサービスをfail2banで保護する方法について学ぶには、Ubuntu 22.04でFail2Banを使用してNginxサーバーを保護する方法を読んでください。