alt round

들어가기

DockerfileDocker 컨테이너 이미지를 빌드할 때 사용되는 각종 설정과 명령어를 선언한 파일입니다. 우리가 개발 환경을 구축하거나 서비스를 배포할 때 누군가 미리 만들어놓은 Docker 이미지를 사용하기도 하지만, 직접 Dockerfile을 작성해서 Docker 이미지로 빌드하는 경우도 많은데요.

더욱 안전한 Docker 이미지를 제작할 수 있는 Dockerfile 작성 팁이 있다는 사실, 알고 계셨나요?

Dockerfile을 작성할 때 보안을 신경써야 하는 이유

오늘날 대부분의 웹 서비스는 마이크로서비스 아키텍처를 따르고 있습니다. 하나의 커다란 서비스를 배포하는 것이 아닌, 기능이나 성격에 따라 나눠진 작은 서비스 여러 개를 배포 및 운영하는 방식을 마이크로서비스 아키텍처라고 하는데요.

이때 마이크로서비스를 각각의 Docker 컨테이너 내부에서 동작하도록 구성하는 것이 일반적입니다. 하지만 이렇게 실제로 배포된 컨테이너 이미지가 외부 공격에 취약하다면… 생각만 해도 아찔한 보안 사고로 이어지겠죠.

그래서 우리는 Dockerfile을 작성할 때부터 보안에 신경써야 합니다.

보안을 위한 Dockerfile 작성 팁 5가지

그렇다면 Dockerfile을 어떻게 작성하면 좋을까요? 여기 보안에 강한 Dockerfile 작성 팁팁 5가지를 소개해드립니다.

Multi-Stage 방식으로 빌드

Dockerfile 내에서 애플리케이션 빌드 명령어 실행 후 나오는 최종 산출물또다른 Base Image로 복사하고, 해당 Base Image를 최종 Docker Image로 빌드하는 기법을 Multi-Stage라고 하는데요.

Multi-Stage 방식으로 빌드된 Docker 이미지 내에는 애플리케이션 구동에 필요한 최소한의 요소만 담겨있으므로, 자연스럽게 잠재된 보안 취약점도 더 적어집니다.

Multi-Stage를 사용해서 간단한 Golang 애플리케이션을 빌드하는 Dockerfile 예제를 같이 살펴보겠습니다.

# /src/main.go 파일을 빌드하는 build 스테이지입니다.
FROM golang:1.21 as build 
WORKDIR /src
COPY <<EOF /src/main.go
package main
 
import "fmt"
 
func main() {
  fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go
 
# build 스테이지로부터 빌드된 산출물들만 가져와 실행하는 최종 스테이지입니다.
FROM scratch
COPY --from=build /bin/hello /bin/hello
CMD ["/bin/hello"]

위 Dockerfile을 실행하면 먼저 build라는 이름이 붙여진 스테이지가 먼저 실행되는데요. golang:1.21 이미지 위에 go build 명령어로 애플리케이션이 빌드되는 구간입니다.

이후 또다른 스테이지가 실행되고, build 스테이지에서 빌드된 최종 산출물을 복사한 뒤 실행하는 로직이 수행되는데요. 위 Dockerfile로 빌드되는 이미지는 이 최종 스테이지의 내용만 담게 되는 것입니다.

필요없는 패키지 제거

Docker 컨테이너 내 애플리케이션 구동에 필요없는 패키지를 제거하는 것 역시 잠재 보안 취약점을 줄여주기 때문에 권장됩니다.

Root가 아닌 별도의 사용자를 생성 및 사용

Container 내에 Root 계정이 사용될 경우, 침입 사고 발생 시 피해가 커질 수 있습니다. 그래서 아래 예시와 같이 Root 계정이 아닌 별도의 그룹 및 사용자를 생성하고 사용하는 것이 안전합니다.

RUN groupadd -r for-example && useradd -r -g for-example for-example
USER for-example

Container 내 민감한 파일들은 Read Only로

배포 이후 Docker Container 내에서 추후 수정이 필요하지 않는 파일들을 Read Only로 설정하면 보안성을 높일 수 있습니다.

chmod -R a-w {폴더명} 또는 chmod a-w {파일명} 명령어를 사용하면, 모든 사용자는 해당 폴더 또는 파일에 대한 쓰기 권한을 잃게 됩니다.

Shell Access 제거

컨테이너 안에서 실행 가능한 shbash 등의 Shell은 동작 중인 컨테이너 내 애플리케이션을 디버깅할 때 사용되는 경우가 있지만, 이런 통로를 제거하면 컨테이너 내부 침입이 어려워져 보안성이 높아집니다.

Shell 접근을 제거할 경우, 아래 주의사항에 대해 고려해야 합니다.

  • 컨테이너 이미지에서 동작하는 애플리케이션이 Shell을 사용하고 있지 않은지 확인해야 합니다.
  • 해당 이미지를 배포한 뒤에 디버깅할 수 있는 다른 대안을 미리 마련해야 합니다.

컨테이너 보안을 지킬 수 있는 또다른 방법

Docker 이미지를 직접 제작할 땐 위와 같은 방법으로 안전한 이미지를 만들어 사용할 수 있지만, 만약 이미 누군가가 제작한 Docker 이미지를 사용할 때엔 그 이미지가 안전한지 어떻게 알 수 있을까요?

이럴 때 사용할 수 있는 것이 바로, 컨테이너 보안 스캐닝 툴입니다. 대표적으로 Trivy가 있는데요. 컨테이너 보안 스캐닝 툴에 대해서는 추후 다른 글에서 소개해보겠습니다.

References