CentOS 7 と CentOS 8 で Cron ジョブに /etc/environment の環境変数が渡るかどうかが異なる

TL;DR

  • CentOS 7 なら /etc/environment の環境変数が渡る
  • CentOS 8 で root でジョブを実行すると /etc/environment の環境変数は渡らない
  • CentOS 8 で root 以外でジョブを実行すると /etc/environment の環境変数が渡る

理由

cron のジョブで /etc/environment が有効になるのは crond が直接なにかしているわけではなく pam_env.so によるものだったと思うので、なにか違いがあるかと思って見てみたのですが・・

### CentOS 7

cat /etc/pam.d/crond
#=> account    required   pam_access.so
#=> account    include    system-auth
#=> session    required   pam_loginuid.so
#=> session    include    system-auth
#=> auth       include    system-auth

cat /etc/pam.d/system-auth | grep env
#=> auth        required      pam_env.so

### CentOS 8

cat /etc/pam.d/crond
#=> auth       include    password-auth
#=> account    required   pam_access.so
#=> account    include    password-auth
#=> session    required   pam_loginuid.so
#=> session    include    password-auth

cat /etc/pam.d/password-auth | grep env
#=> auth        required      pam_env.so

微妙に違いはあるもののどちらも pam_env.so は有効なようです。

ただ、Cron ジョブの開始時に CentOS 7 または CentOS 8 でも root 以外で実行するときは /var/log/messages に次のようなものが出力されますが、

Started Session 50 of user root.

CentOS 8 で root で実行するときはなにも出力されません。

CentOS 8 だと root で実行するときだけ pam がバイパスされているのでしょうか。

crond のバージョンはそれぞれ次のとおりでした。

  • CentOS 7 cronie-1.4.11-23.el7
  • CentOS 8 cronie-1.5.2-4.el8

GitHub の以下のリポジトリでホストされているようです。

差分を見てみたところ・・

このあたりが非常に怪しいです。

 #if defined(WITH_PAM)
-    if (cron_start_pam(pw) != PAM_SUCCESS) {
+    if (getuid() != 0 && cron_start_pam(pw) != PAM_SUCCESS) {
         fprintf(stderr,
             "You (%s) are not allowed to access to (%s) because of pam configuration.\n",
             User, ProgramName);
 #ifdef WITH_PAM
-    if ((ret = cron_start_pam(e->pwd)) != 0) {
+    /* PAM is called only for non-root users or non-system crontab */
+    if ((!u->system || e->pwd->pw_uid != 0) && (ret = cron_start_pam(e->pwd)) != 0) {
         log_it(e->pwd->pw_name, getpid(), "FAILED to authorize user with PAM",
             pam_strerror(pamh, ret), 0);
         return -1;
     }
 #endif

以下のコミットで変更されていました。

Call PAM only when it makes sense.

  • do not check PAM in crontab when uid is 0
  • do not call PAM at all in crond for system cron jobs that are run as uid 0

さいごに

CentOS というか cronie のバージョンの違いによるものでした。

Cron ジョブで pam_env.so によって /etc/environment が有効になっていたのは意図していない副作用のようなものだったということですね。

環境固有の設定値を /etc/environment に記述していて、かつ、root で実行される cron ジョブでその環境変数を参照している場合、CentOS 8 だと /etc/environment が有効にならないので注意が必要です。

実行するジョブの側で↓のように対策する必要があります。

set -a
source /etc/environment
set +a