Amazon ECS 보안 점검은 대부분 “컨테이너가 호스트 권한을 얼마나 침범할 수 있는가”, “외부 인터넷에 직접 노출되는가”, “비밀 정보와 로그가 안전하게 처리되는가”로 정리할 수 있습니다. 특히 ECS 태스크 정의(Task Definition)는 컨테이너 실행 방식, 권한, 파일시스템, 환경 변수, 로그 설정이 모두 들어가는 핵심 보안 지점입니다.
AWS도 ECS 태스크 네트워크 모드와 관련해 특별한 이유가 없다면 awsvpc 네트워크 모드 사용을 권장하고 있으며, Fargate 태스크는 awsvpc 네트워크 모드가 필수입니다.

1. host 네트워크 모드 사용을 피해야 한다
ECS 태스크 정의에서 networkMode를 host로 설정하면 컨테이너가 Docker의 가상 네트워크를 우회하고, EC2 호스트의 네트워크 네임스페이스를 직접 사용하게 됩니다. 이 경우 컨테이너 포트가 호스트 ENI에 직접 매핑되며, 동일 포트를 여러 태스크가 함께 사용할 수 없는 제약도 생깁니다.
보안 관점에서는 더 중요합니다. host 네트워크 모드는 컨테이너와 호스트 사이의 격리 수준을 낮춥니다. 일반적인 웹 애플리케이션, API 서버, 백엔드 서비스라면 host보다 awsvpc 모드를 사용하는 것이 더 안전합니다.
권장 설정은 다음과 같습니다.
{
"networkMode": "awsvpc"
}
2. ECS 서비스의 assignPublicIp는 DISABLED로 설정해야 한다
ECS 서비스에서 assignPublicIp가 ENABLED이면 태스크의 ENI에 퍼블릭 IP가 자동 할당됩니다. AWS Security Hub의 ECS 보안 제어도 AssignPublicIP가 ENABLED이면 실패로 판단하고, DISABLED이면 통과로 판단합니다.
일반적인 구조에서는 ECS 태스크를 프라이빗 서브넷에 배치하고, 외부 접근은 ALB나 NLB를 통해 받는 것이 좋습니다. Fargate 서비스도 프라이빗 서브넷에 배치하고 public IP를 사용하지 않으면, 아웃바운드 트래픽은 NAT Gateway를 통해 나가도록 구성할 수 있습니다.
서비스 설정 예시는 다음과 같습니다.
{
"networkConfiguration": {
"awsvpcConfiguration": {
"subnets": [
"subnet-private-a",
"subnet-private-b"
],
"securityGroups": [
"sg-ecs-service"
],
"assignPublicIp": "DISABLED"
}
}
}
3. pidMode를 host로 설정하지 않아야 한다
pidMode를 host로 설정하면 컨테이너가 호스트의 프로세스 네임스페이스를 공유하게 됩니다. 이 경우 컨테이너 내부에서 호스트의 프로세스를 볼 수 있고, 상황에 따라 호스트 프로세스에 영향을 줄 수 있습니다.
AWS Security Hub의 ECS.3 제어는 ECS 태스크 정의가 호스트의 프로세스 네임스페이스를 공유하는지 확인하며, 컨테이너가 호스트 PID 네임스페이스를 공유하면 격리 효과가 줄어들고 비인가 접근 위험이 커진다고 설명합니다.
권장 설정은 단순합니다. 대부분의 경우 pidMode를 아예 지정하지 않거나, 최소한 host로 지정하지 않으면 됩니다.
{
"pidMode": null
}
실제 태스크 정의 JSON에서는 pidMode 항목을 생략하는 방식이 일반적입니다.
4. privileged는 true로 설정하지 않아야 한다
privileged: true는 컨테이너에 호스트 수준의 강한 권한을 부여합니다. AWS Security Hub의 ECS.4 제어는 ECS 태스크 정의의 컨테이너 정의에서 privileged가 true이면 실패로 판단하며, 이 설정이 컨테이너에 호스트 컨테이너 인스턴스에 대한 상승 권한을 부여한다고 설명합니다.
보안 기준에서는 다음처럼 명시적으로 false를 넣는 것이 좋습니다.
{
"name": "app",
"image": "nginx:latest",
"privileged": false
}
특히 ECS on EC2 환경에서 privileged 컨테이너는 호스트 침해로 이어질 수 있는 위험한 설정입니다. Docker-in-Docker, 보안 에이전트, 특수한 시스템 도구처럼 정말 필요한 경우가 아니라면 사용하지 않는 것이 원칙입니다.
5. readonlyRootFilesystem을 true로 설정해야 한다
readonlyRootFilesystem: true는 컨테이너의 루트 파일시스템을 읽기 전용으로 설정합니다. AWS Security Hub의 ECS.5 제어는 이 값이 false이거나 컨테이너 정의에 없으면 실패로 판단합니다. AWS는 이 설정이 컨테이너 인스턴스의 루트 파일시스템이 변조되거나 쓰이는 공격 벡터를 줄이고, 최소 권한 원칙에도 부합한다고 설명합니다.
권장 설정은 다음과 같습니다.
{
"name": "app",
"image": "nginx:latest",
"readonlyRootFilesystem": true
}
단, 애플리케이션이 /tmp, 캐시 디렉터리, 업로드 디렉터리 등에 쓰기 작업을 해야 한다면 별도 볼륨이나 임시 스토리지 경로를 명확히 설계해야 합니다. 루트 파일시스템 전체를 쓰기 가능하게 두는 대신, 필요한 경로만 제한적으로 쓰기 가능하게 만드는 방식이 좋습니다.
6. 비밀 정보를 environment에 직접 넣지 않아야 한다
ECS 태스크 정의의 environment에 비밀번호, 액세스 키, 토큰 같은 값을 직접 넣으면 위험합니다. AWS 문서에서도 태스크 정의에 지정된 환경 변수는 해당 태스크 정의에 대해 DescribeTaskDefinition 권한이 있는 사용자와 역할이 읽을 수 있다고 안내합니다.
AWS Security Hub의 ECS.8 제어는 environment 변수에 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, ECS_ENGINE_AUTH_DATA 같은 민감한 키가 들어 있는지 확인하며, 비밀 정보는 Parameter Store나 Secrets Manager를 사용하는 방식을 권장합니다.
나쁜 예시는 다음과 같습니다.
{
"environment": [
{
"name": "DB_PASSWORD",
"value": "plain-text-password"
}
]
}
권장 방식은 secrets를 사용하는 것입니다.
{
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-2:123456789012:secret:prod/db/password"
}
]
}
로그 설정에서 민감한 옵션이 필요한 경우에도 secretOptions를 사용할 수 있고, 이 값은 Secrets Manager 또는 Systems Manager Parameter Store에 저장한 뒤 참조할 수 있습니다.
7. logConfiguration을 반드시 설정해야 한다
컨테이너 로그가 남지 않으면 장애 분석, 침해 조사, 감사 대응이 매우 어려워집니다. AWS Security Hub의 ECS.9 제어는 최신 활성 ECS 태스크 정의에 logConfiguration이 없거나, 컨테이너 정의의 logDriver 값이 null이면 실패로 판단합니다. AWS는 로깅이 ECS의 신뢰성, 가용성, 성능 유지에 도움이 되며, 오류의 근본 원인을 찾는 데 필요하다고 설명합니다.
일반적인 CloudWatch Logs 설정 예시는 다음과 같습니다.
{
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/prod-app",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
}
}
보안 기준을 반영한 ECS 태스크 정의 예시
아래는 앞의 기준을 반영한 대표적인 Fargate용 ECS 태스크 정의 예시입니다.
{
"family": "secure-ecs-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsAppTaskRole",
"containerDefinitions": [
{
"name": "app",
"image": "123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/app:latest",
"essential": true,
"user": "1000",
"privileged": false,
"readonlyRootFilesystem": true,
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"environment": [
{
"name": "APP_ENV",
"value": "production"
}
],
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-2:123456789012:secret:prod/db/password"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/secure-ecs-task",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
빠른 점검 체크리스트
| 점검 항목 | 권장 값 |
| networkMode | awsvpc |
| assignPublicIp | DISABLED |
| pidMode | host 사용 금지 |
| privileged | false |
| readonlyRootFilesystem | true |
| 민감 정보 | environment 직접 입력 금지, secrets 사용 |
| 로그 설정 | logConfiguration 설정 |
마무리
ECS 보안은 복잡해 보이지만 핵심은 단순합니다. 컨테이너가 호스트와 과도하게 공유하지 않도록 하고, 외부 인터넷에 직접 노출하지 않으며, 비밀 정보와 로그를 올바르게 다루는 것입니다.
특히 운영 환경에서는 host 네트워크 모드, pidMode: host, privileged: true, 평문 환경 변수, 로그 미설정 같은 항목을 우선적으로 제거해야 합니다. 이 설정들은 단순한 권고가 아니라 실제 침해 사고에서 공격자가 컨테이너 탈출, 자격 증명 탈취, 로그 회피를 시도할 때 자주 악용될 수 있는 지점입니다.
'클라우드' 카테고리의 다른 글
| Bastion Host 없이 EC2에 접속하기: AWS Session Manager와 EC2 Instance Connect Endpoint (0) | 2026.06.13 |
|---|---|
| AWS Network Firewall 이해하기: VPC 트래픽을 통제하는 관리형 네트워크 방화벽 (0) | 2026.06.12 |
| AWS 태그 설계 가이드: 비용, 보안, 운영을 연결하는 가장 기본적인 거버넌스 (1) | 2026.06.10 |
| EC2 Image Builder 이해하기: 골든 AMI를 자동으로 만들고 관리하는 AWS 서비스 (1) | 2026.06.09 |
| AWS VPC 보안 기능 한 번에 이해하기: 클라우드 네트워크를 안전하게 설계하는 방법 (0) | 2026.06.09 |