CentOS Stream 8 にSFTPユーザーを作成

さくらのVPSにCentOS Stream 8をインストールした覚書です。

WEBサイトを複数の人で作っているとき、自分の関係ない個所のファイルって見たくないですよね。

例えば、フロント担当の方だったらPHPファイルは見たくないでしょうし、バックエンド担当の方だったらcssとかjsなんてファイルは見たくないでしょう。

とはいえ、プロジェクトのリーダー的な立ち位置の人なら全部のファイルが見える必要があると思います。

また、外部のA社にはこのディレクトリ以下を、B社にはこのディレクトリ以下を担当して貰いたいってこともよくあると思います。

ということで、いろいろ制限のついたSFTPユーザーを作っていきましょう。

なお本番環境で利用される場合はここにある内容だけを鵜呑みにせずセキュリティ専門家に相談されることをお勧めします。

環境

実施日2021-09-25
サーバさくらのVPS 2G
OSCentOS Stream 8
cat /etc/redhat-release
CentOS Stream release 8

概要

ざっくり下記のようなものを作っていきます。

SFTPしたい
これが本記事の目的ですね。
1アカウント複数ドメインに対応
1つのSFTPアカウントで複数のドメインを扱いたい
ユーザーは他の案件も掛け持ちしてることがあります。その度にアカウントを分けるのを嫌うユーザーもいます。
他のユーザーのディレクトリを見せたくない
無関係なディレクトリやファイルは見えるべきではありません。
ドキュメントルートの実体は別のユーザーが保持
1ドメイン1ユーザーとしている
グループ権限を与えて読み書きできるようにします。
SFTPユーザーだけはパスワード認証を許可したい
公開鍵認証が受け入れられない場合も考慮します。

公開ディレクトリ
/home/owner/public_html
・「owner」というユーザー名で作成している

これにSFTPだけができるユーザーを追加
/home/sftp/owner/public_html
・「sftp」というユーザー名を作成し、sftpだけを許可
・「owner」というディレクトリを作成し、/home/owner のディレクトリ構成に合わせる
・owner の public_html を sftp にマウント

新しいドメインを追加するときは同様に次のようにディレクトリが増えていく
/home/sftp/owner2
/home/sftp/owner3

ざっくりこんな感じなんですが、実際にやっていったほうが分かりやすいですよね。

ユーザーを作成する

ここでは、「例えば」さんのアカウントを作っていきます。
ユーザー名は「example」としたいところですが、sftpに限定する意味で、「sftp_example」とします。

# 変数に設定
# SFTP_USER=SFTPユーザー名
SFTP_USER=sftp_example

# SFTPユーザーを作成する
useradd $SFTP_USER

# オーナーを変更
chown root:root /home/$SFTP_USER

# パーミッションを変更
chmod 0755 /home/$SFTP_USER

# ディレクトリ作成
mkdir /home/$SFTP_USER/chroot
chown root:root /home/$SFTP_USER/chroot
chmod 0755 /home/$SFTP_USER/chroot

パスワード認証を有効にする場合

公開鍵認証だけでOkなら不要です。

# パスワードを設定
passwd $SFTP_USER

# パスワード認証を許可する
vi /etc/ssh/sshd_config
Match User SFTPユーザー名
        PasswordAuthentication yes
        ChrootDirectory /home/SFTPユーザー名/chroot
        ForceCommand internal-sftp -u 007

▲ここはちょっと面倒ですが、「SFTPユーザー名」の2カ所を書き換えて、 /etc/ssh/sshd_config の末尾に追記します。

確認して、反映させるために再起動します

# 確認
/usr/sbin/sshd -t

# 再起動
systemctl restart sshd

途中確認

ここまでで、SFTPソフトなんかで接続できることを確認します。

ドメインの追加

1つのユーザーに複数のドメインを割り当てるにはここの作業を繰り返します。

まずは変数を設定します。

# 新たに設定しようとしているユーザー名
# SFTP_USER=SFTPユーザー名
SFTP_USER=sftp_example

# 連携先のドメイン所有者
# TARGET_USER=ターゲットユーザー名
TARGET_USER=example

# 連携先のドメインが動いているWEBサーバのユーザー
# TARGET_WEB_USER_NAME=nginx
# TARGET_WEB_USER_NAME=apache

対象ドメインごとでディレクトリを準備します。
SFTPで接続した第一階層目は、所属しているドメインのディレクトリが並ぶことになります。

# グループを追加
usermod -aG $SFTP_USER $TARGET_WEB_USER_NAME
usermod -aG $TARGET_USER $SFTP_USER
usermod -aG $SFTP_USER $TARGET_USER

# ドメインディレクトリ
mkdir /home/$SFTP_USER/chroot/$TARGET_USER
chown $SFTP_USER:$SFTP_USER /home/$SFTP_USER/chroot/$TARGET_USER
chmod 0550 /home/$SFTP_USER/chroot/$TARGET_USER

ディレクトリを割り当てる

こではサンプルも兼ねて、ドキュメントルート直下の assets のみを割り当ててみます。

まずはマウント対象のディレクトリを作っていきます。mkdir に -p したり、chown に -R したりしてもOKです。意味を分かっているなら。

作成するディレクトリは、割当先のドメインのディレクトリ構造に合わせると分かりやすいです。

# ディレクトリを作成
mkdir /home/$SFTP_USER/chroot/$TARGET_USER/public_html

# オーナーを変更
chown $SFTP_USER:$SFTP_USER /home/$SFTP_USER/chroot/$TARGET_USER/public_html

# 共有するディレクトリのパーミッションを変更
chmod 0770 /home/$SFTP_USER/chroot/$TARGET_USER/public_html

# もともとあるディレクトリ・ファイルのパーミッションを一気に変えるなら
# find /home/example/public_html -type d -print0 | xargs -0 chmod 775
# find /home/example/public_html -type f -print0 | xargs -0 chmod 664

まずは手動でマウントします。

# 手動で assets マウント
mount --bind /home/$TARGET_USER/public_html /home/$SFTP_USER/chroot/$TARGET_USER/public_html

これで、SFTPのほうのユーザーから、public_html の中身が見えるようになります。

問題なければ自動設定に追加します。
これをしないとOS再起動で解除されます。

# 設定ファイルをバックアップ
ls -la /etc/fs*
cp /etc/fstab /etc/fstab.backup

# 追記する
echo "" >> /etc/fstab
echo "/home/$TARGET_USER/public_html /home/$SFTP_USER/chroot/$TARGET_USER/public_html none bind 0 0" >> /etc/fstab

# ファイルを開いて確認しておきます
vi /etc/fstab

パーミッションエラーが出る場合

SFTPで接続してファイルを編集したら : permission denied が出ることがあります。
しかしながら、ファイルの保存はできています。

ファイルの保存と同時に、そのファイルのいるディレクトリのタイムスタンプを更新しようとして、そのディレクトリに権限がないよ、ということのようです。

これが起こるときはおそらくファイルオーナーがSFTPユーザーと異なっていると思います。

ということで、所有者を変えてやればOKです。

# パーミッションエラーが気になる場合
chown -R $SFTP_USER:$SFTP_USER /home/$TARGET_USER/www/public_html/*

完全な解決方法は調査中ですが、基本的にこういうことをするのはステージング(テスト)サーバであって、本番サーバではこんなことはしません。

ということで調査の優先度はあまり高くないです。すみません。

複数のディレクトリを割り当てる

上記、ディレクトリの割り当てを繰り返します。