Nginxで自己署名を行い、アプリケーション層のL7単位で生IP宛のHTTP/HTTPS通信を拒否する

3 min read

こんにちは、無能です。
このエッジコンピューティングサービスが普及するなかで一部のドメインをわざわざunboundだとかでDNSサーバ等意識して行うことは無いのだが、一部の人たちにはやはり必要なもの。
例えば、自分のような送受信出来るメールサーバーを自己ホストしているような人間にとっては例えばOpenDKIMだとか依存関係でunboundが入ってきたりする。
そうして、公開された生IPアドレスはDDoS攻撃の穴になりうる可能性も無きしもあらずでどうしても生IPでアクセスされると精神衛生上良くないのでブロックすることにする。

まあ、DDoSに対してもFail2banでブロックは出来るのだけれどログから見てブロックする対象IPのDBに突っ込んで管理しているみたいなので負荷がかかりやすくFail2banでやるならドメイン単位でやるとして普段使わないような生IPは別の方法で今回はNginx側でHTTP/HTTPS通信から守ることにしよう。

シンプルにHTTP通信だけブロックする場合

私の場合、グローバルな公開IPアドレスは以下なのでこうなる。

# http通信
server {
    listen 80;
    listen [::]:80;

    server_name 167.179.75.206;

    return 444;
}

しかし、SSL通信の場合だとNginxはlisten 443 ssl;のようにSSL通信であることを明示的にしてあげることでHTTPSのListenとなる。

そうしてこのようにhttpセクションにこれをいれてnginx -tを実行すると・・・。

# https通信
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name 167.179.75.206;

    # IPアドレスへのアクセスを拒否
    return 444;
}

どうなるか?

# nginx -t
nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive in /usr/local/etc/nginx/nginx.conf:90
nginx: configuration file /usr/local/etc/nginx/nginx.conf test failed

そう、SSL通信だから鍵が無いと怒られちゃう。
こういう場合、自己署名が必要で・・・。俺だよ!オレオレ!としてコレ、俺の証明書なwとしてあげなければいけない。俺が俺の証明をする、今、ここで・・・。

という訳でOpenSSLさん、なんとかできません?

OpenSSLの力を借りて、このオレオレ詐・・・オレオレ証明をやっていこう。
OpenBSDから枝分かれしたLibreSSLに次の時代を任せている感は否めないがなかなか一般化まではそれなりに時間は掛かりそうではある。
とりあえず、自分しか使わないので3年とする。

openssl req -x509 -nodes -days 1095 -newkey rsa:2048 -keyout /usr/local/etc/nginx/selfsigned.key -out /usr/local/etc/nginx/selfsigned.crt

で、Enterで何も入れずに進んでくと指定したエクスポート先に鍵が生成される。

Nginxくんただいま

Nginxでこの鍵を指定してあげよう。

# https通信
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name 167.179.75.206;

    # 自己署名証明書と秘密鍵の指定
    ssl_certificate /usr/local/etc/nginx/selfsigned.crt;
    ssl_certificate_key /usr/local/etc/nginx/selfsigned.key;

    return 444;
}

これでいけましたとさ。
おしまい。