Skip to content
ioob.dev
Go back

Linux 기초 2편 — 파일 권한과 사용자/그룹

· 9분 읽기
Linux 시리즈 (2/8)
  1. Linux 기초 1편 — 셸과 파일시스템 구조
  2. Linux 기초 2편 — 파일 권한과 사용자/그룹
  3. Linux 기초 3편 — 프로세스와 시그널
  4. Linux 기초 4편 — 텍스트 처리와 파이프
  5. Linux 기초 5편 — 네트워크 도구
  6. Linux 기초 6편 — Systemd와 서비스 관리
  7. Linux 기초 7편 — 패키지 관리
  8. Linux 기초 8편 — Bash 스크립팅 기초
Table of contents

Table of contents

권한이 왜 이렇게까지 까다로운가

서버에 배포 스크립트를 올렸더니 Permission denied가 떠서 실행이 안 된다. 남이 올린 파일을 수정하려고 하니 “그건 네 것이 아니다”라고 거부당한다. 도대체 왜 이렇게 매번 막히는지, 그리고 왜 이 시스템이 이렇게 생겼는지 — Linux를 처음 만지는 사람이라면 누구나 한 번쯤 짜증내본 길이다.

답은 단순하다. Linux는 처음부터 여러 사용자가 하나의 머신을 공유하는 환경을 전제로 설계됐다. 1970년대 UNIX가 돌던 미니컴퓨터에는 수십 명의 사용자가 동시에 접속해 작업했다. 누군가가 남의 파일을 망가뜨리지 못하도록, 시스템 파일을 일반 사용자가 건드리지 못하도록 — 그 보호막이 파일 권한이다. 이 구조는 50년이 지난 지금도 거의 그대로 살아남았다.

이번 편은 ls -l을 쳤을 때 왼쪽에 뜨는 알 수 없는 기호들을 해독하는 데서 시작한다.

사용자, 그룹, 그리고 나머지

Linux의 모든 파일에는 세 종류의 “관계자”가 있다.

flowchart LR
    FILE["파일 또는 디렉토리"]
    FILE --> OWNER["소유자<br/>(owner / user)"]
    FILE --> GROUP["그룹<br/>(group)"]
    FILE --> OTHER["나머지 전부<br/>(others / world)"]

각 관계자마다 파일에 대해 할 수 있는 행위를 읽기(r), 쓰기(w), 실행(x) 세 가지로 쪼개서 허용/거부한다. 3×3 = 9개의 비트로 접근 권한이 완성된다.

내가 속한 그룹을 확인하는 명령은 id다.

id
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),999(docker)

groups
# alice sudo docker

alice는 자기 이름의 기본 그룹(primary group)에 속하면서, sudodocker 그룹에도 부가적으로 소속되어 있다. Docker 소켓에 접근하려면 docker 그룹에 들어가야 하는 이유가 이 구조에서 나온다.

ls -l의 9글자를 해독한다

ls -l 출력의 맨 앞부분을 다시 꺼내보자.

-rwxr-xr--  1 alice  developers  1024  Apr 20 10:30  deploy.sh

앞에서 언급했듯 첫 글자(-)는 파일 종류다. 그 뒤 9글자가 권한이고, 세 글자씩 세 그룹으로 쪼갠다.

-   rwx   r-x   r--
│    │     │     │
│    │     │     └── others: 읽기만 가능
│    │     └──────── group: 읽기·실행
│    └────────────── owner: 읽기·쓰기·실행
└─────────────────── 일반 파일

디렉토리에서 x가 없으면 cd로 진입 자체가 안 된다. 반대로 r만 있고 x가 없는 디렉토리는 ls로 이름은 볼 수 있어도 그 안의 파일에 접근할 수 없는 묘한 상태가 된다. 두 권한이 조합되면서 생기는 미묘한 차이는 처음엔 헷갈리니 한번 직접 만들어보는 게 낫다.

chmod — 권한을 바꾼다

권한 변경은 chmod(CHange MODe)로 한다. 두 가지 문법이 있다.

기호 모드 — 사람이 읽기 쉽다

사용자 종류 + 연산자 + 권한 형식으로 쓴다.

# 사용자 종류: u(user/owner) g(group) o(others) a(all)
# 연산자:      + (추가) - (제거) = (정확히 이것만)
# 권한:        r w x

chmod u+x deploy.sh          # 소유자에게 실행 권한 추가
chmod g-w notes.txt          # 그룹의 쓰기 권한 제거
chmod o=r secret.env         # 나머지는 읽기만
chmod a+r public.md          # 모두에게 읽기 권한 추가
chmod u=rwx,g=rx,o=r file    # 복수 지정, 쉼표로 구분

숫자 모드 — 한 번 익히면 훨씬 빠르다

각 자리수를 3비트 이진수로 보는 방법이다. r=4, w=2, x=1을 더한다.

권한           이진    십진
---            ---     ---
rwx            111      7
rw-            110      6
r-x            101      5
r--            100      4
-wx            011      3
-w-            010      2
--x            001      1
---            000      0

이걸 세 자리(owner, group, other)로 늘어놓은 게 숫자 모드다.

chmod 755 deploy.sh
# owner=rwx(7), group=r-x(5), other=r-x(5)

chmod 644 notes.txt
# owner=rw-(6), group=r--(4), other=r--(4)

chmod 600 ~/.ssh/id_rsa
# owner만 읽고 쓸 수 있다. SSH 개인키는 반드시 600이어야 동작한다

실무에서 자주 보는 조합이 몇 가지 있다.

재귀적으로 적용할 땐 -R 옵션을 쓴다. 다만 파일과 디렉토리에 같은 권한을 주면 문제가 생긴다 — 디렉토리엔 x가 필요하지만 파일엔 불필요한 x가 붙기 때문이다. 이런 경우 find와 조합한다.

# 디렉토리만 755, 파일만 644로
find /path/to/dir -type d -exec chmod 755 {} \;
find /path/to/dir -type f -exec chmod 644 {} \;

chown — 소유자를 바꾼다

소유자 혹은 소유 그룹을 바꾸는 명령이 chown(CHange OWNer)이다. 보통 root 권한이 필요하다.

# 소유자만 바꾸기
sudo chown alice file.txt

# 소유자와 그룹을 한 번에 (콜론으로 구분)
sudo chown alice:developers file.txt

# 그룹만 바꿀 땐 콜론 앞을 비우거나 chgrp를 쓴다
sudo chown :developers file.txt
sudo chgrp developers file.txt

# 재귀적으로
sudo chown -R alice:developers /var/www/site

웹 서버를 운영할 때 “파일은 내 계정이 올리되, 실행은 www-data 사용자가 한다”라는 시나리오가 흔하다. 이럴 때 소유자는 내 계정으로 두고, 그룹을 www-data로 바꾸고, 그룹에 읽기/실행 권한을 주는 식으로 설계한다.

sudo — 필요한 순간에만 권한을 빌린다

Linux의 최고 관리자는 root 사용자(UID 0)다. 하지만 root로 평소에 로그인해 있는 건 위험하다. 오타 하나로 시스템이 날아갈 수 있고, 실수로 지운 파일을 복구할 방법이 없는 경우도 많다.

그래서 나온 게 sudo(SuperUser DO)다. 평소엔 일반 사용자로 있다가, 관리자 권한이 필요한 명령 하나에만 root의 힘을 빌린다.

# 일반 사용자로 시도 — 거부당함
apt install nginx
# Permission denied

# sudo를 앞에 붙여 한 번만 root 권한
sudo apt install nginx

# root 셸로 아예 넘어가기 (신중하게)
sudo -i
# 또는
sudo su -

sudo를 쓸 수 있는 사용자는 /etc/sudoers 파일(혹은 /etc/sudoers.d/ 안의 파일)에 정의되어 있다. 배포판마다 기본적으로 sudo 또는 wheel 그룹에 속한 사용자가 sudo를 쓸 수 있게 설정되어 있다.

sudoers 파일은 절대 vi로 직접 편집하면 안 된다. 문법 오류가 생기면 시스템이 잠길 수 있다. 반드시 visudo를 써야 한다 — 저장 시 문법 체크를 한 번 해준다.

sudo visudo

umask — 새 파일의 기본 권한을 결정한다

touch new.txt로 빈 파일을 만들면 기본 권한이 어떻게 될까? 대개 644(rw-r--r--)다. 이 기본값을 결정하는 게 umask(User MASK)다.

umask는 “빼낼 권한”을 지정한다. 새 파일의 “잠재적 최대 권한”에서 umask 값을 빼는 방식이다.

일반적인 umask022라고 하자.

파일:    666 - 022 = 644  (rw-r--r--)
디렉토리: 777 - 022 = 755  (rwxr-xr-x)

현재 umask 값과 설정법은 이렇다.

umask
# 0022

# 더 엄격한 값으로 바꾸기 — 그룹/기타 쓰기 권한 완전 차단
umask 077

# 새로 만든 파일을 확인
touch test.txt
ls -l test.txt
# -rw-------  1 alice  alice  0  Apr 20 10:30  test.txt

077로 설정하면 새 파일은 600, 새 디렉토리는 700으로 만들어진다. 서버를 공유하는 환경에서 개인 데이터 보호가 중요하다면 ~/.bashrc~/.zshrcumask 077을 박아두는 게 흔한 패턴이다.

주의할 점. umask이미 존재하는 파일의 권한을 바꾸지 않는다. 어디까지나 “앞으로 새로 만들어질 파일의 기본값”에만 영향을 준다.

SUID, SGID, Sticky bit — 특수 권한 3형제

가끔 ls -l 출력에 s 또는 t가 섞여 있는 걸 본다. 이것들이 특수 권한 비트다. 숫자 모드로는 네 자리 중 맨 앞자리로 표현한다(4xxx, 2xxx, 1xxx).

SUID (Set User ID) — 소유자의 권한으로 실행

실행 파일에 SUID가 붙어 있으면, 누가 실행하든 파일 소유자의 권한으로 동작한다. 소유자 위치의 xs로 바뀐다.

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root  68208 Feb  5 11:35  /usr/bin/passwd

passwd 명령은 일반 사용자가 자기 비밀번호를 바꾸는 도구다. 그런데 실제 비밀번호는 /etc/shadow 파일에 저장돼 있고, 이 파일은 root만 쓸 수 있다. 해결책이 SUID다. passwd 바이너리에 SUID가 걸려 있어서, 일반 사용자가 실행해도 일시적으로 root 권한을 얻어 /etc/shadow를 고친다.

SUID는 힘이 센 만큼 보안 관점에서 가장 위험한 비트다. SUID가 걸린 바이너리에 취약점이 있으면 권한 상승(privilege escalation)의 통로가 된다. 내 서버에 있는 SUID 바이너리 목록을 한 번쯤 훑어두는 게 좋다.

sudo find / -perm -4000 -type f 2>/dev/null

SUID 설정은 chmod u+s 또는 chmod 4xxx로 한다.

SGID (Set Group ID) — 그룹 권한 승계

디렉토리에 SGID가 걸리면, 그 디렉토리 안에서 새로 만드는 파일은 자동으로 그 디렉토리의 그룹을 상속한다. 그룹 위치의 xs로 바뀐다.

sudo mkdir /shared
sudo chown alice:developers /shared
sudo chmod 2775 /shared         # 앞자리 2가 SGID
# drwxrwsr-x  alice  developers  /shared

# 이제 누가 만들든 파일의 그룹은 developers가 된다
cd /shared && touch file.txt
ls -l file.txt
# -rw-r--r-- bob developers ... file.txt

팀이 공유하는 작업 폴더를 만들 때 유용하다. 각자가 어느 그룹으로 로그인했든, 그 폴더 안에 만든 파일은 모두 같은 그룹을 갖는다.

Sticky bit — 내 것만 지울 수 있다

/tmp의 권한을 보면 특이한 게 있다.

ls -ld /tmp
# drwxrwxrwt  root root  /tmp

맨 끝이 x가 아니라 t다. 이것이 sticky bit다. 모두가 쓸 수 있는 디렉토리인데, 자기가 만든 파일만 자기가 지울 수 있게 제한하는 장치다. /tmp처럼 세상 모든 사용자가 임시 파일을 쓰는 곳에서, 다른 사용자의 파일을 삭제하지 못하게 막는 역할이다.

chmod +t mydir
chmod 1777 mydir

권한 디버깅 — 실무에서 막힐 때

“실행이 안 돼요” 할 때 한 번쯤 돌아볼 체크리스트.

  1. 파일 자체에 x가 있는가? ls -l script.sh로 확인. 없으면 chmod +x
  2. 파일이 있는 디렉토리에 x가 있는가? 디렉토리 x가 없으면 그 안의 파일에 접근할 수 없다
  3. 상위 디렉토리들의 x는 다 있는가? /home/alice/scripts/run.sh를 실행하려면 /, /home, /home/alice, /home/alice/scripts 모두 x가 있어야 한다
  4. SELinux나 AppArmor가 걸려 있지 않은가? 특히 RHEL 계열에서 ls -l로 봤을 때 권한이 멀쩡한데도 접근이 막히면 SELinux 컨텍스트를 의심한다 (ls -Z)
  5. 파일시스템 마운트 옵션에 noexec가 붙어있진 않은가? /tmp 같은 곳이 noexec로 마운트돼 있으면 스크립트 실행이 원천 차단된다 (mount | grep /tmp)

권한 문제는 대부분 1번과 3번에서 걸린다. 특히 3번 — 상위 디렉토리의 x 는 초보가 가장 놓치기 쉬운 지점이다.

이번 편 복기

간단히 정리해본다.

다음 편에서는 파일과 권한의 세계를 넘어 프로세스로 넘어간다. PID, 시그널, 백그라운드 실행까지 — 리눅스에서 “실행 중”이라는 말이 무슨 뜻인지 파고든다.

3편: 프로세스와 시그널


Related Posts

Share this post on:

Comments

Loading comments...


Previous Post
Linux 기초 1편 — 셸과 파일시스템 구조
Next Post
Linux 기초 3편 — 프로세스와 시그널