파일 · 권한 · 사용자 관리 34 / 50 · Part 4. 사용자와 그룹 관리
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정 analyst)
기초편 연계: 「리눅스 시스템 기초」 18. Linux 사용자와 그룹

1. 들어가며

27편에서 그룹이 여러 사용자에게 권한을 한 번에 주는 수단이라고 했다. 그 그룹 정보가 저장되는 파일이 /etc/group이다.

이번 글에서는 /etc/group의 4개 필드를 해석하고, 초보자가 가장 많이 헷갈리는 기본 그룹과 보조 그룹의 차이 를 실습으로 확인한다. 핵심 함정은 이것이다. 사용자의 기본 그룹은 /etc/group의 구성원 목록에 나오지 않는다. 기본 그룹은 /etc/passwd의 GID로만 결정되기 때문이다.

그리고 계정 보안 점검의 핵심인 위험 그룹(wheel·sudo·docker) 구성원 확인 을 다룬다.


2. 핵심 개념

2-1. 4개 필드

devops:x:1001:alice,bob,analyst를 :로 나누면:

#필드예의미
1그룹명devops그룹 이름
2비밀번호x/etc/gshadow 참조 (거의 미사용)
3GID1001그룹 번호
4구성원alice,bob,analyst이 그룹을 보조 그룹 으로 가진 사용자

2-2. 기본 그룹 vs 보조 그룹

구분어디서 결정특징
기본(primary)/etc/passwd의 4번 필드(GID)새 파일의 그룹, id의 gid=
보조(supplementary)/etc/group의 4번 필드추가 접근 권한, id의 groups= 뒤쪽

함정: 사용자 alice의 기본 그룹이 users라면, users 그룹의 /etc/group 줄에 alice가 나오지 않을 수 있다. 기본 그룹 멤버십은 passwd에만 기록되기 때문이다. 그래서 "특정 사용자가 어떤 그룹에 속하는가"는 /etc/group만 봐서는 안 되고 id user로 확인한다.


3. 동작 원리

/etc/group — 그룹과 사용자 관계

로그인하면 프로세스는 기본 그룹(GID) 하나와 보조 그룹 여러 개를 갖는다. 권한 검사 시 커널은 파일의 그룹과 프로세스의 기본 그룹 + 모든 보조 그룹 을 비교해, 일치하는 것이 있으면 그룹 권한 칸을 적용한다(21편).

/etc/group은 644 root:root로 누구나 읽을 수 있다. 그래서 getent group으로 그룹 구성을 확인하는 것은 일반 사용자도 가능하다. 쓰기는 root만 가능하며, usermod/gpasswd가 이 파일을 수정한다.

보안 관점에서 이 파일의 4번 필드는 권한 부여 기록 이다. 어떤 계정이 wheel(관리자), docker(사실상 root), shadow(해시 읽기) 그룹에 들어 있는지가 곧 그 계정이 가진 권한이다.


4. 명령어 실습

devops 그룹에 alice·bob·analyst가 보조 그룹으로 속해 있다. alice의 기본 그룹은 users(100)다.

# 1) 그룹 필드 확인
getent group devops root

# 2) 필드 분해
getent group devops | awk -F: '{print "1 그룹명: "$1"\n2 password: "$2"\n3 GID: "$3"\n4 구성원(보조): "$4}'

# 3) 기본 그룹은 group 파일에 안 나온다
id analyst
getent passwd alice | awk -F: '{print "alice GID: "$4}'
getent group $(getent passwd alice | cut -d: -f4)     # alice 기본 그룹

# 4) 위험 그룹 구성원 점검
for g in wheel sudo docker disk; do
  m=$(getent group $g)
  if [ -n "$m" ]; then echo "$g -> 구성원[$(echo $m|cut -d: -f4)]"; else echo "$g -> (그룹 없음)"; fi
done

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — /etc/group 분석

텍스트 원본(실제 출력):

[analyst@rocky9-lab ~]$ echo "=== /etc/group 필드 4개 ==="
=== /etc/group 필드 4개 ===
[analyst@rocky9-lab ~]$ getent group devops root
devops:x:1001:alice,bob,analyst
root:x:0:
[analyst@rocky9-lab ~]$ echo "--- 분해 (devops) ---"
--- 분해 (devops) ---
[analyst@rocky9-lab ~]$ getent group devops | awk -F: '{print "1 그룹명: "$1"\n2 password: "$2"\n3 GID: "$3"\n4 구성원(보조): "$4}'
1 그룹명: devops
2 password: x
3 GID: 1001
4 구성원(보조): alice,bob,analyst
[analyst@rocky9-lab ~]$ echo "=== 기본 그룹 vs 보조 그룹 ==="
=== 기본 그룹 vs 보조 그룹 ===
[analyst@rocky9-lab ~]$ id analyst
uid=1000(analyst) gid=1000(analyst) groups=1000(analyst),1001(devops)
[analyst@rocky9-lab ~]$ echo "alice 의 기본 그룹은 /etc/passwd 의 GID 로 결정 (group 파일에 안 나올 수 있음)"
alice 의 기본 그룹은 /etc/passwd 의 GID 로 결정 (group 파일에 안 나올 수 있음)
[analyst@rocky9-lab ~]$ getent passwd alice | awk -F: '{print "alice GID: "$4}'
alice GID: 100
[analyst@rocky9-lab ~]$ getent group $(getent passwd alice | cut -d: -f4)
users:x:100:
[analyst@rocky9-lab ~]$ echo "=== 특정 그룹의 전체 구성원 ==="
=== 특정 그룹의 전체 구성원 ===
[analyst@rocky9-lab ~]$ getent group devops
devops:x:1001:alice,bob,analyst
[analyst@rocky9-lab ~]$ echo "=== 위험 그룹 점검 ==="
=== 위험 그룹 점검 ===
[analyst@rocky9-lab ~]$ for g in wheel sudo docker disk; do m=$(getent group $g); if [ -n "$m" ]; then echo "$g -> 구성원[$(echo $m|cut -d: -f4)]"; else echo "$g -> (그룹 없음)"; fi; done
wheel -> 구성원[]
sudo -> (그룹 없음)
docker -> (그룹 없음)
disk -> 구성원[]

6. 결과 해석

출력해석
devops:x:1001:alice,bob,analystGID 1001, 세 명이 보조 그룹으로 속함
root:x:0:root 그룹, 구성원 목록 비어 있음(root의 기본 그룹이라 별도 표기 불필요)
id analyst → ...,1001(devops)analyst의 보조 그룹에 devops 포함
alice GID: 100alice의 기본 그룹은 users(100)
getent group 100 → users:x:100:users 그룹 줄에 alice가 없다 — 기본 그룹은 passwd로만 기록
wheel -> 구성원[]wheel 그룹 존재하나 구성원 없음 (Rocky 기본)
sudo -> (그룹 없음)Rocky에는 sudo 그룹이 없음 (Ubuntu는 있음)
docker -> (그룹 없음)docker 미설치

alice GID: 100과 users:x:100:(alice 없음)의 조합이 이번 실습의 핵심이다. alice는 분명 users 그룹에 속하지만, /etc/group의 users 줄에는 나오지 않는다. 기본 그룹은 passwd, 보조 그룹은 group 이라는 분리를 보여 준다.

wheel/sudo 차이도 배포판 포인트다. RHEL 계열은 wheel, Debian/Ubuntu 계열은 sudo 그룹이 관리자 그룹이다(41·42편).


7. 보안 관점

그룹부여되는 권한
wheel(RHEL)/sudo(Debian)sudo로 관리자 명령 실행
docker컨테이너로 호스트 root 접근 = 사실상 root
disk디스크 장치 직접 접근 = 파일 권한 우회
shadow/etc/shadow 읽기 = 해시 접근
adm로그 파일 읽기

점검 원칙: 이들 그룹의 구성원은 최소화하고 정기 확인한다. 공격자가 root를 얻은 뒤 자신의 계정을 wheel/sudo/docker에 추가 하는 것은 흔한 지속성(persistence) 기법이다. /etc/group 변경 시각과 구성원을 Baseline과 비교한다.


8. 보안관제 관점

[Baseline]  민감 그룹 구성원 저장
   for g in wheel sudo docker disk shadow adm; do getent group $g; done > baseline/groups.txt
     ↓
[정기 점검] 현재와 비교
   diff <(for g in wheel sudo docker disk shadow adm; do getent group $g; done) baseline/groups.txt
     ↓
[Detection] /etc/group·/etc/gshadow 변경, gpasswd/usermod 실행(auditd)
     ↓
[Evidence]  변경 시각(stat), secure/auth.log 의 그룹 추가 기록
     ↓
[Response]  무단 멤버십 제거(gpasswd -d user group), 경위 조사(49편)
관점내용
IOC민감 그룹에 예상 밖 계정 추가
Detectionusermod -aG, gpasswd -a 실행을 감시
Baselinewheel/sudo/docker 정상 구성원 목록 관리(48편)

9. 실무에서 자주 발생하는 실수

실수결과예방
/etc/group만 보고 멤버십 판단기본 그룹 누락id user로 확인
usermod -G에서 -a 누락기존 보조 그룹 삭제항상 -aG
편의로 docker/wheel 추가사실상 root 부여최소 권한
/etc/group 직접 편집손상gpasswd/usermod
민감 그룹 미점검은닉 권한 상승정기 점검

10. 실습 체크리스트

[ ] /etc/group 4개 필드를 해석했다
[ ] 기본 그룹과 보조 그룹의 차이를 설명할 수 있다
[ ] 기본 그룹이 group 파일에 안 나오는 것을 확인했다
[ ] id user 로 전체 그룹을 확인했다
[ ] wheel/sudo 배포판 차이를 안다
[ ] 민감 그룹 구성원 점검 방법을 안다

11. 핵심 정리

  • /etc/group은 그룹명·x·GID·구성원 4개 필드다.
  • 4번 필드는 그 그룹을 보조 그룹 으로 가진 사용자 목록이다.
  • 기본 그룹은 /etc/passwd의 GID 로 결정되고 group 파일 구성원에 안 나온다.
  • 사용자의 전체 그룹은 id user로 확인한다.
  • wheel/sudo·docker·disk·shadow 그룹은 강력한 권한이다.
  • 민감 그룹 구성원을 최소화하고 무단 추가를 지속성 흔적으로 점검한다.

12. 다음 편 예고

다음 글 「35. useradd로 사용자 생성」 에서는 계정을 만드는 useradd의 전체 과정을 다룬다. 홈 디렉터리 생성과 skel 복사, UID 자동 할당, 그리고 시스템 계정(-r)과 로그인 불가 셸 설정을 실습한다.


참고 자료


시리즈 이동

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글