TerraformPilot

Cloud Computing

Terraform AWS Security Group: Allow ICMP Ping

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

LLuca Berton2 min read

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.

#Terraform#AWS#security group#ICMP#ping

Share this article