RedHat 7.5でPAMシナリオをテストしています。
pamモジュールpam_succeed_if.soは、PAMが提供する必要がある最も基本的なレベルの条件付きテストのように見えますが、私の要件を満たしていません。 user、uid、gid、shell、home、ruser、rhost、tty、および service フィールドに対してのみテストを生成できます。
私の場合は、「rhost」フィールドに基づいてテストしたかったのですが、モジュールをデバッグに入れた後にrhostフィールドが設定されていないことがわかりました。
私の目標はPAMモジュールのみを実行することです。/etc/pam.d/sudoユーザーがコンピュータにローカルにログインした場合。ユーザーがSSH経由でログインしたことを検出できる場合は、このモジュールをスキップしたいと思います。私は実際に効果があると思った3つの異なるアイデアを思い出しましたが、すべて失敗しました。
最終的に失敗したいくつかの解決策を共有しましょう。
条件付き入力には pam_exec.so を使用します。
条件付きでスキップしたい 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
pam_exec.soのソースコードを調べました。https://github.com/linux-pam/linux-pam/blob/master/modules/pam_exec/pam_exec.c驚くべきことに、スクリプトの終了コードに関係なく、常にPAM_SUCCESSを返します。 pam_execモジュールがPAM_SERVICE_ERR、PAM_SYSTEM_ERR、またはPAM_IGNOREを返すようにするスクリプトを取得できません。
条件付き入力に pam_access.so を使用
今回も条件付きでスキップする 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モジュールをスキップするためにどのような黒魔術を詠唱する必要があるかを知るために、文字通りソースコードを読むのは面倒な日でした。
答え1
これは私に合ったソリューションです。私のもの/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
電話TTY pamに関連付けられているIPアドレスを取得します。${PAM_TTY#/dev/}
デバイス全体のパスが認識されないため、値の前半から削除されました。このフラグを使用すると、IPアドレスまたはプレースホルダが表示されます(IPアドレスがない場合)。デフォルトでは、チェックするのが難しい情報文字列が表示されます。これが私が代わりに同様のオプションを使用しない理由でもあります。このオプションはチェックしている出力の最初の行だけを見ることができるため、必ずしも必要ではありませんが、現在ログインしているユーザーのみを表示するように制限されています。/dev/
last
-i
last
0.0.0.0
last
who
w
-p now
awk
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
。
4.16.11-1-ARCH
カーネルであるArch Linux(Arch Linux)があります。しかし、私はそうする必要はないと思います。
答え2
実際、私は愚かで、このpam_exec.so
モジュールはPAM条件を生成するのに役立つことがわかりました。
Tim Smithの評価は正確です。/etc/security/deny-ssh-user.sh
私のスクリプトの2つのテストでは、変数はSSH_SESSION
trueに設定されていません。スクリプトは通常のシェルで動作しますがpam_exec.so
。
結局のところ、彼の例のようにユーティリティを使用するためにスクリプトを書き直すことになりましたlast
。last
以下は/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
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
/etc/pam.d/sudoの内容
....
auth [success=ok default=1] pam_exec.so /etc/security/deny-ssh-user.sh
auth sufficient pam_module_to_skip.so
....