Proxy(Squid)を経由してSFTP通信する検証をCML上で行う
— 背景・HTTP CONNECTの仕組み・完全設定・検証・トラブルシュート・運用/セキュリティまで
このドキュメントで得られるもの(読む前に)
- 所要時間の目安:構築〜検証まで 30〜60分(CMLが使える前提)
-
習得できるスキル:
- HTTP CONNECT の基礎(SSH/SFTPを通す仕組み)
- Squid を 22/tcp LISTEN で動かすミニマム設定
- UFW で「Proxy 以外は 22/tcp を拒否」する実装
- 多セグメント(3サブネット)ネットワーク設計と静的ルート
- 失敗時のデバッグ手順とログの読み方
-
必要な前提知識:
- Linux 基本操作(sudo, エディタ, systemd, journalctl)
- ネットワーク基礎(L2/L3, デフォルトルート, 静的ルート)
- CML の基礎操作(ノード作成・配線・コンソール接続)
なぜこの構成が必要?(背景・ユースケース)
-
通常の SSH/SFTP が通らない現場
多くの企業・閉域網では「外向きは HTTP/HTTPS のみ」「内部もプロキシ経由で統制」。22/tcp の直通は遮断されやすい。 -
HTTP CONNECT で解決
CONNECT は任意 TCP のトンネルをプロキシ経由で張るメソッド。プロキシが 22/tcp を許可すれば SSH/SFTP を通せる。 -
ユースケース
- 直結禁止・プロキシ経由のみ許可のネットワークでの SFTP
- 監査可能な経路(プロキシのアクセスログに残す)
- 経路制御・あとからの追跡(誰が/いつ/どこへ)
HTTP CONNECT の要点(なぜ SSH/SFTP が通る?)
-
CONNECT <host>:<port> HTTP/1.1をプロキシへ → プロキシが宛先に TCP 接続 → 以後は生バイトストリームを中継 - SSH はアプリ層で暗号化済み → プロキシはL4中継のみ(中身は見えない)
- 一般の HTTP 代理取得(GET/POST)と違い、TCP パイプを作るのが CONNECT の本質
環境・前提条件
- Cisco Modeling Labs (CML):仮想ルータ/VMを配線して実験できるラボ環境。リンク状態が可視化され再現性が高い。
- cloud-config(cloud-init):VM初回起動でネットワーク/ユーザ設定を自動適用。本記事では ens2=DHCP(外)、ens3=固定(内)+静的ルート を配布。
- Ubuntu VM:Squid / OpenSSH / UFW / netcat など標準パッケージが豊富で再現しやすい。
CML実装構成
CML上の実際の構成:各VMはunmanaged-switchで外向き通信、CSRで3セグメントに分離
CMLを活用した検証観点
検証項目の体系化
この構成では以下の観点で検証を行います:
機能検証
- SFTP接続の成功/失敗
- ファイル転送の完了性
- 認証・暗号化の正常動作
セキュリティ検証
- 直接接続の遮断確認
- プロキシ経由の強制確認
- アクセスログの記録確認
パフォーマンス検証
- 転送速度の測定
- 同時接続数の上限確認
- リソース使用量の監視
CMLを活用した検証手法
CMLの可視化機能活用
- トポロジ図:リアルタイムでリンク状態を確認
- ライン品質表示:帯域使用率、パケット廃棄率の監視
- ノード状態監視:CPU、メモリ使用率のリアルタイム表示
パケット解析(CML統合Wireshark)
# CML Web UI から直接 Wireshark を起動してリンクをキャプチャ
# 1. CMLでリンクを右クリック → "Packet Capture"
# 2. Wiresharkが自動起動してパケットキャプチャ開始
# 3. HTTP CONNECT の流れを詳細に確認可能
CLI での詳細解析
# Proxy で:CONNECT リクエストの詳細確認
sudo tcpdump -ni ens3 -A -s0 'tcp port 22 and host 192.168.2.1'
# "CONNECT 192.168.4.1:22 HTTP/1.1" が確認できる
# To で:SSH ハンドシェイクの確認
sudo tcpdump -ni ens3 -X -s0 'tcp port 22 and src 192.168.3.1'
# SSH-2.0 バナー交換が確認できる
検証用スクリプト
# パフォーマンス測定
echo "=== SFTP転送性能測定 ==="
fallocate -l 10M ~/tmp/test10M
time sftp -o "ProxyCommand=nc -X connect -x 192.168.3.1:22 %h %p" sftpuser@192.168.4.1 <<'EOF'
put ~/tmp/test10M upload/
bye
EOF
# 同時接続テスト
echo "=== 同時接続テスト ==="
for i in {1..5}; do
(echo "接続${i}" | sftp -o "ProxyCommand=nc -X connect -x 192.168.3.1:22 %h %p" sftpuser@192.168.4.1) &
done
wait
IP 割り当て(早見表)
| ノード | IF | 設定 | 備考 |
|---|---|---|---|
| From | ens2 | DHCP (ext-conn) | default route、IPは環境により変動 |
| ens3 | 192.168.2.1/24 | 3/4 宛は 192.168.2.254 | |
| Proxy | ens2 | DHCP (ext-conn) | default route、IPは環境により変動 |
| ens3 | 192.168.3.1/24 | 2/4 宛は 192.168.3.254、Squid:22 | |
| To | ens2 | DHCP (ext-conn) | default route、IPは環境により変動 |
| ens3 | 192.168.4.1/24 | 2/3 宛は 192.168.4.254、UFW: allow-from 192.168.3.1 | |
| csr1000v-0 | G3 | 192.168.2.254/24 | From側セグメント |
| G4 | 192.168.3.254/24 | Proxy側セグメント | |
| G5 | 192.168.4.254/24 | To側セグメント |
完全版:設定ファイル & コマンド(コピペOK)
1) cloud-config(各VM:起動時に IP/ルートを確定)
From(ens2=DHCP 外、ens3=192.168.2.1 内)
#cloud-config
hostname: From
manage_etc_hosts: true
system_info: { default_user: { name: cisco } }
password: cisco
chpasswd: { expire: false }
ssh_pwauth: true
timezone: Asia/Tokyo
locale: ja_JP.utf8
write_files:
- path: /etc/netplan/50-cloud-init.yaml
content: |
network:
version: 2
renderer: networkd
ethernets:
ens2:
dhcp4: true
dhcp4-overrides: { use-routes: true, use-dns: true }
ens3:
dhcp4: false
addresses: [192.168.2.1/24]
routes:
- to: 192.168.3.0/24
via: 192.168.2.254
- to: 192.168.4.0/24
via: 192.168.2.254
runcmd: [ "netplan apply" ]
Proxy(ens2=DHCP 外、ens3=192.168.3.1 内)
#cloud-config
hostname: Proxy
manage_etc_hosts: true
system_info: { default_user: { name: cisco } }
password: cisco
chpasswd: { expire: false }
ssh_pwauth: true
timezone: Asia/Tokyo
locale: ja_JP.utf8
write_files:
- path: /etc/netplan/50-cloud-init.yaml
content: |
network:
version: 2
renderer: networkd
ethernets:
ens2:
dhcp4: true
dhcp4-overrides: { use-routes: true }
ens3:
dhcp4: false
addresses: [192.168.3.1/24]
routes:
- to: 192.168.2.0/24
via: 192.168.3.254
- to: 192.168.4.0/24
via: 192.168.3.254
runcmd: [ "netplan apply" ]
To(ens2=DHCP 外、ens3=192.168.4.1 内)
#cloud-config
hostname: To
manage_etc_hosts: true
system_info: { default_user: { name: cisco } }
password: cisco
chpasswd: { expire: false }
ssh_pwauth: true
timezone: Asia/Tokyo
locale: ja_JP.utf8
write_files:
- path: /etc/netplan/50-cloud-init.yaml
content: |
network:
version: 2
renderer: networkd
ethernets:
ens2:
dhcp4: true
dhcp4-overrides: { use-routes: true }
ens3:
dhcp4: false
addresses: [192.168.4.1/24]
routes:
- to: 192.168.2.0/24
via: 192.168.4.254
- to: 192.168.3.0/24
via: 192.168.4.254
runcmd: [ "netplan apply" ]
成功チェック(各VM共通)
ip -br a | egrep 'ens2|ens3'
ip r | head -n 6
# 期待例:
# default は ens2(DHCP) 由来、2/3/4 宛は ens3 → CSR(.254)
2) CSR1000v(基本 L3)
conf t
interface g3
description to From
ip address 192.168.2.254 255.255.255.0
no shutdown
interface g4
description to Proxy
ip address 192.168.3.254 255.255.255.0
no shutdown
interface g1
description to To
ip address 192.168.4.254 255.255.255.0
no shutdown
end
wr
show ip interface brief
期待出力(抜粋)
Gi3 192.168.2.254 up/up
Gi4 192.168.3.254 up/up
Gi1 192.168.4.254 up/up
3) To(SFTPサーバ)+ UFW(Proxy 以外は拒否)
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
sudo adduser sftpuser
sudo -u sftpuser mkdir -p /home/sftpuser/upload
sudo chown -R sftpuser:sftpuser /home/sftpuser
# UFW:Proxy(192.168.3.1) からの 22/tcp のみ許可
sudo ufw --force reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.3.1 to any port 22 proto tcp
sudo ufw logging on
sudo ufw enable
sudo ufw status verbose
期待出力(抜粋)
Status: active
To Action From
22/tcp ALLOW IN 192.168.3.1
4) Proxy(Squid を 22/tcp で LISTEN)
Ubuntu は
ssh.socketが 22 を掴んでいることがあるため、sshd を別ポート(例:2222) に移します。
sudo systemctl stop ssh.socket
sudo systemctl disable ssh.socket
sudo sed -i 's/^#\?Port .*/Port 2222/' /etc/ssh/sshd_config
sudo systemctl enable --now ssh.service
sudo ss -lntp | egrep ':22|:2222' # 22 は空、2222 で sshd LISTEN
Squid のインストール & 完全設定
sudo apt install -y squid netcat-openbsd
sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.bak
sudo tee /etc/squid/squid.conf >/dev/null <<'CONF'
# === Squid on 22/tcp (bind to Proxy's inside IP) ===
http_port 192.168.3.1:22
visible_hostname proxy
# Clients allowed to use this proxy
acl fromnet src 192.168.2.0/24
# Allowed CONNECT destination/port (strictly SSH only)
acl to_ssh dst 192.168.4.1/32
acl SSH_ports port 22
acl CONNECT method CONNECT
# Security: disallow CONNECT except 22
http_access deny CONNECT !SSH_ports
# Allow SFTP via CONNECT from "fromnet" to "to_ssh"
http_access allow CONNECT to_ssh fromnet
# Default deny (must be last)
http_access deny all
# IPv6環境のハマり回避
dns_v4_first on
CONF
sudo systemctl restart squid
sudo ss -lntp | egrep ':22|:3128' # 192.168.3.1:22 を squid がLISTEN
期待出力(例)
LISTEN ... 192.168.3.1:22 ... users:(("squid",pid=...,fd=...))
LISTEN ... 0.0.0.0:2222 ... users:(("sshd",pid=...,fd=...))
代替:sshd を 22 のままにしたい場合、
iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 22 -s 192.168.2.0/24 -j REDIRECT --to-ports 3128で 22→3128 転送も可。
5) 検証(CLI)
CONNECT トンネルのバナー確認(From)
nc -X connect -x 192.168.3.1:22 192.168.4.1 22
# "SSH-2.0-OpenSSH_..." が見えればOK(Ctrl+C)
SFTP 転送(From→Proxy:22→To:22)
mkdir -p ~/tmp; date > ~/tmp/from-test.txt
sftp -o "ProxyCommand=nc -X connect -x 192.168.3.1:22 %h %p" sftpuser@192.168.4.1 <<'EOF'
mkdir -p upload
put ~/tmp/from-test.txt upload/
ls -l upload
bye
EOF
証跡(ログ)
# Proxy
sudo grep "CONNECT 192.168.4.1:22" /var/log/squid/access.log | tail -n1
# To
sudo journalctl -u ssh --since "10 min ago" | grep Accepted | tail -n1
# 直結の反証(失敗ログ)
sudo tail -n1 /var/log/ufw.log
Windows クライアント(WinSCP)の設定
目的:WinSCP から HTTP CONNECT で Proxy(192.168.3.1:22) 経由 → To(192.168.4.1:22) へ SFTP 接続。
手順(GUI)
- WinSCP 起動 → New Site
-
Session
-
File protocol:
SFTP -
Host name:
192.168.4.1(To) -
Port:
22 -
User name:
sftpuser
-
File protocol:
-
Advanced → Connection → Proxy
-
Proxy type:
HTTP -
Proxy hostname:
192.168.3.1(Proxy) -
Port:
22(Squid を 22 で LISTEN) - 認証:未設定(Squid 側で認証有効なら入力)
-
Proxy type:
- OK → Save(任意) → Login(初回はホスト鍵確認 → Yes)
セッションログ(抜粋例)
Connecting to proxy...
HTTP proxy CONNECT 192.168.4.1:22
Proxy: 200 Connection established
Server version: SSH-2.0-OpenSSH_9.x
トラブルシュート(実例ベース)
| 症状 | 原因 | 対処 |
|---|---|---|
Proxy error: 403 Forbidden |
Squid の ACL 順序/範囲ミス |
http_access allow CONNECT to_ssh fromnet を deny all より前へ/IP範囲を実網に合わせる |
Proxy error: 503 Service Unavailable |
Proxy→To:22 到達不可 | Proxy で nc -vz 192.168.4.1 22/To の UFW(Proxy のみ許可)/CSR の配線とルート |
Temporary failure in name resolution |
DNS 未設定 or IPv6影響 | ens2 側の DNS(DHCP配布 or nameservers)/apt -o Acquire::ForceIPv4=true update
|
nc: invalid option -- X |
BusyBox 版 nc |
netcat-openbsd か ncat を導入 |
| Squid が 22 で LISTEN しない |
ssh.socket が 22 を掴んでる |
systemctl stop/disable ssh.socket → Port 2222 に変更 → squid 再起動 |
診断ステップ(順番が重要)
- リンク:CML でリンク up(緑)
-
ルート(各VM):
ip -br a/ip r→ default=ens2(DHCP) / 2-4 宛=ens3→CSR -
Proxy→To:
Proxy$ nc -vz 192.168.4.1 22 -
CONNECT:
From$ nc -X connect -x 192.168.3.1:22 192.168.4.1 22 -
ログ:
/var/log/squid/access.log/journalctl -u ssh//var/log/ufw.log
実運用への橋渡し
複数クライアント対応
# 複数のクライアントサブネットを許可する場合
acl fromnet src 192.168.2.0/24 192.168.10.0/24
# 特定ホストのみ許可する場合
acl fromnet src 192.168.2.1/32 192.168.2.10/32
基本的な認証追加
# 簡易Basic認証の追加(検証レベル)
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/squid/passwords testuser
sudo chown proxy:proxy /etc/squid/passwords
# squid.conf に追加
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
acl authenticated proxy_auth REQUIRED
http_access allow CONNECT to_ssh fromnet authenticated
関連技術への言及
-
他プロキシソフトウェアとの比較
- Squid:フォワードプロキシ用途に強く、ACL とログが豊富(本検証で使用)
- Nginx:HTTPプロキシとして軽量だが、CONNECTの細かい制御は限定的
-
検証環境の発展
- EVE-NG/GNS3:類似のネットワーク仮想化プラットフォームでの応用
- Docker/Podman:コンテナ環境でのSquidプロキシ検証
重要な注意(まとめ)
⚠️ ACL順序が重要:
http_access allow CONNECT ...は必ずdeny allの前に記述
⚠️ ポート競合回避:ssh.socketが 22 を掴んでいると Squid は LISTEN できない
⚠️ 検証ログの確認:squid access.log/ssh journal/ufw.logで動作を確認
⚠️ セキュリティ境界:To の UFW は「Proxy のみ許可」を維持して直接接続を遮断
検証完了の確認
# CONNECT の確立(SSH バナーが出れば成功)
nc -X connect -x 192.168.3.1:22 192.168.4.1 22
# ファイル転送テスト
mkdir -p ~/tmp; date > ~/tmp/test-file.txt
sftp -o "ProxyCommand=nc -X connect -x 192.168.3.1:22 %h %p" sftpuser@192.168.4.1 <<'EOF'
mkdir -p upload
put ~/tmp/test-file.txt upload/
ls -l upload
bye
EOF
# 検証ログの確認
echo "=== Proxy ログ ==="
sudo grep "CONNECT 192.168.4.1:22" /var/log/squid/access.log | tail -n1
echo "=== SSH 接続ログ ==="
sudo journalctl -u ssh --since "10 min ago" | grep "Accepted" | tail -n1
echo "=== 直接接続拒否ログ ==="
sudo tail -n1 /var/log/ufw.log
付録:WinSCP 設定(Windowsクライアント)
-
File protocol:SFTP / Host name:
192.168.4.1/ Port:22/ User:sftpuser -
Proxy type:HTTP / Proxy hostname:
192.168.3.1/ Port:22 - ログを有効化(Preferences → Logging, Debug 1 以上)→
HTTP proxy CONNECT 192.168.4.1:22→200 Connection established→SSH-2.0-...が並べば成功。
