KVM仮想化ゲストOSのインターネット公開
はじめに
お疲れ様です。
現在 KVM で仮想化して ゲスト OS をいくつか入れているが、内部(プライベートアドレス)の IP アドレスを持った ゲスト OS に
外部から直接sshアクセスできるように設定しようと試みた。
※現在までは、プライベートNWの中で運用していたが、ゲストOSを外部からssh接続したいとのリクエストで、ポートフォワーディングを
試みた次第です。
接続はブリッジ接続で、ホスト OS は DMZ に配置しています。グローバル IP アドレスはルーターに割り当てられている1つの
IP アドレスになります。その ルーターの DMZ にホストOS が繋がっているイメージです。
そのホスト OS の中に KVM で仮想サーバー 複数を配置している感じになります。
一般的な運用ですと内部のサーバーに外部から直接アクセスということはあまりしないかもしれませんが
今回は ブリッジ接続により、インターネット側から直接 ポートフォワーディングでゲスト OS に接続したいと思いました。
その中で多少 手こずったこともあったので ここに 覚書として記載しておきます。
以下の手順は、ホストOS(CentOS 9、DMZ配置、IP: 192.168.0.200、ファイアウォールは firewalld を使用)から、
ブリッジ環境下にあるゲストOS(例: 新たなゲストOSの IP: 192.168.0.211と仮定)へ SSH 接続を実現する為のものとなります。
※この例では、ホストの別のポート(例: 2223)を使って新たなゲストOSへの転送を設定するケースを想定してます。
作業をやってみるまでは、単純に多少設定すれば良いものと思っていたが、ちょっと違った!
一旦、成功してみて、それほど難易度は高くはなかったが、きちんと調べてから進めるのが良いと思った。
◆◆◆前提知識◆◆◆◆◆◆
① CentOS9では、従来のiptablesを使っておらず、nftablesに統合している。
NAT(nftablesベース)という表現は、Linuxシステムにおけるネットワークアドレス変換(NAT)の機能が、
従来のiptablesではなく、nftablesという新しいパケットフィルタリングフレームワークを使って
実現されていることを意味する。
nftablesとは、Linuxカーネルでは、以前は、iptablesがパケットフィルタリングとNATの処理を行っていたが、
最近では、nftablesが新たな標準として採用されているとのこと。
nftablesはiptables、ip6tables、arptables、ebtablesの役割を統合して、よりシンプルで柔軟かつ効率的な
ルール管理を実現するために設計されているらしい。(これが今回の肝ポイントであります!)
nftという、一つのコマンド(通常はnft)でIPv4、IPv6、ARP、ブリッジなど複数のプロトコルにまたがるルールを管理できる。
NAT(nftablesベース)は、NAT機能そのものは従来通りの役割(例えば、外部から受けたパケットの宛先IPを内部アドレスに
書き換えるDNAT、内部から出るパケットの送信元IPを変更するSNATなど)を果すが、
そのルールの管理と適用にnftablesが使われていることを示しています。
たとえば、CentOS 9などの最新ディストリビューション(最近はCentOS 10も)では、firewalldがデフォルトで
nftablesバックエンドを利用する設定になっているらしい。
従来のiptablesコマンドで確認するルールとは異なり、nftコマンドでルールを確認する必要が出てくる場合がある。
また、具体的な設定(ポートフォワーディング、MASQUERADEなど)もnftablesの仕組みで動作しているため、
システム管理者はnftables の概念を理解することが重要!
◆◆◆システム要件◆◆◆◆◆◆
ホストOS(CentOS9)
・CentOS 9環境で、DMZ上でKVMでゲストOSを複数稼働
・IP アドレス:192.168.0.200(ホスト名: hsv.redzetm.net)
・ブリッジ環境でネットワークが接続されている
・firewalld が有効であり、内部で NAT(nftablesベース)を利用している
・外部接続用のマスカレード(SNAT)が既に有効になっている
※まだの場合は、以下のコマンドを実行して有効化する。
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --reload
ゲストOS
・CentOS 9(もしくは同等の OS)
・IP アドレス:例として192.168.0.211を使用
・ブリッジ環境により、ゲストはネットワーク内で一意のIPを持っている
・SSH デーモン(sshd)が稼働している
・ゲスト側のファイアウォールで SSH(ポート22)が許可されている
※必要なら以下のコマンドで許可する
firewall-cmd --permanent --add-service=ssh firewall-cmd --reload
注意
一番わからなかったのは、ポートフォワーディングを使う場合の必要条件として、ホストで DNAT(Destination NAT)を
使用して外部からの接続をゲストに転送する場合、ホストはパケットを受け取って、そのパケットを
転送(ルーティング)する必要がある。
Linux カーネルでは、内部でのパケット転送がデフォルトでは無効になっているため、これを有効にしないと
パケットはホスト内に留まり、転送されないということだった。
たとえホスト・ゲストがブリッジ接続であっても、ホスト経由のポートフォワーディングを利用する場合は、
IP フォワードを有効にする必要がある。
# sysctl で有効化し、永続化する。(この作業は、ゲストOSを複数入れる場合でも最初の1回でOK)
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
※sysctl -p は、/etc/sysctl.confに記述した設定を即座に有効化する。/etcsysctl.congの直接編集でもOK
設定手順
1. ゲストOSの準備確認
・SSH サービスの状態確認
・ゲストOS側で以下を実行し、sshd が正常に起動していることを確認する。systemctl status sshd
・ネットワークの確認
・ゲストOSがブリッジ接続となっているか、IP アドレス(この例では 192.168.0.211)が正しく設定されているか確認する。
・ファイアウォール・SELinux の確認
・必要に応じ、SELinux の状態も確認(問題なければvimなどで /etc/selinux/config を開き、SELINUX=disabled
と変更してシステムを再起動する。)
2. ホスト側で転送ルール(フォワーディング)の登録
転送ルールの追加をおこなう。
ゲストOS(192.168.0.211)のポート22へ転送するため、ホストで以下のコマンドを実行。
必要に応じ、適当な外部ポート番号(ここでは 2223)を設定する。
firewall-cmd --permanent --add-forward-port=port=2223:proto=tcp:toaddr=192.168.0.211:toport=22
ルールの確認
設定された転送ルールを確認するには以下を行う。
firewall-cmd --list-forward-ports
下記のような出力が得られれば、登録は成功となる。
port=2223:proto=tcp:toport=22:toaddr=192.168.0.211
※表示がされない場合は、先に2223ポート開放してからの方がいいかも!
3. ホスト側で対象ポートの開放
外部からのアクセスを受け付けるために、ポート2223を開放する。
firewall-cmd --permanent --add-port=2223/tcp
firewall-cmd --reload
4. マスカレード(SNAT)の確認
DMZ環境での外部アクセスの場合、戻りパケットの送信元アドレスがホストに変換される必要がある。
すでに前提条件(1台でもゲストを直接外部からのパケットを受け入れている場合)で
マスカレードを有効にしていれば追加の作業は不要!
まだの場合は、以下のコマンドで有効にする。
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --reload
5. 外部接続の検証
接続テスト
外部のクライアントから、以下のように SSH コマンドを実行してアクセス可能か確認。
ssh -p 2223 ユーザー名@ドメインor IPアドレス
正しく接続できれば、ゲストOS(192.168.0.211)の SSH サービスにアクセスできていることになる。
#####################
以上でありますが、以下を注意して運用する。
ポート番号の重複を避ける。(必ず確認して慎重に!)
各ゲストごとにホスト側の外部ポートは固有である必要があります。(例:2222, 2223, 2224 ...)
ネットワーク設定の確認。
ゲストOSがブリッジ接続で正しい IP アドレスを持っているか、また必要なサービス(SSH)が
正しく稼働しているかを事前に確認!
ホスト側のファイアウォール設定
追加した各転送ルールと開放ポートの設定がファイアウォールに正しく登録されていることを再度確認!
ルーター(DMZ側)の設定(今の私の環境の場合は、ルーターのDMZをホストに向けていれば問題なし)
外部ネットワーク側で、必要に応じた設定が施されているか(WAN側のファイアウォール、DMZ設定)
は別途確認する。
総評
ブリッジ接続の場合、通常は各ゲストOSが独自のIPアドレスを持ち、直接ネットワーク上で通信できるため、
NAT(Masquerade)は不要と思いました。
しかし今回の構成では、外部からの接続がホストのポート(2222)に来て、DNAT(Destination NAT)で
ゲストOS(192.168.0.210)のポート22へ転送されている。
この場合、外部クライアントはホストのIP(例: hsv.redzetm.net / 192.168.0.200)宛にSYNパケットを送る。
ホストはこのパケットの宛先をゲストOSに書き換え(DNAT)で、転送するが、ゲストOSは返信するとき、
通常はソースIPとして自分のIP(192.168.0.210)を使用するとの調べだった。
すると、クライアントには返信元がゲストOSのIPとして届き、接続のトラッキングが乱れてしまうことが
あるとのことだった。
Masquerade(SNAT)を有効にする理由は、ゲストOSから返されたパケットの送信元IPをホストのIPに
書き換えることで、接続全体がホストを中継する一貫したトラフィックとして処理されるようにしなければならないとのこと。
これにより、返信パケットが正しい経路でクライアントに返り、通信が確立できるようになった。
結局は、たとえブリッジ接続であっても、外部からのアクセス時にホスト側でポートフォワーディング(DNAT)を
行う場合、返信パケットの送信元アドレスの統一を図るために、Masquerade(SNAT)の設定が必要となるとのこと。
なるほどーって感じでした。
やってみてーーー!