SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor

Linux umask 설정 및 파일 권한 확인 방법

Linux에서 umask가 파일과 디렉터리 생성 권한에 미치는 영향을 설명합니다. umask 명령어로 현재 마스크를 확인하고, 파일 생성 시 권한 비트가 어떻게 제거되는지 실습을 통해 상세히 알아봅니다. root와 일반 사용자의 권한 차이가 발생하는 원인을 정확히 파악하십시오.

Linux에서 umask의 역할

umask는 Linux의 모든 프로세스가 가지는 숫자이며, 해당 프로세스가 생성하는 각 파일과 디렉터리의 모드를 결정합니다. 프로그램은 생성 시점에 커널에 일련의 권한을 요청합니다. 커널은 마스크에 지정된 모든 비트를 제거하고 남은 비트를 적용합니다. umask는 결코 접근 권한을 부여하지 않습니다. 단지 생성 프로그램이 요청한 권한에서 비트를 제거할 뿐입니다.

이 값은 배포판의 속성이 아닙니다. 어떤 계정인지, 그리고 셸이 어떻게 시작되었는지에 따라 달라집니다. 동일한 머신에서 동일한 시점이라도, 기본 이미지 상태에서 이 두 가지 답변은 서로 다를 수 있습니다. 따라서 첫 번째 단계는 매뉴얼을 찾아보는 것이 아닙니다. 현재 사용 중인 시스템에서 직접 측정하는 것입니다.

현재 셸의 umask 출력하기

umask
umask -S

첫 번째 형식은 마스크를 8진수로 출력합니다. 두 번째 형식은 동일한 마스크를 chmod이 허용하는 기호 형식의 권한으로 출력합니다. 두 줄 모두 화면에 유지하십시오. 아래의 모든 내용은 방금 셸이 출력한 값과의 비교입니다.

umask는 셸 내장 명령어이며 디스크상의 프로그램이 아닙니다. type umask을 사용하여 이를 확인하십시오. 내장 명령어는 셸 프로세스 자체를 변경하기 때문에 중요합니다. 별도의 프로그램은 자신의 프로세스만 변경할 수 있으며, 종료 시 변경 사항도 함께 사라집니다.

파일과 디렉터리를 생성하고 모드 확인하기

cd "$(mktemp -d)"
touch probe.file
mkdir probe.dir
stat -c '%a %A %n' probe.file probe.dir

%a는 모드를 8진수로 출력하며, %Als -l이 사용하는 drwxr-xr-x 형식으로 동일한 모드를 출력합니다. 두 줄을 방금 출력한 마스크와 비교해 보십시오. 마스크에 설정된 모든 비트는 모드에서 빠져 있습니다. 마스크의 유일한 역할은 해당 비트를 제거하는 것이기 때문입니다. %A 열을 읽는 것이 아직 익숙하지 않다면, drwxr-xr-x 권한 문자열을 먼저 확실히 이해해야 합니다.

파일과 디렉터리는 서로 다르며, 그 차이의 원인은 마스크가 아닙니다. touch는 커널에 소유자, 그룹, 기타 사용자에 대한 읽기 및 쓰기 권한을 요청합니다. mkdir은 세 사용자 모두에게 읽기, 쓰기, 실행 권한을 요청합니다. 동일한 마스크가 두 가지 다른 요청에서 차감됩니다. 따라서 touch로 생성된 파일은 마스크 설정과 관계없이 절대 실행 가능하지 않습니다. 실행 비트는 애초에 요청되지 않았으며, 마스크는 비트를 다시 추가할 수 없기 때문입니다.

( umask a=rwx; touch open.file; stat -c '%a %A %n' open.file )

괄호는 명령을 서브셸에서 실행하므로, 변경 사항은 해당 셸이 종료되면 사라집니다. 이제 마스크는 아무것도 제거하지 않도록 설정되었지만, stat는 여전히 파일에 실행 비트가 없다고 보고합니다. 이후에 umask을 다시 실행하면 원래 값이 돌아옵니다. 이는 설정이 프로세스 내부에서 유지되고 자식 프로세스에 상속될 뿐, 디스크 어디에도 저장되지 않음을 보여줍니다.

디렉터리에서는 실행 비트가 제거되었을 때 그 영향이 체감됩니다.

( umask a=rw; mkdir noexec.dir; cd noexec.dir )

일반 사용자로 실행할 경우 cdbash: cd: noexec.dir: Permission denied 오류와 함께 실패합니다. 마스크가 mkdir이 요청한 실행 비트를 제거했기 때문이며, 실행 비트가 없는 디렉터리에는 진입할 수 없습니다. root 계정은 이 검사를 건너뛰므로, 이 현상은 일반 계정에서만 확인할 수 있습니다.

root 계정과 일반 사용자 계정의 umask 값이 다른 이유

다른 계정으로 동일한 측정 명령을 실행하고, 다른 방식으로 시작한 뒤 두 출력 결과를 나란히 비교해 보십시오.

umask
sudo -i umask

sudo -i은 root의 로그인 셸을 시작하고 그 안에서 내장 명령을 실행하므로, 서로 다른 시작 경로를 거쳐 도달한 별개의 계정입니다. 기본 Ubuntu 및 Debian 서버 이미지에서는 두 줄이 서로 다른 값을 출력할 수 있습니다. 두 결과 모두 올바른 값입니다. 각 결과는 해당 계정의 시작 경로가 생성한 값을 보여주는 것이며, 이 글의 나머지 부분은 시스템의 어느 구성 요소가 이 값을 생성하는지에 대해 다룹니다.

이미지에서 해당 값을 결정하는 파일 확인하기

grep -nE '^(UMASK|USERGROUPS_ENAB)' /etc/login.defs
grep -rn pam_umask /etc/pam.d/
grep -rn umask /etc/profile /etc/profile.d/ /etc/bash.bashrc ~/.profile ~/.bashrc 2>/dev/null || echo 'no umask line in the shell startup files'

첫 번째 grep 명령의 결과가 출력되지 않는다면, ^ 앵커를 제외하고 다시 실행하십시오. 해당 줄이 주석 처리되었을 수 있으며, 주석 처리된 줄은 설정이 아닌 문서로 취급됩니다. 세 번째 grep 명령은 예상치 못한 결과를 보여줄 때가 많습니다. Debian 및 Ubuntu에서 제공하는 /etc/profile는 자체적으로 마스크를 설정하기보다 대부분 PAM을 가리키고 있으므로, 설정을 담당한다고 생각했던 파일이 실제로는 그렇지 않은 경우가 많습니다. grep은 일치하는 항목이 없으면 0이 아닌 값을 반환하며, 이것이 해당 줄이 || echo로 끝나는 이유입니다. 시작 파일 중 마스크를 언급하는 파일이 없는 이미지에서는 침묵 대신 메시지가 출력되며, 이 메시지가 곧 확인 결과입니다.

/etc/login.defs는 값을 명시하고 PAM은 이를 적용합니다

/etc/login.defs 파일의 UMASK 줄은 대부분의 가이드에서 인용하는 값입니다. 커널이나 셸은 이 파일을 읽지 않습니다. 이 파일은 세션이 생성될 때 실행되는 PAM(pluggable authentication modules) 모듈인 pam_umask가 읽습니다. pam_umask는 발견한 첫 번째 값을 사용합니다. 우선순위는 사용자의 GECOS 필드에 있는 umask= 항목, 그 다음은 pam_umask.so 줄 자체에 작성된 umask= 인자, 마지막으로 /etc/login.defsUMASK 순서입니다. 배포판마다 이 모듈을 패치하므로, 직접 사용하는 이미지에서 man pam_umask을 실행하여 출력되는 순서를 확인하십시오.

이것이 /etc/login.defs이 한 값을 명시하더라도 세션은 다른 값을 가지게 되는 이유이며, 양쪽 모두 경고 메시지를 출력하지 않습니다. grep 명령을 통해 현재 어떤 경우에 해당하는지 알 수 있습니다. pam_umask.so 줄에 자체적인 umask= 인자가 포함되어 있다면, login.defs의 설정은 무시됩니다.

USERGROUPS_ENAB와 root 예외

id -un
id -gn

두 명령의 출력 결과가 동일하다면, 사용자 전용 그룹(user private group)을 사용 중인 것입니다. 이는 계정 생성 시 계정 이름과 동일한 이름의 그룹이 함께 생성되었음을 의미합니다. pam_umask는 /etc/login.defs 내의 USERGROUPS_ENAB 설정으로 제어되는 usergroups 동작을 지원합니다. 이 기능이 활성화되어 있고 계정이 root가 아니며, 기본 그룹 이름이 사용자 이름과 일치할 경우, 해당 모듈은 umask의 소유자(owner) 자릿값을 그룹(group) 자릿값으로 복사합니다. 결과적으로 세션이 종료될 때 해당 계정이 생성한 모든 파일의 그룹 비트가 열린 상태로 umask가 설정됩니다. root 계정은 모듈 자체적으로 제외되며, 이 예외 사항은 동일한 서버의 두 셸에서 서로 다른 umask가 출력되는 가장 흔한 원인입니다.

이 규칙의 근거는 전용 그룹에는 구성원이 단 한 명뿐이므로, 그룹 쓰기 권한이 곧 소유자 쓰기 권한과 다를 바 없다는 점에 있습니다. 하지만 누군가 해당 그룹에 두 번째 구성원을 추가하는 순간 상황이 달라집니다. 그 시점부터 해당 계정이 과거에 생성했던 모든 파일은 새로운 구성원이 수정할 수 있게 되며, 이를 위해 별도의 명령을 실행할 필요조차 없습니다. 각 서비스에 최소 권한을 가진 전용 사용자 계정을 할당하면, 해당 그룹은 의도한 대로 한 명의 구성원만 유지하게 됩니다.

로그인 셸, 비로그인 셸, 비대화형 셸

umask
bash -lc 'umask'
bash -c 'umask'

세션이 생성될 때 PAM이 실행됩니다. 콘솔에서의 login, 그리고 sshd, su, sudo -i가 이에 해당합니다. 셸이 다른 셸을 시작할 때는 PAM이 실행되지 않습니다. bash -l은 로그인 셸이므로 /etc/profile~/.profile를 읽지만, 세션이 생성되지 않았기 때문에 pam_umask를 호출하지 않습니다. bash -c은 두 파일 모두 읽지 않으며, 자신을 시작한 프로세스의 마스크를 상속받습니다. cron 작업, git hook, 서비스 관리자가 시작한 프로그램 모두 이 마지막 경우에 해당하므로, 이들의 마스크는 부모 프로세스가 가졌던 마스크를 그대로 따릅니다.

이것이 바로 "/etc/profile에 설정했는데 서비스가 여전히 잘못된 모드로 파일을 씁니다"라는 보고가 흔한 이유입니다. 해당 서비스는 그 파일을 읽은 적이 없기 때문입니다.

재부팅 후에도 설정이 유지되도록 하는 방법

워크로드가 실제로 시작되는 지점에 마스크를 설정하십시오. 각 시작 경로마다 읽어 들이는 파일이 다르기 때문입니다.

  1. 로그인하는 계정의 경우: /etc/login.defs 내의 UMASK를 사용합니다. 이는 pam_umask에 의해 시스템의 모든 세션에 적용됩니다. 시스템 전체에 적용되므로 모든 계정의 설정이 한꺼번에 변경됩니다.
  2. 특정 계정의 경우: pam_umask.so 라인의 umask= 인자 역시 시스템 전체에 적용됩니다. 따라서 사용자별 값을 설정하려면 해당 사용자의 GECOS 필드를 사용하거나, 로그인 셸의 경우 ~/.profile, 대화형 셸의 경우 ~/.bashrc에 설정해야 합니다.
  3. systemd에서 실행되는 데몬의 경우: 유닛 파일의 [Service] 섹션에 UMask=를 설정합니다. 유닛은 서비스 관리자에 의해 시작되므로 /etc/profile는 읽히지 않으며 pam_umask도 실행되지 않습니다. 데몬에 적용되는 유일한 방법은 유닛 파일을 수정하는 것입니다.
  4. cron이나 훅(hook)에 의해 시작되는 스크립트의 경우: 스크립트가 파일을 생성하기 전, 첫 번째 줄에 명시적으로 umask를 추가합니다.
[Service]
UMask=<the octal mask you chose>

설정을 마친 후에는 파일을 편집한 셸이 아닌, 해당 경로를 새로 시작하여 확인하십시오. 현재 셸은 이미 이전 마스크 값을 유지하고 있으며, 설정 파일을 편집한다고 해서 이미 실행 중인 프로세스에 소급 적용되지 않기 때문입니다.

bash -lc 'umask'
sudo -i umask

왜 나중에 chmod를 실행하는 것이 동일한 해결책이 아닌가

chmod는 이미 존재하는 파일의 권한을 수정합니다. umask는 아직 생성되지 않은 파일의 모드를 결정합니다. 디렉터리에 chmod -R를 실행하더라도, 서비스가 다음에 생성하는 파일은 다시 이전 모드로 생성됩니다. 파일 모드는 생성 프로세스에 의해 결정되며 디렉터리 설정이 이를 변경하지 않기 때문입니다.

또한 시간적 공백이 존재합니다. 파일이 생성된 순간부터 chmod이 실행되기 전까지, 파일은 더 넓은 권한으로 디스크에 존재하며 해당 디렉터리를 읽을 수 있는 모든 프로세스가 파일을 열 수 있습니다. 개인 키나 백업 아카이브의 경우, 이 짧은 시간 동안의 노출이 바로 제거하고자 했던 위험 요소입니다.

대신 생성 시점에 모드를 설정하십시오. install -m u=rw,go= newfile /etc/app/newfile은 명시적인 모드로 대상 파일을 작성하며, mkdir -m도 디렉터리에 대해 동일하게 동작합니다. 두 명령어 모두 지정한 모드를 사용하며 umask를 무시합니다. ssh-keygen는 자신이 작성하는 개인 키에 모드를 설정하므로, 다른 파일들은 설정이 잘못된 환경에서도 이 파일만큼은 올바른 권한을 유지하는 경우가 많습니다.

가장 흔한 피해자는 SSH입니다. 일반 mkdir로 생성된 ~/.ssh이나 cat >>으로 추가된 authorized_keys는 셸의 umask를 따릅니다. StrictModes가 활성화된 상태에서 sshd는 그룹 쓰기가 가능한 디렉터리에 있는 키 파일을 읽기를 거부합니다. 클라이언트에게는 Permission denied (publickey)라는 메시지가 전달되지만, 서버의 /var/log/auth.log에는 실제 원인이 기록됩니다.

Authentication refused: bad ownership or modes for directory /home/deploy/.ssh

이러한 검사는 의도된 것이며, VPS에서 SSH 강화하기는 이 검사가 유지되는 것에 의존합니다. 새로운 서버를 설정할 때 새로운 VPS에서의 첫 10분 작업과 함께 계정을 생성하기 전 umask를 먼저 측정하십시오. 그러면 해당 계정이 생성하는 모든 파일의 모드가 사전에 올바르게 결정됩니다.

복사 및 아카이브 작업은 마스크를 무시합니다

cp -prsync -a은 원본 파일에 기록된 모드를 복원하므로, 결과에 마스크가 관여하지 않습니다. tar 역시 root 권한으로 추출하거나 -p 옵션을 사용한 일반 사용자로 추출할 때 동일하게 동작합니다. 백업에서 복원된 파일은 백업이 생성될 당시의 모드를 유지합니다. 올바른 마스크가 무시되고 있다고 판단하기 전에 이 점을 확인하십시오. 복원된 데이터의 경우 마스크가 참조된 적이 없기 때문입니다.

FAQ

cron 작업으로 생성한 파일의 모드가 ssh 세션과 다른 이유는 무엇입니까?

cron 작업은 로그인 세션이 아니므로 pam_umask가 실행되지 않으며, /etc/profile이나 ~/.profile를 읽지 않습니다. cron 작업은 해당 프로세스를 시작한 상위 프로세스의 마스크를 상속받습니다. 스크립트의 첫 번째 줄에 파일을 생성하기 전 명시적으로 umask을 추가하십시오. 또한 작업 내부에서 마스크를 한 번 출력하여 본인의 셸이 아닌 해당 작업이 실제로 어떤 마스크를 가지고 있는지 확인하십시오.

/etc/login.defs의 설정과 셸에서 출력되는 값이 다른 이유는 무엇입니까?

/etc/login.defsUMASK는 pam_umask를 위한 마지막 대체 수단일 뿐입니다. 이 모듈은 사용자 GECOS 필드의 umask= 항목을 우선하며, 그 다음으로 /etc/pam.d/pam_umask.so 줄의 umask= 인자를 확인합니다. USERGROUPS_ENAB에 의해 활성화된 usergroups 동작은 기본 그룹 이름이 사용자 이름과 같은 비루트 계정의 그룹 비트를 재작성합니다. grep -rn pam_umask /etc/pam.d/id -un; id -gn를 실행하여 본인 계정에 어떤 설정이 적용되는지 확인하십시오.

umask로 파일을 실행 가능하게 만들 수 있습니까?

아니요. 마스크는 프로그램을 생성하는 과정에서 요청된 비트 중 일부를 제거할 수만 있습니다. touch은 실행 비트를 요청하지 않으므로, 어떤 마스크도 실행 가능한 파일을 생성하지 않습니다. 임시 디렉터리에서 ( umask a=rwx; touch f; stat -c '%a %A' f )를 사용하여 이를 확인하십시오. 실행 비트를 얻으려면 chmod를 사용하거나, 생성 시점에 실행 비트를 요청하는 install -m과 같은 프로그램을 사용해야 합니다.

systemd 서비스의 umask는 어디에서 설정합니까?

유닛 파일의 [Service] 섹션 내 UMask= 항목에서 설정합니다. 서비스는 로그인이 아닌 서비스 관리자에 의해 시작되므로 셸 시작 파일은 읽히지 않으며 pam_umask도 실행되지 않습니다. systemctl daemon-reload를 수행하고 유닛을 재시작한 뒤, 외부에서 확인하십시오. 서비스가 파일을 생성하게 한 다음 stat -c '%a %n'으로 결과를 읽어 확인하면 됩니다.

그룹 쓰기 권한이 있는 기본 마스크는 안전합니까?

그룹 멤버가 정확히 한 명일 때는 안전하며, 이는 사용자 개인 그룹(user private group) 체계의 전제 조건입니다. 해당 그룹에 두 번째 계정을 추가하면 첫 번째 계정이 생성한 모든 파일이 즉시 새 멤버에 의해 쓰기 가능하게 되며, 파일에 별도의 명령을 실행할 필요도 없습니다. id -unid -gn를 실행하십시오. 동일한 이름이 출력된다면 개인 그룹을 사용 중인 것입니다. 계정 간에 그룹을 공유하는 경우 그룹 쓰기 비트를 제거하는 마스크를 설정한 뒤, 파일을 생성하고 stat -c '%a %n'을 읽어 변경 사항이 적용되었는지 확인하십시오.

#umask#permissions#pam#login-defs#linux