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
, 성공하면 다음 항목을 건너뜁니다. 두 번째 줄은 단순히 액세스를 무조건 거부합니다.
/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
세 번째 필드가 아닌 경우 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)가 있습니다 . 하지만 나는 그럴 필요가 없다고 생각합니다.
답변2
사실 나는 바보이고 이 pam_exec.so
모듈은 PAM 조건을 생성하는 데 유용하다는 것이 밝혀졌습니다.
Tim Smith의 평가는 정확합니다. /etc/security/deny-ssh-user.sh
내 스크립트의 두 테스트에서는 변수가 SSH_SESSION
true로 설정되지 않았습니다. 스크립트는 일반 셸에서 작동하지만 pam_exec.so
.
결국 그의 예시처럼 유틸리티를 사용하기 위해 스크립트를 다시 작성하게 되었는데 , 스위치가 Arch Linux에서 RedHat으로 다르기 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
....