[FreeBSD][Linux] ssh経由でコマンド実行すると環境変数を読まないでござる

Pocket

ssh経由bashでコマンド実行するときの環境変数を有効にするには。

以下のようにして、リモートホストでコマンドを実行する場合、リモートでの環境変数が有効にならない事がある。

$ ssh user@remotehost /path/command

 

これはbashの仕様が原因で、解決にはsshdとリモートユーザの設定が必要。
おそらくshでも同じと思うが、ひとくちにshと言ってもいろんな変種があるので調べていない。
以下にまとめる。

なお、複数ホストを用意するのが面倒なので、本記事で実例を示す場合には接続先をlocalhostしている。

sshでコマンド実行すると環境変数が有効にならない。

試しに、user01のprofile、ここでは~user01/.profileでTESTENVという環境変数を設定する。
sudo su – して通常のログインを擬似してみると、意図した通りTESTENVが設定されている。
しかしsshでいきなりコマンド実行した場合(ここではenvコマンド)には、TESTENVは設定されない。

[vanilla@vanilla ~]$ grep TESTENV ~user01/.profile
TESTENV=testenv; export TESTENV
[vanilla@vanilla ~]$
[vanilla@vanilla ~]$ sudo su - user01
[user01@vanilla ~]$
[user01@vanilla ~]$ env | grep TESTENV
TESTENV=testenv
[user01@vanilla ~]$ ssh localhost env|grep TESTENV
[user01@vanilla ~]$

 

 

bashの仕様が原因

ssh経由でコマンド実行した場合、bashはnon-intractive(非対話モード) modeで起動し、.profile等を読み込まない。
これが原因で環境変数が設定できない。
対策には、①コマンド実行時に一手間かける ②sshdの設定を変える の二つがある。

対策の前にbashのマニュアル抜粋を示す。

http://linuxjm.sourceforge.jp/html/GNU_bash/man1/bash.1.html

bash が対話的なログインシェルとして起動されるか、 –login オプション付きの非対話的シェルとして起動されると、 /etc/profile ファイルが存在すれば、 bash はまずここからコマンドを読み込んで実行します。 このファイルを読んだ後、 bash は ~/.bash_profile, ~/.bash_login, ~/.profile をこの 順番で探します。
(中略)
(例えばシェルスクリプトを実行するために) 非対話的に起動されると、 bash は環境変数 BASH_ENV を調べ、この変数が定義されていればその値を展開し、 得られた値をファイル名とみなして、 そこからコマンドの読み込みと実行を行います。

対策①:コマンド実行時にprofile読み込みを明示

コマンド実行時に以下のようにしてprofile読み込みを明示する。

$ ssh user@host "source ~/.profile; /path/to/command"

 

ご覧の通り。

[user01@vanilla ~]$ ssh localhost "source ~/.profile; env"|grep TESTENV
TESTENV=testenv
[user01@vanilla ~]$

 

後述の対策②を採れない場合、つまりsshdの設定ファイルを変更する権限がない場合には有効。
その一方で、sshで実行するスクリプトが大量にある場合には、それら全部に対して修正が必要になるので、きびしい。
単発向けの対策と考えるのがよさそう。

対策②: sshdの設定PermitUserEnvironmentを変える。

sshdの設定を変えて、環境変数を読むようにする。
以下、sshd_configのマニュアルより抜粋。

PermitUserEnvironment
Specifies whether ~/.ssh/environment and environment= options in
~/.ssh/authorized_keys are processed by sshd(8). The default is
``no''. Enabling environment processing may enable users to
bypass access restrictions in some configurations using mecha-
nisms such as LD_PRELOAD.

~/.ssh/environmentを作っておき、sshd設定でPermitUserEnvironmentをYesに設定すると、その中身を読んでくれる。
デフォルトではNoになっている。
セキュリティ上の穴になる可能性があるので推奨はされない。
加えて、先述の通りサーバのsshd設定を書き換える権限が必要。
それらがクリアできれば、クライアント側では何も意識しなくてよいので楽。

対策②-1:sshd設定変更

sshd_configでPermitUserEnvironment yesにする。

$ sudo vi /etc/ssh/sshd_config

#PermitUserEnvironment no
PermitUserEnvironment yes

 

sshdを再起動。

$ sudo service sshd restart
Stopping sshd.
Starting sshd.
$

 

対策②-2:environmentの作成

~/.ssh/environmentを作る。

ここで注意点。
environmentは下記の書式しか受け付けない。詳細は実例で後述。

environment=value

 

再びTESTENVに登場いただき試す。
意図した通り、environmentの内容が反映されている。

$ sudo su - user01
[user01@vanilla ~]$
[user01@vanilla ~]$ echo "TESTENV=testenv" >> ~/.ssh/environment
[user01@vanilla ~]$ cat ~/.ssh/environment
TESTENV=testenv
[user01@vanilla ~]$
[user01@vanilla ~]$ ssh localhost env|grep TESTENV
TESTENV=testenv
[user01@vanilla ~]$

 

しかし$PATHを与えても展開されずそのまま。

$ echo 'TESTENV01=$PATH' >> ~/.ssh/environment
[user01@vanilla ~]$ grep 01 ~/.ssh/environment
TESTENV01=$PATH
[user01@vanilla ~]$ ssh localhost env|grep 01
TESTENV01=$PATH
[user01@vanilla ~]$

 

 

.profileのつもりで書くと大変なことに。

[user01@vanilla ~]$ echo 'TESTENV02=$PATH; export TESTENV02' >> ~/.ssh/environment
[user01@vanilla ~]$ grep 02 ~/.ssh/environment
TESTENV02=$PATH; export TESTENV02
[user01@vanilla ~]$ ssh localhost env|grep 02
TESTENV02=$PATH; export TESTENV02
[user01@vanilla ~]$

environmentのvalueには変数を使わない。exportも使わないこと。

 

以上

 

2 comments

  1. 翻訳の抜粋部分ですが、
    “読み込み可能な 最初のもの を読み込み実行する」の部分が抜けているので、あったほうがいいと思います。
    「 in that order, and reads and executes commands from the first one that exists and is readable.」

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です