Iptablesを使用してLinuxゲートウェイを介してポートを転送する方法
序章
NAT 、またはネットワークアドレス変換は、パケットを代替アドレスにリダイレクトするためにパケットをマングリングするための一般的な用語です。 通常、これはトラフィックがネットワーク境界を超えられるようにするために使用されます。 NATを実装するホストは通常、2つ以上のネットワークにアクセスでき、それらの間でトラフィックをルーティングするように構成されています。
ポート転送は、特定のポートに対する要求を別のホスト、ネットワーク、またはポートに転送するプロセスです。 このプロセスは処理中のパケットの宛先を変更するため、NAT操作の一種と見なされます。
このチュートリアルでは、iptables
を使用して、NAT技術を使用してファイアウォールの背後にあるホストにポートを転送する方法を示します。 これは、プライベートネットワークを構成しているが、指定されたゲートウェイマシンを介して内部の特定のトラフィックを許可したい場合に便利です。
前提条件
このガイドに従うには、次のものが必要です。
- プライベートネットワークが有効になっている同じデータセンターに2台のUbuntu20.04サーバーがセットアップされています。 これらの各マシンで、
sudo
権限を持つ非rootユーザーアカウントを設定する必要があります。 これを行う方法は、Ubuntu20.04初期サーバーセットアップガイドのガイドで学ぶことができます。 このチュートリアルではファイアウォールの設定と構成を行うため、このガイドのステップ4はスキップしてください。 - サーバーの1つで、
iptables
を使用してファイアウォールテンプレートを設定し、ファイアウォールサーバーとして機能できるようにします。 これを行うには、 Ubuntu20.04でIptablesを使用して基本的なファイアウォールを実装する方法に関するガイドに従います。 完了すると、ファイアウォールサーバーで次のものを使用できるようになります。
ファイアウォールテンプレートを設定したサーバーは、プライベートネットワークのファイアウォールおよびルーターとして機能します。 デモンストレーションの目的で、2番目のホストは、プライベートインターフェイスを使用してのみアクセスできるWebサーバーで構成されます。 パブリックインターフェイスで受信したリクエストをWebサーバーに転送するようにファイアウォールマシンを構成します。Webサーバーはプライベートインターフェイスで到達します。
ホストの詳細
始める前に、両方のサーバーで使用されているインターフェースとアドレスを知る必要があります。
ネットワークの詳細を見つける
独自のシステムの詳細を取得するには、ネットワークインターフェイスを見つけることから始めます。 次のコマンドを実行すると、マシンのインターフェイスとそれに関連付けられているアドレスを見つけることができます。
ip -4 addr show scope global
Sample Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 203.0.113.1/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 10.0.0.1/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever
強調表示された出力には、2つのインターフェイス(eth0
とeth1
)とそれぞれに割り当てられたアドレス(それぞれ203.0.113.1
と10.0.0.1
)が表示されます。 これらのインターフェイスのどれがパブリックインターフェイスであるかを確認するには、次のコマンドを実行します。
ip route show | grep default
Outputdefault via 111.111.111.111 dev eth0
この出力からのインターフェース情報(この例ではeth0
)は、デフォルトゲートウェイに接続されているインターフェースになります。 これはほぼ間違いなくあなたのパブリックインターフェースです。
各マシンでこれらの値を見つけ、それらを使用してこのガイドの残りの部分に従ってください。
このガイドで使用されるサンプルデータ
わかりやすくするために、このチュートリアルでは、次の空のアドレスとインターフェイスの割り当てを使用します。 以下にリストされている値を独自の値に置き換えてください。
Webサーバーネットワークの詳細:
- パブリックIPアドレス:
203.0.113.1
- プライベートIPアドレス:
10.0.0.1
- パブリックインターフェイス:
eth0
- プライベートインターフェイス:
eth1
ファイアウォールネットワークの詳細:
- パブリックIPアドレス:
203.0.113.2
- プライベートIPアドレス:
10.0.0.2
- パブリックインターフェイス:
eth0
- プライベートインターフェイス:
eth1
Webサーバーのセットアップ
sudo
ユーザーでログインして、Webサーバーホストへの接続を開始します。
Nginxのインストール
最初のステップは、WebサーバーホストにNginxをインストールし、プライベートインターフェイスのみをリッスンするようにロックダウンすることです。 これにより、ポート転送を正しく設定した場合にのみWebサーバーを使用できるようになります。
ローカルパッケージキャッシュを更新することから始めます。
sudo apt update
次に、apt
を使用して、ソフトウェアをダウンロードしてインストールします。
sudo apt install nginx
Nginxをプライベートネットワークに制限する
Nginxをインストールしたら、デフォルトのサーバーブロック構成ファイルを開いて、プライベートインターフェイスのみをリッスンするようにします。 お好みのテキストエディタを使用してファイルを開きます。 ここではnano
を使用します。
sudo nano /etc/nginx/sites-enabled/default
内部で、listen
ディレクティブを見つけます。 構成の上部に向かって2回続けてリストする必要があります。
/ etc / nginx / sites-enabled / default
server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; . . . }
最初のlisten
ディレクティブで、WebサーバーのプライベートIPアドレスと80
の前にコロンを追加して、Nginxにプライベートインターフェイスでのみリッスンするように指示します。 このガイドではIPv4転送についてのみ説明しているため、IPv6用に構成されている2番目のlistenディレクティブを削除できます。
次に、listen
ディレクティブを次のように変更します。
/ etc / nginx / sites-enabled / default
server { listen 10.0.0.1:80 default_server; . . . }
終了したら、ファイルを保存して閉じます。 nano
を使用した場合は、CTRL + X
、Y
、ENTER
の順に押すとこれを行うことができます。
次に、ファイルの構文エラーをテストします。
sudo nginx -t
Outputnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
出力にエラーがない場合は、Nginxを再起動して新しい構成を有効にします。
sudo systemctl restart nginx
ネットワーク制限の確認
この時点で、Webサーバーへのアクセスレベルを確認すると便利です。
ファイアウォールサーバーから、次のコマンドを使用してプライベートインターフェイスからWebサーバーにアクセスしてみてください。
curl --connect-timeout 5 10.0.0.1
成功すると、出力は次のメッセージになります。
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .
パブリックインターフェイスを使用しようとすると、接続できないことを示すメッセージが表示されます。
curl --connect-timeout 5 203.0.113.1
Outputcurl: (7) Failed to connect to 203.0.113.1 port 80: Connection refused
これらの結果は期待されています。
ポート80を転送するためのファイアウォールの構成
次に、ファイアウォールマシンにポートフォワーディングを実装します。
カーネルでの転送の有効化
最初に行う必要があるのは、カーネルレベルでトラフィック転送を有効にすることです。 デフォルトでは、ほとんどのシステムで転送がオフになっています。
このセッションでのみポート転送をオンにするには、次のコマンドを実行します。
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Output1
ポートフォワーディングを永続的にオンにするには、/etc/sysctl.conf
ファイルを編集する必要があります。 これを行うには、sudo
権限でファイルを開きます。
sudo nano /etc/sysctl.conf
ファイル内で、次のようになっている行を見つけてコメントを外します。
/etc/sysctl.conf
net.ipv4.ip_forward=1
終了したら、ファイルを保存して閉じます。
次に、このファイルの設定を適用します。 最初に次のコマンドを実行します。
sudo sysctl -p
Outputnet.ipv4.ip_forward = 1
次に、同じコマンドを実行しますが、-p
フラグを--system
に置き換えます。
sudo sysctl --system
Output. . . * Applying /usr/lib/sysctl.d/50-pid-max.conf ... kernel.pid_max = 4194304 * Applying /etc/sysctl.d/99-cloudimg-ipv6.conf ... net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.default.use_tempaddr = 0 * Applying /etc/sysctl.d/99-sysctl.conf ... net.ipv4.ip_forward = 1 * Applying /usr/lib/sysctl.d/protect-links.conf ... fs.protected_fifos = 1 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 * Applying /etc/sysctl.conf ... net.ipv4.ip_forward = 1
基本ファイアウォールへの転送ルールの追加
次に、ポート80
でパブリックインターフェイス(eth0
)に流入するトラフィックがプライベートインターフェイス(eth1
)に転送されるようにファイアウォールを構成します。
前提条件のチュートリアルで構成したファイアウォールでは、デフォルトでFORWARD
チェーンがDROP
トラフィックに設定されています。 Webサーバーに接続を転送できるようにするルールを追加する必要があります。 セキュリティ上の理由から、これをかなり厳しくロックして、転送したい接続のみが許可されるようにします。
FORWARD
チェーンでは、パブリックインターフェイスからプライベートインターフェイスに移動するポート80
宛ての新しい接続を受け入れます。 新しい接続はconntrack
拡張子で識別され、次のようにTCPSYNパケットで具体的に表されます。
sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
これにより、接続を確立するための最初のパケットがファイアウォールを通過できるようになります。 また、その接続から生じる双方向の後続のトラフィックを許可する必要があります。 パブリックインターフェイスとプライベートインターフェイス間のESTABLISHED
およびRELATED
トラフィックを許可するには、次のコマンドを実行します。 まず、パブリックインターフェイスの場合:
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
次に、プライベートインターフェイスの場合:
sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
FORWARD
チェーンのポリシーがDROP
に設定されていることを再確認してください。
sudo iptables -P FORWARD DROP
この時点で、パブリックインターフェイスとプライベートインターフェイス間の特定のトラフィックがファイアウォールを通過することを許可しました。 ただし、トラフィックを変換および転送する方法を実際にiptables
に指示するルールを構成していません。
ダイレクトパケットにNATルールを正しく追加する
次に、iptables
にトラフィックのルーティング方法を指示するルールを追加します。 iptables
がパケットを正しく変更して、クライアントがWebサーバーと通信できるようにするには、2つの別々の操作を実行する必要があります。
DNAT
と呼ばれる最初の操作は、nat
テーブルのPREROUTING
チェーンで行われます。 DNAT
は、パケットがネットワーク間を通過するときに正しくルーティングできるようにするために、パケットの宛先アドレスを変更する操作です。 パブリックネットワーク上のクライアントはファイアウォールサーバーに接続し、プライベートネットワークトポロジについての知識はありません。 したがって、各パケットの宛先アドレスを変更して、プライベートネットワークで送信されたときに、Webサーバーに正しく到達する方法を認識できるようにする必要があります。
ポートフォワーディングを構成するだけで、ファイアウォールに到達するすべてのパケットでNATを実行するわけではないため、ルールでポート80
を一致させる必要があります。 ポート80
宛てのパケットをWebサーバーのプライベートIPアドレス(次の例では10.0.0.1
)に一致させます。
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
このプロセスは、全体像の半分を処理します。 パケットはWebサーバーに正しくルーティングされるはずです。 ただし、現時点では、パケットの送信元アドレスはクライアントの元のアドレスのままです。 サーバーはそのアドレスに直接応答を送信しようとします。これにより、正当なTCP接続を確立できなくなります。
DigitalOceanでは、異なる送信元アドレスを持つドロップレットを離れるパケットは実際にはハイパーバイザーによってドロップされるため、この段階のパケットはWebサーバーに到達することさえありません(SNATを一時的に実装することで修正されます)。 これは、リクエスト内の送信元アドレスを偽造することにより、被害者のコンピュータに大量のデータを送信するように要求される攻撃を防ぐために導入されたなりすまし対策です。 詳細については、コミュニティでこの応答をお読みください。
適切なルーティングを構成するには、パケットがWebサーバーに向かう途中でファイアウォールを離れるときに、パケットの送信元アドレスも変更する必要があります。 送信元アドレスをファイアウォールサーバーのプライベートIPアドレス(次の例では10.0.0.2
)に変更する必要があります。 その後、応答はファイアウォールに返送され、ファイアウォールは期待どおりにクライアントに転送します。
この機能を有効にするには、nat
テーブルのPOSTROUTING
チェーンにルールを追加します。このチェーンは、パケットがネットワークに送信される直前に評価されます。 Webサーバー宛てのパケットをIPアドレスとポートで照合します。
sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2
このルールを設定したら、ファイアウォールマシンのパブリックアドレスにWebブラウザを向けることでWebサーバーにアクセスできるようになります。
curl 203.0.113.2
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .
これで、ポート転送のセットアップが完了しました。
永続的なルールセットの調整
ポートフォワーディングを設定したので、これを永続的なルールセットに保存できます。
現在のルールセットにあるコメントを失うことを気にしない場合は、netfilter-persistent
コマンドを使用してiptables
サービスを使用し、ルールを保存します。
sudo service netfilter-persistent save
Output * Saving netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save [ OK ]
コメントをファイルに残したい場合は、コメントを開いて手動で編集します。
sudo nano /etc/iptables/rules.v4
追加されたFORWARD
チェーンルールのfilter
テーブルの構成を調整する必要があります。 また、nat
テーブルを構成するセクションを調整して、PREROUTING
およびPOSTROUTING
ルールを追加できるようにする必要があります。 内容は次のようになります。
/etc/iptables/rules.v4
*filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Rules to forward port 80 to our web server # Web server network details: # * Public IP Address: 203.0.113.1 # * Private IP Address: 10.0.0.1 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.2 # * Private IP Address: 10.0.0.2 # * Public Interface: eth0 # * Private Interface: eth1 -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # End of Forward filtering rules # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] # Rules to translate requests for port 80 of the public interface # so that we can forward correctly to the web server using the # private interface. # Web server network details: # * Public IP Address: 203.0.113.1 # * Private IP Address: 10.0.0.1 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.2 # * Private IP Address: 10.0.0.2 # * Public Interface: eth0 # * Private Interface: eth1 -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 -A POSTROUTING -d 10.0.0.1 -o eth1 -p tcp --dport 80 -j SNAT --to-source 10.0.0.2 # End of NAT translations for web server traffic COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT
コンテンツを追加し、独自のネットワーク環境を反映するように値を調整したら、ファイルを保存して閉じます。
次に、ルールファイルの構文をテストします。
sudo sh -c "iptables-restore -t < /etc/iptables/rules.v4"
エラーが検出されない場合は、ルールセットをロードします。
sudo service netfilter-persistent reload
Output * Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]
次に、ファイアウォールのパブリックIPアドレスを介してWebサーバーにアクセスできることをテストします。
curl 203.0.113.2
これは以前と同じように機能するはずです。
結論
これで、iptables
を使用してLinuxサーバーのポートを転送することに慣れているはずです。 このプロセスには、カーネルレベルでの転送の許可、ファイアウォールシステム上の2つのインターフェイス間の特定のポートのトラフィックの転送を許可するアクセスの設定、およびパケットが正しくルーティングされるようにNATルールの構成が含まれます。 これは扱いにくいプロセスのように見えるかもしれませんが、netfilter
パケットフィルタリングフレームワークとiptables
ファイアウォールの柔軟性も示しています。 これは、サービストラフィックがゲートウェイファイアウォールマシンを自由に通過できるようにしながら、プライベートネットワークのトポロジを偽装するために使用できます。