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のマニュアルより抜粋。
<br /> PermitUserEnvironment<br /> Specifies whether ~/.ssh/environment and environment= options in<br /> ~/.ssh/authorized_keys are processed by sshd(8). The default is<br /> ``no''. Enabling environment processing may enable users to<br /> bypass access restrictions in some configurations using mecha-<br /> 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を再起動。
<br />

$ 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も使わないこと。

 

以上