2018年9月21日金曜日

Fail2banで永久banしたい(CentOS7 firewallcmd-ipset)

昔、GmailはGoogleのメールサーバから全く別のメールアドレスでメールを送信する設定が出来ました。それが、暗号化してないとダメになって、いつの間にかドメインが違うと登録できなくなっていました。昔に設定した既得権でずっと使えていたのですが、つい最近、手違いで設定解除してしまいました。仕方がないので、PostfixにCyrus SASLでSMTP-AUTHを導入しました。数時間後にmaillogを見ると、「SASL LOGIN authentication failed」の嵐になっていました。こういう輩には速攻で、永久にお引き取り願おうと思っております。というわけで、今回はCentOS7+Fail2ban(firewallcmd-ipset)の設定をしていきます。
まずは、インストールします。
# yum install --enablerepo=epel -y fail2ban fail2ban-systemd
次に、/etc/fail2ban/jail.localを作成します。このファイルはjail.confをオーバーライドするものです。
jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 172.16.1.0/24
maxretry = 5
findtime = 3600
bantime  = 86400
backend  = systemd
usedns   = yes

[postfix-sasl]
enabled  = true
findtime = 86400
bantime  = -1
port     = smtp,465,submission
logpath  = %(postfix_log)s
bantimeにマイナスを設定すると永久banになるようです。
早速、起動と行きたいところですが、このままでは上手く動きません。
ipsetのtimeoutにbantimeを入れる動作をするためにエラーになってしまいます。0が永久ですが、bantimeに0入れるとfail2banがban & unbanを繰り返します。
また、ログが更新されると再起動した時にログ落ちしたIPはbanされませんので、追加されるたびに別のファイル(下記では、permanent_bans.ip)に残しておき、起動時にそのファイルから再度、読み込みします。
これを変更するには/etc/fail2ban/action.d/firewallcmd-ipset.confのactionstartとactionbanを編集します。
firewallcmd-ipset.conf(抜粋)
#actionstart = ipset create fail2ban-<name> hash:ip timeout <bantime>
#              firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>

actionstart = ipset create fail2ban-<name> hash:ip timeout 0
              firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
              cat /etc/fail2ban/permanent_bans.ip | awk '/^fail2ban-<name> / {print $2}' | while read IP; do ipset add fail2ban-<name> $IP timeout 0 -exist; done

actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
             ipset flush fail2ban-<name>
             ipset destroy fail2ban-<name>

#actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
actionban = ipset add fail2ban-<name> <ip> timeout 0 -exist
            echo "fail2ban-<name> <ip>" >> /etc/fail2ban/permanent_bans.ip
また、blocktypeは相手に応答しないdropにします。
iptables-common.conf(抜粋)
#blocktype = REJECT --reject-with icmp-port-unreachable
blocktype = DROP
後は起動するだけです。
# systemctl start fail2ban
# systemctl enable fail2ban
banのリストを見るには、
# ipset list
unbanしたいときは、/etc/fail2ban/permanent_bans.ip から該当のipを削除して
# fail2ban-client set postfix-sasl unbunip <ip_addr>
という感じです。

2018年9月20日木曜日

Let's Encrypt で取得したワイルドカード証明書をIISサーバで使いたい


ワイルドカード証明書が取得できましたので、それを使って外部から参照できないWindowsのIISサーバにインストールおよび自動更新をしていきたいと思います。
まずWindowsに証明書をインストールするには、PEM(.pem)形式からPKCS12(.pfx)形式に変換する必要があります。変換にはopensslを使用します。証明書が更新されたときに実行されるスクリプトcertbot-deploy.shに下記を追加します。
openssl pkcs12 -export -in /etc/letsencrypt/live/example.com/fullchain.pem -inkey /etc/letsencrypt/live/example.com/privkey.pem -out /etc/letsencrypt/pfx/example.com/fullchain.pfx -passout file:/etc/letsencrypt/pfx/pass.txt
/etc/letsencryptにpfxディレクトリ、/etc/letsencrypt/pfxにexample.comディレクトリを作成して、任意のパスワードを書いたpass.txtを作成して入れておきます。
# cd /etc/letsencrypt
# mkdir pfx
# cd pfx
# echo password > pass.txt
# mkdir example.com
証明書が更新され上記が実行されると/etc/letsencrypt/pfx/example.com/fullchain.pfxが作成されます。
Windows側にファイルを移す方法はいくつかありますが今回はweb経由で転送します。
VirtualHostにAlias /pfx /etc/letsencrypt/pfx/example.comを追加して、/etc/httpd/conf.d/pfx.confを作成します。
pfx.conf
<Directory /etc/letsencrypt/pfx/example.com/>
    <IfModule mod_authz_core.c>
        Require ip 172.16.1.0/24
    </IfModule>
</Directory>
Require ipで内部からのみ許可するようにします。
Windowsにはwgetが標準ではありませんので、Wget for Windowsをインストールします。インストールしたら実行ファイルにパスを通しておきます。
環境変数pathにC:\Program Files\GnuWin32\bin;を追加します。
cmd.exeを起動して,
D:\letsencrypt>wget https://www.example.com/pfx/fullchain.pfx --no-check-certificate -N
とするとダウンロードできます。
ダウンロードしたら証明書をインストールします。インストールには、certutilコマンドを使います。
D:\letsencrypt>certutil -f -p password -importpfx fullchain.pfx
とするとインストールできます。後は、IISマネージャからバインドすれば有効になるはずです。

更新ですが3か月毎に手動更新するのは大変なのでbatファイルを作成してタスクスケジューラで毎日1回実行することにします。私が管理しているのはIIS6とIIS8があります。IIS6では、appcmd.exeがありませんので、設定をエクスポートして置換してからインポートし直しています。エクスポートしたファイルはUTF-8です。コードページの変更とかが面倒ですので、置換にはmfindを使わせてもらっています。
renew_cert_iis8.bat
@echo off
set url=https://www.example.com/pfx/
set passwd=password
set file1=fullchain.pfx
set file2=fullchain.live.pfx
set cn=*.example.com

setlocal ENABLEDELAYEDEXPANSION

echo * DownloadFile
wget %url%%file1% --no-check-certificate -N

echo * CheckFile
set timestamp1=
set timestamp2=
for %%a in (%file1%) do set timestamp1=%%~ta
for %%b in (%file2%) do set timestamp2=%%~tb
if "%timestamp1%" == "%timestamp2%" (
    echo Not Renew Cert
) else (
    if "%timestamp1%" gtr "%timestamp2%" (
        echo Renew Cert

        echo * Import Cert
        certutil -f -p %passwd% -importpfx %file1%
        copy %file1% %file2% > nul

        echo * SSL CertHash
        set n=0
        for /f "tokens=2,* usebackq" %%a in ( `certutil -store my %cn%^| findstr /c:"Cert ハッシュ(sha1)"` ) do (
          set CERTHASH[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        for /f "tokens=1,2 usebackq" %%a in ( `certutil -store my %cn%^| findstr /c:"この日以前: "` ) do (
          set CERTDATE[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        set t1=0000/00/00
        set t2=0000/00/00
        :BEGIN
        call set dt=%%CERTDATE[!n!]%%
        if defined dt (
          if !t1! leq !dt! (
            set t2=!t1!
            set n2=!n1!
            set t1=!dt!
            set n1=!n!
          ) else (
            if !t2! leq !dt! (
              set t2=!dt!
              set n2=!n!
            )
          )
          set /a n=n+1
          goto BEGIN
        )
        call set NEWHASH=%%CERTHASH[%n1%]: =%%
        call set OLDHASH=%%CERTHASH[%n2%]: =%%
        echo NEWHASH=%NEWHASH% [NotAfter: %t1%]
        echo OLDHASH=%OLDHASH% [NotAfter: %t2%]

        echo * Rewrite CertHash
        %SystemRoot%\System32\inetsrv\appcmd.exe renew binding /oldcert:%OLDHASH% /newcert:%NEWHASH%
        echo Update done
    ) else (
        echo Not Renew Cert
    )
)
renew_cert_iis6.bat
@echo off
set url=https://www.example.com/pfx/
set passwd=password
set cn=*.example.com
set file1=fullchain.pfx
set file2=fullchain.live.pfx
set file3=iiscnfg.xml
set site1=/lm/w3svc/1
set site2=w3svc/1


setlocal ENABLEDELAYEDEXPANSION

echo * DownloadFile
wget %url%%file1% --no-check-certificate -N

echo * CheckFile
set timestamp1=
set timestamp2=
for %%a in (%file1%) do set timestamp1=%%~ta
for %%b in (%file2%) do set timestamp2=%%~tb
if "%timestamp1%" == "%timestamp2%" (
    echo Not Renew Cert
) else (
    if "%timestamp1%" gtr "%timestamp2%" (
        echo Renew Cert

        echo * Import Cert
        certutil -f -p %passwd% -importpfx %file1%
        copy %file1% %file2% > nul

        echo * SSL CertHash
        set n=0
        for /f "tokens=2,* usebackq" %%a in ( `certutil -store -v my %cn%^| findstr /c:"Cert ハッシュ(sha1)"` ) do (
          set CERTHASH[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        for /f "tokens=1,2 usebackq" %%a in ( `certutil -store -v my %cn%^| findstr /c:"この日以前: "` ) do (
          set CERTDATE[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        set t1=0000/00/00
        set t2=0000/00/00
        :BEGIN
        call set dt=%%CERTDATE[!n!]%%
        if defined dt (
          if !t1! leq !dt! (
            set t2=!t1!
            set n2=!n1!
            set t1=!dt!
            set n1=!n!
          ) else (
            if !t2! leq !dt! (
              set t2=!dt!
              set n2=!n!
            )
          )
          set /a n=n+1
          goto BEGIN
        )
        call set NEWHASH=%%CERTHASH[%n1%]: =%%
        call set OLDHASH=%%CERTHASH[%n2%]: =%%
        echo NEWHASH=%NEWHASH% [NotAfter: %t1%]
        echo OLDHASH=%OLDHASH% [NotAfter: %t2%]

        echo * Export Settings
        del /q %file3% 2> nul
        iiscnfg /export /f %file3% /sp %site% /inherited /children

        echo * Rewrite CertHash
        mfind /W /E8 /%OLDHASH%/%NEWHASH%/l %file3%

        echo * Import Setting
        iiscnfg /import /f %file3% /sp %site1% /dp %site1% /inherited /children
        del /q %file3% 2> nul

        echo * Restart IIS
        iisweb /start %site2%
        del %file2%
        copy %file1% %file2% > nul
    ) else (
        echo Not Renew Cert
    )
)

Let's Encryptでワイルドカード証明書を発行&自動更新する

Chrome68から非SSLサイトでは、アドレスバーに「保護されていない通信」と表示されるようになりました。SSL証明書はハードルが高いなーと思っていたところ、少し調べると無料で、なおかつ自動でSSL証明書を発行・更新してくれるLet's Encryptというサイトがありました。
今回は、複数のサブドメインが1つの証明書で利用可能なワイルドカード証明書を取得してみます。
取得するwebサーバはCentOS7.5です。DNSは別サーバのBINDで同じDMZ内にあります。nsupdateが使用できるようにあらかじめnamed.confの該当ゾーンのallow-updateにIPを登録しておき、firewallやUTMの設定をしておきます。今回は面倒なので鍵認証はしません。
certbotというLet's Encryptとの通信クライアントをインストールします。
# yum install --enablerepo=epel certbot -y
Let's Encryptにドメインの管理権があることを証明するために外部から参照できるzoneファイルに一時的に次のようなTXTレコードを書く必要があります。
_acme-challenge.example.com. IN TXT "hogehoge"
nsupdateでTXTレコードを追加できるように次のようなスクリプトを作成しておきます。
certbot-auth.sh
#!/usr/bin/bash
DNSSERVER="dns.example.com"
ZONE="example.com"
TTL=300
printf "server %s\nzone %s.\nupdate add _acme-challenge.%s. %d in TXT \"%s\"\nsend\n" "${DNSSERVER}" "${ZONE}" "${CERTBOT_DOMAIN}" "${TTL}" "${CERTBOT_VALIDATION}" | nsupdate
発行されたら追加したTXTレコードを削除すためのスクリプトを作成しておきます。
certbot-clean.sh
#!/usr/bin/bash
DNSSERVER="dns.example.com"
ZONE="example.com"
TTL=300
printf "server %s\nzone %s.\nupdate delete _acme-challenge.%s. %d in TXT \"%s\"\nsend\n" "${DNSSERVER}" "${ZONE}" "${CERTBOT_DOMAIN}" "${TTL}" "${CERTBOT_VALIDATION}" | nsupdate
証明書が更新された時にapacheを再起動します。
certbot-deploy.sh
#!/usr/bin/bash
systemctl restart httpd
3つのファイルを/usr/local/binに移して、パーミッションを変更して実行できるようにします。
証明書を取得します。
# certbot certonly -n \
  -d *.example.com \
  -m root@example.com \
  --agree-tos \
  --manual-public-ip-logging-ok \
  --manual \
  --preferred-challenges dns \
  --manual-auth-hook /usr/local/bin/certbot-auth.sh \
  --manual-cleanup-hook /usr/local/bin/certbot-clean.sh \
  --deploy-hook /usr/local/bin/certbot-deploy.sh
更新は
$ certbot renew
でOKです。crontab -eで1日1回実行するように登録しておけば、期限切れ1ヵ月前に更新されます。

postfix main.cf smtpd_sender_restrictions

最近、メールサーバでキューを確認すると、やたらと???@0000.comへのバウンスメールが溜まっている。 中身を確認すると、PICほにゃららというファイル名で難読化したJavaScriptが添付されているメールです。 何が目的なのか分かりませんが、ごみメール送ってきてバウン...