💿컨테이너 이미지를 ‘잘’ 만들어야 하는 이유

이제 컨테이너 이미지는 우리가 개발 프로젝트를 진행할 때 쉽게 접하는 개념이 되었습니다. 독립된 환경 안에서 특정한 애플리케이션이 실행되는 걸 보장해주기 때문에 Kubernetes나 퍼블릭 클라우드(AWS, GCP 등)를 사용한다면 거의 필수 요소가 되었죠.

그러다보니 컨테이너 이미지를 직접 만드는 경우도 많습니다. 공개된 레파지토리에서 공유되는 이미지를 그대로 써도 되지만, 내 프로젝트에 맞춰서 커스터마이징이 필요한 때가 있으니까요. 아마 공감하실 거예요.

우리가 컨테이너 이미지를 만들 때 가장 신경 쓰는 건 무엇인가요? 아마 원하는 애플리케이션의 정상 작동 여부일 텐데요. 그럼 ‘애플리케이션이 잘 돌아가는’ 컨테이너 이미지가 ‘잘’ 만들어진 컨테이너 이미지일까요?

컨테이너 이미지의 품질은 단순히 애플리케이션 실행 가능성을 넘어서, 시스템의 전반적인 보안과 안정성, 운영 효율성, 비용과도 연관이 있습니다. 고품질의 컨테이너 이미지는 안정적이고 효율적인 운영 환경 구축의 기반이 되는 거죠.

따라서 이미지 빌드 단계부터 컨테이너 이미지 품질에 대한 인식을 높이고 노력을 기울이는 것이 중요합니다.

즉, 컨테이너 이미지의 최종 품질은 대부분 Dockerfile에 명시된 이미지 빌드 과정에 의해 결정됩니다. 왜냐하면…

  • 베이스 이미지
  • 설치할 패키지
  • 복사할 파일
  • 사용자

이 모든 요소가 컨테이너 이미지 빌드 과정에서 정해지기 때문이죠.

따라서 운영 환경에서 이미지가 안전하고 효율적으로 동작하려면, Dockerfile 작성 및 빌드 과정에 대해 이해하고 최적화하려는 노력이 필수입니다.


🛡️보안 관점에서 잘 만든 컨테이너 이미지란 무엇일까?

그럼 잘 만든 컨테이너 이미지란 정확히 무엇일까요?

보안성과 효율성을 균형 있게 갖춘 컨테이너 이미지가 잘 만들어졌다고 볼 수 있는데요. 그 중 보안 관점에서 요구되는 사항을 큰 틀로 정리해보면 아래와 같습니다.

  • 알맞은 베이스 이미지 선택
  • 불필요한 요소 제거
  • 최소 권한으로 실행

보안성과 효율성이란 두 가지 요소를 잘 갖추는 것은 오늘날 컨테이너 운영 환경에서 매우 중요합니다.

그래서 이번 글에서는 컨테이너 이미지를 빌드할 때 보안성을 챙길 수 있는 팁을 정리했습니다. 바로 적용할 수 있는 실질적인 내용만 다뤘으니 꼭 확인해보세요.


✨컨테이너 이미지의 보안성을 챙기는 팁

1️⃣ 나에게 맞는 베이스 이미지 선택하기 (Alpine vs Distroless)

베이스 이미지는 최종 이미지 보안과 이미지 크기 모두에 직접적인 영향을 미치는 아주 중요한 요소입니다.

특히, 최소 베이스 이미지는 운영체제 구성 요소가 극도록 제한적으로 포함되어 있기 때문에 이미지 크기와 보안 공격 표면을 효과적으로 줄이는 효과가 있습니다.

가장 많이 사용되는 최소 베이스 이미지로는 AlpineDistroless가 있습니다.

  • Alpine:

    • 가벼우면서 패키지 관리도 용이합니다.
    • C 라이브러리로 musl libc를 사용하기 때문에 glibc를 사용하는 애플리케이션과는 호환성 문제가 발생하여 추가 패키지를 설치해야 할 수 있습니다.
  • Distroless:

    • 쉘과 기본 도구가 포함되어 있지 않아 보안성이 높고 Alpine보다 더 경량화된 베이스 이미지입니다.
    • 하지만 쉘이 포함되어있지 않기 때문에 컨테이너 실행 후 디버깅이 어렵다는 단점도 존재합니다.

각 선택지의 특장점이 다르기 때문에 애플리케이션의 의존성과 필요한 도구 유무, 운영 환경 특성을 고려해서 가장 적합한 베이스 이미지를 선택해야 합니다.

2️⃣ Dockerfile RUN 지시어로 이미지 내의 불필요한 요소 제거하기

빌드 과정에서 생성된 불필요한 파일이나 캐시를 제거하면 컨테이너에 대한 보안 공격 표면을 축소할 수 있습니다.

Dockerfile의 RUN 지시어로 필요한 패키지를 모두 설치했다면, apt-get clean이나 캐시 파일 삭제 명령어를 별도로 실행시켜보세요. 애플리케이션 동작에 필요하진 않지만 보안 사고에 악용될 수 있는 데이터를 지울 수 있습니다.

이 방법은 최종 이미지 크기를 줄이는 데에도 도움이 됩니다.

3️⃣ root가 아닌 유저로 컨테이너 실행하기

컨테이너 내부 프로세스가 기본적으로 root 권한으로 실행될 경우, 보안 사고 시 위험이 더욱 커집니다.

애플리케이션을 root가 아닌 유저로 실행하도록 설정하면 컨테이너에 무단 침입이 발생하더라도 공격자가 얻는 권한을 최소화하여 호스트나 다른 컨테이너로의 피해 확산을 막을 수 있습니다.

Dockerfile에 RUN 지시어로 root가 아닌 유저를 생성하고 USER 지시어로 생성한 사용자를 지정하면 해당 유저의 권한으로 이미지 내 명령어를 실행하도록 설정할 수 있습니다. 좀 더 쉬운 이해를 위해 아래와 같이 Dockerfile 예시 코드를 준비했습니다.

# UID 1234 및 GID 1234를 가진 새로운 사용자(customuser) 생성
RUN groupadd -g 1234 customgroup &&
\ useradd -m -u 1234 -g customgroup customuser
 
# 해당 이미지의 사용자를 customuser로 변경
USER customuser

4️⃣ 이미지 빌드 중에 민감정보는 제외하기

데이터베이스 비밀번호나 API 키, 클라우드 자격 증명 등 민감한 정보를 이미지 빌드 과정에 포함시키는 것은 매우 위험합니다.

ADDCOPY로 이미지에 민감정보가 포함된 파일을 넣거나, --build-arg로 민감정보 값을 전달하면 이미지 레이어에 해당 데이터가 남기 때문에 쉽게 노출될 수 있습니다.

그래서 민감정보는 이미지 빌드 시점이 아닌 컨테이너 실행 시점에 안전한 방법으로 주입되어야 합니다.

5️⃣ 컨테이너 이미지 보안 툴 사용하기

TrivyClair라는 컨테이너 이미지 보안 툴을 사용하면 내가 만든 이미지, 또는 내가 사용하려는 이미지에 보안 취약점이 있는지 확인할 수 있습니다.

  • Trivy:

    • 컨테이너 이미지, 파일 시스템, Git 레파지토리 등 다양한 대상을 빠르고 쉽게 스캔하는 오픈소스 취약점 탐지 도구입니다.
    • 운영체제 패키지뿐만 아니라 애플리케이션 종속성까지 검사 가능합니다.
    • CI/CD 파이프라인에 Trivy로 스캔하는 스테이지를 추가하면 보안 취약점이 포함된 이미지가 운영 환경에 배포되는 것을 차단하는 ‘보안 게이트웨이’ 역할을 수행할 수 있습니다.
  • Clair:

    • 컨테이너 이미지의 구성요소를 분석해서 취약점을 보고해주는 오픈소스 도구입니다.
    • 최신 취약점을 주기적으로 업데이트하는 기능과 Webhook을 활용한 알림 기능을 지원합니다.
    • Trivy와 마찬가지로 CI/CD 파이프라인에 적용하여 배포 전 컨테이너 이미지 스캔할 수 있고, 스캔 결과를 알림 기능으로 팀 내에 전파하는 등의 활용이 가능합니다.
    • Clair에 대해 관심이 생기셨다면 제가 이전에 소개한 글을 확인해보세요.

🔭마무리

컨테이너 이미지는 개발 과정에서 한 번 만들고 끝나는 것이 아니기 때문에 지속적인 관리가 필요합니다.

새로운 보안 취약점은 지금도 끊임없이 발견되고, 컨테이너 이미지가 사용하는 베이스 이미지나 애플리케이션 종속성도 업데이트가 필요하죠.

시간이 지날수록 컨테이너 이미지의 보안 상태와 최적성 모두 저하될 가능성이 있는 것입니다.

그렇기 때문에 컨테이너 이미지의 안정성과 최신 상태를 유지하려면 정기적인 취약점 스캔, 베이스 이미지 및 종속성 업데이트가 포함된 재빌드 프로세스가 지속적으로 이루어져야 합니다.

하지만 이런 작업을 수동으로 직접 하기엔 한계가 있습니다.

이때 CI/CD 파이프라인을 활용해서 컨테이너 이미지 빌드와 업로드를 자동화하면 효율성과 반복 가능성이 보장됩니다.

여기에 이전에 살펴봤던 TrivyClair의 자동 보안 스캔 기능을 활용하면 이미지 내에 잠재하고 있던 문제를 조기에 발견하는 데에 큰 도움이 되죠.

진행 중인 프로젝트에 컨테이너 이미지를 사용한다면, 보안 관점에서 개선할 점은 없는지 한번 살펴보는 건 어떨까요?

요즘 IT 업계에서 보안이 화두가 되고 있는 만큼, 보안에 대한 시각이 넓어질 뿐만 아니라 팀에도 기여할 수 있는 기회가 될지도 모르니까요!


References