OpenSSHを使ってRSA公開鍵認証なchroot付きSFTPサーバを立てる方法

簡単なように思えて,結構ハマったのでメモしておきます.
SSH サーバは既に稼働していることを前提に書きますので,SSH,SSHd の細かい設定は他サイト様に委ねます.

仕様および前提

sftpを許可するユーザ: ftpuser(シェルでのログイン不可)
ftpuserの所属グループ: ftpgroup
ftpuserのhome: /home/ftpuser
ftpuserに公開したいディレクトリ: /pass/to/chrooted

環境

$ lsb_release -drc
Description: Ubuntu 11.10
Release: 11.10
Codename: oneiric

$ uname -r
3.0.0-13-generic

$ ssh -v
OpenSSH_5.8p1 Debian-7ubuntu1, OpenSSL 1.0.0e 6 Sep 2011

まずサーバ側でftpgroup,ftpuser を作成します.

# groupadd ftpgroup
# useradd --create-home --home /home/ftpuser --shell /bin/false -g ftpgroup

確認

$ getent group | tail -n 1
ftpgroup:x:133:ftpuser

$ getent passwd | tail -n 1
ftpuser:x:1001:133::/home/ftpuser:/bin/false

/etc/group/etc/passwd を直接編集するという強行手段でも構わないのですが,ログオフが必要な上に結構危険です.
編集するにしても,vigrvipw という専用のコマンドがあります.

クライアント側でRSA鍵ペアを作成します.既に作成済みの場合,飛ばしてください.

$ ssh-keygen -t RSA -b 2048

できたら,エディタでもUSBメモリでもscp でも構わないので,クライアントの~/.ssh/id_rsa.pub をサーバの/home/ftpuser/.ssh/authorized_keys にコピーします. ((今回はPC1 -> PC2 へはssh可能,PC2 -> PC1 へはsftp のみ可能としたかったので,scp 使えるならsftp 要らないじゃん,というツッコミは無しで.))
通常のSSHと同じですね.
パーミッションは以下のように設定します.

/home                755   root:root (おそらくデフォルトでOK)
/home/ftpuser          755   root:root
/home/ftpuser/.ssh        700   ftpuser:ftpgroup
/home/ftpuser/authorized_keys  600   ftpuser:ftpgroup

処理系によっては,authorized_keys が700 の場合もあるようです.既にSSH ログイン可能なuser の/home/user/.ssh を確認してみてください.
ここで注意しなければならないのが,/home/ftpuser の所有者がroot だということです.とはいえ,ここまでは単にchown すればいいだけです.
問題はここからです. /passpass/to//pass/to/chrootedもそれぞれ所有者がroot かつ他ユーザの書き込み不可である必要があります.
「そうすべき」ではなく「そうする必要があります」.
これは,セキュリティの観点からルール化されたものです.詳しい背景はここに書いてあります
それじゃあ/pass/to/chrooted/media/hard_disk/ftp にしたいけど,/media/hard_disk の所有者は一般ユーザに残しておきたい・・・ということができないかというと,そんなことはありません.以下に方法例を書いておきます.と言ってもSimLink貼るだけです.

# cd /home/ftpuser
# ln -s /pass/to/chrooted ./
# chown root:root /pass/to/chrooted
# chmod 755 /pass/to/chrooted

/home/ftpuser の所有者はroot に設定してあるので,/pass/pass/to(あるいは/media/media/hard_disk)の所有者がroot である必要はなくなります.
また,/pass/to/chrooted の所有者はroot である必要があるのですが,/pass/to/chrooted/data の所有権はftpuser:ftpgroup で構いません.
普段使ってるユーザをftpgroup に加えておくか,/pass/to/chrooted/data のパーミッションを777 にでも設定すれば管理が楽でしょう.おそらく前者のほうがセキュリティ的には好ましいと思われます.

次に/etc/sshd_config をエディタで編集します

#AuthorizedKeysFile %h/.ssh/authorized_keys
AuthorizedKeysFile %h/.ssh/authorized_keys

#Subsystem sftp /usr/local/libexec/sftp-server
Subsystem sftp internal-sftp

# 最後の行に以下を追記.全角スペースは半角に変換
Match user ftpuser
 ChrootDirectory /home/ftpuser/chrooted
 AllowAgentForwarding no
 X11Forwarding no
 AllowTcpForwarding no
 ForceCommand internal-sftp

internal-sftp を使うのは,ftpuser はchroot をかけたディレクトリの外に出られないからです.
つまり,/usr/local/libexec/sftp-server にもアクセスできなくなるからです.

書けたら

/etc/init.d/ssh restart

クライアント側からサーバ(192.168.1.1)にアクセスしてみます.ssh -p-p はポートですが,sftpでは-P(大文字)です.

$ ssh -p 10000 ftpuser@192.168.1.1
Enter passphrase for key '/home/client_user/.ssh/id_rsa':
This service allows sftp connections only.
Connection to 192.168.1.1 closed.

$ sftp -P 10000 ftpuser@192.168.1.1
Enter passphrase for key '/home/client_user/.ssh/id_rsa':
Connected to 192.168.1.1.
sftp> exit

上手くいかなければssh -vsftp -v してみれば何か分かるかもしれません.
もう一度,所有権をまとめて書いておきます.

/home/ftpuser/:
drwxr-xr-x root:root .
drwxr-xr-x root:root ..
lrwxrwxrwx root:root share -> /pass/to/chrooted

/home/ftpuser/.ssh:
drwx------ ftpuser:ftpgroup .
-rw------- ftpuser:ftpgroup authorized_keys

/pass/to/chrooted
drwxr-xr-x root:root .
drwxrwxrwx ftpuser:ftpgroup data

nautilus のFile -> Connect to Server にでも登録しておくと便利かもしれません.

参考サイト
restrictive ssh problem (ForceCommand, ChrootDirectory): Write failed: Broken pipe
あるシステム管理者の日常: sftpとChrootDirectory(3)
 

出先にいながら自宅にいるようにインターネットをする方法

(6/14 11:00 間違いに気付いたので大幅に直しました)

自宅のSSHd + SOCKS serverを介してインターネットにアクセスすれば,公開鍵暗号を破られない限り,自分の管理していないFirewallやProxyに通信を閲覧されることがなくなります.
また,SSHが通っていれば簡単に使えるので手軽です.

ローカル:出先(会社,研究室)のLinux
リモート:自宅のLinux

と呼ぶことにします.

まず,ローカルからリモートへSSHでトンネルを掘りましょう

ssh -D 1080 -p 22 user@jitakuhogehoge.com

ポート番号は適宜読み変えてください.

ローカルのFirefoxを以下のように設定します

SSL Proxyの項目は設定しないでください.SSLセッションは元々暗号化されているので,SOCKS通すと上手く通信できなくなります.

tcpdumpでパケットを見てみると,SOCKSを通さない場合は通信内容が丸見えです.
以下は,http://team2ch.orgを表示したときのものです.


sudo tcpdump -t -n -X -s 1000 port 80 > no_socks
cat no_socks

※一部抜粋

0x0000: 4500 028b 38bf 4000 4006 ed40 8299 0db0 E...8.@.@..@....
0x0010: 77f5 0a2f aa73 0050 6623 713b 7bc8 0a43 w../.s.Pf#q;{..C
0x0020: 8018 00b6 5868 0000 0101 080a 000d 74e6 ....Xh........t.
0x0030: 3e43 d1c0 4745 5420 2f69 6e64 6578 2e63 >C..GET./index.c
0x0040: 6769 2048 5454 502f 312e 310d 0a48 6f73 gi.HTTP/1.1..Hos
0x0050: 743a 2074 6561 6d32 6368 2e6f 7267 0d0a t:.team2ch.org..
0x0060: 5573 6572 2d41 6765 6e74 3a20 4d6f 7a69 User-Agent:.Mozi
0x0070: 6c6c 612f 352e 3020 2858 3131 3b20 553b lla/5.0.(X11;.U;

SOCKSを通せば


sudo tcpdump -t -n -X -s 1000 port 22 > socks_haita
cat socks_haita

※一部抜粋


0x0000: 4500 0104 c652 4000 3706 6a34 77f5 0a2f E....R@.7.j4w../
0x0010: 8299 0db0 a2e4 856a 628f d7eb f933 c721 .......jb....3.!
0x0020: 8018 0266 48c7 0000 0101 080a 0a5f 9a0d ...fH........_..
0x0030: 000e 0bc9 3049 7fb9 b473 7a4e 47d9 d50e ....0I...szNG...
0x0040: e8a4 15b4 ee8c 0d60 9506 c829 170e 2d26 .......`...)..-&
0x0050: 4fa2 d2e5 fc49 14c3 9f27 5b83 9a27 f5bf O....I...'[..'..
0x0060: 0368 db97 a2d1 187d f180 2f42 f631 c525 .h.....}../B.1.%
0x0070: 6fea 9341 019a 4f6a 1d7f bb0e 52ea 82fa o..A..Oj....R...

実際にパケットを見ても,通信内容について推測することは(公開鍵暗号を破らない限り)できません.
もし仮にパケット内容を暗号化している共通鍵が解読されたとしても,共通鍵は使い捨てなので,盗聴されたパケットは氷山の一角にすぎません.

ssh -Xはローカルネットワーク内であれば有効ですが,WAN越しだと描画速度の面から実用的ではありません.
この方法でSOCKSを使えば,ローカルから直接接続するのとあまり変わりない描画速度/回線速度で,Firewallを誤魔化しながら通信をすることができます.
もっとも,回線速度に関してはリモートの回線速度にも大きく依存すると考えられます.また,FirewallでSOCKSによる通信をしゃ断されたら使えないというデメリットもあります.