Iptablesを使用してLinuxゲートウェイを介してポートを転送する方法
序章
NAT 、またはネットワークアドレス変換は、パケットを代替アドレスにリダイレクトするためにパケットをマングリングするための一般的な用語です。 通常、これはトラフィックがネットワーク境界を超えられるようにするために使用されます。 NATを実装するホストは通常、2つ以上のネットワークにアクセスでき、それらの間でトラフィックをルーティングするように構成されています。
ポート転送は、特定のポートに対する要求を別のホスト、ネットワーク、またはポートに転送するプロセスです。 このプロセスは処理中のパケットの宛先を変更するため、NAT操作の一種と見なされます。
このチュートリアルでは、使用方法を示します iptables
NAT技術を使用して、ファイアウォールの背後にあるホストにポートを転送します。 これは、プライベートネットワークを構成しているが、指定されたゲートウェイマシンを介して内部の特定のトラフィックを許可したい場合に便利です。
前提条件
このガイドに従うには、次のものが必要です。
- プライベートネットワークが有効になっている同じデータセンターに2台のUbuntu20.04サーバーがセットアップされています。 これらの各マシンで、root以外のユーザーアカウントを設定する必要があります。
sudo
特権。 これを行う方法は、Ubuntu20.04初期サーバーセットアップガイドのガイドで学ぶことができます。 このチュートリアルではファイアウォールの設定と構成を行うため、このガイドのステップ4はスキップしてください。 - サーバーの1つで、ファイアウォールテンプレートを次のように設定します
iptables
そのため、ファイアウォールサーバーとして機能できます。 これを行うには、 Ubuntu20.04でIptablesを使用して基本的なファイアウォールを実装する方法に関するガイドに従います。 完了すると、ファイアウォールサーバーで次のものを使用できるようになります。iptables-persistent
インストール済み- デフォルトのルールセットをに保存しました
/etc/iptables/rules.v4
- ルールファイルを編集するか、を使用してルールを追加または調整する方法の理解
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サーバーのセットアップ
Webサーバーホストへの接続を開始し、 sudo
ユーザー。
Nginxのインストール
最初のステップは、WebサーバーホストにNginxをインストールし、プライベートインターフェイスのみをリッスンするようにロックダウンすることです。 これにより、ポート転送を正しく設定した場合にのみWebサーバーを使用できるようになります。
ローカルパッケージキャッシュを更新することから始めます。
- sudo apt update
次に、 apt
ソフトウェアをダウンロードしてインストールするには:
- sudo apt install nginx
Nginxをプライベートネットワークに制限する
Nginxをインストールしたら、デフォルトのサーバーブロック構成ファイルを開いて、プライベートインターフェイスのみをリッスンするようにします。 お好みのテキストエディタを使用してファイルを開きます。 ここでは使用します nano
:
- sudo nano /etc/nginx/sites-enabled/default
内部で、 listen
指令。 構成の上部に向かって2回続けてリストする必要があります。
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
. . .
}
まず最初に listen
ディレクティブの前に、WebサーバーのプライベートIPアドレスとコロンを追加します。 80
プライベートインターフェイスでのみリッスンするようにNginxに指示します。 このガイドではIPv4転送についてのみ説明しているため、IPv6用に構成されている2番目のlistenディレクティブを削除できます。
次に、 listen
次のようなディレクティブ:
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
ファイル内で、次のようになっている行を見つけてコメントを外します。
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
基本ファイアウォールへの転送ルールの追加
次に、トラフィックがパブリックインターフェイスに流れるようにファイアウォールを構成します(eth0
)ポート上 80
プライベートインターフェースに転送されます(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
トラフィックをルーティングする方法。 のために2つの別々の操作を実行する必要があります iptables
クライアントがWebサーバーと通信できるように、パケットを正しく変更します。
と呼ばれる最初の操作 DNAT
、で行われます PREROUTING
のチェーン nat
テーブル。 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
次の例では)。 その後、応答はファイアウォールに返送され、ファイアウォールは期待どおりにクライアントに転送します。
この機能を有効にするには、ルールをに追加します POSTROUTING
のチェーン nat
テーブル。パケットがネットワークに送信される直前に評価されます。 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
で構成を調整する必要があります filter
のテーブル FORWARD
追加された連鎖律。 また、を構成するセクションを調整する必要があります nat
あなたがあなたを追加できるようにテーブル PREROUTING
と POSTROUTING
ルール。 内容は次のようになります。
*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
これは以前と同じように機能するはずです。
結論
これで、Linuxサーバーのポート転送に慣れているはずです。 iptables
. このプロセスには、カーネルレベルでの転送の許可、ファイアウォールシステム上の2つのインターフェイス間の特定のポートのトラフィックの転送を許可するアクセスの設定、およびパケットが正しくルーティングされるようにNATルールの構成が含まれます。 これは扱いにくいプロセスのように見えるかもしれませんが、 netfilter
パケットフィルタリングフレームワークと iptables
ファイアウォール。 これは、サービストラフィックがゲートウェイファイアウォールマシンを自由に通過できるようにしながら、プライベートネットワークのトポロジを偽装するために使用できます。