この記事のZenn版はこちら。
はじめに #
研究系の職場にいると、大容量のデータをインターネット経由で関係先と共有することがよくあります。
その場合、公開鍵認証のSSHを使ったscp(最近は内部的にはsftpですが)やrsyncでファイルを送受信することが多いです。
しかし、共有用のSSHアカウントを作っただけでは、そのアカウントの権限でアクセスできる他のディレクトリの読み書きや、シェルの利用、ポート転送等もできてしまうため、セキュリティ上好ましくありません。
よく使われる方法としては、sshd_configでユーザごとにChrootDirectoryを設定して、コマンドをinternal-sftpに設定することが多いですが、同期等ではrsyncを使いたくなることも多いです。
そこで本記事では、SSHのauthorized_keysとrsyncのヘルパースクリプトであるrrsync(restricted rsync)を使って、特定のディレクトリ内のファイルのみを簡単に共有する方法を紹介します。
本記事は以下の知識を前提とします。
- Linuxにおけるユーザの作成・設定
- SSHの公開鍵認証
rsyncの基本的な使い方
TL;DR #
- SSHの
authorized_keysでは、実行できるコマンドや機能を公開鍵ごとに制限できます。 authorized_keysのcommandにrrsyncを指定することで、クライアントがrsyncで読み書きできるディレクトリを制限できます。
authorized_keysとrsyncコマンドの例は以下の通りです。
ユーザ名、公開鍵、パス(Path)、コマンドの引数等は、ご自身の環境に合わせて適宜読み替えてください。
例: 読み取りのみを許可 #
サーバのauthorized_keysの例。
# サーバの /srv/project-x の読み取りのみを許可。
restrict,command="/usr/bin/rrsync -ro /srv/project-x" ssh-ed25519 AAAA...クライアントで実行するrsyncコマンドの例。
# サーバの /srv/project-x/dataset/ 内のファイルを、クライアントの mydataset ディレクトリへダウンロードする。
user@client:~$ rsync -av \
-e 'ssh -i ~/.ssh/id_ed25519' \
user@server:dataset/ \
./mydataset/クライアントが指定したパスは、サーバで指定した/srv/project-xを基準に解釈されます。
また、書き込み専用にする場合は、-roの代わりに-woを使用します。
オプションによっては、ファイルが意図せずに転送・削除されることがあります(特に、書き込み時に--deleteオプションを指定した場合等)。
authorized_keys側でしっかり制限するとともに、事前に-n(--dry-run)オプションで動作を確認しましょう。
検証環境 #
- Ubuntu Server 26.04
- rsync 3.4.1(
rrsyncはrsyncパッケージに付属しているものを使用)
記事の執筆中に気づいたのですが、rsync 3.4.1に付属するrrsyncにはディレクトリの制限を回避する脆弱性があるようです(CVE-2026-53783)。
安全に使いたい場合には、3.5.1以降のバージョンを使用しましょう。
authorized_keysとrrsync #
authorized_keysとrrsyncについて簡単に説明します。
authorized_keys #
SSHサーバで公開鍵認証によるログインを許可するには、クライアントの公開鍵をサーバ側のログインユーザの~/.ssh/authorized_keysに1行ずつ登録します。
# ~/.ssh/authorized_keys の例
ssh-ed25519 AAAA...(public-key1)
ssh-ed25519 AAAA...(public-key2)公開鍵のみを記述した場合、サーバ側の設定とユーザの権限の範囲で、シェルやコマンドを利用できます。
公開鍵の前には鍵ごとに設定を書くことができ、その鍵で利用できる機能を制限することができます。
restrict,from="192.0.2.0/24",command="echo 'hello'" ssh-ed25519 AAAA...(public-key3)restrict: PTYの割り当て、ポート・エージェント・X11の転送、および、~/.ssh/rcの実行を禁止する。from="...": 接続元のIPアドレスやホスト名を制限する。CIDR形式も指定できる。command="...": クライアントが要求したコマンドの代わりに、指定したコマンドを実行する。
例えば、上の設定例の場合、PTYの割り当てやポート転送等は禁止、192.0.2.0/24からのみ接続可、実行されるコマンドは(ユーザがどんなコマンドを打っても)常にecho 'hello'(helloと出力するだけ)という動作になります。
authorized_keysで使えるオプションは他にもたくさんありますので、興味がある方はsshdのmanページの「AUTHORIZED_KEYS FILE FORMAT」を確認してください。
rrsync #
rsyncコマンドは、ディレクトリ間のファイルを同期するコマンドです。
rsyncはSSH上でデータを同期できることから、ネットワーク経由のバックアップ等によく使われます。
なお、rsyncはディレクトリ単位の同期で使用されることが多いですが、ファイルを指定することでファイル単体の転送も可能です。
rsyncのヘルパースクリプトとしてrrsync(restricted rsync)というスクリプトがあります。
Pythonで実装されており、名前の通り、機能を制限したrsyncを提供します。
Ubuntu等では、rsyncのパッケージにこのスクリプトが付属しています。
このrrsyncをauthorized_keysのcommandに指定することで、特定のディレクトリのみをクライアントに提供できるようになります。
rrsyncのヘルプは以下の通りです。
$ rrsync -help
usage: rrsync [-ro | -wo] [-munge] [-no-del] [-no-lock] [-no-overwrite] [-help] DIR
Use "man rrsync" to learn how to restrict ssh users to using a restricted rsync command.
positional arguments:
DIR The restricted directory to use.
options:
-ro Allow only reading from the DIR. Implies -no-del and -no-lock.
-wo Allow only writing to the DIR.
-munge Enable rsync's --munge-links on the server side.
-no-del Disable rsync's --delete* and --remove* options.
-no-lock Avoid the single-run (per-user) lock check.
-no-overwrite Prevent overwriting existing files by enforcing --ignore-existing
-help, -h Output this help message and exit.必須の引数は、共有するディレクトリを指定するDIRのみです。
rrsync /srv/project-xをauthorized_keysのcommandに設定した場合、クライアントはrsyncコマンドで/srv/project-x/内のファイルのみを読み書きすることができます。
クライアントが指定したパスは、先の設定では以下のように解釈されます。
| クライアントが指定したパス | サーバ上の実際のパス |
|---|---|
user@server:./ |
/srv/project-x/ |
user@server:dataset/ |
/srv/project-x/dataset/ |
user@server:dataset/file.bin |
/srv/project-x/dataset/file.bin |
読み取りのみ・書き込みのみに制限するには、それぞれ-roと-woオプションを使用します。
-ro: サーバからの読み取りのみを許可する。-wo: サーバへの書き込みのみを許可する。-woだけでは既存ファイルの上書きや削除までは禁止されないので、必要に応じて-no-delや-no-overwriteを併用します。
なお、rrsyncの制限は通常のLinuxのファイルアクセスの権限の上に適用されます。
また、rrsyncはパスやオプションを検査する仕組みであり、chrootのような隔離を実現するものではありません。
共有するディレクトリ(DIR)の設定には、以下の点に注意してください。
DIRにはユーザのホームディレクトリを指定しないでください。DIRが~/.ssh/authorized_keysや~/.bashrcを含む場合、書き込みを許可すると、クライアントがこれらを書き換えて制限を回避できてしまいます。- シンボリックリンクを介した
DIRの外へのアクセスも、制限の対象です。rrsyncはリンクの中身を転送するオプション(--copy-links等)や、DIRの外に解決されるパスを拒否する仕組みになっています。 ただし、検証環境の節で触れた脆弱性があるバージョンでは、この制限を回避されるおそれがあります。
rrsyncの実装 #
rrsyncはPythonで書かれたrsyncのラッパースクリプトです。
authorized_keysのcommandに指定したコマンドには、クライアントが実行しようとしたコマンドの文字列が環境変数SSH_ORIGINAL_COMMANDとして渡されます。
rrsyncは、この文字列をパースして処理し、サーバ側のrsyncを起動することで制限つきのrsyncを実現しています。
主なパスの扱いは以下の通りです。
- パスの構成要素に
..を指定するとエラーになる。 /から始まる絶対パスは、DIRを基準としたパスに置き換えられる。例えば、先の例のuser@server:/dataset/は/srv/project-x/dataset/になる。
自作のスクリプトでSSH_ORIGINAL_COMMANDを検査することで同様の処理を実現できますが、パスやオプションの処理を誤ると制限を回避されるおそれがありますのでご注意ください。
参考: SFTP + chroot の場合 #
参考までに…
rsyncにこだわらないのであれば、SFTPとChrootDirectoryを組み合わせて、アクセス先を制限する方法もあります(おそらくこちらが一般的です)。
その場合、authorized_keysではなく、サーバのsshd_configで制限します。
# /etc/ssh/sshd_config
Match User user2
ChrootDirectory /srv/project-x
ForceCommand internal-sftp
DisableForwarding yes
PermitTTY noChrootDirectory: ログイン後のルートディレクトリを/srv/project-xにする。クライアントからは/として見える。ForceCommand internal-sftp: SFTP以外のコマンドを実行できなくする(内部的にSFTPを使うSCPは可)。読み取りのみにする場合はinternal-sftp -Rとする。
なお、ChrootDirectoryに指定したディレクトリとその上位のディレクトリは、すべてroot所有かつroot以外が書き込めない権限にする必要があります。
そのため、クライアントにアップロードを許可する場合は、/srv/project-x/uploadのように、ユーザが書き込めるサブディレクトリを別途用意してください。
まとめ #
SSHのauthorized_keysとrrsyncを使って、クライアントがrsyncでアクセスできるディレクトリを制限する方法を紹介しました。
この記事で紹介した機能やコマンド以外にも、意外と知られていない便利な機能やコマンドが数多くあります。 皆さんも、ぜひ自分の用途に合わせて調べてみてください。
参考資料 #
- rsync(1)
- rrsync(1)
- sshd(8): AUTHORIZED_KEYS FILE FORMAT (Ubuntu 26.04)
- rsync NEWS(CVE-2026-53783の修正を含む)
- rrsyncの実装
編集履歴 #
- 2026/11/03: 初稿作成。