Terraform 12 - aws subnetting

I’m just starting with Terraform and seem to be stuck on getting some syntax correct.

I’m creating an aws instance on a non-default VPC and need to specify the subnet_id so it’s created in the right place, but I don’t want to hard-code the aws subnet ID which is what I’m seeing in most of the examples I’m coming up with.

I have CIDR blocks defined in a separate variables file but the code I’m inheriting doesn’t seem to have any subnets specifically defined, so I’m not sure if that’s something I need to do beforehand or not.

I appreciate any help anyone can give.

Hi @aricwilisch!

Unfortunately there are a number of different ways to do what you described and it sounds like you’ve inherited a system that already has some decisions made which you may be constrained by. With that said, it’d help if you can share some more details about how that system is structured, and then I or someone else can hopefully offer some specific advice that applies to that context.

The general idea here is that your Terraform configuration will either be managing both the subnets and the instances or it will be managing just the instances and thus need to obtain information about the subnet ids that already exist. Both are possible, but which is appropriate and exactly how to achieve it will depend on how the existing system is set up, whether the subnets you will be working in where already created somehow (Terraform or otherwise), etc.

Eager to hear your responses. TIA

Thanks, sorry for the slow response. Actually I think I figured out the right way to define the subnet.

I already had the cidr range defined in variable cidr with:
burp_colab_ip = “”

So i added this in my variables file :

resource “aws_subnet” “” {
cidr_block = var.cidr._ip
vpc_id = aws_vpc..id
map_public_ip_on_launch = “true”
}

And added it to the aws_instance resource using:
subnet_id = aws_subnet..id

There does seem to be two failures though. When it try the plan goes through with no issues, but when I try to apply I get:

Error: Error creating subnet: InvalidSubnet.Range: The CIDR ‘’ is invalid.
status code: 400, request id: ebd683b3-53a4-4da1-8297-1fb2a6abc97f

I have the CIDR variable set as a /30 but I’ve tried it as big as a /16.

Second hurdle I’m trying to figure out is what the proper syntax is in the aws_instance resource to specify which IP to use out of that range. A co-worker suggested you can have it grab the 2nd address out of the range (or 4th, 8th, etc if the range was bigger).

The invalid subnet range is the bigger blocker right now though .

Hi @aricwilisch,

That CIDR error is coming from the AWS EC2 API rather than from Terraform, so it suggests that your CIDR block is not within the requirements set by the EC2 API. According to the documentation section VPC and Subnet Sizing for IPv4, the longest prefix length permitted for a subnet is /28, so your /30 prefix is too long to fit within that requirement. You’ll need to select a shorter prefix.

Although in principle you can select a specific IP address from the target subnet when declaring an aws_instance resource, that usage pattern is very uncommon. Instead, we usually leave the specific IP address unspecified and let the VPC system in AWS allocate an unused IP address automatically, which then avoids the need to centrally plan exact IP addresses for all of your instances. If you let the VPC API automatically select an IP address for you, you can then refer to the allocated IP address elsewhere in the configuration with an expression like aws_instance.example.private_ip, and thus allow other parts of the configuration to automatically use whichever IP address was selected.

If you do have an unusual situation where selecting a specific IP address is required, you can do this by setting the private_ip argument within the resource "aws_instance" ... block, like this:

  # Use the second IP address available in the containing subnet
  private_ip = cidrhost(aws_subnet.example.cidr_block, 2)

The cidrhost function calculates an IP address by appending a particular host number to a CIDR prefix.

Your code examples were corrupted a little because you didn’t mark them as being “Preformatted text” (the <> button in the editor toolbar), so I’ve written the above assuming you declared your subnet as resource "aws_instance" "example". I expect you’ve used a different name than “example” in practice, so you’ll need to substitute whatever name you selected.

Thanks, that helped. made the subnet a /28 and it took it. Course with every success comes another problem.

The subnet I’m using is a part of the larger subnet assigned to the VPC, which is a /16. When everything created it didn’t associate the subnet with the routing table for that VPC, so I couldn’t reach it at all until I associated it.

I put added this to my variables file, but haven’t tested it yet. Would this be the proper bit of code or is there a better way to do it?

resource “aws_route_table_association” “” {
subnet_id = aws_subnet..id
route_table_id = “<aws route_id”
}

Really appreciate everyones help. This little project is giving me a better understanding on how Terraform works.

In my past experience with managing EC2 VPC networks with Terraform I don’t recall having to explicitly add a subnet to a route table like that, but I guess that is because I had been using only a single route table per VPC and so the EC2 API created the necessary connection automatically.

Again your example was corrupted a little due to it not being marked up as preformatted text in the editor, but indeed based on what I see in the aws_route_table_association docs what you wrote there seems plausible. If the configuration you are writing is not the one that is creating the route table in question then you may wish to arrange for that route table ID to be passed in to your module somehow, but it’s not possible to give general advice about that without knowing more about how your larger system is built.

resource "aws_route_table_association" "example" {
  subnet_id      = aws_subnet.example.id
  route_table_id = "rt-aabc123"
}

Yeah sorry about the corrupted paste. What you listed was pretty much what I had.

I was surprised I had to associate it honestly. The Subnet Association page even says any subnets not explicitly associated will be associated with the main routing table. But I couldn’t ssh to the server until I associated it explicitly.

Only thing left for me to do is get it to associate an EIP :slight_smile: