Linux

리눅스 /etc/passwd, /etc/shadow, /etc/group와 macOS 비밀번호 저장 방식 비교

리눅스의 /etc/passwd, /etc/shadow, /etc/group 세 가지 핵심 계정 파일 구조를 정리하고, PAM 인증 흐름과 macOS에서 비밀번호 해시가 어디에, 어떤 방식으로 저장되는지까지 자세히 설명합니다.

#Linux 계정관리#PAM#macOS#보안#운영체제

소개

리눅스에서 계정을 다루다 보면 항상 등장하는 파일이 있습니다. 바로 /etc/passwd, /etc/shadow, /etc/group입니다. 여기에 사용자, 비밀번호, 그룹 정보가 모두 들어 있고, 로그인·권한과 직결되기 때문에 서버 운영에서 매우 중요합니다.

한편, macOS에서는 /etc/shadow 파일이 보이지 않습니다. 그런데 어떻게 비밀번호를 저장하고 검증할까요? 그리고 이 모든 인증 과정의 중간에 PAM(Pluggable Authentication Modules) 이라는 레이어가 있습니다.

이 글에서 다루는 내용은 다음과 같습니다.

  • 리눅스의 세 가지 핵심 계정 파일 구조와 예시
  • PAM이 인증 과정에서 어떤 역할을 하는지
  • macOS에서 비밀번호 해시가 어디에, 어떤 형식으로 저장되는지
  • 실무에서 계정·인증 관련 문제를 디버깅할 때의 관점

사전지식

  • 대상 환경
    • 리눅스: Ubuntu, Debian, RHEL, Rocky 등 일반적인 배포판
    • macOS: 최신 버전
직접 편집은 매우 위험합니다

/etc/passwd·/etc/shadow·/etc/group는 되도록 useradd, usermod, groupadd, passwd 같은 전용 명령어로만 수정하세요. 포맷을 망가뜨리면 부팅·로그인 실패로 이어질 수 있습니다.

1. 리눅스의 세 가지 계정 정보 파일

리눅스 계정 관리는 크게 세 파일로 나뉩니다.

파일주요 역할접근 권한(일반적)핵심 필드 수
/etc/passwd사용자 계정 기본 정보(UID, 홈 등)모두 읽기 가능(644)7
/etc/shadow비밀번호 해시 + 패스워드 만료 정보root만 읽기 가능(600)9
/etc/group그룹 정보 및 그룹 멤버모두 읽기 가능(644)4

1-1. /etc/passwd – 사용자 기본 정보

형식:

이름:암호:UID:GID:GECOS:홈디렉터리:로그인셸

예시:

root:x:0:0:root:/root:/bin/bash
ubuntu:x:1000:1000:Ubuntu User,,,:/home/ubuntu:/bin/bash

각 필드 의미:

  1. 이름(name): 로그인 ID (root, ubuntu 등)
  2. 암호(password): 보통 x 또는 *
    • x: 실제 해시는 /etc/shadow에 저장됨
    • * 또는 !: 로그인 비활성화 등
  3. UID: 사용자 ID (root는 0)
  4. GID: 기본 그룹 ID (/etc/group와 연결)
  5. GECOS: 사용자 설명(실명, 전화번호 등)
  6. 홈 디렉터리: 예) /home/ubuntu
  7. 로그인 셸: 예) /bin/bash, /usr/sbin/nologin
왜 /etc/passwd는 모두 읽을 수 있을까?

과거 유닉스에서는 해시된 비밀번호도 /etc/passwd에 함께 저장했습니다. 이 파일은 다양한 프로그램이 사용자 정보를 읽어야 하기 때문에 전통적으로 world-readable 이었고, 지금도 UID·홈 경로 등을 위해 계속 공개되어 있습니다. 비밀번호 해시만을 보다 안전한 /etc/shadow로 분리한 것이 현재 구조입니다.

1-2. /etc/shadow – 비밀번호 해시와 만료 정보

/etc/shadow 는 각 계정의 비밀번호 해시와 패스워드 만료 정책(aging)을 저장합니다. 일반 사용자는 읽을 수 없고 root만 읽기 가능해야 합니다.

형식:

로그인명:암호해시:마지막변경일:최소일수:최대일수:경고일수:비활성일수:만료일:예약

예시:

root:$6$R7...$aLongSaltedHash:19500:0:99999:7:::
ubuntu:$6$Kq...$anotherHash:19510:0:99999:7:::
  • 암호해시 필드
    • $id$salt$hash 형태
    • $6$ → SHA-512, $5$ → SHA-256 등
    • ! 또는 * → 이 계정으로 로그인 불가
  • 마지막변경일: 1970-01-01부터의 일 수
  • 최대일수/경고일수 등을 기반으로 패스워드 만료를 결정

1-3. /etc/group – 그룹 정보 및 멤버

/etc/group그룹 이름과 GID, 그룹에 속한 사용자 목록을 저장합니다. 각 줄은 하나의 그룹입니다.

형식:

group_name:password:GID:user_list

예시:

root:x:0:
sudo:x:27:ubuntu,deploy
developers:x:1001:alice,bob
  • group_name: 그룹 이름
  • password: 보통 x (실제 그룹 비밀번호는 /etc/gshadow에 있을 수 있음)
  • GID: 그룹 ID
  • user_list: 보조 그룹 멤버(콤마 구분)

2. PAM(Pluggable Authentication Modules)

PAM은 리눅스/유닉스에서 인증 로직을 모듈화하기 위한 프레임워크입니다. 애플리케이션(예: sshd, login, sudo)은 직접 /etc/shadow를 읽지 않고, PAM에게 “이 사용자가 맞냐?”라고 묻는 구조입니다.

2-1. PAM의 레이어 구조

  • 애플리케이션: ssh, 로그인 매니저, sudo, su, gdm 등
  • PAM 라이브러리 (libpam)
    • /etc/pam.d/<서비스> 설정 파일을 읽어서
    • 어떤 모듈들을 어떤 순서로 호출할지 결정
  • PAM 모듈 (pam_unix.so, pam_ldap.so, pam_tally2.so …)
    • 실제 인증·계정·세션·패스워드 변경 처리

모듈은 다음 4가지 “스택”으로 나뉩니다.

  1. auth: 사용자의 신원 확인 (예: 비밀번호 검사, 2FA)
  2. account: 계정 상태 검사 (락, 만료, 로그인 가능 시간 등)
  3. password: 비밀번호 변경 정책 (복잡도, 재사용 금지 등)
  4. session: 로그인/로그아웃 시 실행할 작업 (마운트, 로그 기록 등)

대표적인 모듈 예시:

  • pam_unix: /etc/passwd, /etc/shadow를 이용한 전통적인 인증
  • pam_ldap: LDAP/디렉터리 서버 기반 인증
  • pam_tally 또는 pam_faillock: 로그인 실패 횟수 제한
  • pam_nologin: 시스템 점검 시 일반 사용자 로그인 차단
  • pam_limits: 리소스 제한 설정

3. macOS의 사용자·비밀번호 저장 구조

macOS는 BSD 계열 유닉스를 기반으로 하지만, 계정 관리는 Open Directory(opendirectoryd)플리스트(plist) 기반 로컬 디렉터리로 구현됩니다. 전통적인 /etc/shadow 대신, 로컬 계정 정보는 다음 경로의 plist 파일에 저장됩니다.

/var/db/dslocal/nodes/Default/users/<username>.plist
/var/db/dslocal/nodes/Default/groups/<groupname>.plist

이 파일들은:

  • root만 접근 가능
  • plutil -p 로 내용을 확인할 수 있는 XML/바이너리 plist
  • 사용자 속성(UID, GID, 홈 디렉터리, Shell, 그룹 멤버십 등)을 키-값 형태로 저장

비밀번호는 일반 텍스트가 아니라 해시 형태로 저장됩니다.

  • 현대 macOS는 SALTED-SHA512-PBKDF2 형식의 해시를 사용합니다.
  • 해시는 계정 속성 내의 특정 키(예: ShadowHashData)에 바이너리 형태로 포함됩니다.
  • 일반 사용자는 이 데이터에 접근할 수 없고, root 권한이 필요합니다.
왜 /etc/shadow가 없을까?

macOS는 계정·그룹·비밀번호를 /etc/passwd·/etc/shadow 파일 조합 대신, **디렉터리 서비스(Directory Services)**와 opendirectoryd 데몬이 관리하는 디렉터리 DB(plist 파일) 형태로 저장합니다. CLI에서 dscl 명령으로 읽을 수 있지만, 해시 자체는 보호되어 있고 평문 비밀번호는 어디에도 저장되지 않습니다.

4. 구현 또는 적용 단계

이제 실제 시스템에서 어떻게 정보를 확인하고, PAM과 macOS에서 어떻게 다르게 동작하는지 명령어 수준에서 살펴보겠습니다.

4-1. 리눅스에서 사용자·그룹 정보 확인

먼저 /etc/passwd, /etc/shadow, /etc/group를 안전하게 읽는 명령들입니다.

# 현재 로그인한 사용자 정보
id
 
# /etc/passwd에서 특정 사용자 검색
grep "^ubuntu:" /etc/passwd
 
# /etc/shadow 해시 및 패스워드 만료 정보 확인 (root만 가능)
sudo grep "^ubuntu:" /etc/shadow
 
# 그룹 목록과 구성원 확인
grep "sudo" /etc/group
getent group sudo

위 명령어들을 통해:

  • /etc/passwd의 7개 필드
  • /etc/shadow의 비밀번호 상태/만료
  • /etc/group의 그룹 멤버십

을 빠르게 확인할 수 있습니다.

4-2. PAM 설정 파일 구조 예시

대부분의 리눅스에서 서비스별 PAM 설정은 /etc/pam.d 디렉터리에 있습니다. 예를 들어 OpenSSH 로그인은 /etc/pam.d/sshd 의 영향을 받습니다.

아래는 단순화된 예시입니다.

# /etc/pam.d/sshd (예시)
 
auth       required     pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
 
account    required     pam_nologin.so
account    include      password-auth
 
password   include      password-auth
 
session    required     pam_selinux.so close
session    include      password-auth
session    required     pam_loginuid.so
session    optional     pam_motd.so
  • auth, account, password, session 스택별로 모듈을 나열
  • 각 줄의 첫 번째 필드가 control flag (required, sufficient, optional 등)
  • pam_unix.so는 보통 password-auth 같은 공용 파일 안에 포함되어 있습니다.

4-3. macOS에서 계정 정보와 해시 위치 확인

macOS에서 /etc/passwd를 열어보면, 비교적 단순한 정보만 들어있거나, 실제 계정 정보가 Open Directory를 통해 제공되는 것을 볼 수 있습니다.

# 로컬 사용자 목록
dscl . list /Users
 
# 특정 사용자 속성 확인
dscl . read /Users/$USER
 
# plist 파일(루트 권한 필요)
sudo plutil -p /var/db/dslocal/nodes/Default/users/$USER.plist | head

여기서 plutil -p 로 보면 ShadowHashData 같은 키가 보이고, 이 안에 비밀번호 해시 관련 데이터가 들어 있습니다.

4-4. Linux vs macOS vs 공통 개념

아래 탭에서는 리눅스 /etc 기반 vs macOS dslocal 기반 vs 공통 개념을 간단한 코드와 함께 비교합니다.

Linux: /etc/passwd, /etc/shadow, /etc/group

리눅스에서는 전통적인 텍스트 파일을 통해 계정 정보를 관리합니다.

# 사용자·그룹·비밀번호 상태를 텍스트 파일에서 직접 확인
getent passwd ubuntu
sudo getent shadow ubuntu
getent group sudo

PAM 모듈 pam_unix.so/etc/passwd/etc/shadow를 이용해 인증을 수행합니다.

5. 로그인 문제를 디버깅하는 흐름

실무에서 흔한 상황 하나를 통합 예제로 정리해보겠습니다.

“새로 생성한 계정이 SSH로 로그인이 안 된다”

리눅스 서버에서 이런 이슈가 발생했을 때 확인할 흐름입니다.

  1. 계정 존재 여부 확인

    id newuser || echo "계정 없음"
    • id 결과가 없으면 계정 자체가 없는 것 → useradd로 재생성 필요
  2. /etc/passwd, /etc/shadow, /etc/group 일관성 확인

    grep "^newuser:" /etc/passwd
    sudo grep "^newuser:" /etc/shadow
    getent group | grep newuser
    • /etc/passwd에는 있는데 /etc/shadow에 없다면 계정이 깨진 상태
    • /etc/group에 기본 그룹·보조 그룹이 적절히 등록되어 있는지 확인
  3. 쉘·홈 디렉터리 설정 확인

    getent passwd newuser
    # 출력의 마지막 필드가 /bin/bash 또는 유효한 셸인지 확인
    • /usr/sbin/nologin 으로 되어 있으면 로그인 불가
  4. PAM 설정 확인

    # sshd 서비스의 PAM 설정
    sudo sed -n '1,80p' /etc/pam.d/sshd
    • pam_nologin.so 또는 pam_deny.so 가 잘못 들어가 있지 않은지
    • LDAP/AD와 연동 중이면 pam_ldap.so 설정에 오류가 없는지 확인
  5. 로그 확인

    sudo journalctl -u sshd -n 50
    # 또는 /var/log/auth.log, /var/log/secure 확인
    • 패스워드 오류인지, 계정 잠김인지, 키 인증 실패인지 로그 레벨에서 구분

이 흐름을 통해 파일 계층(/etc/*)PAM 레이어, 서비스 로그까지 한 번에 연결해서 볼 수 있습니다.

마무리

이 글에서는 다음 내용을 정리했습니다.

  • 리눅스의 /etc/passwd, /etc/shadow, /etc/group 파일 구조와 역할
  • PAM이 인증 레이어에서 수행하는 역할(모듈 스택, pam_unix 등)
  • macOS가 /etc/shadow 대신 /var/db/dslocal/nodes/Default/users/*.plist에 비밀번호 해시를 저장하는 방식
  • 실무에서 계정/로그인 문제를 진단하는 기본 흐름

참고 문서: