nologinユーザーにsuするなら-sでシェルを指定する

  • Linux
  • CLI

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

Webサーバーの実行ユーザー(apache など)の権限でファイルが読めるか確認したくて、su しようとしたら弾かれた。原因と回避方法をまとめておく。

何が起きたか

まず /etc/passwd で apache ユーザーを確認する。

# grep apache /etc/passwd
apache:x:48:48:Apache:/var/www:/sbin/nologin

ログインシェルは /sbin/nologin になっている。この状態で普通に su してみる。

# su - apache
This account is currently not available.

これで終了してしまう。

なぜ弾かれるのか

su は切り替え先ユーザーのログインシェル、つまり /etc/passwd の最後のフィールドを起動する。apache の場合は /sbin/nologin が起動する。nologin は「This account is currently not available.」と出力して終了するだけのプログラムなので、シェルに入れない。

サービス用のユーザーは対話ログインさせないのが前提なので、この挙動は意図どおりになる。

flowchart TD
    A["su - apache"] --> B["/etc/passwd のシェルを参照"]
    B --> C["/sbin/nologin を起動"]
    C --> D["メッセージを出して終了"]
    E["su -s /bin/bash apache"] --> F["-s で指定したシェルを使用"]
    F --> G["/bin/bash が apache 権限で起動"]

-sでシェルを上書きする

su の -s(--shell)で、起動するシェルを指定できる。/etc/passwd のシェルよりこちらが優先される。

# su -s /bin/bash apache
bash-4.1$ id
uid=48(apache) gid=48(apache) 所属グループ=48(apache)
bash-4.1$ pwd
/root

これで apache の権限で bash が動く。ただし、カレントディレクトリは /root のままになる。

- を付けるとログインシェルになる

-(-l / --login)を付けると、ログインシェルとして起動する。

# su -s /bin/bash - apache
-bash-4.1$ id
uid=48(apache) gid=48(apache) 所属グループ=48(apache)
-bash-4.1$ pwd
/var/www

違いは次のとおり。

su -s /bin/bash apache su -s /bin/bash - apache
シェルの種類 非ログインシェル ログインシェル
カレントディレクトリ 元のまま(/root) ホームディレクトリ(/var/www)
環境変数 元のユーザーのものが一部残る 切り替え先ユーザーの環境で初期化
プロンプト bash-4.1$ -bash-4.1$

プロンプト先頭の - は、ログインシェルとして起動したことを表している($0 が -bash になる)。

権限の確認が目的なら、- を付けるほうがいい。root の PATH などが残っていると、確認結果が本番の挙動とずれる可能性がある。

オプションの順番

man には、- は su のオプションの最後に置くよう書かれている。そのため su -s /bin/bash - apache の順番で書くのが正しい。順番を気にしたくないなら、-l を使えばどこに置いてもいい。

# su -l -s /bin/bash apache

コマンドを1つだけ実行する

シェルに入らずにコマンドを1つだけ実行したいなら、-c を使う。

# su -s /bin/bash -c 'ls -l /var/www/html' apache

sudoでやる場合

sudo でも同じことができる。

# sudo -u apache /bin/bash

sudo -u apache -i は、切り替え先ユーザーのログインシェルを起動するので、su - apache と同じく nologin に弾かれる。

RHEL 系なら runuser も使える(root 専用)。

# runuser -s /bin/bash - apache

注意点

  • apache にはパスワードが設定されていないので、この方法が使えるのは root からだけになる。
  • 対話ログインを防ぐための設定なので、/etc/passwd のシェルを書き換えて解決するのは避ける。一時的に入りたいだけなら、-s で十分。
  • 上の出力は bash 4.1(CentOS 6 世代)の環境で取ったもの。su の基本的な挙動は他のディストリビューションでも同じはずだけど、環境変数の引き継ぎ方は su の実装(coreutils / util-linux)によって細かく違う。