わたねこコーリング

野良プログラマ発、日々のアウトプット

複数エンドユーザ用の Jail な SFTP 接続環境を Docker コンテナでサクッと用意する

インターネットアプリケーションの受注開発をしていると、「このディレクトリ以下だけ、自分たちで読み書きできるように FTP アクセスさせてくんない?」的な要求によく遭遇します。サーバがそのクライアント専用ならまだ良いのですが、他のお客様が同居している共有型運用だと、設定も面倒ですし何より各ユーザを Jail に隔離する為のセキュリティ保持に気を使います。

そんな用途にうってつけな SFTP サーバの Docker イメージを見つけたので、これを使ってファイル転送用リモートアクセス環境を作ってみます。

尚、本例ではサーバを AWS にて立てた EC2 インスタンス(OS は Amazon Linux 2023)とします。EC2 サーバ上で docker および docker compose を使えるようにする、および当該インスタンスにインターネット経由でポート 10022 に接続可能にする VPC やセキュリティグループの設定手順は割愛します。

また、提供するリモートアクセスのサービスは、ざっくり以下の諸元とします。

  • FTP はいくら何でもアレなので、SFTP にしてもらう(SCP は不許可)。
  • 読み書き対象のディレクトリは /var/www/client-foo/html 以下とする。
  • SFTP 接続時のユーザ名は client-foo、ポート番号は 10022 とする。また、認証は鍵交換のみとし、公開鍵をお客様から支給してもらう。
  • Docker ホストでのファイルおよびディレクトリのオーナは、uid:1001, gid:1001 とする。

以上を簡単に図式化するとこんな感じ↓ですかね。

では設定を。まず、/var/www/client-foo/ に、docker-compose.yml とお客様から頂いた公開鍵 id_rsa.pub を保存します。前者の内容はこんな感じ。

version: '3'
services:
  sftp:
    image: atmoz/sftp
    container_name: client-foo-sftp
    volumes:
      - ./id_rsa.pub:/home/client-foo/.ssh/keys/id_rsa.pub:ro
      - /var/www/client-foo/html:/home/client-foo/html
    ports:
      - "10022:22"
    # user:pass[:e][:uid[:gid[:dir1[,dir2]...]]]
    command: client-foo::1001:1001

設定は以上です。/var/www/client-foo/html/ 以下は uid:1001, gid:1001 で読み書きできるようパーミション設定を忘れずに。ここで docker compose up -d すれば、お客様のローカル環境(キーペア設定済)から sftp -P 10022 client-foo@<EC2インスタンスのグローバルIP> として接続および読み書きができるようになります。お客様のスキルにより鍵交換が難しい場合はパスワード認証も可能(イメージ供給元のドキュメントを読んでください)ですが、そのぶんセキュリティ品質は落ちるので推奨はしません。

また、さらに別のお客様用に SFTP 環境を追加したいのであれば、上記までの client-foo を client-bar に、ポート 10022 を 10122 とかに読み替えた上で新しく環境一式を用意すれば OK です。

留意事項として、このコンテナを起動しなおすとその度にコンテナ内の /etc/ssh/ に異なるホスト鍵が生成しなおされてしまい、SFTP クライアント側も known_hosts の修正が必要になったりするので、ちょっと面倒です。これを防ぐには、最初にコンテナを起動した際に docker cp でコンテナ内のホスト鍵を Docker ホスト側にコピーしておいて、2回目以降の起動からはそれらをバインドしてやれば良いかと。この辺はイメージ供給元ドキュメントに「Providing your own SSH host key (recommended)」として延べられているのでご一読を。