소개
Docker 에서 권한을 처리하는 것은 컨테이너화된 애플리케이션을 관리하는 데 중요한 측면입니다. 이 튜토리얼에서는 Docker 파일 권한을 이해하고, Docker 컨테이너에서 권한을 설정하며, 권한 관리에 대한 모범 사례를 탐구하는 과정을 안내합니다. 이 튜토리얼을 마치면 Docker 기반 프로젝트에서 권한을 효과적으로 처리하는 데 필요한 지식을 갖추게 될 것입니다.
이 랩에서는 Docker 컨테이너 권한이 어떻게 작동하는지, 컨테이너에서 비루트 사용자 (non-root users) 를 생성하고 사용하는 방법, 호스트와 컨테이너 간에 데이터를 공유할 때 권한을 관리하는 방법을 배우게 됩니다.
기본 Docker 권한 이해
Docker 에서 권한이 어떻게 작동하는지 이해하는 것은 안전한 컨테이너를 유지하는 데 필수적입니다. Docker 컨테이너의 기본 권한 설정을 살펴보는 것으로 시작해 보겠습니다.
Docker 에서 기본 사용자 확인
기본적으로 Docker 는 컨테이너 내에서 프로세스를 root 사용자로 실행합니다. 컨테이너가 손상될 경우 잠재적인 보안 문제를 야기할 수 있습니다. 이러한 동작을 확인하기 위해 간단한 컨테이너를 생성하고 어떤 사용자가 프로세스를 실행하는지 확인해 보겠습니다.
먼저, 프로젝트 디렉토리에 있는지 확인하십시오.
cd ~/project
이제 기본 Ubuntu 컨테이너를 실행하고 현재 사용자를 확인합니다.
docker run -it --rm ubuntu:22.04 whoami
다음과 같은 출력을 볼 수 있습니다.
root
이는 Docker 가 기본적으로 root 사용자를 사용함을 확인합니다. 이제 사용자 ID (UID) 및 그룹 ID (GID) 를 확인해 보겠습니다.
docker run -it --rm ubuntu:22.04 id
출력은 다음과 유사해야 합니다.
uid=0(root) gid=0(root) groups=0(root)
uid=0 및 gid=0은 컨테이너가 root 사용자 및 그룹으로 실행되고 있으며, 컨테이너의 모든 리소스에 대한 전체 액세스 권한을 가지고 있음을 나타냅니다.
컨테이너 내부 파일 권한 탐색
Docker 컨테이너 내부에서 파일 권한이 어떻게 작동하는지 살펴보겠습니다. 컨테이너 내부에 간단한 파일을 생성하고 권한을 확인합니다.
먼저, 백그라운드에서 실행될 컨테이너를 생성합니다.
docker run -d --name permissions-demo ubuntu:22.04 sleep 3600
이제 이 컨테이너 내부에서 명령을 실행하여 파일을 생성하고 권한을 확인합니다.
docker exec permissions-demo touch /test-file
docker exec permissions-demo ls -l /test-file
다음과 유사한 출력을 볼 수 있습니다.
-rw-r--r-- 1 root root 0 May 15 12:34 /test-file
파일이 root 사용자 및 그룹에 의해 소유됨을 확인하십시오. 이는 기본적으로 Docker 컨테이너 내에서 생성된 모든 파일이 root 사용자에 의해 소유됨을 보여줍니다.
디렉토리를 생성하고 권한도 확인해 보겠습니다.
docker exec permissions-demo mkdir /test-directory
docker exec permissions-demo ls -ld /test-directory
출력은 다음과 유사해야 합니다.
drwxr-xr-x 2 root root 4096 May 15 12:35 /test-directory
다시, 디렉토리는 root 사용자 및 그룹에 의해 소유됩니다.
다음 단계로 이동하기 전에 컨테이너를 정리해 보겠습니다.
docker stop permissions-demo
docker rm permissions-demo
이는 사용자 권한과 관련하여 Docker 의 기본 동작을 보여줍니다. 다음 단계에서는 보안을 향상시키기 위해 Docker 컨테이너에서 비루트 사용자 (non-root users) 를 생성하고 사용하는 방법을 배우겠습니다.
Docker 에서 비루트 사용자 생성 및 사용
Docker 컨테이너 내에서 root 사용자로 애플리케이션을 실행하는 것은 보안 위험을 초래합니다. 공격자가 root 로 실행되는 컨테이너를 손상시키면 호스트 시스템에서 권한을 상승시킬 수 있습니다. 이 단계에서는 Docker 컨테이너에서 비루트 사용자 (non-root users) 를 생성하고 사용하는 방법을 배우겠습니다.
비루트 사용자를 포함하는 Dockerfile 생성
비루트 사용자를 정의하고 명령 실행에 대한 기본 사용자로 설정하는 Dockerfile 을 생성해 보겠습니다.
먼저, 프로젝트를 위한 새 디렉토리를 생성합니다.
mkdir -p ~/project/non-root-user
cd ~/project/non-root-user
이제 nano 텍스트 편집기를 사용하여 Dockerfile 을 생성합니다.
nano Dockerfile
Dockerfile 에 다음 내용을 추가합니다.
FROM ubuntu:22.04
## UID 1000으로 'appuser'라는 새 사용자 생성
RUN useradd -m -u 1000 appuser
## 애플리케이션용 디렉토리를 생성하고 소유권 설정
RUN mkdir -p /app && chown -R appuser:appuser /app
## 작업 디렉토리를 /app으로 설정
WORKDIR /app
## 비루트 사용자로 전환
USER appuser
## 테스트 파일 생성
RUN touch test-file.txt
## 컨테이너가 시작될 때 실행할 명령
CMD ["bash", "-c", "echo 'Running as user:' && whoami && echo 'File ownership:' && ls -l test-file.txt && tail -f /dev/null"]
Ctrl+O를 누르고 Enter를 눌러 파일을 저장한 다음, Ctrl+X를 눌러 편집기를 종료합니다.
이 Dockerfile 은 다음을 수행합니다.
- UID 1000 으로
appuser라는 새 사용자를 생성합니다. - 애플리케이션용 디렉토리를 생성하고 appuser 에게 소유권을 부여합니다.
- 작업 디렉토리를
/app으로 설정합니다. - 후속 명령에 대해 비루트 사용자로 전환합니다.
- appuser 가 소유할 테스트 파일을 생성합니다.
- 사용자 및 파일 소유권 정보를 표시하는 명령을 설정합니다.
비루트 사용자 컨테이너 빌드 및 실행
이제 Dockerfile 에서 Docker 이미지를 빌드해 보겠습니다.
docker build -t non-root-image .
Docker 가 이미지를 빌드하고 있음을 나타내는 출력을 볼 수 있습니다. 빌드가 완료되면 이 이미지에서 컨테이너를 실행합니다.
docker run --name non-root-container -d non-root-image
이제 컨테이너에서 출력을 확인해 보겠습니다.
docker logs non-root-container
다음과 유사한 출력을 볼 수 있습니다.
Running as user:
appuser
File ownership:
-rw-r--r-- 1 appuser appuser 0 May 15 12:45 test-file.txt
이는 컨테이너가 appuser 사용자로 실행되고 있으며, 테스트 파일이 appuser에 의해 소유됨을 확인합니다.
비루트 사용자의 권한 테스트
실행 중인 컨테이너에 연결하여 비루트 사용자의 권한을 살펴보겠습니다.
docker exec -it non-root-container bash
이제 appuser로 컨테이너 내부에 있어야 합니다. 이를 확인해 보겠습니다.
whoami
다음과 같은 출력을 볼 수 있습니다.
appuser
사용자 ID 및 그룹 ID 를 확인합니다.
id
출력은 다음과 유사해야 합니다.
uid=1000(appuser) gid=1000(appuser) groups=1000(appuser)
이제 루트 디렉토리에 파일을 생성해 보십시오.
touch /root-test-file
권한 거부 오류가 표시됩니다.
touch: cannot touch '/root-test-file': Permission denied
이는 비루트 사용자가 루트 디렉토리에 쓰기 권한이 없기 때문입니다. 그러나 사용자는 /app 디렉토리에 쓸 수 있습니다.
touch /app/user-test-file
ls -l /app/user-test-file
새 파일이 appuser에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 appuser appuser 0 May 15 12:50 /app/user-test-file
컨테이너 셸을 종료합니다.
exit
다음 단계로 이동하기 전에 컨테이너를 정리해 보겠습니다.
docker stop non-root-container
docker rm non-root-container
이 단계에서는 Docker 컨테이너에서 비루트 사용자를 생성하고 사용하는 방법을 보여주었습니다. 비루트 사용자를 사용하면 애플리케이션에 사용 가능한 권한을 제한하여 컨테이너화된 애플리케이션의 보안을 향상시킬 수 있습니다.
볼륨 마운트 권한 관리
Docker 볼륨을 사용하면 호스트와 컨테이너 간에 데이터를 공유할 수 있습니다. 그러나 볼륨을 사용할 때 문제를 방지하려면 권한을 올바르게 관리하는 것이 중요합니다. 이 단계에서는 볼륨 마운트를 사용할 때 권한을 처리하는 방법을 배우겠습니다.
볼륨 마운트 권한 문제 이해
Docker 볼륨 마운트의 주요 과제는 컨테이너 내부의 사용자 ID 가 호스트 시스템의 사용자 ID 와 일치하지 않을 수 있다는 것입니다. 이는 마운트된 볼륨의 파일에 액세스할 때 권한 문제를 야기할 수 있습니다.
간단한 예제를 통해 이 문제를 설명해 보겠습니다.
먼저, 컨테이너에 마운트할 호스트에 새 디렉토리를 생성합니다.
mkdir -p ~/project/host-data
cd ~/project/host-data
이 디렉토리에 테스트 파일을 생성합니다.
echo "This is a test file created on the host" > host-file.txt
이 파일의 소유권을 확인합니다.
ls -l host-file.txt
파일이 labex 사용자 (호스트의 현재 사용자) 에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 labex labex 39 May 15 13:00 host-file.txt
이제 이 디렉토리를 마운트하고 파일을 수정하려는 컨테이너를 실행해 보겠습니다.
docker run -it --rm -v ~/project/host-data:/container-data ubuntu:22.04 bash
이제 컨테이너 내부에 있습니다. 마운트된 파일의 소유권을 확인해 보겠습니다.
ls -l /container-data/host-file.txt
다음과 유사한 출력을 볼 수 있습니다.
-rw-r--r-- 1 1000 1000 39 May 15 13:00 /container-data/host-file.txt
컨테이너가 호스트의 labex 사용자에 대해 알지 못하므로 파일이 사용자 이름 대신 숫자 ID 를 표시합니다.
마운트된 디렉토리에 새 파일을 생성해 보십시오.
echo "This is a test file created in the container" > /container-data/container-file.txt
이제 이 새 파일의 소유권을 확인합니다.
ls -l /container-data/container-file.txt
다음과 같은 출력을 볼 수 있습니다.
-rw-r--r-- 1 root root 47 May 15 13:05 /container-data/container-file.txt
파일은 컨테이너 내부의 root 사용자에 의해 소유됩니다 (기본적으로 root 로 실행되므로).
컨테이너를 종료합니다.
exit
이제 호스트에서 두 파일의 소유권을 확인합니다.
ls -l ~/project/host-data/
컨테이너 내부에서 생성된 파일이 호스트에서 root에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 root root 47 May 15 13:05 container-file.txt
-rw-r--r-- 1 labex labex 39 May 15 13:00 host-file.txt
이는 호스트의 비루트 사용자가 이러한 파일에 액세스하거나 수정해야 하는 경우 권한 문제를 야기할 수 있습니다.
볼륨 권한 문제 해결
볼륨 권한 문제를 해결하는 방법에는 여러 가지가 있습니다. 몇 가지 일반적인 접근 방식을 살펴보겠습니다.
접근 방식 1: Dockerfile 에서 호스트 사용자와 일치하도록 사용자 설정
이 예제를 위해 새 디렉토리를 생성합니다.
mkdir -p ~/project/volume-permissions
cd ~/project/volume-permissions
새 Dockerfile 을 생성합니다.
nano Dockerfile
다음 내용을 추가합니다.
FROM ubuntu:22.04
## 호스트 사용자와 동일한 UID를 가진 사용자 생성
RUN useradd -m -u 1000 appuser
## 앱 디렉토리 생성 및 소유권 설정
RUN mkdir -p /app/data && chown -R appuser:appuser /app
## 작업 디렉토리 설정
WORKDIR /app
## appuser로 전환
USER appuser
## 실행할 명령
CMD ["bash", "-c", "echo 'I can write to the mounted volume' > /app/data/test.txt && tail -f /dev/null"]
저장하고 편집기를 종료합니다.
이미지를 빌드합니다.
docker build -t volume-permissions-image .
테스트를 위해 호스트 디렉토리를 생성합니다.
mkdir -p ~/project/volume-permissions/host-data
볼륨이 마운트된 컨테이너를 실행합니다.
docker run -d --name volume-test -v ~/project/volume-permissions/host-data:/app/data volume-permissions-image
잠시 후 호스트에서 생성된 파일의 소유권을 확인합니다.
ls -l ~/project/volume-permissions/host-data/
파일이 UID 1000 인 사용자에 의해 소유됨을 볼 수 있으며, 이는 호스트 사용자의 UID 와 일치해야 합니다.
-rw-r--r-- 1 labex labex 35 May 15 13:15 test.txt
이 접근 방식은 컨테이너에서 호스트 사용자와 동일한 UID 를 가진 사용자를 생성했기 때문에 작동합니다.
접근 방식 2: --user 플래그 사용
또 다른 접근 방식은 --user 플래그를 사용하여 컨테이너를 실행할 때 사용할 사용자 ID 를 지정하는 것입니다.
먼저, 이전 컨테이너를 정리합니다.
docker stop volume-test
docker rm volume-test
이제 --user 플래그로 컨테이너를 실행합니다.
docker run -d --name user-flag-test --user "$(id -u):$(id -g)" -v ~/project/volume-permissions/host-data:/data ubuntu:22.04 bash -c "echo 'Created with --user flag' > /data/user-flag-test.txt && sleep 3600"
이 명령은 현재 사용자 ID 및 그룹 ID 로 컨테이너를 실행합니다.
새 파일의 소유권을 확인합니다.
ls -l ~/project/volume-permissions/host-data/user-flag-test.txt
파일이 호스트 사용자에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 labex labex 23 May 15 13:20 user-flag-test.txt
다음 단계로 이동하기 전에 정리해 보겠습니다.
docker stop user-flag-test
docker rm user-flag-test
이러한 접근 방식은 Docker 볼륨을 사용할 때 권한을 관리하는 방법을 보여줍니다. 컨테이너와 호스트 간의 사용자 ID 를 일치시켜 데이터 공유 시 권한 문제를 방지할 수 있습니다.
권한 모범 사례 구현
지금까지 배운 모든 내용을 실천하여 권한 모범 사례를 따르는 Docker 컨테이너의 보다 현실적인 예제를 만들어 보겠습니다. 권한에 대한 보안 모범 사례를 따르는 간단한 웹 애플리케이션 컨테이너를 만들 것입니다.
안전한 웹 애플리케이션 컨테이너 생성
먼저, 예제를 위한 새 디렉토리를 생성합니다.
mkdir -p ~/project/secure-app
cd ~/project/secure-app
간단한 웹 애플리케이션을 만들어 보겠습니다. 먼저, app.py 파일을 생성합니다.
nano app.py
다음 Python 코드를 추가하여 간단한 Flask 웹 서버를 생성합니다.
from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello from a secure container!'
@app.route('/whoami')
def whoami():
return os.popen('id').read()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
저장하고 편집기를 종료합니다.
이제 Python 종속성을 위한 requirements.txt 파일을 생성합니다.
nano requirements.txt
다음 내용을 추가합니다.
flask==2.0.1
저장하고 편집기를 종료합니다.
이제 권한 모범 사례를 따르는 Dockerfile 을 생성합니다.
nano Dockerfile
다음 내용을 추가합니다.
FROM python:3.10-slim
## 애플리케이션을 실행할 비루트 사용자 생성
RUN groupadd -g 1000 appgroup \
&& useradd -u 1000 -g appgroup -s /bin/bash -m appuser
## 작업 디렉토리 설정 및 필요한 디렉토리 생성
WORKDIR /app
## Docker 캐시를 활용하기 위해 먼저 requirements 복사
COPY requirements.txt .
## 종속성을 root로 설치
RUN pip install --no-cache-dir -r requirements.txt
## 애플리케이션 코드 복사
COPY app.py .
## 애플리케이션이 쓸 수 있는 데이터 디렉토리 생성
RUN mkdir -p /app/data \
&& chown -R appuser:appgroup /app
## 적절한 권한 설정
RUN chmod -R 755 /app
## 비루트 사용자로 전환
USER appuser
## 앱이 실행될 포트 노출
EXPOSE 8080
## 애플리케이션을 실행할 명령
CMD ["python", "app.py"]
저장하고 편집기를 종료합니다.
Docker 이미지를 빌드해 보겠습니다.
docker build -t secure-web-app .
이제 컨테이너를 실행합니다.
docker run -d --name secure-app -p 8080:8080 secure-web-app
애플리케이션을 테스트해 보겠습니다. 먼저, 컨테이너가 실행 중인지 확인합니다.
docker ps
secure-app 컨테이너가 목록에 표시됩니다. 이제 curl을 사용하여 애플리케이션을 테스트합니다.
curl http://localhost:8080/
다음과 같은 출력을 볼 수 있습니다.
Hello from a secure container!
애플리케이션이 어떤 사용자로 실행되는지 확인해 보겠습니다.
curl http://localhost:8080/whoami
다음과 유사한 출력을 볼 수 있습니다.
uid=1000(appuser) gid=1000(appgroup) groups=1000(appgroup)
이는 애플리케이션이 비루트 appuser로 실행되고 있음을 확인합니다.
보안 분석
Dockerfile 의 보안 개선 사항을 분석해 보겠습니다.
비루트 사용자 (Non-root user): 애플리케이션을 실행하기 위해 전용 사용자 (
appuser) 를 생성하여 컨테이너가 손상될 경우의 위험을 줄였습니다.최소 권한: 애플리케이션이 작동하는 데 필요한 권한만 설정했습니다.
명확한 소유권: 컨테이너의 모든 파일과 디렉토리는 명확하게 정의된 소유권을 갖습니다.
적절한 디렉토리 구조: 애플리케이션과 해당 데이터를 위한 전용 디렉토리 구조를 생성했습니다.
이러한 관행은 공격자가 애플리케이션의 취약점을 악용하더라도 컨테이너 및 호스트 시스템에 대한 액세스가 제한되도록 하는 데 도움이 됩니다.
안전한 앱으로 볼륨 권한 구현
볼륨과 함께 권한을 적절하게 처리하는 방법을 보여주기 위해 안전한 애플리케이션에 볼륨을 추가해 보겠습니다.
먼저, 기존 컨테이너를 중지하고 제거합니다.
docker stop secure-app
docker rm secure-app
호스트에 데이터 디렉토리를 생성합니다.
mkdir -p ~/project/secure-app/host-data
호스트 디렉토리에 올바른 권한을 설정합니다.
sudo chown 1000:1000 ~/project/secure-app/host-data
이제 볼륨이 마운트된 컨테이너를 실행합니다.
docker run -d --name secure-app-with-volume \
-p 8080:8080 \
-v ~/project/secure-app/host-data:/app/data \
secure-web-app
컨테이너에 연결하여 마운트된 볼륨에 파일을 생성해 보겠습니다.
docker exec -it secure-app-with-volume bash
이제 컨테이너 내부에서 마운트된 볼륨에 테스트 파일을 생성합니다.
echo "Test file created from inside the container" > /app/data/container-file.txt
파일 소유권을 확인합니다.
ls -l /app/data/container-file.txt
파일이 appuser에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 appuser appgroup 43 May 15 13:30 /app/data/container-file.txt
컨테이너를 종료합니다.
exit
이제 호스트에서 파일 소유권을 확인합니다.
ls -l ~/project/secure-app/host-data/container-file.txt
파일이 UID 1000(호스트 사용자에 해당) 에 의해 소유됨을 볼 수 있습니다.
-rw-r--r-- 1 labex labex 43 May 15 13:30 container-file.txt
이는 적절한 권한 구성으로 마운트된 볼륨에서 컨테이너 내부에 생성된 파일이 호스트에서 올바른 소유권을 갖게 됨을 보여줍니다.
마무리하기 전에 정리해 보겠습니다.
docker stop secure-app-with-volume
docker rm secure-app-with-volume
Docker 권한에 대한 이러한 모범 사례를 따르면 컨테이너 내부와 호스트 시스템과 데이터를 공유할 때 파일 권한을 적절하게 관리하는 안전하고 신뢰할 수 있는 컨테이너화된 애플리케이션을 만들 수 있습니다.
요약
이 랩에서는 Docker 컨테이너에서 권한을 관리하기 위한 필수 기술을 배웠습니다.
기본 Docker 권한 이해: Docker 컨테이너가 기본적으로 root 로 실행되는 방식과 이로 인해 발생할 수 있는 잠재적인 보안 위험을 살펴보았습니다.
비루트 사용자 생성 및 사용: Docker 컨테이너에서 사용자 지정 비루트 사용자를 생성하는 방법을 배웠으며, 이는 중요한 보안 모범 사례입니다.
볼륨 마운트 권한 관리: 볼륨을 사용하여 호스트와 컨테이너 간에 데이터를 공유할 때 권한을 처리하는 방법을 배우고 일반적인 권한 문제를 해결했습니다.
권한 모범 사례 구현: 이러한 모든 개념을 적용하여 Docker 권한 모범 사례를 따르는 안전한 웹 애플리케이션 컨테이너를 만들었습니다.
Docker 프로젝트에 이러한 기술을 적용하면 컨테이너화된 애플리케이션의 보안과 안정성을 크게 향상시킬 수 있습니다. 컨테이너를 필요한 최소 권한으로 실행하는 것은 항상 따라야 하는 기본적인 보안 원칙임을 기억하십시오.
몇 가지 주요 내용:
- 항상 컨테이너에서 비루트 사용자를 사용하십시오.
- 볼륨을 사용할 때 호스트와 컨테이너 간의 사용자 ID 를 일치시키십시오.
- 적절한 파일 및 디렉토리 권한을 설정하십시오.
- 최소 권한의 원칙을 따르십시오.
이러한 관행은 보다 안전한 Docker 컨테이너를 구축하고 일반적인 권한 관련 문제를 방지하는 데 도움이 됩니다.



