AWS Container Security with ECS and EKS
AWS Container Security with ECS and EKS
Amazon Web Services offers two primary container orchestration services: Elastic Container Service (ECS) for AWS-native orchestration and Elastic Kubernetes Service (EKS) for managed Kubernetes. Both services integrate deeply with AWS security services, providing comprehensive security capabilities when properly configured. Understanding these integrations enables organizations to build secure, scalable container deployments.
ECS task definitions serve as security boundaries, defining IAM roles, network configurations, and resource limits. Task-level IAM roles provide fine-grained AWS permissions without embedding credentials. AWS Fargate eliminates host management, reducing attack surface but limiting some security controls. EC2-based ECS provides more control but requires host hardening. Choosing between Fargate and EC2 impacts security architecture decisions.
# Example: Secure ECS task definition with AWS security integrations
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Secure ECS Task Definition with comprehensive AWS security controls'
Parameters:
Environment:
Type: String
Default: production
AllowedValues: [development, staging, production]
Resources:
# KMS key for encryption
ContainerEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key for container encryption
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
- Sid: Allow ECS to use the key
Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- logs.amazonaws.com
Action:
- 'kms:Decrypt'
- 'kms:GenerateDataKey'
Resource: '*'
# Task execution role
TaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
Policies:
- PolicyName: SecretAccess
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'secretsmanager:GetSecretValue'
Resource:
- !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/*'
- Effect: Allow
Action:
- 'kms:Decrypt'
Resource:
- !GetAtt ContainerEncryptionKey.Arn
# Task role with minimal permissions
TaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: 'sts:AssumeRole'
Condition:
StringEquals:
'aws:SourceAccount': !Ref 'AWS::AccountId'
Policies:
- PolicyName: ApplicationPermissions
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 's3:GetObject'
- 's3:PutObject'
Resource:
- !Sub 'arn:aws:s3:::${Environment}-app-data/*'
- Effect: Allow
Action:
- 'dynamodb:GetItem'
- 'dynamodb:PutItem'
- 'dynamodb:Query'
Resource:
- !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Environment}-app-table'
# Security group for containers
ContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for ECS containers
VpcId: !ImportValue VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
SourceSecurityGroupId: !ImportValue ALBSecurityGroupId
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: HTTPS outbound for API calls
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
DestinationSecurityGroupId: !ImportValue DatabaseSecurityGroupId
Description: PostgreSQL database access
# ECS Task Definition
SecureTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub '${Environment}-secure-app'
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: '512'
Memory: '1024'
ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
TaskRoleArn: !GetAtt TaskRole.Arn
ContainerDefinitions:
- Name: secure-app
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Environment}-app:latest'
Essential: true
ReadonlyRootFilesystem: true
User: '10001:10001'
LinuxParameters:
InitProcessEnabled: true
Capabilities:
Drop:
- ALL
Environment:
- Name: ENVIRONMENT
Value: !Ref Environment
- Name: AWS_DEFAULT_REGION
Value: !Ref 'AWS::Region'
Secrets:
- Name: DATABASE_URL
ValueFrom: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/database-url'
- Name: API_KEY
ValueFrom: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/api-key'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: ecs
HealthCheck:
Command:
- CMD-SHELL
- 'wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1'
Interval: 30
Timeout: 5
Retries: 3
StartPeriod: 60
MountPoints:
- SourceVolume: tmp-volume
ContainerPath: /tmp
- SourceVolume: cache-volume
ContainerPath: /app/cache
Volumes:
- Name: tmp-volume
Host: {}
- Name: cache-volume
Host: {}
# CloudWatch Log Group with encryption
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/ecs/${Environment}-secure-app'
RetentionInDays: 30
KmsKeyId: !GetAtt ContainerEncryptionKey.Arn
# EventBridge rule for security monitoring
SecurityMonitoringRule:
Type: AWS::Events::Rule
Properties:
Description: Monitor ECS task security events
EventPattern:
source:
- aws.ecs
detail-type:
- ECS Task State Change
detail:
lastStatus:
- STOPPED
stoppedReason:
- anything-but: "Scaling activity initiated by (deployment ecs-svc/*)"
State: ENABLED
Targets:
- Arn: !ImportValue SecuritySNSTopicArn
Id: "1"
EKS security leverages Kubernetes-native controls with AWS integrations. IAM roles for service accounts (IRSA) provide pod-level AWS permissions. AWS VPC CNI enables native VPC networking with security groups. AWS ALB ingress controller integrates with WAF for application protection. These integrations require careful configuration to maintain security while enabling functionality.