wardviaene / terraform-course

Course files for my Udemy course about Terraform
https://www.udemy.com/learn-devops-infrastructure-automation-with-terraform/?couponCode=TERRAFORM_GIT
1.59k stars 4.04k forks source link

Demo-5: Error authorizing security group ingress rules: RulesPerSecurityGroupLimitExceeded: The maximum number of rules per security group has been reached #19

Closed popovserhii closed 5 years ago

popovserhii commented 5 years ago

I watched 22. Demo: Data sources and created securitygroup.tf with the next content on terraform 0.12.7

data "aws_ip_ranges" "european_ec2" {
  regions = ["eu-central-1", "eu-west-1"]
  services = ["ec2"]
}

resource "aws_security_group" "from_europe" {
  name = "from_europe"

  ingress {
    from_port = "443"
    to_port = "443"
    protocol = "tcp"
    cidr_blocks = data.aws_ip_ranges.european_ec2.cidr_blocks
  }
  tags = {
   CreateDate = data.aws_ip_ranges.european_ec2.create_date
   SyncToken = data.aws_ip_ranges.european_ec2.sync_token
  }
}

but when I run terraform apply I get the next error

Error: Error authorizing security group ingress rules: RulesPerSecurityGroupLimitExceeded: The maximum number of rules per security group has been reached.
    status code: 400, request id: 2ce9706d-3bd7-4694-ad18-5213da3123cf

  on securitygroup.tf line 6, in resource "aws_security_group" "from_europe":
   6: resource "aws_security_group" "from_europe" {

My AWS account is new with only default configuration. There is something wrong with my configuration?

wardviaene commented 5 years ago

There is an AWS limit that allows you to only have a certain amount of rules within security groups. Unfortunately we're hitting this limit here, because the IP lists of AWS grew a lot over time. Best would be to also filter on service (in the datasource), which gives you back less IP addresses, which will make this apply work.

-Edward

popovserhii commented 5 years ago

I found the solution of the issue. You can simply replace the line with cidr_blocks:

resource "aws_security_group" "from_europe" {
  name = "from_europe"

  ingress {
    from_port = "443"
    to_port = "443"
    protocol = "tcp"
    #cidr_blocks = data.aws_ip_ranges.european_ec2.cidr_blocks
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
   CreateDate = data.aws_ip_ranges.european_ec2.create_date
   SyncToken = data.aws_ip_ranges.european_ec2.sync_token
  }
}
chrisgelhaus commented 5 years ago

While this solution does allow the demo to complete, it bypasses the data coming from the datasource making it irrelevent. Any chance there is another option that uses data from the datasource?

chrisgelhaus commented 5 years ago

FYI, I used the splice function to get a subset of the data. Like this: cidr_blocks = slice(data.aws_ip_ranges.european_ec2.cidr_blocks, 0, 20)

romansil commented 3 years ago

Based on the vpc limits, it's possible to have 60 egress rules in one VPC. Let's create multiple security groups. An EC2 instance allows to attach multiple SGs.

data "aws_ip_ranges" "european_ec2" {
  regions = ["eu-central-1", "eu-west-1"]
  services = ["ec2"]
}

variable "max_egress_rules" {
  default = 60
}

locals {
  chunks = chunklist(data.aws_ip_ranges.european_ec2.cidr_blocks, var.max_egress_rules)
  chunks_map = { for i in range(length(local.chunks)): i => local.chunks[i] }
}

resource "aws_security_group" "sg" {
  for_each = local.chunks_map

  name = "from_europe_${each.key}"

  egress {
    from_port         = 443
    to_port           = 443
    protocol          = "tcp"
    cidr_blocks       = each.value
  }
}

As alternative, you can just increase the quotas.