はじめに
WinSCP
はSFTP
やSCP
でサーバに接続してファイル転送等を行う際に便利なWindowsアプリケーションですが、OpenSSH
のchroot
の機能で接続できるディレクトリを制限したいと思いやってみたところ、中々苦戦したため記事に残しておこうと思います。
chrootとは
ルートディレクトリを変更する機能となり、chroot
の機能を使用することで、指定のディレクトリ配下をルートディレクトリとして動作させることができるので、今回のように特定のディレクトリ配下しか見せないということができます。
以下のようにuser1
は特に制限せず、user2
とuser3
はchroot
で制限されていた場合、制限がないuser1
は全て閲覧可能ですが、user2
とuser3
は/chroot/userX
より上位には移動できないため、user2
からuser3
、user3
からuser2
のファイル・ディレクトリを閲覧することはできません。
/
├── home
│ └── user1 ← user1は全ての場所を閲覧可能
│ └── dir1
│ └── dir2
└── chroot
├── user2 ← /chroot/user2をchrootでルートとした場合、user2はdir3とdir4のみ閲覧可能
│ └── dir3
│ └── dir4
└── user3 ← /chroot/user3をchrootでルートとした場合、user3はdir5とdir6のみ閲覧可能
└── dir5
└── dir6
但し、指定のディレクトリ配下をルートディレクトリとして動作させると、当然、その配下には/bin
や/etc
等、サーバの動作に必要となるディレクトリは存在しないことから、サーバへのリモート接続時の制限として設定する場合、動作に必要となるコマンドやライブラリをchroot
で制限しているディレクトリ配下に配置する必要が出てくる場合があります。
ちなみに、chroot
はUnixでは昔からある機能となり、最近よく使われているDocker
等のコンテナ技術はchroot
がベースとなっている技術となります。
サーバ構成
今回は以下の構成のサーバで設定を行おうと思います。
OSにより若干手順が異なるかもしれませんが、OpenSSHを使用しているサーバならUbuntuや他のLinuxでも同様の手順でできるかと思います。
項目 | 内容 |
---|---|
OS | Red Hat Enterprise Linux 8.9 |
OpenSSHサーババージョン | 8.0p1-19.el8_9.2 |
SFTP、SCP接続する際のパターン別chroot設定
SFTP
、SCP
どちらもSSHプロトコルを使用してファイル転送する機能となりますが、chroot
で制限を行う場合、SFTP
、SCP
両方接続できるようにするのは大変なので、できればSFTP
のみでファイル転送できるようにすることをおすすめします。
今回SFTP
、SCP
それぞれchroot
で制限する方法は紹介しますが、よほどの理由がなければSFTP
のみで接続できるような運用としたほうがよいと思います。
- 事前設定
- SFTP接続する際のchroot設定
- SCP接続する際のchroot設定
- SFTPユーザとSCPユーザを共存する際のchroot設定
- 同じユーザでSFTP、SCP接続する際のchroot設定
事前設定
事前にchroot
でルートディレクトリ先となるディレクトリの作成と、接続確認用のユーザ、また、共通で必要となるディレクトリを先に作成しておきます。
今回はSFTP
、SCP
でそれぞれユーザを分けたいと思うので、ユーザとchroot
で制限するディレクトリは以下のようにしたいと思います。
ユーザ名 | chrootディレクトリ |
---|---|
sftpuser | /chroot/sftpuser |
scpuser | /chroot/scpuser |
sudo mkdir -p /chroot/sftpuser
sudo mkdir -p /chroot/scpuser
なお、今回作成するユーザはSFTP
、SCP
接続専用ユーザとして、接続時にchroot
でルートディレクトリを変更するため、ユーザ作成時、不要なホームディレクトリは作成しないようにしますが、ホームディレクトリのパスは通常通りのパス指定で行ってください。
sudo useradd -d /home/sftpuser -M sftpuser
sudo useradd -d /home/scpuser -M scpuser
今回は説明簡略化のため、パスワード認証にしたいと思いますので、パスワードも設定しておきますが、実際の運用時はSSH鍵ファイルでの接続を検討しましょう。
sudo passwd sftpuser
sudo passwd scpuser
chroot制限のSFTP、SCPを行った際のルートディレクトリについて
chroot
で制限するルートディレクトリはroot
の権限である必要があるため、デフォルトでは755
のパーミッションでディレクトリ作成されることから、ルートディレクトリ直下にはファイル等作成することができません。
そのため、ファイル転送用のディレクトリ(今回はdata
)を作成してそれぞれのユーザ権限にしておきます。
sudo mkdir -p /chroot/sftpuser/data
sudo mkdir -p /chroot/scpuser/data
sudo chown sftpuser:sftpuser /chroot/sftpuser/data
sudo chown scpuser:scpuser /chroot/scpuser/data
もしルートディレクトリ直下にファイルを格納したい場合はchroot
で制限するディレクトリのパーミッションを777
等に変更してください。
SFTP接続する際のchroot設定
以下より実際にSFTP
接続時のchroot
設定を行っていきます。
SFTP
でのchroot
制限を行うため、/etc/ssh/sshd_config
をvi
等で開き、以下のように設定します。
# /usr/libexec/openssh/sftp-serverをコメントアウト
#Subsystem sftp /usr/libexec/openssh/sftp-server
# internal-sftpを追記
Subsystem sftp internal-sftp
# ファイル末尾にsftpuser用のchroot設定を追加
Match User sftpuser
ChrootDirectory /chroot/sftpuser
OpenSSHサーバ(sshd
サービス)を使用している場合、chroot
で制限したSFTP
接続を行うためにはサブシステム設定でinternal-sftp
を使用する必要があるため、デフォルトで設定されているsftp-server
をコメントアウトしたうえで、ChrootDirectory
でルートディレクトリとするディレクトリを指定します。
設定後、sshd
サービスを再起動しておきます。
sudo systemctl restart sshd
WinSCPによるSFTP接続確認
chroot
制限を行っているとはいえ、接続方法は変わらないので、WinSCP
で通常の接続と同様SFTP
接続を行います。
接続すると以下のようにルートディレクトリ直下に先ほど作成したファイル転送用のdata
ディレクトリしか存在しないことが確認できるかと思います。
なお、SFTP
ではなくSCP
で接続した場合は以下のようなエラーメッセージが表示されます。
開始時のメッセージ省略のエラー。選択したシェルは WinSCP 互換ではないかもしれません。 (bash をお勧めします)
これだとどのようなエラーなのかよくわかりませんが、PowerShell
等で、SSHコマンドで接続してみると以下のように表示され、SFTP
以外では接続できないことがわかります。
This service allows sftp connections only.
Connection to hostname closed.
chroot
設定を行わずに、デフォルトのsshd
の設定(sftp-server
)で接続する場合はSFTP
でもSCP
でも接続できますが、internal-sftp
とchroot
制限を行うとSFTP
接続しかできなくなるので、ご注意ください。
SCP接続する際のchroot設定
SCP
でchroot
の制限を行う場合はSFTP
のように簡単にはいかず、SCP
接続時に必要となるコマンドファイルやライブラリ等をchroot
で指定したルートディレクトリ配下に配置して、機能制限されたミニOSを作成するような作業を行う必要があります。
/etc/ssh/sshd_config
の設定としてはファイル末尾にscpuser
用のchroot
設定を行うのみとなるため、以下のように設定してsshd
サービスを再起動しておきます。
# デフォルトのまま
Subsystem sftp /usr/libexec/openssh/sftp-server
# ファイル末尾にscpuser用のchroot設定を追加
Match User scpuser
ChrootDirectory /chroot/scpuser
sudo systemctl restart sshd
必要ファイルのコピー
SCP
接続した際に裏で行われている操作を行えるようにするため、必要なファイルをchroot
で指定するルートディレクトリ配下に配置します。
以下の例を見るとイメージできるかと思いますが、scpuser
は/chroot/scpuser
配下がルートディレクトリとなるため、本物のディレクトリ・ファイル構造と同じように、配下に必要となるディレクトリやファイルを配置していきます。
/
├── bin
├── dev
├── etc
├── (略)
│
└── chroot
└── scpuser
├── bin ←シンボリックリンクで設定
├── dev ←/devをbindでマウント
├── data ←ファイル転送用ディレクトリ
├── etc ←scpuserのみ記載されたpasswdファイルを配置
├── lib ←シンボリックリンクで設定
├── lib64 ←シンボリックリンクで設定
└── usr
├── bin ←必要なコマンドファイルのみコピー
├── lib ←/usr/libをbindでマウント
└── lib64 ←/usr/lib64をbindでマウント
まずは、必要なディレクトリをmkdir
コマンドで作成します。
sudo mkdir -p /chroot/scpuser/dev
sudo mkdir -p /chroot/scpuser/data
sudo mkdir -p /chroot/scpuser/etc
sudo mkdir -p /chroot/scpuser/usr
sudo mkdir -p /chroot/scpuser/usr/bin
sudo mkdir -p /chroot/scpuser/usr/lib
sudo mkdir -p /chroot/scpuser/usr/lib64
bin
、lib
、lib64
は通常の構成でもシンボリックリンクで/usr/xxx
にリンクされているため、同じように/chroot/scpuser/usr/xxx
にシンボリックリンクでリンクしておきます。
sudo ln -s usr/bin /chroot/scpuser/bin
sudo ln -s usr/lib /chroot/scpuser/lib
sudo ln -s usr/lib64 /chroot/scpuser/lib64
また、dev
、usr/lib
、usr/lib64
はmount
コマンドのbind
オプションで同サーバ上の本物のディレクトリをマウントしてしまいます。
sudo mount --bind /dev /chroot/scpuser/dev
sudo mount --bind /usr/lib /chroot/scpuser/usr/lib
sudo mount --bind /usr/lib64 /chroot/scpuser/usr/lib64
マウントした領域は再起動するとマウントが外れてしまうため、以下の情報を/etc/fstab
にも記載しておきます。
/dev /chroot/scpuser/dev none bind 0 0
/usr/lib /chroot/scpuser/usr/lib none bind 0 0
/usr/lib64 /chroot/scpuser/usr/lib64 none bind 0 0
bin
に含まれるコマンドも、bindオプションでマウントしてしまっても良いですが、必要なコマンドのみに絞るほうがセキュリティ的には望ましいため、今回はWinSCPで接続した際に使うコマンドのみ/chroot/scpuser/usr/bin
にコピーしておきます。
sudo cp -a /usr/bin/bash /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/chgrp /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/chmod /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/chown /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/cp /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/ln /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/ls /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/mkdir /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/mv /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/rm /chroot/scpuser/usr/bin/
sudo cp -a /usr/bin/scp /chroot/scpuser/usr/bin/
/etc/passwd
の設定のうち、scpuser
の分のみ必要となるため、以下でscpuser
のみ抜き出したものを出力します。
sudo grep scpuser /etc/passwd > /chroot/scpuser/etc/passwd
WinSCPによるSCP接続確認
設定できたのでWinSCPでSCP接続を行います。
SCP
の場合、先ほど配置したファイル、ディレクトリが必要となることから、SFTP
の場合とは異なり、以下のように/chroot/scpuser
配下の各種ファイル・ディレクトリも表示されています。
また、今回はWinSCP
で使用する基本的なコマンド(赤枠)は実行できるようにコマンド実行用のファイルを配置していますが、カスタムコマンド(青枠)まで実行できるようにはしていないため、もしカスタムコマンドも使いたいという場合はusr/bin
等の配下に必要なファイルを配置してください。
なお、SCP
ではなくSFTP
で接続した場合は以下のようなエラーメッセージが表示されます。
SFTP プロトコルを初期化できません。SFTP サーバが起動していますか?
SFTP
接続をした場合、ChrootDirectory
の設定は有効のため、ChrootDirectory
に従ってルートディレクトリが設定されますが、internal-sftp
ではなく、sftp-server
での動作となるため、接続するために必要なファイルが足りず、接続できないことが原因となります。
こちらについては「同じユーザでSFTP、SCP接続する際のchroot設定」で対処方法を説明していきます。
SFTPユーザとSCPユーザを共存する際のchroot設定
ここまでのSFTP
、SCP
の設定では、chroot
制限のSFTP
を有効にした場合はinternal-sftp
サブシステムが全体にかかるため、chroot
制限のSCP
は使用できず、chroot
制限のSCP
を有効にした場合はchroot
制限のSFTP
を使用できませんでした。
internal-sftp
はForceCommand
の設定で特定のユーザ接続でのみ使用するように設定することができるため、デフォルトのサブシステムはsftp-server
のまま、sftpuser
のみinternal-sftp
を使用することで、chroot
制限のSFTP
、SCP
それぞれ使用することができるようになります。
# sftp-server設定はデフォルトのまま
Subsystem sftp /usr/libexec/openssh/sftp-server
# ForceCommand設定でsftpuserのみinternal-sftpを有効化する
Match User sftpuser
ChrootDirectory /chroot/sftpuser
ForceCommand internal-sftp
# scpuser用のchroot設定を追加
Match User scpuser
ChrootDirectory /chroot/scpuser
設定後、sshd
サービスを再起動しておきます。
sudo systemctl restart sshd
この設定を行うことで、sftpuser
でSFTP
接続した場合はSFTP
のchroot
制限が行われ、scpuser
でSCP
接続した場合はSCP
のchroot
制限が行われるようになります。
同じユーザでSFTP、SCP接続する際のchroot設定
chroot
制限のSCP
設定を行った際には、同じユーザでSFTP
接続することはできませんでしたが、そもそもchroot
設定を行わない場合はどちらも同じ使用感で使用できるため、chroot
設定を行ったから使用できないわけではなくchroot
設定を行ったことで、SFTP
接続するのに必要となるファイル・ディレクトリが参照できずに接続できなかったことが原因となります。
そのため、chroot
のルートディレクトリに、SFTP
接続に必要となるファイルも配置することで対処します。
ベースとしてはSCP
接続する際の設定となるため、SCP
接続する際の設定が行われている前提で進めます。
scpuser
でSFTP
、SCP
接続するよう設定するため、/etc/ssh/sshd_config
はSCP
のときと同様以下のように設定します。
# デフォルトのまま
Subsystem sftp /usr/libexec/openssh/sftp-server
# ファイル末尾にscpuser用のchroot設定を追加
Match User scpuser
ChrootDirectory /chroot/scpuser
sudo systemctl restart sshd
必要なファイル・ディレクトリについては、/usr/libexec
配下のファイル・ディレクトリが必要となるため、こちらは他のlib
系ディレクトリと同様、bind
オプションでマウントしようと思います。
sudo mkdir -p /chroot/scpuser/usr/libexec
sudo mount --bind /usr/libexec /chroot/scpuser/usr/libexec
lib
やlib64
と同様、/etc/fstab
にも記載しておきます。
/usr/libexec /chroot/scpuser/usr/libexec none bind 0 0
結果として、WinSCPでSFTP
、SCP
ともに同じユーザで接続するためにはlibexec
のマウントを追加するだけでできました。
これで、scpuser
でSFTP
、SCP
どちらでもchroot
で制限された接続、ファイル転送ができるようになります。
おわりに
SFTP
をchroot
で制限する方法は多くの方が紹介していたため、SCP
も同じだろうと軽く考えていたら、まんまとハマりました。
SCP
のchroot
制限については、スバリこの設定をすればOKというような記事は見つからず、当然SFTP
、SCP
両方同じユーザでchroot
制限を行って接続するような記事は見当たらなかったため、中々苦労しました。
今回の記事をまとめたことで、chroot
の仕組みの復習、SCP
とSFTP
の違いなど、色々と知ることができ、昔ながらの機能ながら新たな発見ができました。