Skip to main content
Terraform AWS Security Group: Allow ICMP Ping

Terraform AWS Security Group: Allow ICMP Ping

Key Takeaway

Create AWS security group rules for ICMP ping using Terraform. Covers ingress/egress rules, ICMP types and codes, VPC configuration

Table of Contents

Quick Answer

resource "aws_security_group_rule" "allow_ping" {
  type              = "ingress"
  from_port         = 8      # ICMP type 8 = Echo Request
  to_port           = 0      # ICMP code 0
  protocol          = "icmp"
  cidr_blocks       = ["10.0.0.0/16"]
  security_group_id = aws_security_group.web.id
}

This allows ping (ICMP Echo Request) from 10.0.0.0/16 to any instance using the web security group.

Why Ping Doesn’t Work by Default

AWS security groups block all inbound traffic by default. ICMP (ping) is no exception. You must explicitly allow it.

Common scenario: you launch an EC2 instance, SSH works, but ping times out:

$ ping 10.0.1.50
PING 10.0.1.50 (10.0.1.50): 56 data bytes
# ...hangs forever

Fix: add an ICMP ingress rule to the security group.

Complete Security Group with Ping

resource "aws_security_group" "web" {
  name        = "web-server-sg"
  description = "Allow SSH, HTTP, and ICMP"
  vpc_id      = aws_vpc.main.id

  # SSH
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [var.my_ip]
  }

  # HTTP
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # ICMP Ping
  ingress {
    from_port   = 8       # ICMP type 8 (Echo Request)
    to_port     = 0       # ICMP code 0
    protocol    = "icmp"
    cidr_blocks = ["10.0.0.0/16"]
  }

  # All outbound
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web-server-sg"
  }
}

Understanding ICMP Types and Codes

ICMP doesn’t use ports like TCP/UDP. Instead, it uses types and codes. In Terraform’s aws_security_group_rule:

  • from_port = ICMP type
  • to_port = ICMP code
ICMP TypeCodeNameUse
80Echo RequestPing (outgoing)
00Echo ReplyPing (response)
30-15Destination UnreachableNetwork errors
110Time ExceededTraceroute
-1-1All ICMPEverything

Allow Only Ping

# Allow ping requests IN
ingress {
  from_port   = 8    # Echo Request
  to_port     = 0
  protocol    = "icmp"
  cidr_blocks = ["10.0.0.0/16"]
}

Allow All ICMP

# Allow ALL ICMP (ping, traceroute, unreachable, etc.)
ingress {
  from_port   = -1
  to_port     = -1
  protocol    = "icmp"
  cidr_blocks = ["10.0.0.0/16"]
}

Allow Traceroute

ingress {
  from_port   = 11   # Time Exceeded
  to_port     = 0
  protocol    = "icmp"
  cidr_blocks = ["10.0.0.0/16"]
}

Using aws_security_group_rule (Separate Resource)

For complex security groups, use separate rule resources:

resource "aws_security_group" "app" {
  name   = "app-sg"
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app-sg"
  }
}

# Separate ping rule
resource "aws_security_group_rule" "allow_ping" {
  type              = "ingress"
  from_port         = 8
  to_port           = 0
  protocol          = "icmp"
  cidr_blocks       = [aws_vpc.main.cidr_block]
  security_group_id = aws_security_group.app.id
  description       = "Allow ICMP ping from VPC"
}

# Allow ping from another security group
resource "aws_security_group_rule" "allow_ping_from_bastion" {
  type                     = "ingress"
  from_port                = 8
  to_port                  = 0
  protocol                 = "icmp"
  source_security_group_id = aws_security_group.bastion.id
  security_group_id        = aws_security_group.app.id
  description              = "Allow ICMP ping from bastion"
}

IPv6 ICMP (ICMPv6)

For IPv6, use protocol icmpv6:

ingress {
  from_port        = 128   # ICMPv6 Echo Request
  to_port          = 0
  protocol         = "icmpv6"
  ipv6_cidr_blocks = ["::/0"]
}

Bidirectional Ping

Security groups are stateful — if you allow the Echo Request inbound, the Echo Reply outbound is automatically allowed. You only need:

# This is enough for ping to work both ways
ingress {
  from_port   = 8
  to_port     = 0
  protocol    = "icmp"
  cidr_blocks = ["10.0.0.0/16"]
}

You do NOT need a separate egress rule for the reply.

However, if you want your instance to initiate pings to external hosts, you need an outbound rule:

# Allow instance to ping external hosts
egress {
  from_port   = 8
  to_port     = 0
  protocol    = "icmp"
  cidr_blocks = ["0.0.0.0/0"]
}

Network ACLs vs Security Groups

If ping still doesn’t work after adding security group rules, check Network ACLs:

Security GroupNetwork ACL
StatefulYes (reply auto-allowed)No (need explicit inbound + outbound)
DefaultDeny all inboundAllow all
LevelInstance (ENI)Subnet

Network ACL ICMP rules:

resource "aws_network_acl_rule" "allow_ping_in" {
  network_acl_id = aws_network_acl.main.id
  rule_number    = 100
  egress         = false
  protocol       = "icmp"
  rule_action    = "allow"
  cidr_block     = "0.0.0.0/0"
  icmp_type      = 8
  icmp_code      = 0
}

resource "aws_network_acl_rule" "allow_ping_out" {
  network_acl_id = aws_network_acl.main.id
  rule_number    = 100
  egress         = true
  protocol       = "icmp"
  rule_action    = "allow"
  cidr_block     = "0.0.0.0/0"
  icmp_type      = 0
  icmp_code      = 0
}

NACLs are stateless — you must add both inbound and outbound rules.

Troubleshooting: Ping Still Not Working

  1. Security group: Is ICMP type 8 allowed inbound?
  2. Network ACL: Are both ICMP type 8 (inbound) and type 0 (outbound) allowed?
  3. Route tables: Can the source reach the destination subnet?
  4. OS firewall: Is iptables/firewalld/ufw blocking ICMP on the instance?
  5. Public vs private: Are you pinging a private IP from outside the VPC?
  6. Internet Gateway: For public IPs, does the VPC have an IGW and correct route?

Quick debug on the instance:

# Check if OS firewall blocks ICMP
sudo iptables -L -n | grep icmp

# Allow ICMP in iptables
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

Hands-On Courses

Learn by doing with interactive courses on CopyPasteLearn:

Conclusion

Add from_port = 8, to_port = 0, protocol = "icmp" to your security group ingress rules to allow ping. Security groups are stateful, so you don’t need a separate egress rule for the reply. If ping still fails, check Network ACLs (stateless — need both directions), route tables, and OS firewalls. Use from_port = -1, to_port = -1 to allow all ICMP types.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.