실행 계정과 파일 권한
90분 안팎
학습 목표
서비스 파일의 읽기·쓰기·실행 범위를 구분합니다.
개념
왜 실행 계정부터 확인할까요
설정을 읽지 못하면 파일이 있다는 사실만으로 원인을 알 수 없습니다. 운영 서비스는 사람이 로그인한 계정과 다른 계정으로 실행되기도 합니다. 파일 소유자와 실제 실행 계정이 맞는지 먼저 확인하고 필요한 권한만 부여합니다. 이 레슨에서는 새 시스템 계정을 만들거나 계정을 전환하지 않습니다. 개인 실습 계정이 소유한 작업 폴더의 권한을 직접 조정하여 읽기·쓰기·실행이 각각 어떤 작업을 허용하는지 익힙니다. 이후 서비스 계정 분리는 별도 모듈에서 확장합니다.
권한 표기를 읽습니다
ls -l의 첫 칸에는 파일 종류와 권한이 표시됩니다. 일반 파일은 -로, 디렉터리는 d로 시작합니다. 뒤의 아홉 자리는 소유자·그룹·기타의 읽기 r, 쓰기 w, 실행 x입니다. 해당 권한이 없으면 -가 표시됩니다. 숫자 표기는 읽기 4, 쓰기 2, 실행 1의 합입니다. 600은 소유자 읽기와 쓰기만, 700은 소유자 읽기·쓰기·실행만 허용합니다. 소유자가 아닌 계정에 600 파일의 읽기를 허용한 것으로 해석하면 안 됩니다. id와 ls -l을 함께 읽어 적용 대상을 구분합니다.
파일과 디렉터리의 x는 다릅니다
일반 파일의 x는 프로그램으로 직접 실행할 권한입니다. 디렉터리의 x는 그 경로를 통과하고 내부 항목에 접근하는 권한입니다. 디렉터리의 r은 내부 이름을 나열하는 권한이며 w는 항목 생성·삭제 같은 변경에 관계됩니다. 안쪽 설정 파일이 읽기 가능해도 상위 디렉터리를 통과할 수 없으면 읽기에 실패할 수 있습니다. 이번 프로젝트는 workspace를 700으로 닫고 그 안의 app.env를 600으로 둡니다. 이 조합은 같은 소유 계정이 준비와 읽기 작업을 맡는 실습 계약입니다.
직접 실행과 해석기 실행을 비교합니다
./scripts/read-config.sh는 실행 비트와 첫 줄의 해석기 지정에 영향을 받습니다. bash scripts/read-config.sh는 Bash가 파일을 읽어 실행하므로 스크립트 자체의 실행 비트가 없어도 읽기 권한이 있으면 실행할 수 있습니다. 따라서 bash로 실행해 성공했다는 사실만으로 직접 실행 권한을 검증하지 않습니다. 검사기는 read-config.sh를 직접 실행하고 설정을 읽을 수 있는지 확인합니다. 설정 값은 출력하지 않고 config readable이라는 진단만 출력해 접근 가능성과 내용 공개를 구분합니다.
권한을 넓히기 전에 필요한 작업을 정합니다
설정에는 실행 권한이 필요하지 않고 스크립트에는 직접 실행을 위한 x가 필요합니다. chmod 600 workspace/app.env와 chmod 700 scripts/read-config.sh처럼 파일 역할에 따라 대상을 지정합니다. chmod 777로 모든 사용자에게 쓰기를 열면 실습은 성공할 수 있지만 다른 계정이 설정을 수정할 수 있게 됩니다. chmod -R로 설정과 데이터 전체를 한 번에 같은 권한으로 바꾸지 않습니다. 이번 검사기는 정확한 모드를 비교하므로 과도한 권한도 실패로 판단합니다. 접근 성공만이 안전한 권한 설계의 증거는 아닙니다.
Permission denied를 읽습니다
오류가 난 경로를 보고 ls -ld workspace, ls -l workspace/app.env, id 순서로 디렉터리와 파일·계정을 확인합니다. 파일의 소유자가 다른 경우 본인 파일인지부터 확인하고 관리 권한으로 우회하지 않습니다. 이 실습은 본인 소유 파일만 대상으로 합니다. 권한 비트가 맞는데도 실패하면 읽기 전용 파일 시스템이나 추가 접근 정책 같은 다른 조건을 조사해야 합니다. root는 일반 사용자와 다르게 권한 제한을 우회할 수 있어 권한 재현에 적합하지 않습니다. 일반 사용자로 수행했다는 전제를 기록합니다.
검사의 범위를 설명합니다
시작 코드는 권한을 조정하지 않으므로 검사기가 준비한 644 설정과 755 디렉터리를 그대로 남깁니다. prepare.sh에 역할에 맞는 chmod를 추가하면 숫자 모드 검사와 직접 실행 검사가 통과합니다. 검사기는 다른 사용자 계정을 생성하지 않으며 소유자·그룹·기타 비트와 같은 계정의 읽기를 검증합니다. 다른 계정의 실제 접근 거부까지 확인했다고 보고하지 않습니다. 접근 제어 목록과 확장 권한의 상세 설명은 서재에 맡기고 여기서는 미션에서 사용할 기본 권한 계약을 완성합니다.
기존 파일의 권한과 생성 기본값
umask는 새 파일을 만들 때 요청된 권한에서 일부 비트를 제외하는 기본값입니다. 이미 존재하는 파일의 모드는 umask를 바꾸어도 바뀌지 않습니다. 따라서 설정 예시를 복사한 뒤 실제 app.env에 chmod를 적용해야 합니다. cp가 기존 목적지 파일을 덮어쓸 때와 새 목적지를 만들 때 권한 결과는 다를 수 있으므로 복사 명령이 끝났다는 이유만으로 600이라고 판단하지 않습니다. ls -l로 결과를 확인하고 준비 스크립트가 반복 호출되어도 동일한 권한 계약을 만드는지 검사합니다. 기본값과 최종 상태를 구분하면 다른 셸에서 실행했을 때 생기는 차이를 설명할 수 있습니다.
디렉터리 쓰기와 파일 쓰기를 구분합니다
파일의 w는 그 파일 내용을 수정하는 권한입니다. 파일 이름을 삭제하거나 다른 이름으로 바꾸는 작업은 부모 디렉터리의 권한과 관련됩니다. 읽기 전용 파일이라도 부모 디렉터리에 쓰기와 탐색 권한이 있으면 삭제할 수 있는 경우가 있으므로 파일의 600만으로 삭제 방지를 설명하지 않습니다. sticky bit나 접근 제어 목록은 별도 조건입니다. 이번 workspace의 700은 다른 계정이 디렉터리에 진입하거나 항목을 변경하는 범위를 닫는 기본 설계입니다. 실제 서비스 계정으로 전환하지 않은 검사 결과는 같은 계정의 접근 성공과 모드 확인으로 기록합니다.
실습에서 적용할 구현
scripts/prepare.sh에 디렉터리 700, 설정 600, 직접 실행 스크립트 700을 적용합니다. ROOT로 경로를 지정하여 호출 위치에 관계없이 같은 대상의 권한을 조정합니다.
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
chmod 700 "$ROOT/workspace"
chmod 600 "$ROOT/workspace/app.env"
chmod 700 "$ROOT/scripts/read-config.sh"
printf 'permissions ready\n'
따라하기
권한 조정
모범 답안 zip을 새 폴더에 푼 루트에서 실행합니다. 시작 코드는 아래 검사에서 실패하며 실습에서 수정합니다. 권한 조정 단계를 먼저 수행합니다.
cp workspace/app.example.env workspace/app.env
bash scripts/prepare.sh실행 결과
permissions ready
직접 실행과 읽기
첫 단계에서 설정 복사와 권한 조정을 마친 같은 폴더에서 실행합니다. 파일 내용 대신 읽기 성공 진단만 출력합니다.
./scripts/read-config.sh실행 결과
config readable
권한과 노출 범위 검사
모범 답안 zip을 새 폴더에 푼 루트에서 실행합니다. 시작 코드는 아래 검사에서 실패하며 실습에서 수정합니다. 권한 조정 단계를 먼저 수행합니다.
cp workspace/app.example.env workspace/app.env
bash check.sh실행 결과
PASS example config exists PASS permission setup succeeds PASS mode workspace PASS mode workspace/app.env PASS mode scripts/read-config.sh PASS owner executes and reads without disclosure RESULT: 0 failure(s)
확인 문제
실습
시작 코드 zip을 개인 폴더에 풀고 README를 읽은 뒤 bash check.sh로 실패 항목을 확인합니다. scripts/prepare.sh에 chmod를 추가해 workspace는 700, app.env는 600, read-config.sh는 700으로 맞춥니다. 설정 내용을 출력하지 않고 직접 실행으로 읽기 가능 여부를 확인합니다. 검사기는 복사본에서 정상·경계 상황을 확인합니다. check.sh와 check.py는 수정하지 않습니다.
실행 명령
bash check.sh
기대 결과
모든 항목 PASS, RESULT: 0 failure(s), 종료 상태 0
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 파일과 디렉터리의 실행 권한은 각각 무엇을 의미하나요?
- 설정 파일 600과 작업 디렉터리 700을 함께 사용하는 이유는 무엇인가요?