サーバー間のトラフィックを保護するためにIptablesファイアウォールを設定する方法

前書き

アプリケーションのセットアップで個別のコンポーネントを異なるノードにデプロイすることは、負荷を減らして水平方向にスケーリングを開始する一般的な方法です。 典型的な例は、アプリケーションとは別のサーバーにデータベースを構成することです。 このセットアップには多くの利点がありますが、ネットワークを介した接続には新しいセキュリティ上の懸念が伴います。

このガイドでは、分散セットアップで各サーバーに簡単なファイアウォールを設定する方法を示します。 他のトラフィックを拒否しながら、コンポーネント間の正当なトラフィックを許可するようにポリシーを構成します。

このガイドのデモでは、2台のUbuntu 14.04サーバーを使用します。 1つはNginxで提供されるWordPressインスタンスを持ち、もう1つはアプリケーションのMySQLデータベースをホストします。 このセットアップを例として使用しますが、サーバーの要件に合うように、関連する手法を推定できるはずです。

前提条件

開始するには、2つの新しいUbuntu 14.04サーバーが必要です。 それぞれにsudo権限を持つ通常のユーザーアカウントを追加します。 これを正しく行う方法を学ぶには、Ubuntu 14.04 initial server setup guideに従ってください。

保護するアプリケーションのセットアップは、this guideに基づいています。 従う場合は、そのチュートリアルの指示に従ってアプリケーションとデータベースサーバーをセットアップします。

基本的なファイアウォールのセットアップ

まず、各サーバーにベースラインファイアウォール構成を実装します。 実装するポリシーは、セキュリティ優先のアプローチを採用しています。 SSHトラフィック以外のほとんどすべてをロックダウンし、特定のアプリケーション用にファイアウォールに穴を開けます。

this guideのファイアウォールは、必要な基本設定を提供します。 iptables-persistentパッケージをインストールし、基本ルールを/etc/iptables/rules.v4ファイルに貼り付けます。

sudo apt-get update
sudo apt-get install iptables-persistent
sudo nano /etc/iptables/rules.v4

/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

# 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]
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

これをライブ環境do not reload your firewall rules yetに実装している場合。 ここで説明した基本的なルールセットをロードすると、アプリケーションとデータベースサーバー間の接続がすぐに切断されます。 リロードする前に、運用上のニーズを反映するようにルールを調整する必要があります。

サービスで使用されているポートを発見する

コンポーネント間の通信を許可する例外を追加するには、使用されているネットワークポートを知る必要があります。 構成ファイルを調べることで正しいネットワークポートを見つけることができましたが、正しいポートを見つけるためのアプリケーションに依存しない方法は、各マシンの接続をリッスンしているサービスをチェックすることです。

netstatツールを使用してこれを見つけることができます。 このアプリケーションはIPv4を介してのみ通信しているため、-4引数を追加しますが、IPv6を使用している場合は削除できます。 実行中のサービスを見つけるために必要な他の引数は-pluntです。

Webサーバーでは、次のように表示されます。

sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1058/sshd
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      4187/nginx

強調表示されている最初の列には、回線の終わりに向かって強調表示されているサービスがリッスンしているIPアドレスとポートが表示されます。 特別な0.0.0.0アドレスは、問題のサービスが使用可能なすべてのアドレスをリッスンしていることを意味します。

データベースサーバーでは、次のように表示されます。

sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1097/sshd
tcp        0      0 192.0.2.30:3306     0.0.0.0:*               LISTEN      3112/mysqld

これらの列はまったく同じように読むことができます。 上記の例では、192.0.2.30アドレスはデータベースサーバーのプライベートIPアドレスを表しています。 アプリケーションのセットアップでは、セキュリティ上の理由からMySQLをプライベートインターフェイスにロックしました。

このステップで見つけた値に注意してください。 これらは、ファイアウォール構成を調整するために必要なネットワークの詳細です。

このシナリオ例では、Webサーバーで、次のポートにアクセスできることを確認する必要があることに注意できます。

  • すべてのアドレスのポート80

  • すべてのアドレスのポート22(ファイアウォールルールで既に考慮されています)

データベースサーバーでは、次のポートにアクセスできるようにする必要があります。

  • アドレス192.0.2.30(またはそれに関連付けられたインターフェイス)のポート3306

  • すべてのアドレスのポート22(ファイアウォールルールで既に考慮されています)

Webサーバーのファイアウォールルールを調整する

必要なポート情報を取得したので、Webサーバーのファイアウォールルールセットを調整します。 sudo権限でエディターでルールファイルを開きます。

sudo nano /etc/iptables/rules.v4

Webサーバーで、許容トラフィックのリストにポート80を追加する必要があります。 サーバーは使用可能なすべてのアドレスをリッスンしているため、インターフェイスまたは宛先アドレスによってルールを制限しません。

Web訪問者は、TCPプロトコルを使用して接続します。 基本的なフレームワークには、TCPアプリケーション例外用のTCPと呼ばれるカスタムチェーンがすでにあります。 SSHポートの例外のすぐ下に、そのチェーンにポート80を追加できます。

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 80 -j ACCEPT

. . .

Webサーバーは、データベースサーバーとの接続を開始します。 ファイアウォールでは発信トラフィックが制限されておらず、確立された接続に関連付けられた着信トラフィックが許可されているため、この接続を許可するこのサーバーで追加のポートを開く必要はありません。

完了したら、ファイルを保存して閉じます。 Webサーバーには、すべての正当なトラフィックを許可し、他のすべてをブロックするファイアウォールポリシーがあります。

構文エラーのルールファイルをテストします。

sudo iptables-restore -t < /etc/iptables/rules.v4

構文エラーが表示されない場合は、ファイアウォールをリロードして新しいルールセットを実装します。

sudo service iptables-persistent reload

データベースサーバーのファイアウォールルールを調整する

データベースサーバーでは、サーバーのプライベートIPアドレスのポート3306へのアクセスを許可する必要があります。 私たちの場合、そのアドレスは192.0.2.30でした。 このアドレス宛のアクセスを明確に制限することも、そのアドレスが割り当てられているインターフェイスと照合してアクセスを制限することもできます。

そのアドレスに関連付けられているネットワークインターフェイスを見つけるには、次のように入力します。

ip -4 addr show scope global
Output2: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 203.0.113.5/24 brd 104.236.113.255 scope global eth0
       valid_lft forever preferred_lft forever
3: eth1:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.0.2.30/24 brd 192.0.2.255 scope global eth1
       valid_lft forever preferred_lft forever

強調表示された領域は、eth1インターフェイスがそのアドレスに関連付けられていることを示しています。

次に、データベースサーバーのファイアウォールルールを調整します。 データベースサーバーでsudo権限でルールファイルを開きます。

sudo nano /etc/iptables/rules.v4

ここでも、TCPチェーンにルールを追加して、Webサーバーとデータベースサーバー間の接続の例外を形成します。

問題の実際のアドレスに基づいてアクセスを制限する場合は、次のようなルールを追加します。

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -d 192.0.2.30 -j ACCEPT

. . .

そのアドレスを格納するインターフェイスに基づいて例外を許可する場合は、代わりに次のようなルールを追加できます。

/etc/iptables/rules.v4

*filter
. . .

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -i eth1 -j ACCEPT

. . .

完了したら、ファイルを保存して閉じます。

次のコマンドで構文エラーを確認します。

sudo iptables-restore -t < /etc/iptables/rules.v4

準備ができたら、ファイアウォールルールを再読み込みします。

sudo service iptables-persistent reload

これで、両方のサーバーは、それらの間のデータの必要なフローを制限することなく保護されるはずです。

結論

適切なファイアウォールを実装することは、アプリケーションをセットアップするときのデプロイメント計画の一部である必要があります。 NginxとMySQLを実行する2台のサーバーを使用してWordPressインスタンスを提供するこの構成を示しましたが、上記の手法は特定の技術の選択に関係なく適用できます。

特にファイアウォールとiptablesの詳細については、次のガイドを参照してください。

Related