← 아티클 목록

쿠버네티스 SecurityContext — runAsNonRoot로 컨테이너 굳히기

2027-04-05#kubernetes#securitycontext#보안

컨테이너가 기본값으로 root(UID 0)로 돌고 파일시스템 전체에 쓰기가 가능하다면, 컨테이너가 뚫렸을 때 공격자가 그대로 root 권한을 얻습니다. SecurityContext는 "이 컨테이너는 root가 아니어야 하고, 디스크에 함부로 못 쓴다"를 쿠버네티스 수준에서 강제하는 장치입니다. 핵심은 두 가지, runAsNonRootreadOnlyRootFilesystem입니다.

지금 root로 돌고 있는지 확인

Kubernetes
# 컨테이너 안에서 실행 중인 UID 확인
kubectl exec <pod> -- id

# uid=0(root) 이면 위험 신호

uid=0(root)가 나오면 이미지가 root로 돌고 있다는 뜻입니다.

적용할 설정

YAML
apiVersion: v1
kind: Pod
metadata:
  name: hardened
spec:
  securityContext:
    runAsNonRoot: true       # root면 아예 기동 거부
    runAsUser: 1000          # 비-root UID 지정
    fsGroup: 2000            # 볼륨 그룹 소유권
  containers:
    - name: app
      image: myapp:1.0
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true     # 루트 FS 쓰기 금지
        capabilities:
          drop: ["ALL"]                  # 모든 리눅스 capability 제거

옵션별 의미

옵션역할효과
runAsNonRoot: trueroot 기동 차단UID 0이면 Pod이 시작 실패
runAsUser: 1000실행 UID 강제이미지가 root여도 1000으로
readOnlyRootFilesystem루트 FS 읽기전용침투해도 바이너리 변조 불가
allowPrivilegeEscalation: falsesetuid 권한 상승 차단sudo류 권한 획득 봉쇄
capabilities.drop: ALL커널 권한 최소화필요한 것만 add로 다시 부여

적용하면 깨지는 흔한 케이스

runAsNonRoot인데 이미지가 root — Pod이 CreateContainerConfigError로 뜨고 container has runAsNonRoot and image will run as root 메시지가 납니다. Dockerfile에 USER 1000을 넣어 비-root 이미지로 다시 빌드해야 합니다.

readOnlyRootFilesystem인데 앱이 임시파일을 씀/tmp나 캐시 디렉터리에 쓰려다 read-only file system 에러가 납니다. 쓰기가 필요한 경로만 emptyDir 볼륨으로 마운트해 뚫어줍니다.

YAML
      volumeMounts:
        - name: tmp
          mountPath: /tmp
  volumes:
    - name: tmp
      emptyDir: {}

③ 포트 바인딩 실패 — 비-root는 1024 미만 포트를 못 엽니다. 80 대신 8080처럼 높은 포트를 쓰고 Service에서 매핑합니다.

체크리스트

Kubernetes
kubectl exec <pod> -- id                       # 비-root UID 확인
kubectl get pod <pod> -o jsonpath='{.spec.securityContext}'
kubectl describe pod <pod>                      # 기동 실패 사유 확인

세 줄이면 root 잔존·읽기전용 충돌을 바로 잡아냅니다.


SecurityContext를 직접 걸고 일부러 깨뜨려 보며 어떤 에러가 나는지 관찰하는 실습은 쿠버네티스 트랙에서 해볼 수 있습니다 — 회원가입 없이 무료로.