본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 26. · 4 Views
Docker 보안 베스트 프랙티스 완벽 가이드
Docker 컨테이너 환경에서 보안을 강화하는 필수 기법들을 다룹니다. 루트 사용자 제한부터 시크릿 관리, 리소스 제한까지 실무에서 바로 적용할 수 있는 보안 설정을 배워봅니다.
목차
1. 루트가 아닌 사용자 실행
어느 날 김개발 씨가 운영 중인 서비스에서 보안 감사를 받게 되었습니다. 감사관이 Docker 컨테이너 설정을 살펴보더니 한숨을 쉬며 말했습니다.
"컨테이너가 전부 root 권한으로 실행되고 있네요. 이건 굉장히 위험합니다."
루트가 아닌 사용자 실행은 컨테이너 내부에서 root 권한 대신 일반 사용자 권한으로 애플리케이션을 실행하는 것입니다. 마치 회사에서 모든 직원에게 관리자 권한을 주지 않는 것과 같습니다.
만약 컨테이너가 해킹당하더라도 공격자가 할 수 있는 일이 크게 제한됩니다.
다음 코드를 살펴봅시다.
# Dockerfile에서 non-root 사용자 생성 및 사용
FROM node:18-alpine
# 애플리케이션 전용 사용자 생성
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
# 작업 디렉토리 설정 및 권한 부여
WORKDIR /app
COPY --chown=appuser:appgroup . .
# non-root 사용자로 전환
USER appuser
# 애플리케이션 실행
CMD ["node", "server.js"]
김개발 씨는 입사 2년 차 백엔드 개발자입니다. Docker를 사용한 지 꽤 되었지만, 보안에 대해서는 깊이 생각해본 적이 없었습니다.
그저 컨테이너가 잘 돌아가면 된다고 생각했죠. 그런데 보안 감사관의 지적을 듣고 나니 등골이 서늘해졌습니다.
"만약 해커가 우리 컨테이너에 침입하면 어떻게 되는 거죠?" 감사관이 차분히 설명했습니다. "root 권한으로 실행되는 컨테이너가 뚫리면, 공격자는 컨테이너 내부에서 무엇이든 할 수 있어요.
심지어 호스트 시스템까지 영향을 줄 수 있습니다." 그렇다면 non-root 사용자로 실행한다는 것은 정확히 무엇일까요? 쉽게 비유하자면, 회사 건물의 출입 권한과 같습니다.
모든 직원에게 마스터키를 주면 편리하겠지만, 누군가 그 키를 잃어버리면 건물 전체가 위험해집니다. 그래서 각 직원에게는 자기 사무실 열쇠만 주는 것이 안전합니다.
컨테이너의 사용자 권한도 마찬가지입니다. 예전에는 많은 개발자들이 이 부분을 신경 쓰지 않았습니다.
Docker 이미지를 만들 때 별다른 설정을 하지 않으면 기본적으로 root 사용자로 실행되기 때문입니다. "어차피 컨테이너 안이니까 괜찮겠지"라고 생각하기 쉬웠습니다.
하지만 이것은 매우 위험한 생각입니다. 컨테이너 탈출이라는 공격 기법이 존재하기 때문입니다.
root 권한을 가진 공격자는 컨테이너의 격리 경계를 뚫고 호스트 시스템에 접근할 가능성이 높아집니다. 위의 Dockerfile 코드를 살펴보겠습니다.
먼저 addgroup과 adduser 명령으로 appgroup이라는 그룹과 appuser라는 사용자를 생성합니다. 여기서 -g와 -u 옵션으로 고정된 ID를 지정하는 것이 중요합니다.
이렇게 하면 파일 권한 문제를 예방할 수 있습니다. 다음으로 COPY --chown 옵션을 사용하여 복사되는 파일들의 소유권을 새로 만든 사용자에게 부여합니다.
마지막으로 USER appuser 지시어로 이후의 모든 명령과 컨테이너 실행이 appuser 권한으로 이루어지도록 설정합니다. 실제 현업에서는 이 설정이 필수입니다.
특히 금융권이나 의료 분야처럼 보안 규정이 엄격한 곳에서는 root 사용자로 실행되는 컨테이너는 배포 자체가 불가능합니다. Kubernetes 환경에서도 PodSecurityPolicy나 SecurityContext를 통해 non-root 실행을 강제하는 경우가 많습니다.
주의할 점도 있습니다. 일부 애플리케이션은 root 권한이 필요한 작업을 수행할 수 있습니다.
예를 들어 1024 미만의 포트에 바인딩하거나, 특정 시스템 파일에 접근해야 하는 경우입니다. 이럴 때는 애플리케이션 설정을 변경하거나, 필요한 권한만 부여하는 Linux Capabilities를 활용해야 합니다.
김개발 씨는 감사관의 설명을 듣고 바로 팀에 공유했습니다. "여러분, 우리 모든 Dockerfile에 USER 지시어를 추가해야 합니다!" 이제 팀의 모든 컨테이너는 최소 권한 원칙을 따르게 되었습니다.
실전 팁
💡 - alpine 이미지를 사용하면 adduser 명령이 약간 다릅니다. -D 옵션으로 패스워드 없이 생성하세요.
- 컨테이너 실행 시 --user 플래그로도 사용자를 지정할 수 있습니다: docker run --user 1001:1001
2. 이미지 취약점 스캔
박시니어 씨가 김개발 씨에게 다급히 메시지를 보냈습니다. "개발 씨, 우리가 쓰는 베이스 이미지에 치명적인 보안 취약점이 발견됐대요.
당장 확인해봐야 해요!" 김개발 씨는 그제야 이미지 보안 스캔의 중요성을 깨달았습니다.
이미지 취약점 스캔은 Docker 이미지에 포함된 패키지나 라이브러리의 알려진 보안 취약점을 자동으로 탐지하는 과정입니다. 마치 공항 보안 검색대에서 위험물을 찾아내는 것처럼, 이미지 내부의 위험 요소를 사전에 발견하여 조치할 수 있습니다.
다음 코드를 살펴봅시다.
# Docker Scout로 이미지 취약점 스캔 (Docker Desktop 내장)
docker scout cves myapp:latest
# Trivy를 사용한 이미지 스캔 (오픈소스)
# 설치: brew install trivy 또는 apt-get install trivy
trivy image myapp:latest
# 심각도 HIGH 이상만 필터링하여 스캔
trivy image --severity HIGH,CRITICAL myapp:latest
# CI/CD에서 취약점 발견 시 빌드 실패 처리
trivy image --exit-code 1 --severity CRITICAL myapp:latest
# Snyk을 사용한 스캔 (상용 서비스)
snyk container test myapp:latest
김개발 씨는 평소에 npm이나 pip의 보안 경고는 신경 썼지만, Docker 이미지 자체의 보안은 생각해본 적이 없었습니다. 베이스 이미지를 가져다 쓰면 당연히 안전할 거라고 믿었죠.
박시니어 씨가 화면을 보여주며 설명했습니다. "여기 봐요.
우리가 쓰는 node:16 이미지에만 해도 수십 개의 CVE가 있어요. 그중에는 CRITICAL 등급도 있고요." CVE란 Common Vulnerabilities and Exposures의 약자로, 공개적으로 알려진 보안 취약점에 부여되는 고유 식별자입니다.
전 세계 보안 전문가들이 취약점을 발견하면 이 목록에 등록됩니다. 이미지 취약점 스캔이란 무엇일까요?
쉽게 비유하자면, 자동차 정기 검사와 같습니다. 겉으로 보기에 멀쩡해 보여도 내부에 결함이 있을 수 있습니다.
정기적으로 검사하지 않으면 어느 날 갑자기 큰 사고로 이어질 수 있습니다. Docker 이미지도 마찬가지입니다.
스캔 도구로는 여러 가지가 있습니다. Trivy는 Aqua Security에서 만든 오픈소스 도구로, 설치가 간단하고 속도가 빠릅니다.
Docker Scout는 Docker Desktop에 내장되어 있어 별도 설치 없이 사용할 수 있습니다. Snyk는 더 정교한 분석과 수정 제안을 제공하는 상용 서비스입니다.
위의 코드에서 trivy image 명령은 지정한 이미지를 분석하여 취약점 목록을 보여줍니다. --severity 옵션으로 특정 심각도 이상만 필터링할 수 있어서, 정말 중요한 취약점에 집중할 수 있습니다.
특히 중요한 것은 --exit-code 1 옵션입니다. 이 옵션을 사용하면 취약점이 발견되었을 때 명령이 실패 상태로 종료됩니다.
CI/CD 파이프라인에서 이를 활용하면, 보안 취약점이 있는 이미지가 프로덕션에 배포되는 것을 자동으로 차단할 수 있습니다. 실무에서는 이 스캔을 여러 시점에 적용합니다.
첫째, 개발자가 로컬에서 이미지를 빌드할 때 스캔합니다. 둘째, CI/CD 파이프라인에서 자동으로 스캔합니다.
셋째, 이미 배포된 이미지도 정기적으로 재스캔합니다. 새로운 취약점이 계속 발견되기 때문입니다.
주의할 점은 모든 취약점을 당장 해결할 필요는 없다는 것입니다. 취약점의 심각도와 실제 악용 가능성을 고려해야 합니다.
CRITICAL 등급이라도 우리 애플리케이션에서 해당 기능을 사용하지 않는다면 위험도가 낮을 수 있습니다. 반대로 MEDIUM 등급이라도 우리 서비스에 직접적인 영향이 있다면 우선 처리해야 합니다.
김개발 씨는 바로 GitHub Actions에 Trivy 스캔을 추가했습니다. 이제 취약한 이미지는 자동으로 배포가 차단됩니다.
"이제야 좀 안심이 되네요."
실전 팁
💡 - 베이스 이미지는 alpine이나 distroless처럼 최소화된 이미지를 사용하면 취약점이 적습니다.
- 스캔 결과를 무시하는 whitelist 기능도 있지만, 명확한 사유를 문서화해두세요.
3. 시크릿 관리 방법
김개발 씨가 코드 리뷰를 하다가 식은땀이 났습니다. 누군가 Dockerfile에 데이터베이스 비밀번호를 하드코딩해놓은 것입니다.
더 큰 문제는 이 이미지가 이미 Docker Hub에 푸시되어 있었습니다.
시크릿 관리는 비밀번호, API 키, 인증서 같은 민감한 정보를 안전하게 다루는 방법입니다. Dockerfile이나 이미지에 시크릿을 직접 포함하면 안 됩니다.
마치 집 열쇠를 현관문 앞 화분에 숨겨두는 것처럼 위험합니다. Docker Secrets, 환경 변수, 또는 전문 시크릿 관리 도구를 사용해야 합니다.
다음 코드를 살펴봅시다.
# 잘못된 예시 - 절대 이렇게 하지 마세요!
# ENV DB_PASSWORD=supersecret123
# 방법 1: 런타임에 환경 변수로 전달
docker run -e DB_PASSWORD="${DB_PASSWORD}" myapp:latest
# 방법 2: Docker Secrets 사용 (Swarm 모드)
echo "mysecretpassword" | docker secret create db_password -
docker service create --secret db_password myapp:latest
# 방법 3: BuildKit의 시크릿 마운트 (빌드 시)
# Dockerfile에서:
# RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm install
# 빌드 명령:
DOCKER_BUILDKIT=1 docker build --secret id=npmrc,src=.npmrc -t myapp .
# 방법 4: docker-compose에서 시크릿 사용
# docker-compose.yml에서 secrets 섹션 정의
이번 사건은 김개발 씨에게 큰 교훈이 되었습니다. 다행히 빠르게 발견해서 이미지를 삭제하고 비밀번호도 변경했지만, 하마터면 큰 보안 사고로 이어질 뻔했습니다.
시크릿이 이미지에 포함되면 왜 위험할까요? Docker 이미지는 레이어로 구성되어 있습니다.
한번 레이어에 기록된 데이터는 나중에 삭제해도 이전 레이어에 남아있습니다. docker history 명령으로 누구나 이미지의 빌드 과정을 볼 수 있고, 그 과정에서 시크릿이 노출될 수 있습니다.
쉽게 비유하자면, 화이트보드에 비밀번호를 적었다가 지우개로 지운 것과 같습니다. 겉보기에는 지워졌지만, 자세히 보면 흔적이 남아있을 수 있습니다.
디지털 세계에서는 이 흔적을 복원하기가 훨씬 쉽습니다. 그렇다면 시크릿을 어떻게 관리해야 할까요?
첫 번째 방법은 런타임 환경 변수입니다. docker run 명령에서 -e 옵션으로 전달하면, 이미지 자체에는 시크릿이 포함되지 않습니다.
다만 docker inspect 명령으로 환경 변수를 볼 수 있으므로 완벽한 방법은 아닙니다. 두 번째 방법은 Docker Secrets입니다.
Docker Swarm 모드에서 사용할 수 있는 기능으로, 시크릿을 암호화하여 저장하고 필요한 컨테이너에만 전달합니다. 컨테이너 내부에서는 /run/secrets/ 경로에 파일로 마운트됩니다.
세 번째 방법은 BuildKit의 시크릿 마운트입니다. 빌드 과정에서 시크릿이 필요한 경우, 예를 들어 프라이빗 npm 패키지를 설치해야 할 때 유용합니다.
--mount=type=secret 옵션을 사용하면 시크릿이 빌드 캐시나 이미지 레이어에 남지 않습니다. 실무에서는 HashiCorp Vault나 AWS Secrets Manager 같은 전문 시크릿 관리 도구를 많이 사용합니다.
이런 도구들은 시크릿의 생성, 교체, 폐기를 자동화하고, 누가 언제 시크릿에 접근했는지 감사 로그를 남깁니다. Kubernetes 환경에서는 Secrets 리소스를 사용합니다.
다만 기본적으로 base64 인코딩만 되어 있어서 암호화가 아닙니다. 프로덕션에서는 Sealed Secrets나 외부 시크릿 관리 도구와 연동하는 것이 좋습니다.
흔히 하는 실수 중 하나는 .env 파일을 이미지에 포함시키는 것입니다. .dockerignore 파일에 .env를 반드시 추가해야 합니다.
git에도 커밋되지 않도록 .gitignore에도 추가하세요. 김개발 씨는 팀 전체에 시크릿 관리 가이드라인을 공유했습니다.
"이제 시크릿은 코드에 절대 넣지 않습니다. 환경 변수로 전달하거나 시크릿 관리 도구를 사용합니다."
실전 팁
💡 - git-secrets 같은 도구를 사용하면 실수로 시크릿을 커밋하는 것을 방지할 수 있습니다.
- 시크릿이 노출되었다면, 즉시 해당 시크릿을 폐기하고 새로 발급받으세요. 노출된 시크릿을 그냥 두면 안 됩니다.
4. Read-only 파일시스템
보안팀에서 김개발 씨의 팀에 새로운 보안 정책을 전달했습니다. "컨테이너 파일시스템을 읽기 전용으로 설정해주세요." 김개발 씨는 처음 듣는 요구 사항에 당황했습니다.
"파일을 못 쓰면 로그는 어떻게 남기죠?"
Read-only 파일시스템은 컨테이너가 자신의 파일시스템에 쓰기 작업을 하지 못하도록 제한하는 보안 설정입니다. 마치 박물관의 전시물처럼, 볼 수는 있지만 손댈 수는 없게 만드는 것입니다.
공격자가 컨테이너에 침입해도 악성 파일을 생성하거나 기존 파일을 변조할 수 없습니다.
다음 코드를 살펴봅시다.
# 읽기 전용 파일시스템으로 컨테이너 실행
docker run --read-only myapp:latest
# 임시 파일이 필요한 경우 tmpfs 마운트 추가
docker run --read-only \
--tmpfs /tmp:rw,noexec,nosuid \
--tmpfs /var/run:rw,noexec,nosuid \
myapp:latest
# docker-compose.yml 설정 예시
# services:
# web:
# image: myapp:latest
# read_only: true
# tmpfs:
# - /tmp
# - /var/run
# 볼륨을 사용한 로그 저장 (읽기 전용과 함께 사용)
docker run --read-only \
--tmpfs /tmp \
-v /var/log/myapp:/app/logs:rw \
myapp:latest
김개발 씨는 왜 파일시스템을 읽기 전용으로 해야 하는지 이해가 되지 않았습니다. 박시니어 씨에게 물어보기로 했습니다.
"시니어님, 파일시스템을 읽기 전용으로 하면 뭐가 좋은 건가요?" 박시니어 씨가 예를 들어 설명했습니다. "해커가 우리 컨테이너에 침입했다고 생각해봐요.
그 해커가 제일 먼저 하고 싶은 일이 뭘까요?" "음... 악성 프로그램을 설치하거나, 백도어를 만들거나..." "맞아요.
그런데 파일을 전혀 쓸 수 없다면요?" 읽기 전용 파일시스템의 핵심은 불변성입니다. 컨테이너가 시작될 때의 상태 그대로 유지되어야 합니다.
쉽게 비유하자면, 유리 진열장 안에 물건을 넣어두는 것과 같습니다. 밖에서 볼 수는 있지만, 유리를 깨지 않고는 손댈 수 없습니다.
하지만 현실적으로 모든 애플리케이션이 완전히 파일 쓰기 없이 동작할 수는 없습니다. 임시 파일을 생성해야 하거나, PID 파일을 만들어야 하거나, 로그를 남겨야 합니다.
이 문제를 해결하는 방법이 tmpfs입니다. tmpfs는 메모리에 존재하는 임시 파일시스템입니다.
컨테이너가 종료되면 tmpfs의 내용도 함께 사라집니다. --tmpfs 옵션으로 /tmp나 /var/run 같은 디렉토리를 tmpfs로 마운트하면, 필요한 임시 파일은 쓸 수 있으면서도 영구적인 파일 변조는 방지할 수 있습니다.
코드에서 주목할 부분은 noexec,nosuid 옵션입니다. noexec는 해당 파일시스템에서 실행 파일을 실행할 수 없게 합니다.
nosuid는 setuid 비트를 무시합니다. 이 옵션들을 추가하면 tmpfs에 악성 실행 파일을 만들어도 실행할 수 없습니다.
로그 파일은 어떻게 처리할까요? 두 가지 방법이 있습니다.
첫째, 외부 볼륨을 마운트하여 로그를 호스트에 저장합니다. 둘째, stdout/stderr로 로그를 출력하고 Docker의 로깅 드라이버가 처리하도록 합니다.
12-factor app 원칙에서도 후자를 권장합니다. 실무에서 읽기 전용 파일시스템을 적용할 때 가장 많이 만나는 문제는 라이브러리나 프레임워크가 예상치 못한 곳에 파일을 쓰려고 하는 경우입니다.
예를 들어 Python의 pycache 디렉토리나, Node.js의 node_modules/.cache 같은 것들입니다. 이런 경로들을 파악해서 tmpfs로 마운트해주어야 합니다.
Kubernetes에서는 securityContext의 readOnlyRootFilesystem: true 설정으로 같은 효과를 얻을 수 있습니다. Pod Security Policy나 Pod Security Standards에서도 이 설정을 강제할 수 있습니다.
김개발 씨는 애플리케이션을 분석하여 필요한 tmpfs 경로들을 파악했습니다. 몇 번의 시행착오 끝에 읽기 전용으로 안정적으로 동작하는 설정을 완성했습니다.
실전 팁
💡 - 처음에는 --read-only 없이 컨테이너를 실행하고, strace나 로그로 파일 쓰기 위치를 파악한 후 tmpfs를 설정하세요.
- 데이터베이스처럼 영구 저장이 필요한 컨테이너는 데이터 디렉토리를 볼륨으로 마운트하세요.
5. 리소스 제한 설정
어느 월요일 아침, 김개발 씨의 서버가 멈췄습니다. 모니터링을 확인해보니 하나의 컨테이너가 서버의 모든 메모리를 집어삼키고 있었습니다.
옆에 있던 다른 컨테이너들도 덩달아 죽어버렸습니다.
리소스 제한 설정은 컨테이너가 사용할 수 있는 CPU와 메모리의 최대치를 지정하는 것입니다. 마치 가정집의 전기 차단기처럼, 특정 컨테이너가 과도한 자원을 사용하면 자동으로 제한됩니다.
이를 통해 한 컨테이너의 문제가 전체 시스템에 영향을 주는 것을 방지할 수 있습니다.
다음 코드를 살펴봅시다.
# 메모리 제한 설정 (최대 512MB)
docker run --memory=512m myapp:latest
# 메모리와 스왑 제한 (스왑 사용 금지)
docker run --memory=512m --memory-swap=512m myapp:latest
# CPU 제한 설정 (1.5 코어)
docker run --cpus=1.5 myapp:latest
# 종합 리소스 제한 설정
docker run \
--memory=512m \
--memory-swap=512m \
--cpus=1.5 \
--pids-limit=100 \
--ulimit nofile=1024:1024 \
myapp:latest
# docker-compose.yml 설정 예시
# services:
# web:
# image: myapp:latest
# deploy:
# resources:
# limits:
# cpus: '1.5'
# memory: 512M
그날의 장애는 김개발 씨에게 큰 트라우마로 남았습니다. 단 하나의 컨테이너 때문에 서비스 전체가 마비되다니.
어떻게 이런 일이 가능했을까요? 문제의 컨테이너는 메모리 누수가 있는 애플리케이션이었습니다.
평소에는 괜찮았지만, 특정 조건에서 메모리를 무한정 할당하는 버그가 있었습니다. 리소스 제한이 없었기 때문에, 이 컨테이너는 서버의 모든 가용 메모리를 소진했습니다.
리눅스 커널은 메모리가 부족해지면 OOM Killer를 동작시킵니다. Out of Memory Killer라는 이름 그대로, 메모리를 많이 사용하는 프로세스를 강제로 종료시킵니다.
문제는 이 과정에서 중요한 프로세스도 죽을 수 있다는 것입니다. 리소스 제한은 이런 상황을 방지합니다.
쉽게 비유하자면, 뷔페에서 1인당 접시 개수를 제한하는 것과 같습니다. 한 사람이 모든 음식을 가져가버리면 다른 사람은 굶게 됩니다.
적절한 제한이 있어야 모두가 공평하게 이용할 수 있습니다. --memory 옵션은 컨테이너가 사용할 수 있는 메모리의 상한을 설정합니다.
512m은 512 메가바이트를 의미합니다. 이 한도를 초과하면 컨테이너의 프로세스가 OOM Killer에 의해 종료됩니다.
--memory-swap 옵션도 중요합니다. 메모리 제한만 설정하면 컨테이너가 스왑 영역을 사용할 수 있습니다.
--memory-swap을 --memory와 같은 값으로 설정하면 스왑 사용이 금지됩니다. 스왑을 사용하면 성능이 급격히 떨어지므로 대부분의 경우 금지하는 것이 좋습니다.
--cpus 옵션은 CPU 사용량을 제한합니다. 1.5는 1.5개의 CPU 코어에 해당하는 처리량을 의미합니다.
CPU 제한은 메모리와 달리 초과해도 프로세스가 죽지 않고, 단지 속도가 느려집니다. --pids-limit 옵션은 컨테이너 내에서 생성할 수 있는 프로세스 수를 제한합니다.
이른바 Fork Bomb 공격을 방지합니다. Fork Bomb은 프로세스가 자기 자신을 무한히 복제하여 시스템을 마비시키는 공격입니다.
--ulimit 옵션으로 파일 디스크립터 수 같은 시스템 제한도 설정할 수 있습니다. 너무 많은 파일이나 네트워크 연결을 열지 못하도록 제한하여 리소스 고갈을 방지합니다.
실무에서는 이 값들을 어떻게 정해야 할까요? 먼저 애플리케이션의 정상 동작 시 리소스 사용량을 모니터링합니다.
그 값에 적절한 여유분을 더해서 제한을 설정합니다. 너무 타이트하게 설정하면 정상 동작도 방해받을 수 있으니 주의가 필요합니다.
Kubernetes에서는 resources.limits와 resources.requests로 설정합니다. limits는 상한선이고, requests는 스케줄링에 사용되는 보장 수치입니다.
두 값을 같게 설정하면 Guaranteed QoS 클래스가 되어 리소스 경합 시 우선권을 얻습니다. 김개발 씨는 모든 컨테이너에 리소스 제한을 적용했습니다.
이제 하나의 컨테이너에 문제가 생겨도 다른 서비스는 안전합니다.
실전 팁
💡 - Java 애플리케이션은 컨테이너 메모리 제한을 인식하도록 -XX:+UseContainerSupport 옵션을 사용하세요.
- 리소스 사용량은 docker stats 명령으로 실시간 모니터링할 수 있습니다.
6. Docker Bench Security
보안 감사를 앞두고 김개발 씨는 걱정이 많았습니다. "우리 Docker 환경이 보안 기준에 맞는지 어떻게 확인하죠?" 박시니어 씨가 웃으며 답했습니다.
"좋은 도구가 있어요. Docker Bench Security라고."
Docker Bench Security는 Docker 환경의 보안 설정을 자동으로 점검하는 오픈소스 도구입니다. CIS Docker Benchmark라는 국제 보안 표준을 기반으로 호스트 설정, 데몬 설정, 컨테이너 설정 등을 종합적으로 검사합니다.
마치 건강검진처럼, 현재 상태를 진단하고 개선이 필요한 부분을 알려줍니다.
다음 코드를 살펴봅시다.
# Docker Bench Security 실행 (공식 방법)
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /etc:/etc:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
docker/docker-bench-security
# 특정 섹션만 검사 (예: 컨테이너 이미지)
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-v /etc:/etc:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
docker/docker-bench-security -c container_images
# 결과를 파일로 저장
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-v /etc:/etc:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v $(pwd):/output \
docker/docker-bench-security -l /output/bench-results.txt
김개발 씨는 Docker Bench Security라는 이름을 처음 들었습니다. "Bench가 뭔가요?
벤치마크인가요?" 박시니어 씨가 설명했습니다. "네, 일종의 벤치마크예요.
CIS라는 국제 보안 단체에서 만든 Docker 보안 표준이 있거든요. 그 표준에 맞는지 자동으로 검사해주는 도구입니다." CIS는 Center for Internet Security의 약자로, 다양한 시스템에 대한 보안 구성 가이드라인을 발표하는 비영리 단체입니다.
CIS Docker Benchmark는 Docker 환경에 대한 상세한 보안 권고사항을 담고 있습니다. Docker Bench Security를 실행하면 여러 카테고리를 검사합니다.
첫째, 호스트 설정입니다. Docker가 설치된 서버 자체의 보안 상태를 점검합니다.
둘째, Docker 데몬 설정입니다. dockerd의 시작 옵션과 설정 파일을 검사합니다.
셋째, Docker 데몬 설정 파일의 권한을 확인합니다. 중요한 설정 파일에 부적절한 권한이 설정되어 있으면 경고합니다.
넷째, 컨테이너 이미지와 빌드 파일을 검사합니다. 루트 사용자로 실행되는지, HEALTHCHECK가 정의되어 있는지 등을 확인합니다.
다섯째, 컨테이너 런타임을 검사합니다. 현재 실행 중인 컨테이너들이 보안 권고사항을 따르는지 확인합니다.
앞서 배운 리소스 제한, 읽기 전용 파일시스템, 권한 제한 등이 여기에 해당합니다. 여섯째, Docker Security Operations입니다.
보안 운영 관점에서의 권고사항을 검사합니다. 실행 명령어가 복잡해 보이지만, 각 옵션에는 이유가 있습니다.
--net host, --pid host, --userns host는 호스트의 네트워크, 프로세스, 사용자 네임스페이스에 접근하기 위함입니다. 이래야 호스트 설정을 제대로 검사할 수 있습니다.
/var/run/docker.sock 마운트는 Docker 데몬과 통신하기 위해 필요합니다. /etc와 /var/lib 마운트는 설정 파일들을 읽기 위함입니다.
모두 읽기 전용(ro)으로 마운트되어 있어 시스템을 변경하지 않습니다. 검사 결과는 색상으로 구분됩니다.
녹색 PASS는 권고사항을 따르고 있다는 의미입니다. 빨간색 WARN은 권고사항을 따르지 않아 개선이 필요합니다.
파란색 INFO는 정보 제공 목적이며, 주황색 NOTE는 참고 사항입니다. 처음 실행하면 WARN이 많이 나와서 당황할 수 있습니다.
모든 항목을 한 번에 해결하려고 하지 마세요. 우선순위를 정해서 중요한 것부터 하나씩 개선해 나가면 됩니다.
특히 scored 항목들이 점수에 반영되므로 먼저 처리하는 것이 좋습니다. 김개발 씨는 Docker Bench Security를 실행하고 결과를 분석했습니다.
WARN이 20개나 나왔지만, 하나씩 해결해 나가기로 했습니다. 다음 감사 때는 자신 있게 결과를 보여줄 수 있을 것입니다.
실전 팁
💡 - Docker Bench Security를 CI/CD 파이프라인에 통합하면 지속적인 보안 검사가 가능합니다.
- 모든 권고사항을 100% 따를 필요는 없습니다. 환경에 맞게 적절히 조정하세요.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
백업 및 복구 전략 완벽 가이드
메일 서버와 중요 데이터를 안전하게 보호하는 백업 전략을 알아봅니다. Maildir 백업부터 증분 백업, 오프사이트 백업, 그리고 재해 복구 계획까지 실무에서 바로 적용할 수 있는 내용을 담았습니다.
Roundcube 웹메일 인터페이스 완벽 가이드
Docker 컨테이너 기반으로 Roundcube 웹메일을 구축하고, Nginx 리버스 프록시부터 플러그인 관리, 테마 커스터마이징까지 전체 과정을 다룹니다. 초급 개발자도 쉽게 따라할 수 있는 실무 중심 가이드입니다.
ClamAV 바이러스 스캔 완벽 가이드
리눅스 서버에서 ClamAV를 활용한 바이러스 스캔 시스템을 구축하는 방법을 다룹니다. 메일 서버와 연동하여 악성코드를 자동으로 탐지하고 처리하는 실무 노하우를 배워봅니다.
SSL/TLS 인증서 설정 완벽 가이드 (Let's Encrypt)
메일 서버 운영에 필수적인 SSL/TLS 인증서 설정 방법을 다룹니다. Let's Encrypt를 활용한 무료 인증서 발급부터 자동 갱신까지, 실무에서 바로 적용할 수 있는 내용을 담았습니다.
Dovecot으로 IMAP/POP3 메일 서버 구축하기
Linux 환경에서 Dovecot을 활용하여 IMAP과 POP3 메일 서버를 구성하는 방법을 다룹니다. 메일 저장소 설정부터 사용자 인증, 쿼터 관리까지 실무에서 필요한 핵심 설정을 단계별로 학습합니다.