前書き

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

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

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

前提条件

開始するには、2つの新しいUbuntu 14.04サーバーが必要です。 それぞれに `+ sudo +`権限を持つ通常のユーザーアカウントを追加します。 これを正しく行う方法については、https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-14-04 [Ubuntu 14.04初期サーバーセットアップガイド]に従ってください。

セキュリティで保護するアプリケーションのセットアップは、https://www.digitalocean.com/community/tutorials/how-to-set-up-a-remote-database-to-optimize-site-performance-with-mysql [このガイド]。 従う場合は、そのチュートリアルの指示に従ってアプリケーションとデータベースサーバーをセットアップします。

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

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

https://www.digitalocean.com/community/tutorials/how-to-implement-a-basic-firewall-template-with-iptables-on-ubuntu-14-04 [このガイド]のファイアウォールは、基本的なセットアップを提供しますそれが必要です。 `+ 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

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

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

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

これを見つけるには、 `+ 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:*               LISTEN      1058/
tcp        0      0               0.0.0.0:*               LISTEN      4187/

強調表示されている最初の列には、回線の終わりに向かって強調表示されているサービスがリッスンしている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:*               LISTEN      1097/
tcp        0      0      0.0.0.0:*               LISTEN      3112/

これらの列はまったく同じように読むことができます。 上記の例では、 `+ 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


. . .

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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
   inet /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


. . .

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

/etc/iptables/rules.v4

*filter
. . .

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


. . .

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

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

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

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

sudo service iptables-persistent reload

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

結論

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

ファイアウォールと「+ iptables +」の詳細については、以下のガイドをご覧ください。