리눅스 권한 체계
Linux는 모든 것이 파일입니다. 일반 파일, 디렉토리, 장치, 소켓까지 파일로 표현됩니다. 따라서 파일 권한 체계가 곧 시스템 보호의 기초입니다. 이 권한 체계는 40년 넘게 Unix의 핵심으로 동작해 왔습니다.
사용자, 그룹, 기타
Linux 파일 권한은 세 범주로 나뉩니다.
- 소유자(Owner, u): 파일을 만든 사용자
- 그룹(Group, g): 소유자가 속한 그룹의 멤버들
- 기타(Others, o): 나머지 모든 사용자
각 범주에 세 가지 권한이 있습니다.
| 권한 | 비트 | 파일에 대한 효과 | 디렉토리에 대한 효과 |
|---|---|---|---|
| 읽기(r) | 4 | 파일 내용 읽기 | 디렉토리 목록 보기(ls) |
| 쓰기(w) | 2 | 파일 내용 수정 | 파일 생성·삭제·이름 변경 |
| 실행(x) | 1 | 프로그램으로 실행 | 디렉토리에 진입(cd) |
디렉토리의 권한은 파일과 의미가 다릅니다. 디렉토리에 읽기 권한만 있으면 파일 목록은 볼 수 있지만, 파일의 내용이나 상세 정보(크기, 시각)는 볼 수 없습니다(inode 접근에 x가 필요). 실행 권한이 없으면 cd로 디렉토리에 진입할 수 없습니다. 즉 디렉토리에 rx가 함께 있어야 실질적으로 내용을 볼 수 있습니다.
ls -la
# -rw-r--r-- 1 user group 1024 Jan 15 10:30 report.txt
# │├──┤├──┤├──┤
# │ u g o
# └ 파일 유형 (- = 일반, d = 디렉토리, l = 심볼릭 링크)
# drwxr-x--- 디렉토리: 소유자 rwx, 그룹 rx, 기타 접근불가rw-r--r--은 소유자가 읽기+쓰기, 그룹과 기타는 읽기만 가능하다는 뜻입니다. 숫자(8진수)로 표현하면 644입니다 (6=4+2, 4=4, 4=4).
권한 확인 순서
프로세스가 파일에 접근할 때, 커널은 다음 순서로 권한을 확인합니다.
- 프로세스의 EUID(유효 사용자 ID)가 파일 소유자와 같으면 → 소유자 권한 적용
- 프로세스의 EGID가 파일 그룹과 같으면 → 그룹 권한 적용
- 둘 다 아니면 → 기타 권한 적용
중요: 소유자가 그룹에도 속하지만, 소유자 권한이 먼저 평가됩니다. 소유자 권한이 rw-이고 그룹 권한이 rwx인 경우, 소유자는 실행 불가입니다.
chmod, chown, umask
# 숫자 방식 (8진수)
chmod 755 script.sh # rwxr-xr-x
chmod 600 secret.key # rw-------
chmod 644 readme.txt # rw-r--r--
# 기호 방식
chmod u+x script.sh # 소유자에 실행 권한 추가
chmod go-w secret.txt # 그룹과 기타에서 쓰기 권한 제거
chmod a+r public.txt # 모두(all)에게 읽기 권한 추가
chmod o= private.txt # 기타의 모든 권한 제거
# 재귀적 변경
chmod -R 755 /var/www/html#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int main() {
/* 파일 생성 후 권한 변경 */
FILE *fp = fopen("test.txt", "w");
fprintf(fp, "sensitive data\n");
fclose(fp);
/* 소유자만 읽기/쓰기 가능하게 변경 */
chmod("test.txt", S_IRUSR | S_IWUSR); /* 0600 */
/* 권한 확인 */
if (access("test.txt", R_OK) == 0)
printf("읽기 가능\n");
if (access("test.txt", X_OK) != 0)
printf("실행 불가 (errno=%d)\n", errno);
return 0;
}# 소유자와 그룹 변경 (root만 가능)
chown user:group file.txt
chown -R www-data:www-data /var/www # 재귀적 변경
# 그룹만 변경
chgrp developers project/umask
umask는 새로 생성되는 파일의 기본 권한에서 제거할 권한을 지정합니다. 파일의 기본 권한은 666, 디렉토리는 777입니다.
| umask | 파일 결과 | 디렉토리 결과 | 의미 |
|---|---|---|---|
| 022 | 644 (rw-r--r--) | 755 (rwxr-xr-x) | 기본 (기타 쓰기 방지) |
| 027 | 640 (rw-r-----) | 750 (rwxr-x---) | 기타 접근 완전 차단 |
| 077 | 600 (rw-------) | 700 (rwx------) | 소유자만 접근 |
umask # 현재 umask 확인 (보통 0022)
umask 027 # 설정: 기타 사용자의 모든 권한 제거
touch new_file.txt # 640으로 생성됨
mkdir new_dir # 750으로 생성됨SetUID, SetGID, Sticky Bit
일반 권한 외에 세 가지 특수 권한이 있습니다.
SetUID (4000)
이 비트가 설정된 실행 파일은 실행 시 파일 소유자의 권한으로 실행됩니다. passwd 명령이 대표적입니다. 일반 사용자가 passwd를 실행하면 root 권한으로 /etc/shadow를 수정할 수 있습니다.
# SetUID가 설정된 파일 찾기
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 59640 ... /usr/bin/passwd
# ^ s = SetUID + 실행 권한
# 시스템에서 SetUID 파일 전체 검색 (보안 감사)
find / -perm -4000 -type f 2>/dev/null
# /usr/bin/passwd
# /usr/bin/sudo
# /usr/bin/su
# /usr/bin/newgrpSetUID는 편리하지만 보안 위험이 큽니다. SetUID root 프로그램에 취약점이 있으면 root 권한 탈취로 이어집니다. 불필요한 SetUID는 제거해야 합니다.
SetGID (2000)
파일에 설정하면 실행 시 파일 그룹의 권한으로 실행됩니다. 디렉토리에 설정하면 더 유용합니다 — 그 안에 생성되는 모든 파일과 디렉토리가 부모 디렉토리의 그룹을 상속합니다.
# 팀 공유 디렉토리 설정
mkdir /shared/project
chgrp developers /shared/project
chmod 2775 /shared/project # SetGID + rwxrwxr-x
# 이제 누가 파일을 만들든 그룹은 developers
touch /shared/project/test.txt
ls -la /shared/project/test.txt
# -rw-rw-r-- 1 alice developers ... test.txtSticky Bit (1000)
디렉토리에 설정하면, 해당 디렉토리의 파일은 파일 소유자와 디렉토리 소유자만 삭제할 수 있습니다. /tmp에 설정되어 있어 다른 사용자의 임시 파일을 삭제하지 못하게 합니다.
ls -ld /tmp
# drwxrwxrwt 18 root root 4096 ... /tmp
# ^ t = Sticky Bit + 실행 권한
# Sticky Bit 없으면: /tmp에 쓰기 권한이 있는 모든 사용자가
# 다른 사용자의 파일도 삭제 가능 (매우 위험!)sudo와 root 권한 관리
root(UID 0)는 모든 권한 검사를 우회합니다. root로 직접 로그인하는 것은 위험합니다. 실수 하나(rm -rf / 오타)로 시스템 전체가 망가질 수 있습니다.
sudo는 일반 사용자가 특정 명령만 root 권한으로 실행할 수 있게 합니다. /etc/sudoers 파일에 정책을 정의합니다.
# /etc/sudoers (visudo로만 편집!)
# 사용자 alice는 모든 명령을 root로 실행 가능
alice ALL=(ALL:ALL) ALL
# 사용자 deploy는 systemctl만 root로 실행 가능
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl restart app
# dev 그룹은 docker 명령만 실행 가능
%dev ALL=(root) /usr/bin/dockersudo apt update # root 권한으로 패키지 업데이트
sudo -u postgres psql # postgres 사용자로 psql 실행
sudo -l # 내가 실행할 수 있는 명령 목록
# sudo 로그 확인 (감사 추적)
grep sudo /var/log/auth.log보안 모범 사례
- root 직접 로그인 비활성화 (
/etc/ssh/sshd_config에서PermitRootLogin no) - sudo를 통해 최소한의 명령만 허용
- SSH 키 기반 인증 사용 (패스워드 비활성화)
- 2FA(Two-Factor Authentication) 적용
- 정기적으로 SetUID 파일 감사
프로세스 권한의 실제
프로세스에는 여러 ID가 있습니다.
| ID | 이름 | 용도 |
|---|---|---|
| RUID | 실제 사용자 ID | 프로세스를 시작한 사용자 |
| EUID | 유효 사용자 ID | 접근 제어 시 사용되는 ID |
| SUID | 저장된 사용자 ID | SetUID 실행 시 원래 EUID 저장 |
일반적으로 RUID = EUID입니다. SetUID 파일을 실행하면 EUID가 파일 소유자 ID로 바뀝니다. 프로그램은 seteuid()로 SUID에 저장된 원래 권한으로 돌아갈 수 있습니다.
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Real UID: %d\n", getuid());
printf("Effective UID: %d\n", geteuid());
/* SetUID root 프로그램에서:
* getuid() = 1000 (일반 사용자)
* geteuid() = 0 (root) */
/* 특권 작업 완료 후 권한 내려놓기 (보안!) */
/* seteuid(getuid()); */
return 0;
}다음 절에서는 OS를 위협하는 보안 공격과 방어 기법을 살펴보겠습니다.