RedHat 7.5でPAMシナリオをテストしています
PAMモジュールpam_succeed_if.soは、PAMが提供する必要がある条件テストの最も基本的なレベルのように見え、それは私のニーズを満たしていません。テストは、user、uid、gid、Shell、home、ruser、rhost、tty、およびserviceフィールドでのみ作成できます。
私の状況では、「rhost」フィールドに基づいてテストしたいのですが、モジュールをデバッグに入れた後、rhostフィールドが設定されていないことがわかりました。
私の目標は、ユーザーがローカルでマシンにログインしている場合にのみ、/ etc/pam.d/SudoでPAMモジュールを実行することです。ユーザーがSSH経由でログインしていることを検出できた場合は、モジュールをスキップします。私は実際にはうまくいくと思っていた3つの異なるアイデアを思いついたが、すべて失敗した。
失敗してしまったいくつかの解決策を共有します
条件付きでスキップするpamモジュールの上に次のpamエントリを追加したいと思いました。
auth [success=ok default=1] pam_exec.so /etc/security/deny-ssh-user.sh
/etc/security/deny-ssh-user.shの内容
#!/bin/bash
# Returns 1 if the user is logged in through SSH
# Returns 0 if the user is not logged in through SSH
SSH_SESSION=false
if [ -n "${SSH_CLIENT}" ] || [ -n "${SSH_TTY}" ] || [ -n "${SSH_CONNECTION}" ]; then
SSH_SESSION=true
else
case $(ps -o comm= -p $PPID) in
sshd|*/sshd) SSH_SESSION=true;;
esac
fi
if "${SSH_SESSION}"; then
exit 1
else
exit 0
fi
https://github.com/linux-pam/linux-pam/blob/master/modules/pam_exec/pam_exec.c でpam_exec.soのソースコードを調べたところ、驚くほど、スクリプトの終了コードに関係なく、常にPAM_SUCCESSを返します。また、pam_execモジュールがPAM_SERVICE_ERR、PAM_SYSTEM_ERR、またはPAM_IGNOREを返すようにするスクリプトを取得できません。
繰り返しますが、条件付きでスキップするpamモジュールの上に次のpamエントリを追加します
auth [success=ok perm_denied=1] pam_access.so accessfile=/etc/security/ssh-Sudo-access.conf noaudit
/etc/security/ssh-Sudo-access.confの内容
+:ALL:localhost 127.0.0.1
-:ALL:ALL
うわー、すごくきれいだよね?ローカルにログインしている場合は成功を返し、それ以外はすべて拒否します。うーん、ダメ。 pam_access.soモジュールがデバッグに入ると判明します。リモートホストの知識はなく、使用されているターミナルのみです。したがって、pam_accessは実際にはリモートホストによるアクセスをブロックできません。
PAMモジュールをスキップできるように、どのような黒魔術をかけなければならないかを知るために、文字通りソースコードを読むのは大変な一日でした。
まあ、私は実際にはばかであることが判明しました。pam_exec.so
モジュールはPAM条件を作成するのに完全に適しています。
Tim Smithは、私の/etc/security/deny-ssh-user.sh
スクリプトの両方のテストで変数SSH_SESSION
がtrueに設定されていないことを評価する際に正しかったです。スクリプトは通常のシェルで機能するため、これは考慮しませんでしたが、pam_exec.so
によって実行されると、環境コンテキストが削除されます。
彼の例のようにlast
ユーティリティを使用するようにスクリプトを書き直してしまいましたが、last
のスイッチがArch LinuxからRedHatに異なるため、一部を変更する必要がありました。
#!/bin/bash
# Returns 1 if the user is logged in through SSH
# Returns 0 if the user is not logged in through SSH
SSH_SESSION=false
function isSshSession {
local terminal="${1}"
if $(/usr/bin/last -i |
/usr/bin/grep "${terminal}" |
/usr/bin/grep 'still logged in' |
/usr/bin/awk '{print $3}' |
/usr/bin/grep -q --invert-match '0\.0\.0\.0'); then
echo true
else
echo false
fi
}
function stripTerminal {
local terminal="${1}"
# PAM_TTY is in the form /dev/pts/X
# Last utility displays TTY in the form pts/x
# Returns the first five characters stripped from TTY
echo "${terminal:5}"
}
lastTerminal=$( stripTerminal "${PAM_TTY}")
SSH_SESSION=$(isSshSession "${lastTerminal}")
if "${SSH_SESSION}"; then
exit 1
else
exit 0
fi
....
auth [success=ok default=1] pam_exec.so /etc/security/deny-ssh-user.sh
auth sufficient pam_module_to_skip.so
....
ここに私のために働く解決策があります。私の_/etc/pam.d/Sudo
_:
_#%PAM-1.0
auth [success=1] pam_exec.so /tmp/test-pam
auth required pam_deny.so
auth include system-auth
account include system-auth
session include system-auth
_
そして_/tmp/test-pam
_:
_#! /bin/bash
/bin/last -i -p now ${PAM_TTY#/dev/} | \
/bin/awk 'NR==1 { if ($3 != "0.0.0.0") exit 9; exit 0; }'
_
私はこの動作をします:
_$ Sudo date
[Sudo] password for jdoe:
Thu Jun 28 23:51:58 MDT 2018
$ ssh localhost
Last login: Thu Jun 28 23:40:23 2018 from ::1
valli$ Sudo date
/tmp/test-pam failed: exit code 9
[Sudo] password for jdoe:
Sudo: PAM authentication error: System error
valli$
_
デフォルトの_pam.d/Sudo
_に追加された最初の行は_pam_exec
_を呼び出し、成功した場合は次のエントリをスキップします。 2行目は、無条件にアクセスを拒否するだけです。
_/tmp/test-pam
_では、last
を呼び出して、pamが呼び出されたTTYに関連付けられたIPアドレスを取得します。 _${PAM_TTY#/dev/}
_は、last
が完全なデバイスパスを認識しないため、値の前から_/dev/
_を削除します。 _-i
_フラグを使用すると、IPアドレスがない場合はlast
にIPアドレスまたはプレースホルダー_0.0.0.0
_が表示されます。デフォルトでは、確認が非常に難しい情報文字列が表示されます。これが、last
またはwho
ではなくw
を使用した理由でもあります。それらには同様のオプションはありません。 awk
は出力の最初の行のみをチェックするため、_-p now
_オプションは厳密には必要ありませんが、現在ログインしているユーザーのみを表示するようにlast
を制限していますに。
awk
コマンドは最初の行をチェックするだけで、3番目のフィールドが_0.0.0.0
_でない場合、エラーで終了します。これは_/tmp/test-pam
_の最後のコマンドなので、awkの終了コードがスクリプトの終了コードになります。
私のシステムでは、_deny-ssh-user.sh
_で試行したテストはどれも機能しませんでした。スクリプトの先頭に_env > /tmp/test-pam.log
_を配置すると、環境が取り除かれているため、SSH_FOO変数は設定されません。また、$ PPIDは任意の数のプロセスを指すことができます。たとえば、Perl -e 'system("Sudo cat /etc/passwd")'
を実行して、$ PPIDがPerl
プロセスを参照していることを確認します。
これは、Arch Linux、カーネル_4.16.11-1-Arch
_です(重要な場合)。とはいえ私はそうは思わない。