AWS Amazonlinux 2023 nginx に fail2ban を使ってみた。

さて頼まれごとでAWSを使っているわけですが、調べれば調べるほどAmazonlinux 2023は2からの乗換えにもあまりおススメ出来ません。っつまり新規に作るなら結構イケてるんじゃないかと思い、(それがドツボにはまるわけですが)webサーバー案件で使ってみました。
  • ユーザー設定
  • php設定
  • nginx設定
  • Let’sEncryptの設定
  • fail2ban設定
  • 仮想ルーターで世界の皆さんこんにちは
  • ログの監視
  • filterのカスタマイズ
となります。

今回はfail2banがうまく機能しなかったのでそこを重点に説明します。
fail2banの実際の制限方法に昔はiptablesでしたがfirewalldを使っています。
今後さらに変わる可能性もありますのでこの記事が古くなるかもしれませんね。
そこらへんは自分で確認してください。

fail2banの前にやれること。

nginxのセキュリティ設定ですね。出来るだけ新しい技術を使ってあげてください。
SSL周りはnginxのバージョンが低くてHTTP3がサポートされていませんでした。

nginx.confの注意点


/etc/nginx/nginx.conf

        ssl_certificate     /etc/letsencrypt/live/www.ddd.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.ddd.com/privkey.pem;
        ssl_session_cache shared:SSL:15m;
        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;
#       add_header Alt-Svc 'h3=":443"; ma=86400';
        ssl_protocols       TLSv1.2 TLSv1.3;
#    ssl_ciphers         HIGH:!aNULL:!MD5;
        ssl_ciphers     'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-CCM:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256';
    #ssl_ciphers                     ECDHE+AESGCM:DHE+AESGCM:HIGH:!aNULL:!MD5;
    ssl_buffer_size                 8k;

HTTP2は使えるので圧縮転送はします。

   #gzip
    gzip                on;
    gzip_types          text/plain
                        text/xml
                        text/css
                        application/xml
                        application/xhtml+xml
                        application/rss+xml
                        application/atom_xml
                        application/javascript
                        application/x-javascript
                        application/x-httpd-php
                        application/x-font-ttf
                        font/opentype
                        font/x-woff
                        font/x-woff2
                        application/vnd.ms-fontobject
                        image/svg+xml;
#                        video/mp4;
    gzip_proxied        any;
    gzip_min_length     1000;
    gzip_buffers        8 32k;
    gzip_comp_level     5;
    gzip_static         on;
    gzip_vary           on;

クロスサイトスクリプティング関係はいい加減だとダメです。
一番重要なのはコメント行のContent-Security-Policyです。
ここを何行かに分けて設定するのが一番いいです。今回はほぼリンクが無いのでパス。

    add_header                      X-Cache         $upstream_cache_status;
    add_header                      X-Frame-Options "DENY";
    add_header                      X-Content-Type-Options "nosniff";
    add_header                      X-XSS-Protection "1; mode=block";
#    add_header Content-Security-Policy "default-src 'self'";

robots.txtも無視して検索してくるので直リンク防止もしておきましょう。この拡張子は実際の攻撃されたログから抽出しました。もちろん.pyは動かすなら外しておいてもいいですよ。

        location ~* \.(jpg|jpeg|png|gif|bak|old|dat|core|env|mp4|zip|gz|tar|tgz|json|txt|conf|config|HEAD|yaml|yml|ini|bash_history|log|error_log|ftpconfig|git|htaccess|idea|sh|local|credentials|msmtprc|mysql_history|php_history|production|remote|s3cfg|authorized_keys|id_rsa|pub|svn|key|jenkinsFile|xml|phpinfo|dockerfunc|DS_Store|sql|py)$ {
        valid_referers none blocked www.ddd.com *.ddd.com;
        if ($invalid_referer) {
            return 403;
        }
    }

ではnginx -tしてsystemctl restart nginxする。
つぎにrobots.txtを設置します。

コンテンツのRootにrobots.txtを置く


User-agent: Googlebot
Disallow: /*.mp4$
Disallow: /*.png$
Disallow: /*.json$
Disallow: /*.txt$
Disallow: /*.sql$

User-agent: bingbot
Disallow: /*.mp4$
Disallow: /*.png$
Disallow: /*.json$
Disallow: /*.txt$
Disallow: /*.sql$

User-agent: Applebot
Disallow: /*.mp4$
Disallow: /*.png$
Disallow: /*.json$
Disallow: /*.txt$
Disallow: /*.sql$

User-agent: DuckDuckBot
Disallow: /*.mp4$
Disallow: /*.png$
Disallow: /*.json$
Disallow: /*.txt$
Disallow: /*.sql$

User-agent: *
Disallow: /

#御覧の通り4つ以外のクローラーには死んでもらう。

つぎにfail2banの設定

jail.confの設定


まず自分のIPがBANされちゃうと困るので空白区切りで好きなだけ登録しておきましょう。
そしてデフォルトの牢屋行きの基準値も書いておきましょう。
ハッキングしにくるクローラーは[nginx-botsearch]になりますのでこれをenableにします。

ignoreip = 127.0.0.1/8 ::1 <BANされたくないIP>
bantime  = 1d
findtime  = 60m
maxretry = 3

[nginx-botsearch]
enabled = true

さて牢屋行きはいますか?

# fail2ban-client status nginx-botsearch

Status for the jail: nginx-botsearch
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/nginx/error.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

はい、nginxのログフォーマットと全くマッチしていません。

nginx-botsearch.confの変更と試験

技術者の中でも難易度の高い正規表現を治します。ファイルの場所は/etc/fail2ban/filter.d/nginx-botsearch.confです。実際の/var/log/nginx/error.logの先頭は日付と時間ですのでマッチするわけがありませんね。

#failregex = ^<HOST> \- \S+ \[\] \"(GET|POST|HEAD) \/<block> \S+\" 404 .+$
#            ^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: <HOST>\, server\: \S*\, request: \"(GET|POST|HEAD) \/<block> \S+\"\, .*?$
failregex = \(2: No such file or directory\), client: <HOST>

いいじゃんこれでw
確認用のコマンドがあります。

# fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-botsearch.conf

どんどん牢屋に入れられます。実に清々しいですね。

fail2ban関連でよく使うコマンド

filterの試験
# fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-botsearch.conf
特定IPアドレスをBANする。
# fail2ban-client set nginx-botsearch banip 157.173.197.163
すべての BAN の解除
# fail2ban-client unban --all
特定の IP アドレスの BAN の解除
# fail2ban-client set nginx-botsearch unbanip 157.173.197.163
firewalld側での永久BAN
# firewall-cmd --permanent --zone=public --add-rich-rule="rule family='ipv4' source address='141.98.11.83' DROP"
firewalldの解放中ポート確認
# firewall-cmd --list-ports --zone=public
firewalldでBAN中の確認
# firewall-cmd --list-rich-rules  --zone=public

ん。ほとんどログが増えませんw
いんですよそれで。

コメント