### ECS Cluster
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: document-portal-cluster
### ECS Execution Role with Secrets + Logs
ECSExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: ecsTaskExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: ecs-secrets-logs-access
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
- logs:CreateLogGroup
Resource: "*"
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: "*"
### Security Group
ECSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP access to container
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: 0.0.0.0/0
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: document-portal-cluster
What it creates: An ECS Cluster named document-portal-cluster.
Purpose: logical container for running your ECS services and tasks (whether Fargate or EC2-backed). Think of it as the namespace/management surface for your containers.
Note: cluster itself is lightweight — resources come from task definitions/services you attach to it.
ECSExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: ecsTaskExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: ecs-secrets-logs-access
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
- logs:CreateLogGroup
Resource: "*"
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: "*"
Creates an IAM role that ECS tasks can assume (via sts:AssumeRole) when starting. The Principal is the ECS tasks service (ecs-tasks.amazonaws.com), which is required for the container runtime to call AWS APIs on the task’s behalf.
Attaches an inline policy named ecs-secrets-logs-access with two permission blocks:
CloudWatch Logs permissions (CreateLogGroup, CreateLogStream, PutLogEvents) with Resource: "*". This allows tasks to create log groups/streams and push logs.
SecretsManager permission secretsmanager:GetSecretValue with Resource: "*" so tasks can read secrets.
When ECS (Fargate or the ECS agent on EC2) pulls images from ECR, writes logs to CloudWatch, or fetches secrets from Secrets Manager, these actions require AWS permissions. The execution role is the role allowing those operations.
If you use Fargate, AWS requires a task execution role for image pull & logging.
Resource: "*" is broad. For production, prefer least privilege:
Limit CloudWatch Logs to specific log group ARNs.
Limit Secrets Manager to specific secret ARNs used by your app.
Missing common ECS/ECR permissions: If you’ll pull images from ECR, you typically need:
ecr:GetAuthorizationToken
ecr:BatchGetImage
ecr:GetDownloadUrlForLayer
(and possibly kms:Decrypt if images or secrets are encrypted with a customer KMS key).
Recommendation: Use AWS-managed policy AmazonECSTaskExecutionRolePolicy which contains standard required permissions for image pull + logs, then attach a separate minimal policy for Secrets Manager access.
Example pattern (conceptual):
# Prefer managed role + scope-limited inline secret policy
ECSExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: ...
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Policies:
- PolicyName: secrets-only
PolicyDocument:
Statement:
- Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: arn:aws:secretsmanager:ap-south-1:123456789012:secret:myapp-db-*
ECSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP access to container
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: 0.0.0.0/0
Creates a security group attached to your VPC that allows inbound TCP traffic on port 8080 from anywhere (0.0.0.0/0).
Default egress in AWS security groups is allow-all, so outbound traffic is permitted unless explicitly restricted.
You attach this SG to your ECS tasks (or to an ENI created by tasks) or to the service’s network interface so external requests can reach your containers on port 8080.
If you front your service with a load balancer (recommended), the LB would have its own security group that allows port 80/443 from the internet, and the LB’s SG would be allowed to talk to this ECS SG (via an ingress rule allowing the LB SG as a source) or you allow the LB subnet CIDRs — common pattern is to allow LB security group as the source.
Avoid 0.0.0.0/0 in production unless necessary. Alternatives:
If a public load balancer sits in front of the service, restrict the SG to only accept traffic from the LB’s security group (more secure).
If the service must be public, consider using port 80/443 on an ALB and have containers listen on 8080 but only allow the ALB→task SG traffic.
Add egress rules only if you want to restrict outbound traffic (default allows all).
Use descriptive Names/Tags for auditing.
Example more secure pattern:
# (pseudo)
ECSSecurityGroup:
Properties:
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
Execution role (what you created above): used by the ECS agent/container runtime to:
Pull images from ECR
Send logs to CloudWatch
Fetch secrets from Secrets Manager BEFORE handing control to the container
Task role (not shown in your snippet): assumed by the containerized application itself at runtime. Use a task role to give the app permissions to call AWS APIs (e.g., DynamoDB, S3, SQS). Usually more restricted and scoped to application needs.
If you haven’t defined a TaskRoleArn in your Task Definition, your container won’t have IAM permissions to call AWS services directly.
Use Amazon-managed execution policy for standard ECS permissions:
arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Replace "Resource": "*" with specific ARNs for logs & secrets.
Create a Task Role (IAM Role) for runtime app permissions (if the app needs to access AWS services).
Harden security group rules:
If you have an ALB, allow traffic only from the ALB SG to the tasks.
Otherwise, restrict CidrIp to known IP ranges if feasible.
Add KMS decrypt permission to execution role if your Secrets Manager secrets use a customer-managed KMS key.
You create an ECS cluster, an execution IAM role (so ECS can fetch images, logs, secrets), and a security group that allows inbound traffic to your container on port 8080.
The template works, but tighten the IAM permissions (avoid Resource: "*") and secure the security group (avoid open 0.0.0.0/0 where possible). Also add an explicit Task Role for your app’s runtime AWS permissions.