Security groups don’t actually restrict traffic to your ECS tasks; they restrict traffic from your ECS tasks.

Let’s say you have an ECS task running a web server, and you want to ensure it only talks to your RDS database. You’ve got a security group attached to your ECS task, sg-task-webserver, and another attached to your RDS instance, sg-rds-db. You’d think you’d add a rule to sg-task-webserver to allow outbound traffic to sg-rds-db. That’s not how it works.

Here’s how it actually works:

  1. Security groups are stateful firewalls: This means if you allow outbound traffic from a security group, the return traffic for that established connection is automatically allowed back in, regardless of inbound rules. Conversely, if you allow inbound traffic, the outbound response is automatically allowed.

  2. Security groups are applied at the Elastic Network Interface (ENI) level: When an ECS task is launched, it’s assigned an ENI (or multiple ENIs if using awsvpc network mode). The security groups you associate with the task definition or service are attached to this ENI.

  3. Outbound rules control what your task can initiate: To control what your ECS task can talk to, you need to configure the outbound rules of the security group attached to the task’s ENI.

Let’s walk through the web server to RDS example.

Scenario:

  • An ECS Fargate service running a web application.
  • The web application needs to connect to an RDS PostgreSQL database.
  • We want to ensure the web app can only connect to the RDS instance and nothing else (for outbound traffic).

Configuration:

  • ECS Task Security Group: sg-ecs-webapp (attached to the task ENI).
  • RDS Security Group: sg-rds-db.

What to do:

  1. Configure sg-ecs-webapp (Outbound Rules):

    • Go to the VPC console -> Security Groups.
    • Select sg-ecs-webapp.
    • Under "Outbound rules," click "Edit outbound rules."
    • Add a rule:
      • Type: Custom TCP
      • Protocol: TCP
      • Port range: 5432 (default PostgreSQL port)
      • Destination: sg-rds-db (select the RDS security group by ID or name).
      • Description: Allow outbound to RDS DB

    This rule tells the ENI associated with sg-ecs-webapp that it’s allowed to initiate TCP connections on port 5432 to any resource that also has sg-rds-db attached.

  2. Configure sg-rds-db (Inbound Rules):

    • Go to the VPC console -> Security Groups.
    • Select sg-rds-db.
    • Under "Inbound rules," click "Edit inbound rules."
    • Add a rule:
      • Type: PostgreSQL (or Custom TCP, Port 5432)
      • Protocol: TCP
      • Port range: 5432
      • Source: sg-ecs-webapp (select the ECS task security group by ID or name).
      • Description: Allow inbound from ECS Web App

    This rule tells the RDS instance’s ENI that it’s allowed to accept incoming TCP connections on port 5432 from any resource that has sg-ecs-webapp attached.

Why this works:

  • The outbound rule on sg-ecs-webapp permits the web server task to send connection requests to the RDS instance.
  • Because security groups are stateful, the return traffic from the RDS instance back to the web server for this established connection is automatically permitted by sg-ecs-webapp, even if there were no explicit inbound rules on sg-ecs-webapp for this traffic.
  • The inbound rule on sg-rds-db ensures that only traffic originating from your ECS web app (or more precisely, from an ENI with sg-ecs-webapp attached) can reach the database on port 5432.

Crucial Point: By default, all outbound traffic from a security group is allowed. If you want to restrict outbound traffic (which is usually the goal when talking about "restricting traffic"), you must explicitly deny all outbound traffic first, and then add specific allow rules for what is permitted.

Example of Restrictive Outbound:

Suppose sg-ecs-webapp has a default "Allow All Outbound" rule. If you want to only allow connections to RDS:

  1. Remove the default "Allow All Outbound" rule from sg-ecs-webapp.
  2. Add the specific outbound rule to sg-ecs-webapp allowing TCP to port 5432, with the destination set to sg-rds-db.
  3. Add the inbound rule to sg-rds-db allowing TCP from port 5432 from sg-ecs-webapp.

Now, your ECS task can only initiate connections to resources that have sg-rds-db attached on port 5432. Any other outbound connection attempt will be implicitly denied because there’s no rule allowing it.

Common Pitfalls:

  • Confusing Inbound/Outbound: Most people instinctively think about controlling what comes into a service. For ECS tasks and outbound traffic control, you must focus on the security group’s outbound rules.
  • Forgetting Stateful Nature: If you only set the outbound rule on the task SG, you might miss the inbound rule on the target service’s SG, and vice-versa. Both sides need to agree.
  • Using IP Addresses Instead of Security Group IDs: While you can use CIDR blocks (like 0.0.0.0/0 or specific IPs), referencing security group IDs is far more dynamic and robust. When the IPs of your tasks or RDS instance change (which can happen), your rules remain valid.
  • Network Mode (awsvpc is Key): This entire discussion assumes you’re using the awsvpc network mode for your ECS tasks. In older network modes like bridge or host, security groups are applied differently (e.g., to the EC2 instance itself for host mode), and the ENI concept doesn’t apply directly to the task. awsvpc is the modern, recommended approach for granular network control.
  • Order of Operations: If you have multiple outbound rules and the first one matches, subsequent rules are not evaluated. For example, if you have "Allow All Outbound" and then a specific "Deny" rule, the "Allow All" will take precedence if it’s listed first and matches. AWS security groups don’t have explicit "Deny" rules in the same way traditional firewalls do; denial is implicit for anything not explicitly allowed.

After setting up these rules correctly, the next common issue you’ll encounter is your application failing to resolve DNS names for internal AWS services because outbound DNS traffic (UDP/TCP port 53) isn’t explicitly allowed.

Want structured learning?

Take the full Ecs course →