신입 개발자에게 서버 접근 권한을 줬더니 실수로 /etc/passwd를 잘못 건드려 다른 계정들의 로그인이 안 되는 사태가 벌어졌습니다. 퇴사한 직원 계정이 6개월째 살아 있었고, 특정 서비스가 root 권한으로 돌아가고 있었습니다. 계정과 권한을 제대로 관리하는 것은 보안의 시작이자 시스템 안정성의 기반입니다.
사용자와 그룹 관리
리눅스는 멀티유저 운영체제입니다. 시스템의 모든 리소스는 사용자와 그룹 단위로 관리되며, 이 정보는 /etc/passwd, /etc/shadow, /etc/group 파일에 저장됩니다. 리눅스마스터 1급 시험에서 계정 관리는 매회 다수 문제가 출제되는 핵심 영역입니다.
사용자·그룹 관리는 리눅스 운영 및 관리 영역의 핵심입니다. /etc/passwd와 /etc/shadow 파일 구조, useradd 옵션, su와 sudo의 차이는 시험에 반드시 출제됩니다.
- 1/etc/passwd 7개 필드 — 각 필드의 의미와 시스템 계정 특성
- 2/etc/shadow 9개 필드 — 패스워드 해시와 만료 정책
- 3useradd / usermod / userdel — 계정 생명주기 관리
- 4groupadd / groupmod / gpasswd — 그룹 생성과 멤버 관리
- 5su / sudo — 권한 전환 방식의 차이와 보안 고려사항
- 6PAM — 플러그인 방식의 인증 모듈 구조
사용자 관리 명령어는 대부분 root 권한이 필요합니다. 실습 시 sudo를 활용하거나 root 계정으로 진행하세요.
cat /etc/passwd | head -5sudo cat /etc/shadow | head -3id && groups/etc/passwd와 /etc/shadow 파일 구조
/etc/passwd — 사용자 계정 데이터베이스
사용자명 : 패스워드 : UID : GID : GECOS : 홈디렉토리 : 기본셸
1 2 3 4 5 6 7
실제 예시:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
nginx:x:998:996:Nginx web server:/var/lib/nginx:/sbin/nologin
john:x:1001:1001:John Doe,Room 101:/home/john:/bin/bash
| 필드 | 설명 | 특이값 |
|---|---|---|
| 사용자명 | 로그인 이름 (최대 32자) | |
| 패스워드 | x=shadow 사용, *=비활성화 | |
| UID | 사용자 고유 번호 | 0=root, 1-999=시스템계정, 1000+=일반사용자 |
| GID | 기본 그룹 번호 | /etc/group과 연결 |
| GECOS | 사용자 설명 (풀네임, 전화번호 등) | |
| 홈 디렉토리 | 로그인 시 이동할 디렉토리 | 없는 경우 / 또는 /var/empty |
| 기본 셸 | 로그인 셸 | /sbin/nologin=로그인 비활성화 |
시스템 계정 vs 일반 계정
# 시스템 계정 (UID 0-999): 서비스 실행용
cat /etc/passwd | awk -F: '$3 < 1000 {print $1, $3}'
# root 0
# daemon 1
# bin 2
# nginx 998
# 일반 사용자 계정 (UID 1000+)
cat /etc/passwd | awk -F: '$3 >= 1000 {print $1, $3}'
# john 1001
# jane 1002
/etc/shadow — 패스워드 보안 데이터베이스
사용자명:해시패스워드:최종변경일:최소:최대:경고:비활성:만료:예약
1 2 3 4 5 6 7 8 9
실제 예시:
root:$6$rounds=5000$salt$hashedpassword...:19450:0:99999:7:::
john:$6$xyz$abc...:19450:7:90:7:30:20000:
locked_user:!$6$abc...:19400:0:99999:7:::
| 필드 | 설명 |
|---|---|
| 해시패스워드 | $알고리즘$솔트$해시 형태. $6=SHA-512, $5=SHA-256, $1=MD5 |
| 최종변경일 | 1970-01-01 기준 일수 |
| 최소 사용 기간 | 패스워드 변경 후 최소 유지 일수 (0=제한없음) |
| 최대 사용 기간 | 패스워드 강제 변경 주기 (99999=무제한) |
| 경고 기간 | 만료 전 경고 시작 일수 |
| 비활성 기간 | 만료 후 계정 비활성화까지의 유예 기간 |
| 계정 만료일 | 절대적인 계정 만료일 (1970-01-01 기준 일수) |
계정 관리 명령어
useradd — 사용자 계정 생성
# 기본 사용법
useradd username
# 주요 옵션
useradd -m -s /bin/bash -u 1500 -g developers -G sudo,docker -c "John Doe" john
# 옵션 설명
# -m : 홈 디렉토리 생성 (/home/john)
# -s : 기본 셸 지정
# -u : UID 직접 지정
# -g : 기본 그룹(primary group) 지정
# -G : 보조 그룹(supplementary groups) 지정 (쉼표 구분)
# -c : GECOS 설명 필드
# -d : 홈 디렉토리 경로 지정 (기본값과 다른 경로 사용 시)
# -e : 계정 만료일 (YYYY-MM-DD)
# -r : 시스템 계정 생성 (UID < 1000, 홈 디렉토리 없음)
# 패스워드 설정 (useradd 후 반드시 실행)
passwd john
# 또는
echo "john:secretpassword" | chpasswd # 스크립트에서 사용
usermod — 사용자 계정 수정
# 셸 변경
usermod -s /bin/zsh john
# 보조 그룹 추가 (-aG: append + Groups)
usermod -aG docker john
# ⚠️ -G만 쓰면 기존 보조 그룹이 모두 교체됨!
usermod -G docker,sudo john # 기존 그룹 모두 교체
# 계정 잠금/해제
usermod -L john # Lock (shadow에 ! 추가)
usermod -U john # Unlock (! 제거)
# 사용자명 변경
usermod -l newname oldname
# 홈 디렉토리 변경 및 이동
usermod -d /new/home -m john # -m: 파일도 함께 이동
userdel — 사용자 계정 삭제
# 계정만 삭제 (홈 디렉토리 유지)
userdel john
# 홈 디렉토리와 메일 스풀까지 삭제
userdel -r john
# 주의: /home/john 디렉토리가 삭제됨
# 삭제된 사용자가 소유한 파일 찾기
find / -nouser -o -nogroup 2>/dev/null
그룹 관리 명령어
# 그룹 생성
groupadd developers
groupadd -g 2000 dbteam # GID 직접 지정
# 그룹에 사용자 추가/삭제
gpasswd -a john developers # 추가
gpasswd -d john developers # 삭제
# 그룹 관리자 지정
gpasswd -A john developers
# 그룹 삭제
groupdel developers # 해당 그룹이 기본 그룹인 사용자 있으면 삭제 불가
# 현재 사용자의 그룹 확인
groups john
# john : john developers sudo docker
id john
# uid=1001(john) gid=1001(john) groups=1001(john),27(sudo),998(docker),2000(developers)
/etc/group 파일 구조
그룹명:패스워드:GID:멤버목록
developers:x:2000:john,jane,bob
sudo:x:27:john
su와 sudo — 권한 전환
su (Switch User)
# root로 전환 (root 패스워드 필요)
su
su - # 로그인 셸로 전환 (환경변수, PATH도 root 것으로 교체)
# 특정 사용자로 전환
su john # john의 환경변수 미적용
su - john # john으로 완전 전환 (홈 디렉토리, 환경변수 적용)
# 단일 명령어 실행 후 복귀
su -c "cat /etc/shadow" root
sudo (SuperUser Do)
# 단일 명령어를 root 권한으로 실행 (자신의 패스워드로 인증)
sudo apt-get update
sudo systemctl restart nginx
# root 셸로 전환
sudo -i # 로그인 셸 (-i: interactive)
sudo su -
# 다른 사용자로 명령 실행
sudo -u nginx nginx -t
# sudo 가능한 명령어 목록 확인
sudo -l
/etc/sudoers 구조 (visudo로 편집)
# visudo 사용 (문법 검사 포함)
visudo
# 주요 설정 예시
# 사용자에게 모든 명령어 허용
john ALL=(ALL:ALL) ALL
# 패스워드 없이 특정 명령어 허용
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp
# 그룹에 sudo 권한 부여 (%는 그룹 표시)
%developers ALL=(ALL:ALL) ALL
# 특정 명령어만 허용
john ALL=(ALL) /usr/bin/apt-get, /usr/bin/systemctl
su vs sudo 비교
| 항목 | su | sudo |
|---|---|---|
| 인증 | 대상 사용자 패스워드 | 자신의 패스워드 |
| 범위 | 셸 전체 전환 | 명령어 단위 |
| 감사 로그 | 기록 약함 | /var/log/auth.log에 모두 기록 |
| 권한 설정 | 불가 (전부 or 없음) | 세밀한 명령어 단위 제어 |
| 보안 | root 패스워드 공유 위험 | root 패스워드 불필요 |
PAM (Pluggable Authentication Modules)
PAM이란?
PAM은 인증 메커니즘을 애플리케이션에서 분리하여 모듈로 관리하는 프레임워크입니다. 애플리케이션을 수정하지 않고도 인증 방식을 변경할 수 있습니다.
PAM 설정 파일 구조
ls /etc/pam.d/
# login sudo sshd su passwd system-auth ...
설정 파일 형식:
모듈타입 제어플래그 모듈경로 모듈인자
auth required pam_unix.so nullok
account required pam_nologin.so
모듈 타입
| 타입 | 역할 |
|---|---|
auth | 사용자 인증 (패스워드 확인) |
account | 계정 유효성 검사 (만료, 잠금 등) |
password | 패스워드 변경 처리 |
session | 세션 설정/해제 (홈 디렉토리 마운트 등) |
제어 플래그
| 플래그 | 동작 |
|---|---|
required | 실패해도 계속 실행, 최종 결과는 실패 |
requisite | 실패 시 즉시 중단하고 실패 반환 |
sufficient | 성공 시 이전 required 실패 없으면 즉시 성공 |
optional | 결과가 전체 인증에 영향 없음 |
자주 사용되는 PAM 모듈
# /etc/pam.d/system-auth 예시
auth required pam_env.so
auth required pam_faildelay.so delay=2000000 # 실패 시 2초 지연
auth sufficient pam_unix.so nullok
auth required pam_deny.so
account required pam_unix.so
account sufficient pam_localuser.so
account required pam_permit.so
password required pam_pwquality.so try_first_pass # 패스워드 복잡도 검사
password sufficient pam_unix.so sha512 shadow nullok
session required pam_limits.so # /etc/security/limits.conf 적용
session required pam_unix.so
계정 생명주기 전체 과정을 실습합니다.
mkdir -p /tmp/linux-master/part1/user-mgmt && cd /tmp/linux-master/part1/user-mgmt
# 실습용 사용자/그룹 관리 기록 파일
cat > user_plan.txt << 'EOF'
# 생성할 사용자 목록
# username:group:shell:comment
webuser:www-data:/sbin/nologin:Web service account
appuser:appgroup:/bin/bash:Application user
deployer:deployers:/bin/bash:Deployment user
EOF
cat > group_plan.txt << 'EOF'
# 생성할 그룹 목록
appgroup
deployers
developers
EOF
1단계: 사용자 생성 전 현재 상태 확인
# 현재 최대 UID 확인
cat /etc/passwd | awk -F: '{print $3}' | sort -n | tail -5
# 1001
# 1002
# 사용 중인 그룹 확인
getent group | grep -v "^[a-z]" | head -5
2단계: 그룹과 사용자 생성
# 개발팀 그룹 생성
sudo groupadd -g 2000 devteam
# 사용자 생성 (홈 디렉토리 포함, bash 셸)
sudo useradd -m -s /bin/bash -u 1500 -g devteam -G sudo -c "개발자 김철수" devkim
# 패스워드 설정
sudo passwd devkim
# New password:
# Retype new password:
# passwd: password updated successfully
# 생성 결과 확인
grep devkim /etc/passwd
# devkim:x:1500:2000:개발자 김철수:/home/devkim:/bin/bash
grep devkim /etc/shadow
# devkim:$6$...:19450:0:99999:7:::
ls -la /home/devkim/
# drwx------ 2 devkim devteam 62 Mar 28 .
# -rw-r--r-- 1 devkim devteam 18 .bash_logout
# -rw-r--r-- 1 devkim devteam 141 .bash_profile
# -rw-r--r-- 1 devkim devteam 376 .bashrc
3단계: 계정 수정
# docker 그룹에 추가 (기존 그룹 유지)
sudo usermod -aG docker devkim
# 그룹 확인
id devkim
# uid=1500(devkim) gid=2000(devteam) groups=2000(devteam),27(sudo),998(docker)
# 패스워드 만료 정책 설정
sudo chage -M 90 -m 7 -W 14 devkim
# -M 90: 최대 사용 기간 90일
# -m 7: 최소 사용 기간 7일
# -W 14: 만료 14일 전 경고
sudo chage -l devkim
# Last password change : Mar 28, 2026
# Password expires : Jun 26, 2026
# Password inactive : never
# Account expires : never
# Minimum number of days between password change : 7
# Maximum number of days between password change : 90
# Number of days of warning before password expires : 14
4단계: 계정 잠금과 해제
# 계정 잠금
sudo usermod -L devkim
# 또는
sudo passwd -l devkim
# 잠금 상태 확인 (! 확인)
sudo grep devkim /etc/shadow | cut -d: -f2 | cut -c1-2
# !$ ← ! 가 패스워드 앞에 추가됨
# 계정 해제
sudo usermod -U devkim
sudo passwd -u devkim
5단계: 계정 삭제
# 홈 디렉토리와 함께 삭제
sudo userdel -r devkim
# 삭제 확인
grep devkim /etc/passwd
# (출력 없음)
ls /home/devkim
# ls: cannot access '/home/devkim': No such file or directory
visudo를 사용하여 세밀한 sudo 권한을 설정합니다.
mkdir -p /tmp/linux-master/part1/user-mgmt && cd /tmp/linux-master/part1/user-mgmt
# 실습용 사용자/그룹 관리 기록 파일
cat > user_plan.txt << 'EOF'
# 생성할 사용자 목록
# username:group:shell:comment
webuser:www-data:/sbin/nologin:Web service account
appuser:appgroup:/bin/bash:Application user
deployer:deployers:/bin/bash:Deployment user
EOF
cat > group_plan.txt << 'EOF'
# 생성할 그룹 목록
appgroup
deployers
developers
EOF
1단계: 현재 sudo 설정 확인
sudo cat /etc/sudoers
# Defaults env_reset
# Defaults mail_badpass
# Defaults secure_path="/usr/local/sbin:..."
#
# root ALL=(ALL:ALL) ALL
# %sudo ALL=(ALL:ALL) ALL
2단계: 사용자별 sudo 권한 부여
# visudo로 안전하게 편집 (문법 오류 방지)
sudo visudo
# 추가할 내용:
# 웹마스터는 nginx 재시작만 가능 (패스워드 없이)
webmaster ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx
# 개발자 그룹은 패키지 설치 가능
%devteam ALL=(ALL) /usr/bin/apt-get install *, /usr/bin/yum install *
3단계: /etc/sudoers.d/ 활용
# 별도 파일로 관리 (권장 방식)
sudo visudo -f /etc/sudoers.d/devteam
# 파일 내용:
%devteam ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp
# 권한 설정
sudo chmod 440 /etc/sudoers.d/devteam
4단계: sudo 로그 확인
# Ubuntu/Debian
sudo grep sudo /var/log/auth.log | tail -5
# Mar 28 10:00:00 server sudo: devkim : TTY=pts/0 ; PWD=/home/devkim ; USER=root ; COMMAND=/usr/bin/apt-get update
# CentOS/RHEL
sudo grep sudo /var/log/secure | tail -5
증상
sudo useradd newuser
su - newuser
# su: warning: cannot change directory to /home/newuser: No such file or directory
# 또는
ssh newuser@localhost
# Permission denied, please try again.
원인 1: 홈 디렉토리 미생성
# 확인
ls /home/newuser
# ls: cannot access '/home/newuser': No such file or directory
grep newuser /etc/passwd
# newuser:x:1003:1003::/home/newuser:/bin/bash
# 홈 디렉토리 경로는 있지만 실제로 없음
해결:
# 홈 디렉토리 생성 및 기본 파일 복사
sudo mkdir /home/newuser
sudo cp -r /etc/skel/. /home/newuser/
sudo chown -R newuser:newuser /home/newuser
sudo chmod 700 /home/newuser
원인 2: 패스워드 미설정
# shadow 파일 확인
sudo grep newuser /etc/shadow
# newuser:!!:19450:0:99999:7:::
# !! = 패스워드 미설정 상태
해결:
sudo passwd newuser
원인 3: 셸이 /sbin/nologin으로 설정
grep newuser /etc/passwd
# newuser:x:1003:1003::/home/newuser:/sbin/nologin
해결:
sudo usermod -s /bin/bash newuser
증상
sudo usermod -aG docker john
docker ps
# permission denied while trying to connect to the Docker daemon socket
원인
그룹 변경은 현재 로그인 세션에 즉시 반영되지 않습니다. 그룹 정보는 로그인 시 로드됩니다.
확인
# 현재 세션의 그룹 (아직 docker 없음)
groups
# john sudo
# 실제 /etc/group 확인 (이미 추가됨)
grep docker /etc/group
# docker:x:998:john
해결
# 방법 1: 재로그인 (가장 확실)
exit
# 다시 로그인
# 방법 2: 현재 세션에서 그룹 새로고침
newgrp docker
# 단, 이 방법은 서브셸을 열어 docker 그룹으로 전환
# 방법 3: sudo로 그룹 적용 확인
sudo -u john groups
# john sudo docker ← 이미 적용됨 (새 프로세스이므로)
최소 권한 원칙 적용
실무에서 계정 관리의 핵심은 **최소 권한 원칙(Principle of Least Privilege)**입니다.
# 서비스 전용 시스템 계정 생성 (로그인 불가)
sudo useradd -r -s /sbin/nologin -d /var/lib/myapp myapp
# -r: 시스템 계정 (UID < 1000)
# -s /sbin/nologin: 로그인 불가
# 서비스 프로세스 실행에만 사용
# 계정 만료 정책 일괄 설정
for user in $(awk -F: '$3>=1000 {print $1}' /etc/passwd); do
sudo chage -M 90 -W 14 $user
done
비활성 계정 점검
# 90일 이상 로그인 없는 계정 찾기
lastlog | awk '$4 != "**Never" {print}' | awk '{print $1, $4, $5, $6, $7, $8, $9}'
# 패스워드 만료된 계정 확인
sudo passwd -S -a | grep " P " | awk '{print $1}'
# (P: 패스워드 있음, L: 잠금, NP: 패스워드 없음)
감사 추적을 위한 로그 모니터링
# 실패한 로그인 시도 확인
sudo grep "Failed password" /var/log/auth.log | tail -10
# Mar 28 09:00:00 server sshd[1234]: Failed password for root from 1.2.3.4 port 22
# sudo 사용 기록 확인
sudo grep "sudo" /var/log/auth.log | grep -v "sudo:" | tail -10
# 계정 생성/삭제 이벤트 확인
sudo grep -E "useradd|userdel|usermod" /var/log/auth.log