Docker 컨테이너 보안
Categories:tech
Docker 컨테이너 보안
발생
최근에 Docker를 사용해서 애플리케이션을 배포하는 프로젝트를 진행하고 있다. 개발 환경에서는 문제없이 동작했는데, 프로덕션 환경에 배포할 때 보안에 대한 고민이 생겼다.
컨테이너는 가상머신보다 가볍고 빠르지만, 그만큼 보안 취약점도 있을 수 있다. Docker 컨테이너를 안전하게 사용하기 위한 방법들을 알아보자.
컨테이너 보안의 중요성
컨테이너의 특성
- 공유 커널: 호스트 OS의 커널을 공유
- 네임스페이스 격리: 프로세스, 네트워크, 파일시스템 격리
- cgroups: 리소스 사용량 제한
- 레이어드 파일시스템: 이미지 레이어 공유
이러한 특성으로 인해 보안 위험이 발생할 수 있다.
주요 보안 위험 요소
1. 취약한 베이스 이미지
# 나쁜 예시
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nodejs
# 좋은 예시
FROM node:18-alpine
2. 루트 권한으로 실행
# 나쁜 예시
USER root
RUN npm install
# 좋은 예시
RUN adduser -D -s /bin/sh appuser
USER appuser
RUN npm install
3. 민감한 정보 노출
# 나쁜 예시
ENV DB_PASSWORD=secret123
# 좋은 예시
ENV DB_PASSWORD_FILE=/run/secrets/db_password
Docker 보안 모범 사례
1. 최소 권한 원칙
비루트 사용자 사용
FROM node:18-alpine
# 사용자 생성
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# 작업 디렉토리 설정
WORKDIR /app
# 소유권 변경
RUN chown -R nextjs:nodejs /app
USER nextjs
# 애플리케이션 복사 및 실행
COPY --chown=nextjs:nodejs . .
CMD ["npm", "start"]
2. 멀티스테이지 빌드
# 빌드 스테이지
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 프로덕션 스테이지
FROM node:18-alpine AS production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --chown=nextjs:nodejs . .
USER nextjs
CMD ["npm", "start"]
3. 이미지 스캔
# Trivy를 사용한 취약점 스캔
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myapp:latest
4. 시크릿 관리
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp:latest
secrets:
- db_password
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
5. 네트워크 보안
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp:latest
networks:
- frontend
- backend
database:
image: postgres:13
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
런타임 보안
1. 리소스 제한
# docker-compose.yml
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
2. 읽기 전용 파일시스템
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN chmod -R 755 /app
USER node
CMD ["npm", "start"]
# 읽기 전용으로 실행
docker run --read-only -v /tmp:/tmp myapp:latest
3. 네트워크 정책
# Kubernetes NetworkPolicy 예시
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-network-policy
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 3000
모니터링 및 로깅
1. 컨테이너 로그 관리
# docker-compose.yml
services:
app:
image: myapp:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
2. 보안 이벤트 모니터링
# Docker 데몬 로그 확인
journalctl -u docker.service -f
# 컨테이너 프로세스 모니터링
docker stats --no-stream
결론
Docker 컨테이너 보안은 개발부터 배포까지 전 과정에서 고려해야 한다.
주요 원칙:
- 최소 권한: 필요한 최소한의 권한만 부여
- 최소 공격 표면: 불필요한 패키지나 서비스 제거
- 정기적 업데이트: 베이스 이미지와 의존성 정기 업데이트
- 모니터링: 지속적인 보안 모니터링
보안은 한 번에 완성되는 것이 아니라 지속적으로 개선해나가는 과정이다. 작은 실수 하나가 큰 보안 사고로 이어질 수 있으니 항상 주의해야 한다.
Day-18