Linux 서비스 권한 분리 및 일반 사용자 실행 방법
서비스를 root 권한으로 실행하면 보안 사고 시 서버 전체가 위협받습니다. 최소 권한의 원칙에 따라 systemd 유닛 파일에 DynamicUser 설정을 추가하거나 전용 계정을 생성하여 프로세스 권한을 제한하는 구체적인 방법을 안내합니다.
왜 모든 것을 root로 실행하면 안 되는가
root는 시스템에서 무엇이든 할 수 있습니다. 모든 파일을 읽고, 설정을 변경하며, 시스템 전체를 삭제할 수 있습니다. 서비스를 root로 실행하면 그 서비스에 이러한 모든 권한을 부여하는 셈입니다. 만약 서비스에 공격자가 악용할 수 있는 버그가 있다면, 공격자는 단순히 서비스만 장악하는 것이 아니라 root 권한을 획득하게 되며, root는 곧 서버 전체를 의미합니다. 권한이 없는 일반 사용자로 서비스를 실행하면 피해를 제한할 수 있습니다. 제한된 계정으로 실행되는 서비스에 버그가 발생하더라도, 공격자는 해당 계정이 접근할 수 있는 범위 내의 것만 손댈 수 있으며, 이는 사실상 아무것도 할 수 없어야 정상입니다.
이것이 최소 권한의 원칙입니다. 시스템의 각 부분에 작업을 수행하는 데 필요한 만큼의 권한만 부여하고, 그 이상은 허용하지 않는 것입니다. 이는 침해 사고 발생 시 피해 범위를 제한하는 가장 효과적인 습관이며, 현대적인 서버 환경에서는 이를 적용하는 데 비용이 거의 들지 않습니다.
서비스별 전용 계정 사용
전통적인 방식은 각 서비스마다 별도의 시스템 사용자를 생성하는 것입니다. 이 사용자는 해당 서비스의 파일만 소유하며 로그인할 수 없습니다. 웹 애플리케이션을 위한 시스템 계정은 다음과 같이 구성할 수 있습니다.
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvc모든 플래그가 중요합니다. --system는 해당 계정을 사람이 로그인하는 용도가 아닌 서비스 계정으로 지정합니다. --no-create-home은 필요하지 않은 홈 디렉터리 생성을 건너뜁니다. --shell /usr/sbin/nologin은 공격자가 계정 권한을 탈취하더라도 셸을 열 수 없도록 제한합니다. 이 계정은 오직 프로세스와 그 파일들을 소유하기 위해서만 존재합니다.
그다음, 해당 사용자에게 필요한 파일에 대해서만 권한을 부여합니다.
sudo chown -R appsvc:appsvc /opt/myapp이제 서비스는 자신의 디렉터리만 읽고 쓸 수 있으며, 디스크의 다른 영역에는 접근할 권한이 없습니다. 서비스가 공격받더라도 공격자가 수정할 수 있는 파일은 /opt/myapp로 제한됩니다. 해당 계정은 여전히 모든 사용자에게 읽기 권한이 있는 파일은 읽을 수 있지만, 시스템의 나머지 부분을 수정할 수는 없습니다.
해당 사용자로 systemd가 실행하도록 설정
계정이 생성되면 systemd가 해당 계정으로 서비스를 실행하도록 설정합니다. 유닛 파일에 다음 한 줄을 추가하면 됩니다.
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc는 프로세스가 root가 아닌 해당 계정의 제한된 권한으로 시작됨을 의미합니다. 이는 systemd에서 애플리케이션을 실행하는 일반적이고 검증된 방식이며, 유닛 파일을 작성하는 모든 서비스에 적용할 가치가 있습니다. 다만, systemd가 잘못된 프로세스를 감시하고 있다면 권한을 낮추는 것은 아무런 도움이 되지 않습니다. 데몬이 조용히 종료되었는데도 유닛이 여전히 active 상태로 보고된다면, 프로세스 시작 방식에 맞는 올바른 Type=을 선택했는지 확인하십시오.
DynamicUser를 사용하여 계정 생성 생략하기
systemd는 한 걸음 더 나아가 서비스가 실행되는 동안에만 존재하는 일회용 사용자를 생성할 수 있습니다. DynamicUser=yes을 설정하면 계정을 직접 관리할 필요가 전혀 없습니다.
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myapp서비스가 시작될 때 systemd는 사용되지 않는 사용자 ID를 할당하며, 서비스가 중지되면 이를 해제합니다. 또한 해당 서비스는 전용 /tmp을 부여받으며, 대부분의 파일 시스템을 읽기 전용으로 보게 됩니다. StateDirectory=이 설정하고 전달하는 /var/lib/myapp 아래의 상태 디렉터리만 쓰기가 가능합니다. SysV init 환경에서는 이러한 방식이 불가능했습니다. 당시에는 권한 하락(dropping privileges)을 각 서비스의 시작 스크립트가 알아서 처리해야 했으며, 이러한 공백은 배포판들이 systemd로 전환하게 된 주된 이유 중 하나입니다. 자체 상태 디렉터리만 필요한 독립적인 서비스의 경우, DynamicUser=yes는 강력한 격리를 구현하는 가장 효율적인 방법입니다. 공격자가 표적으로 삼을 만한 장기 지속 계정이 존재하지 않기 때문입니다.
단위 파일을 직접 작성하는 것은 번거로운 작업이며, 보안 강화 지시어를 올바르게 설정하는 것이 핵심 가치입니다. systemd 서비스 및 타이머 가이드에 있는 생성기를 사용하면 이러한 옵션을 자동으로 채워주므로 처음부터 올바른 단위 파일을 만들 수 있습니다.
전체 구성에서의 위치
최소 권한 원칙은 하나의 계층일 뿐이며, 다른 보안 조치를 대체하는 것이 아니라 상호 보완적으로 작동합니다. 기본 거부 방화벽은 서비스에 도달할 수 있는 대상을 제어하고, 권한이 없는 사용자로 서비스를 실행하는 것은 서비스가 침해되었을 때 수행할 수 있는 작업을 제한하며, 강화된 SSH는 애초에 공격자가 서버에 접근하지 못하도록 차단합니다. 이 중 어느 하나만으로는 충분하지 않으며, 모두 함께 적용해야 한 서비스의 버그가 전체 서버의 침해로 이어지는 것을 방지할 수 있습니다. 비밀 정보를 보호하는 서비스를 운영할 때 이러한 계층의 한계가 드러납니다. 제한된 계정은 침해된 프로세스가 접근할 수 있는 범위를 제한하지만, Vaultwarden과 같은 자체 호스팅 비밀번호 관리자의 보안은 관리자 토큰과 백업 파일을 어떻게 보호하느냐에 달려 있으며, 사용자 격리만으로는 이를 모두 보호할 수 없습니다.
다음 단계로 넘어가기 전에, 서버 전체에 대한 보안 강화 체크리스트를 검토하고 작업에 활용할 개인화된 사본을 생성하십시오.
FAQ
왜 서비스를 root 권한으로 실행하면 안 됩니까?
root는 시스템에서 무엇이든 할 수 있기 때문입니다. root 권한으로 실행 중인 서비스가 공격당하면, 공격자는 서비스뿐만 아니라 서버 전체에 대한 제어권을 얻게 됩니다. 권한이 제한된 일반 계정으로 서비스를 실행하면 피해 범위를 해당 계정이 접근할 수 있는 영역으로 한정할 수 있습니다. root 권한은 관리 작업에만 사용하고, 상시 실행되는 모든 서비스는 제한된 사용자 계정으로 실행하십시오.
로그인할 수 없는 사용자는 어떻게 만듭니까?
sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME를 실행하십시오. nologin 셸을 사용하면 계정 정보가 탈취되더라도 대화형 세션을 열 수 없으며, --system은 해당 계정을 서비스 계정으로 지정하고, --no-create-home은 필요 없는 홈 디렉터리 생성을 건너뜁니다. chown를 사용하여 해당 계정이 자신의 파일에 대해서만 소유권을 갖도록 설정하십시오.
systemd의 DynamicUser란 무엇입니까?
DynamicUser=yes은 서비스가 실행되는 동안에만 존재하는 임시 사용자를 생성하도록 systemd에 지시하므로, 장기적으로 계정을 관리할 필요가 없습니다. 또한 이 설정은 서비스에 개인용 /tmp, 대부분 읽기 전용인 파일 시스템 뷰, 관리되는 상태 디렉터리를 제공합니다. 이는 일회성 저권한 ID로 독립적인 서비스를 실행하는 가장 간편한 방법입니다.
비 root 사용자로 실행하면 방화벽을 대체할 수 있습니까?
아니요. 방화벽과 비 root 사용자 실행은 서로 다른 대상을 보호합니다. 비권한 사용자로 실행하면 서비스가 침해되었을 때 서비스가 할 수 있는 일을 제한하고, 방화벽은 서비스에 도달할 수 있는 대상을 제한합니다. 각 계층이 서로 보완할 수 있도록 강화된 SSH와 함께 두 가지 모두를 사용하십시오.
서비스 사용자는 어떤 파일의 소유권을 가져야 합니까?
서비스가 실제로 필요로 하는 파일만 소유해야 합니다. 해당 계정에는 작업 디렉터리와 데이터에 대한 소유권만 부여하고, 나머지 모든 파일은 root가 소유하도록 하십시오. 애플리케이션 디렉터리에 sudo chown -R svc-app:svc-app /opt/svc-app를 사용하는 것은 좋은 패턴이며, /etc 아래의 설정 파일은 root가 소유하고 서비스는 읽기만 가능하도록 유지하는 것이 좋습니다. 프로세스가 침해되더라도 변경 가능한 파일이 시스템 전체가 아닌 해당 서비스의 데이터로만 제한되도록 하는 것이 목적입니다.