↓ メインコンテンツへスキップ
  1. 技術ブログ/

rsyncで特定のディレクトリのみを共有する(w/ authorized_keys)

·
mkt
著者
mkt
A researcher, an engineer, a workaholic, and a nomad.
目次

この記事の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 no
  • ChrootDirectory: ログイン後のルートディレクトリを/srv/project-xにする。クライアントからは/として見える。
  • ForceCommand internal-sftp: SFTP以外のコマンドを実行できなくする(内部的にSFTPを使うSCPは可)。読み取りのみにする場合はinternal-sftp -Rとする。

なお、ChrootDirectoryに指定したディレクトリとその上位のディレクトリは、すべてroot所有かつroot以外が書き込めない権限にする必要があります。 そのため、クライアントにアップロードを許可する場合は、/srv/project-x/uploadのように、ユーザが書き込めるサブディレクトリを別途用意してください。

まとめ
#

SSHのauthorized_keysとrrsyncを使って、クライアントがrsyncでアクセスできるディレクトリを制限する方法を紹介しました。

この記事で紹介した機能やコマンド以外にも、意外と知られていない便利な機能やコマンドが数多くあります。 皆さんも、ぜひ自分の用途に合わせて調べてみてください。

参考資料
#

編集履歴
#

  • 2026/11/03: 初稿作成。

関連記事

脱 sudo su のすすめ(Ubuntu 26.04、sudo-rs)

sudo su ではなく sudo -i を使いましょう。Ubuntu 26.04では、 sudo コマンドが従来の sudo から sudo-rs に置き換えられ、シグナル処理の挙動が少し変わったようです。その結果、SSHでサーバに接続し、sudo su を実行した状態で接続が切れると、sudo su のプロセスが延々と生き残ります…