背景
前回の投稿から約1年が経ちました。仕事上のある案件をきっかけに、以前「やるやる詐欺」と称して予告していたリバースSSH接続の検証に、本気で取り組むことにしました。
一年前と比べると、生成AIは徐々に生活の中に浸透してきています。今回は、自分の考えに加え、ChatGPT 5.0の指導を受けながら検証環境を構築した経験をまとめます。
少し本題から逸れますが、生成AIは非常に便利ですが、常に「なぜその結論になったのか」を意識しながら利用することが重要だと思います。
本題に戻ると、今回の検証環境は以下のゴールを達成するために構築しました。
・リバースSSHとポートフォワーディングを組み合わせて利用するメリットを実感すること
・個人でも手軽に再現できる方法を探ること
・構築時の注意点を経験として学ぶこと
まとめると、「手を動かして覚える」ことを目的としています。
注意点
検証に入る前に、事前練習を行うことをお勧めします。事前練習を通じて、つまずきやすいポイントを把握でき、あらかじめ対策を準備することが可能です。
例えば、事前練習を通じて以下のことが分かりました:
・ARMベースのMac(Apple Silicon:M1/M2/M4など) を使用している場合、VMware Fusionで仮想マシンを動かす際には、ARMアーキテクチャ対応のOSイメージが必要です。
・VMware Fusion の NAT は、MacからNAT IPへアクセスする場合、一部のアプリ(Chromeなど)でループバック接続がブロックされることがあります。
・SSHトンネルサービスを管理するsystemdの設定ファイル内ではExecStartは1行しか書けないです。
・ChatGPTの助言はとても参考になりますが、鵜呑みにすると、間違った設定の泥沼から抜けられなくなる可能性があります。
事前準備
・MacBook Pro 1台
世の中の多くの個人の方が手軽に再現できることを想定し、PC1台で検証を完結させることにしました。
PCスペック:メモリ36GB、HDD 1TB、チップ Apple M4 Max
(最近新しいPCを購入したことも、「ちゃんと検証しよう」というモチベーションになっています)
・Mac上で仮想マシンを動かすためのソフトウェア:VMware Fusion
VMware Fusionについては説明記事が充実しているので、好きな記事を参考にすれば問題ありません。個人的にはこの記事が丁寧にまとめられていると思います。
・環境構成を考えること
「リバースSSH環境の中でポートフォワードも使いたい」
「VMware Fusionを使ってMacBook内に構築したい」
こうしたキーワードをもとに、ChatGPT先生の助言を受けていくつかの案を検討し、最終的に下記の構成を選びました。
[Mac (Remote PC)]
↓ (SSH ポートフォワード)
[Gateway VM (踏み台)]
↑ (Reverse SSHトンネル)
[Internal Server VM (Webサーバ:80)]
・Remote PC:外部から接続する役。VMでもいいし、Mac本体でも代用可
・Gateway VM (踏み台サーバ):2枚NICを持つ(外向けと内向け)
・Internal Server VM:踏み台の内側にあるサーバ。通常は直接アクセスできない
環境構築
検証用サーバインストール
Gateway VM (踏み台)インストール
・Ubuntu Desktop (ARM64)
・vCPU 2、RAM 4GB 、ディスク20GB目安
・NICを2枚設定
-NAT または Bridged → 外部アクセス用
-Host-Only → 内部ネットワーク用
実際の設定画面
2.インストール方法を選択 > ディスクまたはイメージからインストール > 続ける
3.事前にダウンロードしたUbuntu Server 24.04.03 TLSイメージを選択 > 続ける
Ubuntu 22.04/24.04 LTSには公式のARM64デスクトップISOイメージがないため、Ubuntu Server ARM64をインストールした上で、Desktop環境を追加する形でUbuntu Desktopを利用しました。
Ubuntu Serverのまま検証しても問題ありませんが、個人的にはUbuntu Desktopの方が見た目で検証結果を確認しやすいため、検証時にはDesktop環境を好んで使用する傾向があります。
4.VMのイメージ設定が終わったら、NICを追加します。デフォルトではNAT NICが存在しているため、Host-Onlyを追加
設定 > 取り外し可能デバイス > ネットワークアダプタ > デバイスを追加
5.構成を「インターネット共有:Macを共有(NAT)」から「カスタム:Macをプライベート(Host-Only)に変更」
6.VMの設定に戻ると、ネットワークアダプタは二つあることを確認
7.この状態でVMを起動し、「Try or Install Ubuntu Server」でUbuntuをインストール
その後も画面のガイダンスに従って、インストールを完了させます。
8.SSHは利用するため、インストール時に「Install OpenSSH Server」を選ぶと便利
SSH鍵は後で設定するため、ここではImportしなくていいです。
9.Ubuntu Serverのインストールが完了し、コマンドラインが利用できたら下記のコメントでUbuntu Desktopへ変換
sudo apt update && sudo apt upgrade -y
sudo apt install ubuntu-desktop-minimal -y #テストのため、軽量版のデスクトップを利用
sudo reboot
このステップでは少し時間がかかります。
10.Ubuntuの基本設定
# 基本ツールインストール、必要なものをご自由に追加
sudo apt install -y net-tools curl vim git ufw
# SSH 有効化(デフォルトではdisabledになっている)
sudo systemctl enable --now ssh
# IPアドレスの確認/固定化(任意)
ip -4 addr show
sudo nano /etc/netplan/01-netcfg.yaml
# Host‑Only側インタフェース(例:ensX)に静的IPを付けたい場合(サブネットは実環境に合わせて)は下記のようにYamlファイルを作成:
ーーーーーーーーーーーーーーーーーーーーーーーーー
network:
version: 2
ethernets:
ens160: # 外向きNIC(NAT/Bridged)検証環境では172.16.112.133を利用
dhcp4: true
ens192: # 内向きNIC(Host-Only)
addresses: [192.168.244.134/24]
ーーーーーーーーーーーーーーーーーーーーーーーーー
#反映
sudo netplan apply
11.SSHサーバ設定(ポートフォワードを許可)
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config
# 変更点:
AllowTcpForwarding yes # SSH ポートフォワーディングの利用を許可
GatewayPorts yes # リバースフォワード (ssh -R) で待ち受けるアドレス範囲を制御、Yesでは 0.0.0.0 で待ち受けるようになり、LAN 内や外部のクライアントからもアクセス可能になる
#反映
sudo systemctl restart ssh
12.ホストベースのFW(ufw)で必要なセキュリティ設定
sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow from 192.168.244.0/24 to any port 8080 proto tcp # 内向きNIC側のサブネットから8080ポート(SSH)に対する接続を許可
sudo ufw allow from 172.16.112.0/24 to any port 8080 proto tcp # NAT NIC側のサブネットから8080ポートに対する接続を許可
sudo ufw enable # ufwを有効化
sudo ufw status verbose # ufwの基本設定を確認
Internal Server VM (Webサーバ:80)インストール
・Ubuntu Desktop (ARM64)
・vCPU 2、RAM 2GB 、ディスク20GB目安
・NICを1枚設定
-Host-Only → 内部ネットワーク用
(初期設定時は2枚目のNAT NICを有効化 → Apacheなどを入れるため、その後無効化)
1.VMをインストール
Gateway-VMとほぼ同じ手順で行うため、ここでは詳細は割愛します。
2.基本ツールインストール
sudo apt update && sudo apt -y upgrade
sudo apt install -y net-tools curl vim git ufw openssh-server autossh apache2
# Gateway-VMにはない、後で使用する autossh と Apache をインストール
3.テスト用Apacheを有効化し、テストページを作成
sudo systemctl enable --now apache2
sudo nano /var/www/html/index.html
# サンプル内容
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
<!DOCTYPE html>
<html>
<head>
<title>Internal VM Test Page</title>
</head>
<body>
<h1>This is a test page for Reverse SSH</h1>
<p>This page is from Apache on Internal VM.</p>
</body>
</html>
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
# ローカルから動作確認
curl -I http://127.0.0.1
4.リバースSSHを手動テスト
# Internal-VM -> Gateway-VM へリバースフォワード
ssh -N -R 8080:localhost:80 <gateway_user>@<gateway_in_ip>
これで Gateway-VMの 8080 が Internal-VMの80 につながります。
Remote(Mac)から http://gateway_out_ip:8080 へアクセスでApacheのテストページが表示されます。
5.リバースSSHを自動維持
# 自動リバースSSH用のsystemdユニット作成
sudo nano /etc/systemd/system/reverse-tunnel.service
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
[Unit]
Description=Reverse SSH Tunnel
After=network.target
[Service]
User=youruser
ExecStart=/usr/bin/ssh -N -R 0.0.0.0:8080:localhost:80 user@gateway-Internal-IP
Restart=always
RestartSec=5
Environment="HOME=/home/youruser"
[Install]
WantedBy=multi-user.target
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
# 有効化
sudo systemctl daemon-reload
sudo systemctl enable --now reverse-tunnel.service
sudo systemctl status reverse-tunnel.service
# 自動リバースSSHをリアルタイムで確認するログを表示させる
journalctl -u reverse-tunnel.service -f
6.必要なセキュリティ設定
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp # 内部だけでOK、Webは外に出さない(ポートフォワード経由で見せる)
sudo ufw enable
7.SSH鍵を作成し、Gateway-VM に公開鍵を登録
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub user@gateway-Internal-IP
ssh -v user@gateway-Internal-IP # パスワードを聞かれずにログインできればOK
Remote PC(Mac)上の設定・作業
1.SSH接続用の鍵を生成し→Gateway-VMへ配布(Internal-VMに対しては直接SSH接続ではなく、リバースSSHトンネルで接続するため、Internal-VMへの配布は不要)
ssh-keygen -t ed25519 -C "mac-m4max"
ssh-copy-id <user>@<gateway_out_ip> # Gateway-VMへSSH公開鍵を配布
2.Macbookのターミナルからリバースポートフォワードを使い、本来到達できないInternal-VMへアクセス
# Apacheに到達(Internalの80番)
curl http://<gateway_out_ip>:8080
3.ブラウザからhttp://gateway_out_ip:8080へアクセス
Internal-VMのテストページ(80)にフォワードされたことを確認できました!
注意:Chromeではセキュリティの制約でテストページにアクセスできず、検証の場合はFirefoxを利用してください。
4.ローカルフォワードを併用可能(延長線上にできることを確認)
# Mac側の 9090 を Gateway:8080 に接続(結果として Internal:80 へ)
ssh -L 9090:localhost:8080 <user>@<gateway_out_ip>
# → http://localhost:9090 で表示
5.ここまで来て、MacからGateway-VM経由でInternal-VMへのSSHアクセスも実現してみたい
トンネルを常に貼りたいため、まずはInternal-VMのsystemd サービスファイルに下記の記述を追加
5.1下記はInternal-VM側で作業
sudo nano /etc/systemd/system/reverse-tunnel.service
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
[Unit]
Description=Reverse SSH Tunnel
After=network.target
[Service]
User=youruser
# 追加 (例: Gatewayの2222ポート→Internal VMの22)
ExecStart=/usr/bin/ssh -N -R 2222:localhost:22 -R 8080:localhost:80 user@gateway_Internal_ip -p 22 -o ServerAliveInterval=60 -o ServerAliveCountMax=3
#ExecStart=/usr/bin/ssh -N -R 0.0.0.0:8080:localhost:80 user@gateway-Internal-IP
Restart=always
RestartSec=5
Environment="HOME=/home/youruser"
[Install]
WantedBy=multi-user.target
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
sudo systemctl daemon-reload
sudo systemctl enable reverse-tunnel
sudo systemctl start reverse-tunnel
5.2Gateway-VM側のUFW設定を追加
# Internal VM へのリバーストンネル (SSH 用)を追加
sudo ufw allow 2222/tcp
# セキュリティを考えると、ポートを全開放するのは危険なので Mac の IP アドレスに限定すると安心
sudo ufw allow from <mac-global-ip> to any port 2222 proto tcp
sudo ufw enable
sudo ufw reload
5.3 Mac側から接続確認
ssh -p 2222 <user>@<gateway_public_ip>
Internal-VMへSSH接続できたことを確認できました!
Gateway-VM上のポート稼働状況を確認
sudo ss -tulnp
-t → TCP
-u → UDP
-l → LISTEN(待ち受け中のポート)
-n → 数字で表示(ポート番号/IP)
-p → プロセス名/PID 表示
結果から言えること:
・ポート22 、2222、8080が待機して、sshd が待ち受けている
・IPv4 (0.0.0.0) と IPv6 ([::]) の両方で listen 中
・リバーストンネルはきちんと動いている
つまり、リバースSSHトンネル自体は正常に確立しています!
これで、1台のPC上でリバースSSH接続とポートフォワーディング環境を再現できました。
学んだこと
リバースSSH接続とポートフォワーディングを組み合わせると、通常の「外部からアクセスできない環境」でも柔軟かつ安全に接続できるようになります。
具体的には、下記の代表的なメリットが考えられます:
・NAT越え / ファイアウォール越えが簡単
-普通は外部から家庭内や社内のサーバに直接アクセスできません(NATやFWで遮断)。
-リバースSSHは内部から外部へ接続する仕組みなので、通常のアウトバウンド通信として許可されやすいです。
・単一のIP/ポート経由で複数サービスにアクセス可能
-1台の踏み台サーバ(Gateway-VMなど)経由で、複数の内部サービスに接続できる。
-外部に直接公開せずに済むのでセキュリティ上安全。
・セキュリティの向上
-ファイアウォールで制限されたポートやサービスにも、安全にアクセスできる。
-外部に直接サービスを公開しないため、攻撃リスクが低くなる。
・VPNを張らなくてもリモートアクセスが可能
-VPN構築よりも簡単。サーバ1台とSSHだけで最低限の環境を作れる。
・シンプルで導入しやすい
-専用ソフト不要、SSHだけで実現可能。
最後に
ようやく自分に約束した検証を完成させました。
これからはコンテナとクラウドの勉強を再開する予定なので、近いうちにクラウドに関する投稿をするかもしれません。
この未熟な記事が、どこかで誰かの参考になれば幸いです。いつも温かく見守ってくださる方々に、心から感謝します!