조건부 입력에는 pam_exec.so를 사용하십시오.

조건부 입력에는 pam_exec.so를 사용하십시오.

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-ilast0.0.0.0lastwhow-p nowawklast

이 명령은 첫 번째 줄만 확인하고 awk세 번째 필드가 아닌 경우 0.0.0.0오류와 함께 종료됩니다 . 이것이 의 마지막 명령이므로 /tmp/test-pamawk의 종료 코드가 스크립트의 종료 코드가 됩니다.

당신이 시도한 테스트 중 어느 것도 내 시스템에서 작동하지 않았습니다 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_SESSIONtrue로 설정되지 않았습니다. 스크립트는 일반 셸에서 작동하지만 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
....

관련 정보