序章

SSH is the de facto method of connecting to a cloud server. It is durable, and it is extensible — as new encryption standards are developed, they can be used to generate new SSH keys, ensuring that the core protocol remains secure. However, no protocol or software stack is totally foolproof, and SSH being so widely deployed across the internet means that it represents a very predictable attack surface or attack vector through which people can try to gain access.

Any service that is exposed to the network is a potential target in this way. If you review the logs for your SSH service running on any widely trafficked server, you will often see repeated, systematic login attempts that represent brute force attacks by users and bots alike. Although you can make some optimizations to your SSH service to reduce the chance of these attacks succeeding to near-zero, such as disabling password authentication in favor of SSH keys, they can still pose a minor, ongoing liability.

Large-scale production deployments for whom this liability is completely unacceptable will usually implement a VPN such as WireGuard in front of their SSH service, so that it is impossible to connect directly to the default SSH port 22 from the outside internet without additional software abstraction or gateways. These VPN solutions are widely trusted, but will add complexity, and can break some automations or other small software hooks.

Prior to or in addition to committing to a full VPN setup, you can implement a tool called Fail2ban. Fail2ban can significantly mitigate brute force attacks by creating rules that automatically alter your firewall configuration to ban specific IPs after a certain number of unsuccessful login attempts. This will allow your server to harden itself against these access attempts without intervention from you.

In another tutorial, we discussed How to protect SSH with Fail2ban. In this guide, we’ll discuss in more depth how Fail2ban actually works and how you can use this knowledge to modify or extend the behavior of this service.

The Fundamentals of Fail2ban

The purpose of Fail2ban is to monitor the logs of common services to spot patterns in authentication failures.

When fail2ban is configured to monitor the logs of a service, it looks at a filter that has been configured specific to that service. The filter is designed to identify authentication failures for that specific service through the use of complex regular expressions. Regular expressions are a common templating language used for pattern matching. It defines these regular expression patterns into an internal variable called failregex.

By default, Fail2ban includes filter files for common services. When a log from any service, like a web server, matches the failregex in its filter, a predefined action is executed for that service. The action 管理者の設定に応じて、さまざまなことを実行するように構成できる変数です。

The default action is to ban the offending host/IP address by modifying the local firewall rules. You can expand this action to, for example, send an email to your system administrator.

By default, action will be taken when three authentication failures have been detected in 10 minutes, and the default ban time is for 10 minutes. This is configurable.

デフォルトを使用する場合 iptables firewall, fail2ban creates a new set of firewall rules, also called a chain, when the service is started. It adds a new rule to the INPUT chain that sends all TCP traffic directed at port 22 to the new chain. In the new chain, it inserts a single rule that returns to the INPUT chain. The chain and associated rules are removed if the Fail2ban service is stopped.

Fail2banサービス設定の調査

Fail2ban is configured through several files located within a hierarchy under the /etc/fail2ban/ ディレクトリ。

The fail2ban.conf file configures some operational settings like the way the daemon logs info, and the socket and pid file it will use. The main configuration, however, is specified in the files that define the per-application “jails”.

デフォルトでは、fail2banには jail.conf file. However, this can be overwritten in updates, so you should copy this file to a jail.local ファイルし、そこで調整を行います。

すでにお持ちの場合 jail.local file, open it using nano or your favorite text editor:

  1. sudo nano /etc/fail2ban/jail.local

あなたが持っていない場合 jail.local すでにファイルがあるか、開いたファイルが空白だった場合は、 jail.conf ファイルを作成し、新しいファイルを開きます。

  1. sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
  2. sudo nano /etc/fail2ban/jail.local

ここで利用可能なオプションを見て、このファイルがシステム上の他の構成ファイルとどのように相互作用するかを確認します。

デフォルトセクション

The first portion of the file will define the defaults for fail2ban policy. これらのオプションは、個々のサービスの構成セクションでオーバーライドできます。

コメントを削除すると、デフォルトのセクション全体が次のようになります。

/etc/fail2ban/jail.local
[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

Let’s go over what some of this means:

  • ignoreip: This parameter identifies IP addresses that should be ignored by the banning system. By default, this is just set to ignore traffic coming from the machine itself, so that you don’t fill up your own logs or lock yourself out.
  • bantime: This parameter sets the length of a ban, in seconds. The default is 10 minutes.
  • findtime: This parameter sets the window that Fail2ban will pay attention to when looking for repeated failed authentication attempts. The default is set to 10 minutes, which means that the software will count the number of failed attempts in the last 10 minutes.
  • maxretry :これは、 findtime 禁止が開始される前のウィンドウ。
  • backend: This entry specifies how Fail2ban will monitor log files. の設定 auto fail2banが試行することを意味します pyinotify、 それから gamin, and then a polling algorithm based on what’s available. inotify is a built-in Linux kernel feature for tracking when files are accessed, and pyinotify is a Python interface to inotify, used by Fail2ban.
  • usedns: This defines whether reverse DNS is used to help implement bans. Setting this to “no” will ban IPs themselves instead of their domain hostnames. The warn setting will attempt to look up a hostname and ban that way, but will log the activity for review.
  • destemail :これは、アラートをメールで送信するようにアクションを構成した場合に通知メールが送信されるアドレスです。
  • sendername :これは、生成された通知メールの[Emailfrom]フィールドで使用されます
  • banaction: This sets the action that will be used when the threshold is reached. This is actually a path to a file located in /etc/fail2ban/action.d/ と呼ばれる iptables-multiport.conf. これは実際の iptables firewall manipulation to ban an IP address. これについては後で説明します。
  • mta :これは通知メールの送信に使用されるメール転送エージェントです。
  • protocol: This is the type of traffic that will be dropped when an IP ban is implemented. これは、新しいiptablesチェーンに送信されるトラフィックのタイプでもあります。
  • chain :これは、トラフィックをfail2banファネルに送信するためのジャンプルールで構成されるチェーンです。

The rest of the parameters define different actions that can be specified. They pass in some of the parameters that we’ve defined above using variable substitution within text strings like this:

%(var_name)s

上記の行は、の内容に置き換えられます var_name. これを使用して、 action 変数はに設定されます action_ デフォルトの定義(禁止のみ、メールアラートなし)。

これは、順番に、を呼び出すことによって構成されます iptables-multiport action with a list of parameters (service name, port, protocol, and chain) that is needed to perform the ban. The __name__ 以下のセクションヘッダーで指定されているサービスの名前に置き換えられます。

サービス固有のセクション

Beneath the default section, there are sections for specific services that can be used to override the default settings. This follows a convention of only modifying the parameters that differ from the normal values (convention over configuration).

各セクションヘッダーは次のように指定されます。

[service_name]

Any section that has the line enabled = true will be read and enabled.

Within each section, the parameters are configured, including the filter file that should be used to parse the logs (minus the file extension) and the location of the log files themselves.

これを念頭に置いて、SSHサービスのアクションを指定するセクションは次のようになります。

/etc/fail2ban/jail.local
[SSH]

enabled     = true
port        = ssh
filter      = sshd
logpath     = /var/log/auth.log
maxretry    = 6

This enables this section and sets the port to the default “ssh” port (port 22). It tells Fail2ban to look at the log located at /var/log/auth.log このセクションでは、で定義されているフィルタリングメカニズムを使用してログを解析します。 /etc/fail2ban/filters.d と呼ばれるファイル内のディレクトリ sshd.conf.

必要な他のすべての情報は、 [DEFAULT] section. たとえば、アクションは次のように設定されます action_ これは、問題のあるIPアドレスを使用して禁止します iptables-multiport banactionは、というファイルを参照します iptables-multiport.conf で見つかりました /etc/fail2ban/action.d.

ご覧のとおり、 [DEFAULT] section should be general and flexible. Using parameter substitution along with parameters that provide sensible defaults will make it possible to override definitions when necessary.

フィルタファイルの調査

構成で何が起こっているかを理解するには、作業の大部分を実行するフィルターファイルとアクションファイルを理解する必要があります。

The filter file will determine the lines that fail2ban will look for in the log files to identify offending characteristics. アクションファイルは、サービスの開始時にファイアウォール構造を構築することから、ルールを追加および削除すること、サービスが停止するときにファイアウォール構造を破棄することまで、必要なすべてのアクションを実装します。

上記の構成でSSHサービスが要求したフィルターファイルを見てみましょう。

  1. sudo nano /etc/fail2ban/filter.d/sshd.conf
/etc/fail2ban/sshd.conf
[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 =

The [INCLUDES] section header specifies other filter files that are read in before or after this file. この例では、 common.conf file is read in and placed before the other lines in this file. これにより、構成で使用するいくつかのパラメーターが設定されます。

次に、 [Definition] section that defines the actual rules for our filter matches. まず、監視しているデーモンの名前を、 _daemon パラメータ。

その後、実際に見ていきます failregex definition, which sets the patterns that will trigger when a matching line in the log file is found. これらは、ユーザーが正しく認証されなかった場合にスローされる可能性のあるさまざまなエラーや失敗に基づいて一致する正規表現です。

のような行の部分 %(__prefix_line)s のパラメータ設定の値に置き換えられます common.conf file that we sourced. This is used to match the different leading information that operating systems write to log files when they use standard methods. たとえば、 /var/log/auth.log 次のようになります。

/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]

The highlighted portion is a standard pattern that the operating system inserts to provide more context. After that, there are quite a few different ways that the iptables firewall service writes failure attempts to the log.

We see two separate failures in the first two lines above (a PAM authentication error and a password error). The regular expressions defined in the filter are designed to match any of the possible failure lines. これらの行を調整する必要はありませんが、自分でフィルターファイルを作成する必要がある場合は、保護しようとしているアプリケーションの不正使用エラーを示すすべてのログエントリをキャッチする必要があることに注意してください。 。

下部に、 ignoreregex parameter, which is currently blank. This can be used to exclude more specific patterns that would typically match a failure condition in case you want to negate the failure trigger for fail2ban for certain scenarios. これは調整しません。

調べ終わったら、ファイルを保存して閉じます。

アクションファイルの調査

Now, let’s take a look at the action file. This file is responsible for setting up the firewall with a structure that allows modifications for banning malicious hosts, and for adding and removing those hosts as necessary.

The action that our SSH service invokes is called iptables-multiport. 関連するファイルを今すぐ開きます。

  1. sudo nano /etc/fail2ban/action.d/iptables-multiport.conf

コメントを削除すると、このファイルは次のようになります。

/etc/fail2ban/action.d/iptables-multiport.conf
[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 that defines the blocktype parameter, which configures the restriction that will be set when a client is banned. デフォルトでは、 blocktype is set to reject packets and reply to pings sent by banned clients with a rejection message that the port is unreachable. これを以下の禁止規則で使用します。

Next, we get to the rule definitions themselves. The actionstart action sets up the iptables firewall when the fail2ban service is started. 新しいチェーンを作成し、そのチェーンにルールを追加して呼び出し元のチェーンに戻し、INPUTチェーンの先頭に、正しいプロトコルとポートの宛先に一致するトラフィックを新しいチェーンに渡すルールを挿入します。

これは、で渡した値を使用して行われます。 action 私たちが jail.local file. The name is taken from the section header for each service. The chain, protocol、 と port から取られます action そのファイルにそれ自体を行します。

ここで、他のファイルによって設定されたすべてのパラメーターは、山括弧内にパラメーター名を含めることによって参照されます。

&lt;param_name&gt;

コンパニオンに移動するとき actionstop definition, we can see that the firewall commands are implementing a reversal of the actionstart commands. When the Fail2ban service stops, it cleanly removes any firewall rules that it added.

と呼ばれる別のアクション actioncheck 禁止ルールを追加する前に、適切なチェーンが作成されていることを確認してください。

次に、実際の禁止ルールに到達します。 actionban. This rule works by adding a new rule to our created chain. The rule matches the source IP address of the offending client – this parameter is read in from the authorization logs when the maxretry limit is reached. It institutes the block defined by the blocktype で調達したパラメータ [INCLUDE] ファイルの上部にあるセクション。

The actionunban rule removes this rule. これは、禁止時間が経過すると、fail2banによって自動的に実行されます。

最後に、 [Init] section. これは、適切な値をすべて渡さずにアクションファイルが呼び出された場合に備えて、いくつかのデフォルトを提供するだけです。

Fail2banサービスが構成ファイルを処理して禁止を実装する方法

詳細を確認したので、fail2banの開始時に発生するプロセスを見ていきましょう。

初期構成ファイルのロード

まず、メイン fail2ban.conf file is read to determine the conditions that the main process should operate under. 必要に応じてソケット、pid、およびログファイルを作成し、それらの使用を開始します。

次に、fail2banは jail.conf file for configuration details. これに続いて、アルファベット順に、で見つかったファイルを読み取ります。 jail.d で終わるディレクトリ .conf. これらのファイルにある設定を内部構成に追加し、で説明されている値よりも新しい値を優先します。 jail.conf ファイル。

次に、 jail.local file and repeats this process, adapting the new values. 最後に、 jail.d ディレクトリを再度、アルファベット順のファイルで終わるファイルを読み取ります .local.

私たちの場合、 jail.conf ファイルと jail.local file. 私たちの中で jail.local ファイルの場合、定義する必要があるのは、 jail.conf file. fail2banプロセスには、検出されたすべてのファイルの組み合わせを表す一連のディレクティブがメモリにロードされるようになりました。

各セクションを調べて、 enabled = true directive. If it finds one, it uses the parameters defined under that section to build a policy and decide what actions are required. サービスのセクションにないパラメータは、で定義されたパラメータを使用します [DEFAULT] セクション。

アクションファイルを解析して開始アクションを決定する

Fail2banは action directive to figure out what action script to call to implement the banning/unbanning policies. 見つからない場合は、上記で決定されたデフォルトのアクションにフォールバックします。

The action directive consists of the name of the action file(s) that will be read, as well as a key-value dictionary that passes the parameters needed by those files. The values of these often take the form of parameter substitutions by referencing the settings configured in the service’s section. 「名前」キーには通常、特別な値が渡されます __name__ セクションのヘッダーの値に設定される変数。

次に、Fail2banはこの情報を使用して、 action.d directory. 最初に、で終わる関連アクションファイルを探します .conf 次に、そこにある情報を、付随する設定に含まれている設定で修正します .local ファイルも action.d ディレクトリ。

It parses those files to determine the actions that it needs to take. それは読みます actionstart value to see the actions it should take to set up the environment. これには、将来の禁止ルールに対応するためのファイアウォール構造の作成が含まれることがよくあります。

このファイルで定義されているアクションは、から渡されたパラメータを使用します action directive. It will use these values to dynamically create the appropriate rules. 特定の変数が設定されていない場合は、アクションファイルに設定されているデフォルト値を調べて空白を埋めることができます。

フィルタファイルを解析してフィルタリングルールを決定する

のサービスのパラメータ jail.* ファイルには、ログファイルの場所と、ファイルをチェックするために使用する必要のあるポーリングメカニズムも含まれます(これは、 backend parameter). また、ログの行が障害を表すかどうかを判断するために使用する必要があるフィルターも含まれています。

Fail2banは filter.d で終わる一致するフィルターファイルを見つけるためのディレクトリ .conf. It reads this file to define the patterns that can be used to match offending lines. 次に、末尾が .local デフォルトのパラメータのいずれかが上書きされたかどうかを確認します。

It uses the regular expressions defined in these files as it reads the service’s log file. それぞれを試します failregex で定義された行 filter.d サービスのログファイルに書き込まれるすべての新しい行に対するファイル。

正規表現が一致を返す場合、正規表現によって定義された正規表現に対して行をチェックします。 ignoreregex. If this also matches, fail2ban ignores it. 行がの式と一致する場合 failregex but does not match an expression in the ignoreregex、行の原因となったクライアントの内部カウンターがインクリメントされ、イベントに関連付けられたタイムスタンプが作成されます。

によって設定された時間のウィンドウとして findtime のパラメータ jail.* ファイルに到達すると(イベントのタイムスタンプによって決定されます)、内部カウンターが再びデクリメントされ、イベントは禁止ポリシーに関連しているとは見なされなくなります。

If, over the course of time, additional authentication failures are logged, each attempt increments the counter. カウンタがによって設定された値に達した場合 maxretry 設定された時間枠内のパラメータであるfail2banは、 actioncheck で定義されているサービスのアクション action.d/ files for the service. これは、 actionstart action set up the necessary structure. 次に、 actionban action to ban the offending client. このイベントのタイムスタンプも設定します。

によって指定された時間が経過したとき bantime パラメータ、fail2banは、を呼び出すことによってクライアントの禁止を解除します actionunban アクション。

結論

By now you have a fairly in-depth understanding of how fail2ban operates. When you deviate from the standard configuration, it is helpful to know how fail2ban functions in order to manipulate its behavior in a predictable way.

To learn about how to protect other services with fail2ban, you can read How To Protect an Nginx Server with Fail2Ban on Ubuntu 22.04.