This post is part of a series on AWS networking. Check out the other posts here.
This post starts with an image caption contest! Look at this image:
Then submit a caption:
Now on with the post!
We’re connecting an EC2 instance to the internet. We have learned a ton, but we still can’t connect to the internet, because we haven’t taken care of…
…security.
Here’s where we are now:
Setting up subnets, route tables etc is not enough. You also need to allow internet connections to pass through security: through your security groups, and through your NACLs. Those are two different things, and operate on different levels:
Security groups operate at the firewall (or EC2 instance) level
NACLs operate at the network (or subnet) level.
Security Groups
By default, your instance's security group is not set up for it to talk to the internet. You will have to explicitly set this up.
To set up a security group to talk to the internet, you need to set up rules. A security group has inbound rules and outbound rules.
Inbound requests are requests coming from outside to your EC2 instance.
Outbound requests are requests going from your EC2 instance to the broader internet.
Let’s look at an outbound rule that says you can connect to the internet. No inbound rules. That means that your servers can hit the internet, but no one from the internet can connect to your server.
Here’s a security group that allows outbound traffic to anywhere:
resource "aws_security_group" "sg" {
name = "terraform"
# We need to explicitly put the security group in this VPC
vpc_id = aws_vpc.main.id
# Outbound HTTP to anywhere
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
We’ll cover the options shortly. For now just know we just defined a security group with a rule using terraform, and that rules.
Here’s another security group example. This one allows inbound traffic to port 80 from anywhere:
resource "aws_security_group" "sg" {
name = "terraform"
# We need to explicitly put the security group in this VPC
vpc_id = aws_vpc.main.id
# Inbound HTTP from anywhere
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
You’ll want that one if you’re trying to put a server online.
Lets break down those fields
For the inbound rule above, we're saying that
We allow connections only on port 80
The server is running on port 80
We allow the TCP protocol
We allow connections from any IP.
The outbound rule we had seen above is even more permissive. That rule allows connections from and to any port, using any protocol, from any IP.
Note: On a toy server, you probably want that outbound rule so you can install packages on your EC2 instance. On production servers, people often don't have an outbound rule. This is so if a hacker gains access to the EC2 instance, they can't phone home. Users can still connect to their server because they have an inbound rule.
Here’s one more useful one – ssh from anywhere:
# ssh from anywhere
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
Useful so you can log on to your box. People often recommend making this more restrictive, so only your IP address is allowed to SSH onto the server.
State your purpose
Going back to that outbound rule example. Now we can hit google.com from our server (an outbound request). But wait: the response from Google would be inbound traffic. And we have no inbound rules!
nuance incoming
Normally that inbound traffic wouldn’t be allowed, but since this is a response to your request, it is allowed. However, if Google wanted to initiate a connection, that would not be allowed.
Sometimes you will hear security groups described as stateful. This is what that means. Stateful means the response to a request is allowed, even if inbound requests aren’t allowed. You don’t need to do anything special to enable this: it’s just how it works.
A couple misc notes
You attach a security group to an instance. An instance can have multiple security groups attached to it, and you can attach a security group to multiple instances, so it's a many-to-many relationship.
Now, before we move on to NACLs, here's a quick debugging tip.
If you try to connect to your server and the connection just hangs for a long time, the issue is probably your security group.
But if it connects but fails instantly, it's because your server is not running.
NACLs
We won't talk too much about Network ACLs, or NACLs, because the good news is, NACLs by default allow you to connect to the internet. You shouldn't need to do anything here.
Most of the time, if you want to make a security change, you will be making it to your security group.
So why use NACLs? It's useful to use a NACL when you want to block a specific IP.
Notice that you can only allow connections using security groups. You can't create a rule that would deny a connection. That plus the fact that we use CIDR blocks to specify IP addresses, means you can't really block a single IP address using security groups. But you can using NACLs. With NACLs, you specify a bunch of rules with a priority level, and rules with a smaller priority level are applied first. You can use this functionality to block specific IPs.
Summary
You don't need to change your NACL.
You do need to change your security group to explicitly allow inbound connections.
You attach your security group to one or more EC2 instances.
If you can't connect to your EC2 instance, and the request just hangs forever, it's probably because of your security group.
Thanks for reading. In the next post, we'll put it all together, and finally talk to the internet!