주식회사 누리아이티

정보자산의 보안강화를 위한 3단계 인증 보안SW(BaroPAM) 전문기업인 누리아이티

▶ BaroSolution/기술문서

PAM(Pluggable Authentication Module, 플러그인 가능한 인증 모듈)

누리아이티 2016. 12. 1. 04:07

 

PAM(Pluggable Authentication Module, 플러그인 가능한 인증 모듈)

 

 

1. PAM이란?

 

PAM Linux/Unix 시스템에서 중앙집중적인 인증 매커니즘을 지원하는 것이다. 게다가 시스템의 기본적인 인증 기법을 제공하여 이것을 사용하면 응용 프로그램 개발자 뿐만 아니라 시스템 관리자들이 인증을 유연성 있게 관리할 수 있도록 도와 준다.

 

전통적으로 시스템 자원에 대한 접근을 관리하는 프로그램들은 내장된 메커니즘에 의해 사용자 인증 과정을 수행한다. 이러한 방식은 오랫동안 이루어졌지만 이러한 접근 방식은 확장성이 부족하고 매우 복잡하다. 그렇기 때문인지 이러한 인증 매커니즘을 끌어내기 위한 수많은 해킹 시도가 있었다.

 

Solaris의 방식을 따라서 Unix/Linux 사용자들은 그들만의 PAM을 구현하는 방식을 찾았다.

 

PAM의 기본 원리는 응용 프로그램이 password 파일을 읽어 오는 대신 PAM이 직접 인증을 수행 하도록 하는 것이다. PAM은 시스템 관리자가 원하는 인증 매커니즘이 무엇이든 상관하지 않는다.

 

여러 사이트에서 선택 받은 인증 매커니즘은 아직도 password 파일이다. 왜 그럴까? 우리가 원하는 것을 해주기 때문이다. 대부분의 사용자는 password 파일이 필요한 것이 무엇인지 이미 알고 있다. 그리고 원하는 작업을 수행하는데 있어 이미 그 기능이 검증되었기 때문일 것이다.

 

PAM의 아키텍처는 다음과 같다.

 

PAM의 인증 절차는 다음과 같다.

 

 

2. PAM 동작 원리

 

PAM Windows 환경의 DDL(Dynamic Link Library)과 같은 것이다. Library로 프로그램이 어떤 사용자에 대한 인증을 수행하려면 PAM Library이 있는 함수를 호출한다. PAM은 해당 함수의 Library를 제공하여 응용 프로그램이 특정 사용자를 인증하도록 요청할 수 있다.

 

PAM을 통해 /etc/passwd 파일이나 /etc/shadow 파일을 확인하거나 또는 보다 복잡한 확인 작업을 수행하기도 하는데, 예로는 LDAP 서버에 접속하는 것이다.

 

확인 작업을 마치고, 인증 여부를 결정하게 되면 "인증됨/인증되지 않음"의 메시지를 자신을 호출한 응용 프로그램에 전송한다.

 

간단한 확인 작업이라고 했는데, 그 과정이 많아 보일 수가 있다. 여기에 나오는 각 모듈은 크기가 작고 작업 수행 시간이 매우 빠르다. 이것은 매우 놀랍기도 하지만 PAM을 단연코 사용하게 된다.

 

3. PAM 파일과 위치

 

파일 위치
설명
비고
/lib64/security
/lib/security
PAM 모듈 디렉토리로 실제 PAM Library를 동적으로 인증 모듈을 호출하여 실행한다.
 
/etc/security
/lib64/security에 있는 모듈에 대한 설정 파일.
 
/etc/pam.d
어플리케이션별 PAM의 설정 파일 위치로 PAM을 사용하는 응용 프로그램이 설정 파일이 없다면 기본값으로 설정된 설정 파일을 자동으로 사용한다.
 

 

4. PAM 라이브러리

 

라이브러리
설명
비고
pam_permit
pam_deny
항상 성공/실패를 리턴해서 접근을 허용, 거부.
 
pam_warn
호출한 사용자 및 호스트 정보를 syslog에 기록.
 
pam_access
사용자 계정, 호스트/도메인을 통해서 시스템 접근을 허용.
/etc/security/access.conf에서 설정한다.
 
pam_unix
pam_pwdb
암호를 확인하고 변경되는데 사용되는 모듈.
/etc/passwd shadow 사용시 /etc/shadow 파일에서 계정의 정보를 얻어온다.
 
pam_env
환경 변수를 지정.
/etc/security/pam_env.conf
설정 파일에서 환경 변수를 불러온다.
/etc/environment /etc/security/pam_env.conf 설정 파일이 비었을 경우 변수 설정 없이 성공 값을 반환한다.
 
pam_issue
pam_motd
로그인 시 issue message를 출력하며, 성공적으로 로그인한 후 나타난다. /etc/issue, /etc/motd
 
pam_limits
사용자의 프로세스 자원을 설정 파일에 따라 제한한다.
/etc/security/limits.conf
 
pam_listfile
파일에 있는 사용자명 목록에 따라 접근을 허용/거부.
 
pam_mkhomedir
사용자 홈 디렉토리가 없다면 홈 디렉토리를 생성하고, /etc/skel 디렉토리에 있는 파일들을 복사.
 
pam_nologin
/etc/nologin 파일이 존재하면 root만 로그인 가능하고, 일반 사용자 로그인 불가능하며, root로 로그인 시 nologin 파일의 내용이 보여진다.
 
pam_rhosts_auth
Rhost 방식으로 네트워크간 원격 세션을 허용.
 
pam_rootok
암호 없이 root의 접근을 허용.
 
pam_security
현재 터미널이 /etc/security 파일에 나열돼 있지 않으면 root 접근 거부.
 
pam_time
시간, 사용자, 그룹, 터미널, 쉘 등으로 접근을 제어한다.
/etc/security/time.conf
 
pam_wheel
Su 서비스에서 사용, 특정 그룹에 속하지 않은 사용자는 root로의 접근을 거부, deny 옵션을 사용하여 특정 그룹만 접근을 거부할 수 있게 설정 가능하다.
 
pam_cracklib
입력 받은 암호를 /usr/lib/cracklib_dict에 있는 사전과 비교하여 새로운 암호를 /etc/security/opasswd에 저장되어 있는 이전 암호 목록과 비교하여 이전 암호와 비숫한지 확인.
 
pam_succed_if
주어진 조건이 참일 경우 성공 값 반환, 인자로 quiet가 들어갈 경우 syslog에 알리지 않는다.
 

 

5. PAM 설정하기

 

우리가 다룰 설정 파일은 /etc/pam.d 디렉토리에 있다. /etc/security 디렉토리에 있는 특정 모듈에 적용되는 설정 파일을 변경하려면 모듈과 함께 잇는 문서를 확인해야 한다.

 

/etc/pam.d 디렉토리에 있는 각각 PAM 설정 파일의 형식은 다음과 같다.

 

[module-type][control-flag][module-path][module-arguments]

 

1) module-type

 

PAM이 어떤 타입의 인증이 사용될 것인가를 지정

 

모듈 타입
설명
비고
auth
사용자 인증에 사용하며, 올바른 비밀번호인지 확인하는 절차를 가진다.
응용 프로그램이 사용자에게 비밀번호를 입력하도록 안내하고, 사용자와 해당 사용자의 그룹에 대한 권한을 인증한다.
 
account
사용자의 접근 허가 여부를 확인하며 계정 만료, 특정 시간대에 접근이 허용되었는지 여부를 확인한다.
인증하는 기능이 아니며 현재 시간, 사용자의 위치와 같은 다른 요소들의 접근 권한을 결정하는데, 예로 root 사용자의 로그인은 콘솔로만 한다. 이런 식으로 결정하는 것이다.
 
password
비밀번호를 설정하고 확인한다.
비밀번호를 기준에 맞게 변경하도록 하는 모듈을 지정한다.
 
session
사용자가 인증 받기 전후에 필요한 홈 디렉토리 마운트, 메일박스 생성 등의 유저 섹션을 구분하기 위해 부가적인 작업을 수행한다.
혹시라도 사용자의 로그인 전후에 수행해야 할 작업이 있다는 내용을 지정한다.
 

 

2) contol-flag

 

PAM에서 사용되는 모듈들이 결과에 따라 어떠한 동작을 취해야 하는지를 지시한다.

 

flag
설명
비고
required
인증이 거부되기 전에 PAM이 이 서비스에 등록된 모든 모듈들을 요구함에도 불구하고 실패할 경우 인증을 거부하도록 한다.
해당 모듈은 개별 사용자에 대한 인증을 반드시 진행해야 한다. 인증이 안될 경우 실패가 반드시 반환되어야 한다.
 
requisite
이 모듈을 이용하는 인증이 실패할 경우, 즉시 인증을 거부하도록 한다.
required와 비슷하지만 이 플래그가 인증을 실패할 경우 설정 파일에서 이 값 다음으로 나오는 모듈들을 호출되지 않는다. 실패한 결과는 즉시 응용 프로그램으로 전달된다.
 
sufficient
이전에 요청되어진 모듈이 실패하더라도 이 모듈에 의해서 인증이 성공할 경우 PAM은 인증을 승인한다.
모듈이 성공 값을 반환하고 설정 파일에서 required sufficient 제어 플래그가 필요하지 않다면 PAM은 해당 응용 프로그램에서 성공을 반환한다.
 
optional
이 모듈이 성공 또는 실패하는지는 그 모듈이 서비스에 대한 형식에 유일한 모듈일 경우에 해당한다.(성공 여부 상관 X)
이 제어 플래그는 모듈의 결과를 무시한다. PAM으로 다른 모듈을 지속적으로 확인하도록 한다. 확인 작업이 실패하게 되더라도 계속 진행하게 된다.
특정 모듈이 실패하더라도 사용자가 로그인하는 것을 허용하고자 할 때 리 플래그를 사용하면 된다.
 
include
이 플래그는 인자(argument)에 지정된 또 다른 설정 파일의 내용이나 지침을 포함시키기 위해 사용된다. , 서로 다른 PAM 설정 파일의 내용을 연결하고 구성하는 방식으로 사용된다.
 

 

3) module-path

 

PAM에게 어떤 모듈을 사용할 것인지 그리고 그것을 어디서 찾을지를 알려준다.(인증 작업을 수행하는 모듈이 있는 실제 디렉토리 경로를 지정해 준다) 대부분 구성은 로그인 구성 파일의 경우 마찬가지로 모듈의 이름만 가지고 있다. 이와 같은 경우, PAM은 기본 PAM 모듈의 디렉토리(/lib64/security 또는 /lib/security) 모듈을 찾는다.

 

4) module-arguments

 

모듈에게 전달되는 인수를 나타낸다. 각각의 모듈들은 각각의 인수를 가지고 있다.

 

arguments
설명
비고
debug
시스템 로그에 디버깅 정보를 남기다.
 
no_warn
응용 프로그램에 경고 메시지를 제공하지 않는다.
 
use_first_pass
비밀번호를 두 번 확인하지 않는다. 대신 auth 모듈에서 입력한 비밀번호를 사용자 인증 과정 시에도 재사용 해야 한다.(이 옵션은 auth password 모듈에 해당하는 옵션임)
 
try_first_pass
이 옵션은 use_first_oass 옵션과 비슷한데, 사용자는 두 번 비밀번호를 입력할 필요가 없기 때문이다. 하지만 기존의 비밀번호를 다시 입력하도록 되어 있다.
 
use_mapped_pass
이 인자는 이전 모듈에서 입력된 텍스트 인증 토큰을 입력 받도록 하는데, 이 값으로 암호화 또는 암호화가 해제된 키 값을 생성한다. 그 이유는 모듈에 대한 인증 토큰 값을 안전하게 저장하거나 불러오기 위함이다.
 
expose_account
이 값은 모듈로 하여금 계정 정보를 중요하다고 판단하지 않게 한다. 시스템 관리자에 의해 임의로 설정한 것이라 여겨진다.
 
nullok
이 인자는 호출된 PAM 모듈이 null 값의 비밀번호를 입력하는 것을 허용한다.
 

 

) /etc/pam.d/su의 내용

 

제일 먼저 "auth  sufficient  pam_rootok.so" 모듈을 사용하여 인증을 확인하고 성공 시 남은 모듈도 모두 성공처리, 실패 시 남은 모듈을 차례대로 확인한다.(pam_rootok.so root 계정이면 성공, 일반 계정이면 실패를 반환하는 모듈이다)

 

) /etc/pam.d/remote의 내용

 

"auth  required  pam_securetty.so" pam_securetty.so 모듈을 사용하여 인증을 확인한다. 성공 시 남은 모듈 확인, 실패 시 남은 모듈을 확인 하지만 접근은 실패(pam_securetty.so root 계정이 접근할 수 잇는 터미널이 지정되어 있는 모듈)

 

"auth  substack  password-auth"은 윗 줄에서 성공 값이 반환되면 password-auth 설정 파일에서 입력한 암호와 계정의 암호가 일치하는지 확인한다. 성공 시 최종 성공 처리, 실패 시 최종 실패 처리

 

) /etc/pam.d/system-auth의 내용

 

내용
설명
auth required pam_env.so
Pam_env.so 모듈을 사용하여 인증을 확인한다. 성공 시 남은 모듈 확인, 실패 시 남은 모듈을 확인 하지만 접근은 실패(pam_env.so는 설정 파일에서 환경 변수를 불러온다. /etc/environment, /etc/security/pam_env.conf)
auth sufficient pam_fprintd.so
password prompt를 대신하는 인증 서비스 중 한가지이다. 현재 사용되지 않으며 무조건 실패 처리
auth sufficient pam_unix.so nullok try_first_pass
/etc/passwd, /etc/shadow 파일과 비교하여 비밀번호를 검증한다.
nullok: 공백 비밀번호를 허용
try_first_pass: 이전에 입력 받은 비밀번호로 인증을 시도, 비밀번호가 없다면 사용자에게 물어본다.
auth requisite pam_succeed_if.so uid < 1000 quiet
uid 1000 보다 작으면 인증을 수행한다.
quiet: 로그를 남기지 않는다.

 

6. pam_nologin.so & pam_securetty.so

 

/etc/nologin 파일이 존재하면 root만 로그인이 가능하고, 일반 사용자는 로그인이 거부된다. "account  required  pam_nologin.so" 설정으로 인해 /etc/nologin 파일이 있으면 사용자들의 접근이 거부된다.

 

/etc/nologin 파일이 생성되면, root 사용자만 로그인이 가능하며, /etc/nologin 파일의 내용과는 상관없이 파일의 생성유무만 판단한다.

 

7. ssh 접속 제한

 

ssh 접속을 제한하기 위해 다음과 같이 vi 명령어를 사용하여 다음과 같은 내용을 추가한다.

 

$ vi /etc/pam.d/sshd
auth  required  pam_listfile.so  item=user  sense=deny  file=/etc/ssh/sshusers  onerr=succeed

 

추가 후 /etc/ssh/sshusers 파일을 생성한 후 ssh 접속을 제한할 사용자를 다음과 같이 입력한다. (파일 경로와 파일명은 임의로 설정

 

$ vi /etc/ssh/sshusers
nuriapp
nuriotp
nuripam
nurifds

 

저장 후 해당 계정으로 ssh 접속을 시도할 경우 "Access denied" 메시지를 출력하며 접속이 불가능.

 

8. PAM 설정 파일의 예

 

/etc/pam.d/login 파일의 내용이다.

 

#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth       include      system-auth
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    optional     pam_keyinit.so force revoke
session    required     pam_loginuid.so
session    include      system-auth
session    optional     pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open

 

9. PAM 프로그래밍

 

아래 소스 코드는 PAM 모듈의 기본 형태로 "#if 0"으로 막혀 있는 부분에 통제를 할 수 있는 코드를 넣어 두면 원하는 동작(차단 또는 허용, 로그 기록)을 쉽게 처리할 수 있다.

 

/* pam_test.c */
 
#include <stdio.h>
#include <stdlib.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
 
#ifdef PAM_MODULE_ENTRY
PAM_MODULE_ENTRY("pam_test");
#endif
 
#ifndef PAM_EXTERN
#define PAM_EXTERN extern
#endif
 
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}
 
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}
 
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}
 
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}
 
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}
 
/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,int argc, const char **argv) {
#if 0
    // 아래 조건을 만족하지 못할 경우 로그인 실패로 처리함
    if (check_auth_pam(pamh) < 0)
        return PAM_PERM_DENIED;
#endif
    return PAM_SUCCESS;
}

 

위에 있는 pam_sm_...으로 된 함수들이 사용자가 임으로 추가한 함수가 아니라 PAM에서 기본 함수들로서 해당 함수 부분에 원하는 동작 코드를 넣도록 되어 있다.

 

PAM 모듈 자체게 기존에 동작하는 telnet이나, ssh, login 바이너리에 동적 라이브러리 형태로 붙기 때문에 위 코드에 삽입한 코드들은 로그인과 동시에 해당 서버로의 접속자의 모든 상황들을 감시하고 제어할 수 있다.

 

10. OS PAM 컴파일 방법

 

PAM 인증 모듈은 Linux/Unix의 특성별 OS에서 제공하는 최적화 옵션에 따라 컴파일 하는 방법은 다음과 같다.

 

1) Linux

 

gcc -fPIC -fno-stack-protector -c pam_test.c
ld -x --shared -o pam_test.so pam_test.o
cp pam_test.so /lib/security/ or /lib64/security/
chmod 555  /lib/security/pam_test.so or /lib64/security/pam_test.so
chown root /lib/security/pam_test.so or /lib64/security/pam_test.so

 

2) HP-UX

 

cc -c pam_test.c
ld -b -G -o pam_test.so pam_test.o
cp pam_test.so /usr/lib/security/ or /usr/lib64/security/
chmod 555  /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so
chown root /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so

 

3) AIX(XLC)

 

cc -c pam_test.c -ldl -lc -lpam  -lcfg -lodm
cc -G -o pam_test.so pam_test.o -ldl -lc -lpam  -lcfg -lodm 
cp -pf pam_test.so /usr/lib/security/ or /usr/lib64/security/
chmod 555  /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so
chown root /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so

 

4) Solaris(gcc)

 

gcc -c -o pam_test.so pam_test.c
cp -pf pam_test.so /usr/lib/security/ or /usr/lib64/security/
chmod 555       /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so
chown root:root /usr/lib/security/pam_test.so or /usr/lib64/security/pam_test.so

 

11. PAM 환경설정

 

보통 Unix의 경우에는 /etc/pam.conf에 서비스에 따라 아래와 같은 내용을 추가해 주면 되고, Linux의 경우는 /etc/pam.d/ 디렉토리 안에 서비스마다 별도 설정을 해줘야 한다. 단 설정 양식은 아래와 비슷하다.

 

login   auth required /usr/lib/security/pam_test.so common
ftp     auth required /usr/lib/security/pam_test.so ftp
sshd    auth required /usr/lib/security/pam_test.so ssh
telnet  auth required /usr/lib/security/pam_test.so telnet
rsh     auth required /usr/lib/security/pam_test.so rsh
rlogin  auth required /usr/lib/security/pam_test.so rlogin
dtlogin auth required /usr/lib/security/pam_test.so dtlogin

 

PAM설정이 되어 있는 경우 PAM모듈 프로그램이 잘못되거나 환경설정 파일 수정에 실수가 있는 경우, 그 순간부터 신규 접속은 모두 차단된다.

 

따라서 반드시 작업 전에 telnet/ssh 창을 접속해 둔 다음 테스트 하시고, 테스트 중에 문제가 발생한 경우 이전에 붙여 놓았던 창을 이용하여 복원해야 한다.