

# Amazon ECS 태스크 및 컨테이너 보안 모범 사례
<a name="security-tasks-containers"></a>

컨테이너 이미지를 공격에 대한 첫 번째 방어선으로 보아야 합니다. 이미지가 안전하지 않고 잘못 구성되어 있으면 공격자가 컨테이너의 경계를 벗어나 호스트에 액세스할 수 있습니다. 이러한 상황이 발생할 위험을 줄이려면 다음과 같이 해야 합니다.

작업 및 컨테이너를 설정할 때 다음을 수행하는 것이 좋습니다.

## 최소로 생성하거나 distroless 이미지 사용
<a name="security-tasks-containers-recommendations-images"></a>

먼저 컨테이너 이미지에서 불필요한 바이너리를 모두 제거합니다. Amazon ECR 퍼블릭 갤러리의 익숙하지 않은 이미지를 사용하는 경우 이미지를 검사하여 각 컨테이너 레이어의 콘텐츠를 참조하는지 확인합니다. 이를 위해 [Dive](https://github.com/wagoodman/dive)와 같은 애플리케이션을 사용할 수 있습니다.

또는 애플리케이션과 해당 런타임 종속성만 포함하는 **distroless** 이미지를 사용할 수도 있습니다. 이런 이미지는 패키지 관리자 또는 셸을 포함하지 않습니다. Distroless 이미지는 “스캐너의 신호 대 노이즈 비율을 개선하고 프로비넌스를 필요한 만큼으로 설정하여 부담을 줄입니다”. 자세한 내용을 알아보려면 GitHub 설명서의 [distroless](https://github.com/GoogleContainerTools/distroless)를 참조하세요.

Docker에는 **scratch**라고 하는 예약된 최소 이미지에서 이미지를 생성하는 메커니즘이 있습니다. 자세한 내용은 Docker 설명서의 [Creating a simple parent image using **scratch**](https://docs.docker.com/develop/develop-images/baseimages/#create-a-simple-parent-image-using-scratch)를 참조하세요. Go와 같은 언어를 사용하면 정적 연결 바이너리를 생성하고 Dockerfile에서 참조할 수 있습니다. 다음 예제에서 이 작업을 수행하는 방법을 안내합니다.

```
############################
# STEP 1 build executable binary
############################
FROM golang:alpine AS builder
# Install git.
# Git is required for fetching the dependencies.
RUN apk update && apk add --no-cache git
WORKDIR $GOPATH/src/mypackage/myapp/
COPY . .
# Fetch dependencies.
# Using go get.
RUN go get -d -v
# Build the binary.
RUN go build -o /go/bin/hello
############################
# STEP 2 build a small image
############################
FROM scratch
# Copy our static executable.
COPY --from=builder /go/bin/hello /go/bin/hello
# Run the hello binary.
ENTRYPOINT ["/go/bin/hello"]
This creates a container image that consists of your application and nothing else, making it extremely secure.
```

앞의 예제는 다단계 빌드의 예이기도 합니다. 이러한 유형의 빌드는 컨테이너 레지스트리로 푸시되는 최종 이미지의 크기를 최소화하는 데 사용할 수 있으므로 보안 측면에서 매력적입니다. 빌드 도구 및 기타 불필요한 바이너리가 없는 컨테이너 이미지는 이미지의 공격 표면을 줄여 보안 태세를 향상합니다. 다단계 빌드에 대한 자세한 내용은 Docker 설명서의 [다단계 빌드](https://docs.docker.com/build/building/multi-stage/)를 참조하세요.

## 이미지를 스캔하여 취약성 확인
<a name="security-tasks-containers-recommendations-vulnerability-scanning"></a>

컨테이너 이미지는 해당하는 가상 머신과 마찬가지로 취약성이 있는 바이너리 및 애플리케이션 라이브러리를 포함하거나 시간에 따라 취약성이 증가할 수 있습니다. 악용을 방지하는 가장 좋은 방법은 이미지 스캐너로 이미지를 정기적으로 스캔하는 것입니다.

Amazon ECR은 일반적인 취약성 및 노출도(CVE) 데이터베이스를 사용하는 두 가지 버전의 기본 스캔을 제공합니다.
+ **AWS 네이티브 기본 스캔** - 현재 GA이며 권장되는 AWS 네이티브 기술을 사용합니다. 이 향상된 기본 스캔은 널리 사용되는 다양한 운영 체제에서 고객에게 더 나은 스캔 결과와 취약성 감지를 제공하도록 설계되었습니다. 이를 통해 고객은 컨테이너 이미지의 보안을 더욱 강화할 수 있습니다. 모든 신규 고객 레지스트리에는 기본적으로 이 향상된 버전이 선택됩니다.
+ **Clair 기본 스캔** - 오픈 소스 Clair 프로젝트를 사용하는 이전 기본 스캔 버전으로 더 이상 사용되지 않습니다. Clair에 대한 자세한 내용은 GitHub의 [Clair](https://github.com/quay/clair)를 참조하세요.

AWS 네이티브 기본 스캔과 Clair 기본 스캔 모두 2024년 9월 이후 추가된 리전을 제외하고 [리전별 AWS 서비스](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)에 나열된 모든 리전에서 지원됩니다. Clair 지원은 더 이상 사용되지 않으므로 Clair는 새 리전이 추가될 때 지원되지 않으며 2025년 10월 1일부터 모든 리전에서 더 이상 지원되지 않습니다.

Amazon ECR은 가능한 경우 업스트림 배포 소스의 CVE에 대한 심각도를 사용합니다. 그렇지 않으면 공통 취약성 평가 시스템(CVSS) 점수가 사용됩니다. CVSS 점수를 사용하여 NVD 취약성 심각도 등급을 얻을 수 있습니다. 자세한 내용은 [NVD 취약성 심각도 등급](https://nvd.nist.gov/vuln-metrics/cvss)을 참조하세요.

또한 스캔 결과를 Amazon ECR 콘솔 내에서 보거나 [DescribeImageScanFindings](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeImageScanFindings.html) API를 호출하여 확인할 수 있습니다. `HIGH` 또는 `CRITICAL` 취약성이 있는 이미지는 삭제하거나 다시 빌드해야 합니다. 배포된 이미지에서 취약성이 발견되면 가능한 한 빨리 교체해야 합니다.

[Docker Desktop Edge 버전 2.3.6.0](https://www.docker.com/products/docker-desktop/) 이상에서는 로컬 이미지를 [스캔](https://docs.docker.com/engine/scan/)할 수 있습니다. 스캔은 애플리케이션 보안 서비스인 [Snyk](https://snyk.io/)에서 제공합니다. 취약성이 발견되면 Snyk는 Dockerfile에서 취약성이 있는 계층 및 종속성을 식별합니다. 또한 취약성이 적은 더 슬림한 기본 이미지를 사용하거나 특정 패키지를 최신 버전으로 업그레이드하는 것과 같은 안전한 대안도 추천합니다. Docker 스캔을 사용하면 개발자가 이미지를 레지스트리에 푸시하기 전에 잠재적인 보안 문제를 해결할 수 있습니다.
+ [Automating image compliance using Amazon ECR and AWS Security Hub CSPM](https://aws.amazon.com/blogs/containers/automating-image-compliance-for-amazon-eks-using-amazon-elastic-container-registry-and-aws-security-hub/)에서는 AWS Security Hub CSPM에서 Amazon ECR의 취약성 정보를 표시하고 취약한 이미지에 대한 액세스를 차단하여 문제 해결을 자동화하는 방법을 설명합니다.

## 이미지에서 특수 권한 제거
<a name="security-tasks-containers-recommendations-defang-images"></a>

액세스 권한 플래그 `setuid` 및 `setgid`가 지정되면 실행 파일의 소유자 또는 그룹의 권한으로 실행 파일을 실행할 수 있습니다. 이러한 액세스 권한이 있는 바이너리는 권한을 에스컬레이션하는 데 사용될 수 있으므로 이미지에서 모두 제거하세요. 악의적인 목적으로 사용될 수 `nc` 및 `curl`과 같은 셸 및 유틸리티를 모두 제거하는 것이 좋습니다. `setuid` 및 `setgid` 액세스 권한이 있는 파일을 찾으려면 다음 명령을 사용할 수 있습니다.

```
find / -perm /6000 -type f -exec ls -ld {} \;
```

이러한 파일에서 이러한 특수 권한을 제거하려면 컨테이너 이미지에 다음 지시문을 추가합니다.

```
RUN find / -xdev -perm /6000 -type f -exec chmod a-s {} \; || true
```

## 큐레이팅한 이미지 세트 생성
<a name="security-tasks-containers-recommendations-curated-images"></a>

개발자가 직접 이미지를 생성하도록 하지 말고, 조직의 다양한 애플리케이션 스택에 대해 검증된 이미지 세트를 생성하세요. 이렇게 하면 개발자는 Dockerfile 작성 방법을 배울 필요 없이 코드 작성에 집중할 수 있습니다. 변경 사항이 코드베이스에 병합되면 CI/CD 파이프라인은 자산을 자동으로 컴파일한 다음 아티팩트 리포지토리에 저장할 수 있습니다. 그리고 마지막으로, 아티팩트를 적절한 이미지에 복사한 다음 Amazon ECR과 같은 Docker 레지스트리로 푸시할 수 있습니다. 최소한 기본 이미지 세트를 생성해야 합니다. 그래야만 개발자가 이를 바탕으로 자체 Dockerfile을 생성할 수 있습니다. 이미지를 Docker Hub에서 가져오지 마세요. 이미지에 무엇이 들어 있는지 항상 알 수 있는 것은 아니며, 이미지에는 취약성이 포함될 수 있습니다.

## 애플리케이션 패키지 및 라이브러리에서 취약성 스캔
<a name="security-tasks-containers-recommendations-vulnerability-scanning"></a>

이제는 오픈 소스 라이브러리를 일반적으로 사용합니다. 운영 체제 및 OS 패키지와 마찬가지로 이러한 라이브러리에는 취약성이 있을 수 있습니다. 개발 수명 주기의 일부로 이러한 라이브러리를 스캔하고 중요한 취약성이 발견되면 업데이트해야 합니다.

Docker Desktop은 Snyk를 사용하여 로컬 스캔을 수행합니다. Snyk는 오픈 소스 라이브러리의 취약성과 잠재적 라이선스 문제를 찾는 데에도 사용할 수 있습니다. 개발자 워크플로에 직접 통합하여 오픈 소스 라이브러리로 인한 위험을 완화할 수 있습니다. 자세한 내용은 다음 항목을 참조하세요.
+ [Open Source Application Security Tools](https://owasp.org/www-community/Free_for_Open_Source_Application_Security_Tools)에는 애플리케이션의 취약성을 탐지하기 위한 도구 목록이 포함되어 있습니다.

## 정적 코드 분석 수행
<a name="security-tasks-containers-recommendations-static-code-analysis"></a>

컨테이너 이미지를 빌드하기 전에 정적 코드 분석을 수행해야 합니다. 이 분석은 소스 코드를 대상으로 수행되며 코딩 오류뿐 아니라 오류 주입과 같이 악의적인 행위자가 악용할 수 있는 코드를 식별하는 데 사용됩니다. Amazon Inspector를 사용할 수 있습니다. 자세한 내용은 *Amazon Inspector 사용 설명서*의 [Amazon Inspector로 Amazon ECR 컨테이너 이미지 스캔](https://docs.aws.amazon.com/inspector/latest/user/scanning-ecr.html)을 참조하세요.

## 루트가 아닌 사용자로 컨테이너 실행
<a name="security-tasks-containers-recommendations-run-non-root-users"></a>

루트가 아닌 사용자로 컨테이너를 실행해야 합니다. 기본적으로 컨테이너는 Dockerfile에 `USER` 지시문이 포함되어 있지 않으면 `root` 사용자로 실행됩니다. Docker에서 할당하는 기본 Linux 기능에 따라 `root`로 실행할 수 있는 작업이 제한되지만, 그 효과는 미미합니다. 예를 들어 `root`로 실행되는 컨테이너는 여전히 디바이스에 액세스할 수 없습니다.

CI/CD 파이프라인의 일부로 Dockerfiles를 lint하여 `USER` 지시문을 찾고 이 지시문이 없으면 빌드할 수 없게 해야 합니다. 자세한 내용은 다음 항목을 참조하세요.
+ [Dockerfile-lint](https://github.com/projectatomic/dockerfile_lint)는 파일이 모범 사례를 따르는지 확인하는 데 사용할 수 있는 RedHat의 오픈 소스 도구입니다.
+ [Hadolint](https://github.com/hadolint/hadolint)는 모범 사례를 준수하는 Docker 이미지를 빌드하기 위한 또 다른 도구입니다.

## 읽기 전용 루트 파일 시스템 사용
<a name="security-tasks-containers-recommendations-read-only-file-system"></a>

읽기 전용 루트 파일 시스템을 사용해야 합니다. 컨테이너의 루트 파일 시스템은 기본적으로 쓰기 가능합니다. `RO`(읽기 전용) 루트 파일 시스템으로 컨테이너를 구성하면 데이터를 유지할 수 있는 위치를 명시적으로 정의해야 합니다. 이 경우 특별히 권한을 부여받지 않는 한 컨테이너의 파일 시스템에 쓸 수 없으므로 공격 표면이 줄어듭니다.

**참고**  
읽기 전용 루트 파일 시스템을 사용하면 파일 시스템에 쓸 수 있어야 하는 특정 OS 패키지에서 문제가 발생할 수 있습니다. 읽기 전용 루트 파일 시스템을 사용할 계획이라면 사전에 철저히 테스트하세요.

## CPU 및 메모리 제한과 함께 작업 구성(Amazon EC2)
<a name="security-tasks-containers-recommendations-configure-limits"></a>

CPU 및 메모리 제한과 함께 작업을 구성하여 다음과 같은 위험을 최소화해야 합니다. 작업의 리소스 제한은 작업 내의 모든 컨테이너에서 예약할 수 있는 CPU 및 메모리 양의 상한을 설정합니다. 제한을 설정하지 않으면 작업에서 호스트의 CPU와 메모리에 액세스할 수 있습니다. 이로 인해 공유 호스트에 배포된 작업이 다른 작업의 시스템 리소스를 부족하게 만드는 문제가 발생할 수 있습니다.

**참고**  
AWS Fargate 기반 Amazon ECS 작업에서는 CPU 및 메모리 제한 값이 결제 목적으로 사용되므로 이러한 값을 지정해야 합니다. Amazon ECS Fargate에서는 각 작업이 자체 전용 인스턴스에서 실행되므로 하나의 작업이 시스템 리소스를 모두 독차지하더라도 문제가 되지 않습니다. 메모리 제한을 지정하지 않는 경우 Amazon ECS는 각 컨테이너에 최소 4MB를 할당합니다. 마찬가지로 작업의 CPU 제한을 설정하지 않으면 Amazon ECS 컨테이너 에이전트는 최소 2개 CPU를 할당합니다.

## Amazon ECR에서 변경 불가능한 태그 사용
<a name="security-tasks-containers-recommendations-immutable-ecr-tags"></a>

Amazon ECR에서는 변경 불가능한 태그를 사용하여 이미지를 구성할 수 있으며, 구성해야 합니다. 이렇게 하면 이미지의 변경 또는 업데이트된 버전을 동일한 태그를 사용하여 이미지 리포지토리로 푸시하지 못하게 됩니다. 따라서 공격자가 손상된 버전의 이미지를 동일한 태그가 지정된 이미지에 푸시하는 것을 방지할 수 있습니다. 변경 불가능한 태그를 사용하면 결과적으로 변경할 때마다 다른 태그의 새 이미지를 푸시할 수밖에 없게 됩니다.

## 컨테이너를 privileged로 실행하지 않음(Amazon EC2)
<a name="security-tasks-containers-recommendations-avoid-privileged-containers"></a>

컨테이너를 privileged로 실행하지 않아야 합니다. 백그라운드의 경우 `privileged`로 실행되는 컨테이너는 호스트에서 확장된 권한으로 실행됩니다. 즉, 이 컨테이너는 호스트에서 `root`에 할당된 Linux 기능을 모두 상속합니다. 이 파라미터 사용을 엄격하게 제한하거나 금지해야 합니다. Amazon ECS 컨테이너 에이전트 환경 변수 `ECS_DISABLE_PRIVILEGED`를 `true`로 설정하여 `privileged`가 필요하지 않은 경우 특정 호스트에서 컨테이너가 `privileged`로 실행되지 않게 하는 것이 좋습니다. 또는 AWS Lambda를 사용하여 작업 정의를 스캔하고 `privileged` 파라미터를 사용하는지 확인할 수 있습니다.

**참고**  
AWS Fargate 기반 Amazon ECS에서는 컨테이너를 `privileged`로 실행할 수 없습니다.

## 컨테이너에서 불필요한 Linux 기능 제거
<a name="security-tasks-containers-recommendations-remove-linux-capabilities"></a>

다음은 Docker 컨테이너에 할당되는 기본 Linux 기능의 목록입니다. 각 기능에 대한 자세한 내용은 [Overview of Linux Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html)를 참조하세요.

```
CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL,
CAP_SETGID, CAP_SETUID, CAP_SETPCAP, CAP_NET_BIND_SERVICE, 
CAP_NET_RAW, CAP_SYS_CHROOT, CAP_MKNOD, CAP_AUDIT_WRITE, 
CAP_SETFCAP
```

컨테이너에서 위에 나열된 Docker 커널 기능 중 필요하지 않은 것이 있으면 컨테이너에서 삭제하는 것이 좋습니다. 각 Docker 커널 기능에 대한 자세한 내용은 [KernalCapabilities](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_KernelCapabilities.html)를 참조하세요. 다음을 수행하여 사용 중인 기능을 확인할 수 있습니다.
+ OS 패키지 [libcap-ng](https://people.redhat.com/sgrubb/libcap-ng)를 설치하고 `pscap` 유틸리티를 실행하여 각 프로세스에서 사용 중인 기능을 나열합니다.
+ 또한 [capsh](https://www.man7.org/linux/man-pages/man1/capsh.1.html)를 사용하여 프로세스에서 사용 중인 기능의 암호를 해제할 수 있습니다.

## 고객 관리형 키(CMK)를 사용하여 Amazon ECR로 푸시된 이미지 암호화
<a name="security-tasks-containers-recommendations-cmk-encryption"></a>

고객 관리형 키(CMK)를 사용하여 Amazon ECR로 푸시된 이미지를 암호화해야 합니다. Amazon ECR로 푸시된 이미지는 저장 시 AWS Key Management Service(AWS KMS) 관리형 키를 사용하여 자동으로 암호화됩니다. 대신 자체 키를 사용하고 싶은 경우 이제 Amazon ECR에서는 고객 관리형 키(CMK)를 사용한 AWS KMS 암호화를 지원합니다. CMK를 사용하여 서버 측 암호화를 활성화하기 전에 설명서의 [저장된 데이터 암호화](https://docs.aws.amazon.com/AmazonECR/latest/userguide/encryption-at-rest.html)에 열거된 고려 사항을 검토하세요.