What is a security group - a firewall you will actually understand
A security group is AWS's version of a firewall for your cloud resources — but it's a firewall with one rule you won't find on any router you've configured before: it can only allow traffic. It has no "block this IP" button, no deny list, nothing. Every security group in every AWS account on Earth starts from "deny everything" and gets opened up one allow-rule at a time — and once you understand that one fact, half the confusing behavior you've seen in the EC2 console suddenly makes sense.
Jake found this out the expensive way. He'd just moved his phone repair shop's inventory tracker onto a small EC2 instance — nothing fancy, just a web app his two employees use to log parts. He asked a friend for help, the friend typed a command, and by Friday afternoon nobody outside the shop's Wi-Fi could reach the app. Jake assumed something had "broken." Nothing had broken. A security group was doing exactly what it was built to do: block everything that wasn't explicitly allowed.
"So it's broken," Jake said, staring at a browser tab that just kept spinning.
"It's not broken," Ethan told him. "It's working perfectly. You just haven't told it what to let through yet."
What a security group actually controls
According to AWS's own documentation, a security group controls the traffic that's allowed to reach and leave whatever it's attached to. Attach it to an EC2 instance, and it governs the inbound and outbound traffic for that instance specifically — not the whole network, not the whole subnet, just that one resource (or that one network interface, to be precise, since one instance can technically have more than one).
Think of it less like a fence around your whole property and more like a bouncer standing at one specific door. The bouncer doesn't care what's happening at the other three doors of the building. He has one list, for his one door, and he checks every single person against it. Other doors have their own bouncers with their own lists. That's a security group: door-specific, list-based, and completely indifferent to what any other security group in your account is doing.
When you launch an EC2 instance in a VPC (a Virtual Private Cloud — your own private, isolated slice of AWS's network, sized and shaped however you define it), that instance gets assigned to at least one security group. If you don't pick one yourself, AWS quietly assigns it to the VPC's default security group, and that default group has opinions of its own — more on that shortly, because it's one of the more misunderstood pieces of this whole system.
♂️ Jake's Reality Check
"Wait — so this is nothing like the firewall on my home router? I can't just tell it to block one annoying IP address that keeps hitting my site?"
No, you genuinely can't — not with a security group. A security group has no "deny" rule type at all. It can only say yes to things. If you need to explicitly block one bad actor's IP address while leaving everything else open, that's a network ACL's job, or a service like AWS WAF for web traffic — not the security group. We'll get to exactly where that line is drawn.
Stateful vs. stateless: why you never write a "reply" rule
Here's a piece of behavior that confuses almost everyone the first time they notice it: you write one inbound rule allowing HTTP traffic on port 80, and somehow the response traffic — the actual webpage going back out to the visitor's browser — just works, with no matching outbound rule. You didn't do anything to make that happen. AWS did.
Security groups are stateful. In plain terms: if a request is allowed in, the reply to that exact request is automatically allowed back out, no matter what your outbound rules say. And the reverse is true too — if your instance sends a request out, the response coming back is automatically allowed in, regardless of your inbound rules. AWS's own VPC documentation states this directly: responses to allowed inbound traffic are allowed to leave the instance regardless of the outbound rules, and vice versa.
"Stateful just means it remembers the conversation," Ethan explained. "Picture a receptionist who checks your name against a visitor list before letting you into the building. Once you're inside and you leave again, she doesn't stop you at the door and demand you prove you're 'allowed to leave' — she already knows you're supposed to be there because she let you in five minutes ago. That's the whole idea. The security group tracks the connection, not just the direction."
This one fact single-handedly explains why brand-new AWS accounts often seem to "just work" outbound with zero configuration. When you first create a security group, it starts with no inbound rules at all — meaning nothing gets in — but it does start with one default outbound rule that allows all outbound traffic. Combine that default outbound-allow with statefulness, and most instances can reach the internet (to download updates, call an API, whatever) without you touching a single setting. It's only inbound access — someone else reaching your instance — that you have to build by hand.
⚠️ What this actually breaks
If you delete that default "allow all outbound" rule and replace it with something narrower — which plenty of security-conscious teams do on purpose — remember that a rule you removed doesn't get quietly re-added for you. If your outbound rules end up not covering something your instance needs (a software update server, an API endpoint, an NTP time server), that traffic goes nowhere and gives you nothing to click on — no error dialog, no popup. It just times out. Test outbound rule changes on a non-production instance first.
The default security group: what you get whether you ask for it or not
Every VPC you create — and the default VPC AWS gives every account — comes with a security group named literally "default." AWS's documentation is specific about what that default group does out of the box:
- Default inbound rule: allows all traffic, on all ports and protocols, but only from other resources that are also in that same default security group. Nothing from the internet, nothing from another security group — just siblings inside the same group talking to each other freely.
- Default outbound rules: allows all IPv4 traffic to anywhere (0.0.0.0/0), and if the VPC has an IPv6 CIDR block, all IPv6 traffic to anywhere (::/0) as well.
In practice that means two instances sitting in the same default security group can chat with each other over any port with zero setup, but neither one is reachable from your laptop, your office, or the open internet, because none of those sources are "the default security group" itself. That's exactly what tripped Jake up — his inventory app instance landed in the default group because nobody specified otherwise, and the default group has no rule that lets anything from outside AWS in.
Two things people assume about the default security group that are both wrong, according to AWS's own docs:
You cannot delete it. If you try, AWS returns an error code of Client.CannotDelete. It's permanent for the life of the VPC. You can, however, edit its rules freely — add to them, strip them down to nothing, whatever you want. AWS's stated recommendation is to avoid relying on the default group for real workloads and instead build purpose-specific security groups, one per role (web tier, database tier, and so on), precisely so a mistake in one doesn't cascade into every resource that happened to land in "default."
It isn't automatically "safe." A lot of people assume "default" implies "AWS's recommended safe configuration." It doesn't. It's just the group AWS falls back to when you don't pick one — a parking spot, not a policy.
✅ Why this is the one to use
Create a dedicated security group for every distinct role in your setup — one for your web servers, a separate one for your database, another for your load balancer — rather than dumping everything into "default." AWS's own best-practice guidance says to create the minimum number of groups needed and use each one to manage resources with similar functions and security needs. It also means when you're staring at a rule six months from now, the group's name already tells you what it's for.
Anatomy of a rule: what actually goes into "allow this"
Every single rule you add to a security group — inbound or outbound — is built from the same handful of pieces:
Protocol
Which type of network conversation the rule applies to. The three you'll see constantly are TCP (protocol number 6 — the reliable, connection-based protocol most web traffic, SSH, and databases use), UDP (protocol 17 — a faster, connectionless protocol used for things like DNS lookups and streaming), and ICMP (protocol 1 — the diagnostic protocol behind the "ping" command).
Port range
For TCP and UDP, the specific "door number" on the instance the traffic is aimed at. Port 22 is SSH (remote command-line access to Linux machines), port 3389 is RDP (Remote Desktop, for Windows machines), port 80 is plain HTTP, port 443 is HTTPS. You can allow a single port (22) or a range (7000–8000) — AWS's documentation is explicit that you can specify either.
ICMP type and code
If the protocol is ICMP instead of TCP or UDP, you don't specify a port — you specify a type and code instead. Type 8 is an ICMP Echo Request, which is what lets someone ping your instance and get a response.
Source (inbound) or destination (outbound)
Who the rule applies to. This is the part with the most flexibility, and AWS supports several formats: a single IPv4 address (must use the /32 prefix, e.g. 203.0.113.1/32), a range of IPv4 addresses in CIDR notation (e.g. 203.0.113.0/24), a single or range of IPv6 addresses, the ID of a managed prefix list (a reusable, named group of IP ranges), or — this is the one worth pausing on — the ID of another security group.
That last option, referencing another security group as the source, is arguably the single most useful trick in the whole system, and it's the one Jake had never seen before.
♂️ Jake's Reality Check
"You mean instead of typing an IP address into the rule, I can just type another security group's name in there? Why would I ever do that instead of just using the address?"
Because IP addresses change and security groups don't. If your web server's address changes tomorrow — a reboot, a replacement, an Auto Scaling event — a rule that references its security group keeps working with zero edits. A rule that hardcoded its old IP address silently stops matching, and now you're debugging a "connection refused" error at 11pm with no idea why.
Dual-stack (IPv4 and IPv6) rules aren't automatic
If your VPC supports IPv6, a rule you write for IPv4 traffic does not automatically cover the IPv6 version of the same traffic — they're separate rules entirely. AWS's own reference examples for a typical web server lay this out as four distinct rows: TCP port 80 from 0.0.0.0/0, TCP port 443 from 0.0.0.0/0, TCP port 80 from ::/0, and TCP port 443 from ::/0. Skip the two IPv6 rows and any visitor connecting over IPv6 gets quietly refused, even though the "same" rule already exists for IPv4. This is also exactly why the 60-rule quota mentioned later is tracked separately for IPv4 and IPv6 — AWS treats them as genuinely different rule sets, not two flavors of one rule.
Editing, tagging, and deleting rules later
Rules aren't fixed at creation. In the console, select the security group, then choose Edit inbound rules or Edit outbound rules from the Actions menu (or the matching tab) to add, change, or remove entries. Two shortcuts save time on the most common sources: choosing Anywhere-IPv4 auto-fills 0.0.0.0/0, and Anywhere-IPv6 auto-fills ::/0, so you don't have to remember or type either by hand. From the CLI, the equivalent options are the --cidr flag for a single IPv4 range, --source-group for a security group, and --ip-permissions for anything more complex, like a prefix list or an IPv6 range, in a single command.
Every rule gets a unique ID the moment you create it, and AWS's documentation notes you can use that ID through the API or CLI later to modify or delete that one specific rule without disturbing any of the others in the group — useful once a group has grown past a handful of entries and you can't eyeball which line is which anymore.
One quirk worth knowing before you paste a CIDR block into a rule by hand: AWS canonicalizes it automatically. Enter 100.68.0.18/18 and AWS stores it as 100.68.0.0/18. Try adding the same range again later in its original, non-canonical form, and the API rejects it as a duplicate rule — confusing the first time it happens, since the rule you're "missing" is actually already there under its canonical form. And when you do save a change, expect it to apply fast but not necessarily instantly: AWS's own wording is that rule changes propagate to associated instances "as quickly as possible," with a brief delay possible, so testing the exact same second you save isn't a fair test of whether the rule worked.
Security group referencing: the three-tier example straight from AWS's docs
AWS's own VPC documentation walks through a specific scenario that's worth stealing wholesale, because it's the pattern almost every real web application ends up using: a load balancer in front, web servers behind it, and a database behind those. Three tiers, three security groups, and each one only opens up to the tier immediately in front of it — never directly to the internet, except the load balancer.
| Security group | Inbound rule allows | Source |
|---|---|---|
| Load balancer SG | HTTP (80) and HTTPS (443) | 0.0.0.0/0 (the internet) |
| Web server SG | HTTP (80) and HTTPS (443) | The load balancer's security group |
| Database SG | Database port (e.g. 3306 for MySQL) | The web server's security group |
Notice what's not in that database rule: an IP address, a subnet, anything numeric at all. The database only ever hears from "whatever is currently wearing the web-server-SG badge." A new web server gets launched next week with a different private IP address? It's already trusted, because it inherited the badge, not a hardcoded number.
A few conditions govern when this referencing trick works, straight from AWS's documentation: you can reference a security group in another group's inbound rule if both groups sit in the same VPC, if there's a VPC peering connection between the two VPCs they belong to, or if a transit gateway connects them. For outbound rules, the peering-connection option applies too, but the transit-gateway path does not.
One subtlety worth knowing: referencing a security group doesn't pull in that group's own rules. AWS is explicit that no rules from the referenced security group get copied over — the reference only grants network reachability from resources wearing that badge, nothing more.
Creating your first security group in the console
Here's how AWS's own documentation describes creating one through the VPC console:
- Open the Amazon VPC console.
- In the left navigation pane, choose Security groups.
- Choose Create security group.
- Enter a name and description. This part matters more than it sounds — AWS will not let you change either one after the group is created. Pick a name that describes the group's job ("web-server-sg"), not a name based on today's project.
- For VPC, choose which VPC this group belongs to. A security group only works with resources inside the VPC it was created in.
- (Optional) Add inbound rules — choose Inbound rules, then Add rule, and set the protocol, port, and source for each one.
- (Optional) Add outbound rules the same way, under Outbound rules, specifying a destination instead of a source.
- (Optional) Add tags if you use them for cost tracking or organization.
- Choose Create security group.
Remember: a brand-new security group starts with zero inbound rules — meaning nothing gets in until you add something — and one default outbound rule allowing all traffic out. You have to build the inbound side yourself, every time, from a blank slate.
If you already have a security group configured the way you like and want a near-identical one for a second project, AWS also supports copying: select an existing group, choose Actions, then Copy to new security group. The copy carries over the same inbound and outbound rules and the same VPC, though you can point it at a different VPC before saving, and you can't copy a group across AWS Regions.
Creating a security group with the AWS CLI
If you'd rather script it or you're building this into infrastructure-as-code, the AWS CLI's create-security-group command does the same job as the console form. A typical flow looks like this:
- Create the empty security group inside a specific VPC, giving it a name and description:
aws ec2 create-security-group --group-name web-server-sg --description "Web server security group" --vpc-id vpc-0abc123def456
This returns a security group ID that looks likesg-0123456789abcdef0— save it, you'll need it for the next steps. - Add an inbound rule opening HTTP traffic using
authorize-security-group-ingress, specifying the protocol, port, and source CIDR. - Add an inbound rule for HTTPS the same way, on port 443.
- Attach the security group ID to your EC2 instance, either at launch time or afterward by modifying the instance's network interface.
Security group names have a few rules worth knowing before you script this at scale: names must be unique within the VPC, they're not case-sensitive, they can run up to 255 characters, they're limited to a specific character set (letters, numbers, spaces, and a handful of punctuation marks), trailing spaces get silently trimmed, and — this one catches people — a security group name can't start with sg-, since that prefix is reserved for the auto-generated IDs.
Security groups vs. network ACLs: when you actually need both
This is the comparison almost every reader lands here looking for, and it's directly addressed in AWS's own infrastructure security documentation. A network ACL (Access Control List) is a second, completely separate firewall layer that operates at the subnet level instead of the instance level — it doesn't care which instance the traffic is headed to, only which subnet.
| Characteristic | Security group | Network ACL |
|---|---|---|
| Level of operation | Instance level | Subnet level |
| Scope | Applies to every instance associated with the group | Applies to every instance in the associated subnets |
| Rule type | Allow rules only | Allow and deny rules |
| Rule evaluation | Every rule is evaluated before a decision is made | Rules are checked in numbered order until one matches |
| Return traffic | Automatically allowed (stateful) | Must be explicitly allowed both ways (stateless) |
AWS's own guidance is direct about which one to reach for first: use security groups as the primary way to control access to your VPC, and bring in network ACLs when you need a coarser, stateless layer on top — for example, to explicitly block a specific chunk of malicious traffic across an entire subnet, something a security group can't do at all because it has no deny rules. AWS also notes that because a network ACL applies to the whole subnet, it works as a defense-in-depth backstop in case an instance somehow ever gets launched without the correct security group attached.
"Think of the network ACL as the fence around the whole yard, and the security group as the lock on your specific front door," Ethan said. "The fence can turn away a car before it even reaches your driveway. The lock only cares about the one door it's bolted to. Most of the time, for most of what Jake's shop needs, the lock is enough. You reach for the fence when you need to say 'nobody from this address range gets anywhere near this subnet, full stop' — because that's the one sentence a security group physically cannot say."
The limits nobody reads until they hit one
There's no charge for using security groups — AWS states plainly that they carry no additional cost. But they do carry quotas, and hitting one mid-project with no idea it exists is a genuinely common way people lose an afternoon. Here are the ones you're most likely to run into, per AWS's published VPC quotas:
| Quota | Default | Adjustable? |
|---|---|---|
| Security groups per Region | 2,500 | Yes |
| Inbound (or outbound) rules per security group | 60 | Yes |
| Security groups per network interface | 5 | Yes, up to 16 |
| Rules per network ACL | 20 | Yes, up to 40 per direction |
A couple of gotchas buried in the fine print here. First, the 60-rule quota is counted separately for inbound and outbound, and separately again for IPv4 versus IPv6 — so with the default quota you can actually have up to 60 inbound IPv4, 60 inbound IPv6, 60 outbound IPv4, and 60 outbound IPv6 rules on one group. Second, and this genuinely surprises people: if a rule references a customer-managed prefix list, it doesn't count as one rule — it counts as however many entries that prefix list can hold. A prefix list with room for 20 entries eats 20 rules' worth of your quota the moment you reference it, even before you've added a single actual entry to the list.
Third, and worth remembering if you're ever tempted to attach five different security groups to squeeze in more rules: the "rules per group" quota multiplied by "security groups per network interface" can never exceed 1,000 total. AWS designed it that way on purpose, so stacking groups isn't an unlimited loophole around the rule cap.
Customer-managed prefix lists carry their own separate quotas worth knowing if you use them to group CIDR ranges for reuse: 100 prefix lists per Region by default, up to 1,000 entries per list, and up to 10,000 references to any single prefix list across all of your security groups combined. That last figure matters if you're centralizing something like an "approved office networks" list and referencing it from many groups at once — it's a shared budget across your whole account, not a fresh allowance for every group that uses it.
The mistakes that actually cost people money and customers
"So what did I actually do wrong on Friday?" Jake asked. Turns out — nothing yet. Everyone gets locked out of their own instance on day one; that's just how a default-deny system behaves. The real mistakes come later, once things are working and people stop being careful.
⚠️ What this actually breaks
Opening SSH (port 22) or RDP (port 3389) to 0.0.0.0/0 — "anywhere on the internet" — is the single most common security group mistake, and AWS's own best-practice documentation calls it out by name: authorize only specific IP address ranges for those ports, because 0.0.0.0/0 and ::/0 let literally anyone, anywhere, attempt to log in. Bots scan for exactly this configuration around the clock. If you need remote access, scope it to your office's IP range, your home connection, or route it through a bastion host instead.
Beyond that headline mistake, AWS's guidance flags a few others worth internalizing:
- Opening large, unnecessary port ranges. AWS's own recommendation is not to open wide ranges "just in case" — restrict access to only the ports and sources that genuinely need it.
- Letting IAM permissions run wide open. AWS recommends authorizing only specific IAM principals to create or modify security groups at all, so a compromised account with broad permissions can't quietly loosen every firewall in your environment.
- Sprawling into too many overlapping groups. More groups means more surface area for a mistake to hide in. AWS's advice is to create the minimum number needed and group resources by shared function.
- Assuming a security group filters everything. It doesn't — and this is the one that genuinely surprises experienced people, not just beginners.
That last one deserves its own explanation. AWS's documentation lists specific categories of traffic that security groups do not filter at all, regardless of what your rules say: Amazon's own DNS service, DHCP (the protocol that hands your instance its IP address automatically), the EC2 instance metadata service (the internal address instances use to fetch their own configuration and credentials), Amazon ECS task metadata endpoints, Windows license activation traffic, the Amazon Time Sync Service, and a handful of reserved addresses used internally by the default VPC router. None of these get blocked by a security group, full stop — they're structurally exempt.
When your security group rules look right but nothing's getting through
This is the part most articles skip entirely, and it's the part people actually search for once the basic setup is done and something is still wrong.
You added the rule, but you're checking the wrong resource
Remember that a resource can sit behind multiple security groups at once, and all their rules get combined into one effective rule set. If you added your new rule to the wrong group — one that isn't actually attached to the instance you're testing — nothing changes, and there's no error to tell you why. Double-check exactly which groups are attached to the network interface in question before assuming the rule itself is wrong.
A network ACL is quietly blocking it upstream
Your security group can be flawless and traffic can still get dropped by the network ACL sitting in front of the subnet. Because a network ACL is stateless, it's also easy to allow inbound traffic on one but forget the matching outbound rule for the reply — something a security group would have handled for you automatically. If your security group rules check out, the ACL is the very next place to look.
You just saved the rule and it "still" isn't working
Give it a moment. AWS's own documentation states that rule changes propagate to associated instances as quickly as possible, but a brief delay is possible. Testing in the same second you click Save isn't a fair test — wait a few seconds and retry before concluding the rule itself is wrong.
Long-lived connections dropping for no visible reason
If a connection that's been idle for a while suddenly disconnects, that's not usually a security group rules problem — it's connection tracking. AWS tracks the state of allowed connections to make statefulness work, and idle connections eventually time out and get evicted from that tracking table. AWS's documentation specifies a default idle timeout for established TCP connections of up to 432,000 seconds (5 days) on most instance types, though newer Nitro-based instance generations use a shorter default of 350 seconds unless you explicitly configure it higher — a detail that catches people migrating to newer instance types by surprise. UDP flows time out much faster: 180 seconds for an established "stream," 30 seconds for a single one-way exchange. If your app opens a connection and goes quiet for a while, plan for that window, not for "5 days" as a universal assumption.
Your instance is running out of tracked connections entirely
Every instance has a finite allowance for how many connections it can track at once, tied to instance type. AWS's guidance for diagnosing this is to check two Elastic Network Adapter driver metrics: conntrack_allowance_available, which tells you how much headroom is left, and conntrack_allowance_exceeded, which tells you if you've blown past the limit and started dropping packets. If a high-traffic instance is mysteriously refusing new connections while your rules look completely fine, this is where to look next — and notably, VPC Flow Logs won't show you these particular drops, since packets rejected for exceeding the connection allowance never get logged there.
You changed a security group rule while a connection was already open
AWS's documentation notes that the effect of a rule change can depend on how the traffic is already being tracked — meaning tightening a rule doesn't necessarily kill an already-established connection instantly. If you revoke access and the old connection stubbornly keeps working for a bit, that's expected behavior, not a bug.
A rule referencing a peered VPC's security group stopped working
If your security group has a rule that references a group in a peer VPC, or a VPC shared by another account, that reference gets marked stale the instant the referenced security group is deleted, or the underlying peering connection itself is removed. A stale rule doesn't clean itself up automatically — it sits there until you find it and delete it manually, exactly like any other rule. In an account with several peered VPCs and more than one team touching them, this is often the real answer when access "that used to work" suddenly doesn't, and nobody remembers changing anything on your side.
⚠️ What this actually breaks
If your infrastructure routes traffic between two instances in different subnets through a middlebox appliance (a firewall or inspection device sitting in the path), referencing the other instance's security group as the source will not work for that traffic pattern. AWS's documentation is explicit here: in this scenario, each security group must reference the other instance's private IP address, or the CIDR range of the subnet it lives in — a security-group reference specifically does not allow that traffic to flow.
Security groups beyond EC2: a worked example with RDS
People tend to learn security groups in the context of a single EC2 instance and stop there, but AWS's own documentation frames them more broadly: they control traffic for "the resources that they're associated with," and it lists EC2 instances specifically as one example among "other AWS resources" that live inside a VPC. In practice that means the same rule-writing logic — allow-only, stateful, source-and-port-based — applies wherever something sits inside a VPC and needs a firewall: a load balancer, a managed database, a Lambda function attached to a VPC, an EFS file system mount target.
Amazon RDS, AWS's managed database service, is the clearest real example, and AWS's own RDS documentation walks through the exact pattern. Say you already have an EC2 instance with its own security group. You create a second, separate security group for the database itself, and its one inbound rule allows traffic on the database's port — say 3306 for MySQL — with the EC2 instance's security group named as the source, not an IP address. You then attach that new database security group to your RDS instance (through the Modify action in the console), matching the same port used in the rule. That's the identical referencing pattern from the three-tier load balancer example earlier in this post, just applied to a fully managed database instead of a self-hosted one — proof the concept isn't theoretical, it's the actual recommended setup AWS documents for its own database service.
There's an honest limit worth stating plainly here too. AWS's own EC2 documentation says security groups are one of the tools for securing your instances, and explicitly notes that if your requirements aren't fully met by security groups alone, you can maintain your own firewall on the instance itself, in addition to using them. That's a useful admission: a security group protects the network path leading to your instance, but it doesn't replace host-based firewall rules, operating system patching, or access controls running inside the instance itself. Getting the network path locked down is necessary, not sufficient.
One more structural note AWS documents: a security group can now be associated not just with resources in the VPC where it was created, but — using the Security Group VPC Association feature — with resources in other VPCs in the same AWS Region too. And you're not limited to one group per resource either; a single instance can carry multiple security groups simultaneously, up to the network interface quota mentioned earlier, with all of their rules combined into one effective set.
Best practices, straight from AWS's own playbook
Pulling together the recommendations scattered across AWS's own VPC documentation into one list:
- Restrict who can create or modify security groups to specific IAM principals — don't leave that ability broadly available.
- Keep the number of security groups you maintain to the minimum needed, and group resources by shared function and shared security requirements.
- Never open SSH or RDP to
0.0.0.0/0— scope those specific ports to known IP ranges. - Avoid opening large port ranges; restrict each opening to exactly what needs it.
- Layer network ACLs on top of security groups where you need coarser, subnet-wide guard rails or the ability to explicitly deny something.
- Turn on VPC Flow Logs so you have a record of what traffic is actually reaching your instances, which makes future troubleshooting dramatically faster.
- Use AWS Security Hub's cloud security posture management checks to catch unintended network exposure you might have missed by hand.
None of this is exotic. It's mostly discipline: name things clearly, keep rules narrow, don't reuse the default group as a dumping ground, and remember that "it works" and "it's scoped correctly" are two different questions.
Frequently asked questions
What is a security group in AWS?
It's a virtual firewall attached to a specific resource — most commonly an EC2 instance — that controls what inbound and outbound network traffic is allowed to reach or leave it. It works at the level of that individual resource, not the whole network.
Is a security group the same as a firewall?
Functionally, yes — it does a firewall's job. But it's a restricted kind of firewall: it can only allow traffic, never explicitly deny it, which is different from most traditional firewalls people have used before.
Can a security group block an IP address?
No. Security groups only support allow rules — there is no deny or block rule type. To explicitly block a specific IP address or range, you need a network ACL, which supports both allow and deny rules at the subnet level.
What's the difference between a security group and a network ACL?
A security group operates at the instance level, only allows traffic, is stateful, and evaluates all its rules together. A network ACL operates at the subnet level, supports both allow and deny rules, is stateless, and evaluates rules in numbered order until one matches.
Do I need to write a rule for return traffic?
No. Security groups are stateful, so if a request is allowed in one direction, the response is automatically allowed back in the opposite direction, regardless of what your rules say for that direction.
What happens if I don't attach a security group to my EC2 instance?
You can't launch an instance with no security group at all. If you don't pick one, AWS automatically associates the instance with the default security group for its VPC, which allows traffic only between resources inside that same default group and nothing from outside it.
Can I delete the default security group?
No. Attempting to delete a default security group returns the error code Client.CannotDelete. You can edit its rules however you like, but the group itself cannot be removed for the life of the VPC.
How many security groups can I attach to one instance?
Up to 5 security groups per network interface by default, adjustable up to 16. An instance can have multiple network interfaces, so the total across an instance can be higher depending on its configuration.
How many rules can one security group have?
60 inbound and 60 outbound rules by default, counted separately for IPv4 and IPv6, and this quota is adjustable. A rule referencing another security group counts as one rule regardless of that group's size, but a rule referencing a customer-managed prefix list counts as however many entries that prefix list can hold.
Can two security groups have the same name?
Not within the same VPC — names must be unique per VPC and are not case-sensitive. You can, however, have a VPC security group and an EC2-Classic security group share the same name, since those are separate namespaces.
Is there a cost to using security groups?
No. AWS states there's no additional charge for creating or using security groups, regardless of how many rules or groups you configure.
Can a security group reference another security group instead of an IP address?
Yes, and it's one of the most useful features of the whole system. Instead of hardcoding an IP address, a rule can name another security group's ID as its source or destination, allowing any resource wearing that group to communicate, even as individual IP addresses change underneath it.
Why can't I ping my EC2 instance even though ICMP is allowed?
Check that you allowed the correct ICMP type — type 8 is what's needed for a standard ping (Echo Request). Also confirm the rule sits in a security group that's actually attached to the right network interface, and that no network ACL upstream is silently dropping the ICMP traffic before it reaches the instance.
Why did my SSH connection drop even though nothing changed in my security group?
Most likely connection tracking timed out an idle connection. AWS's default idle timeout for established TCP connections can be as short as 350 seconds on newer Nitro-based instance types, or up to 5 days on others, so a session that sits quiet long enough can simply expire without any rule ever changing.
Do security groups filter DNS and instance metadata traffic?
No. AWS explicitly excludes several categories of traffic from security group filtering entirely, including Amazon DNS, DHCP, the EC2 instance metadata service, ECS task metadata endpoints, Windows license activation, and the Amazon Time Sync Service. None of these can be blocked by security group rules.
What is the safest way to allow SSH or RDP access?
Scope the inbound rule to a specific, known IP address or a narrow range you control, rather than 0.0.0.0/0. AWS's own best-practice guidance flags open SSH and RDP access as a specific, named risk to avoid, since it lets anyone on the internet attempt to connect.
Jake's inventory app got fixed in about four minutes once Ethan showed him where to click — one inbound rule, port 443, scoped to the shop's own office IP instead of the whole internet. No customer ever noticed the outage; the two employees just used their phones for an afternoon. But Jake kept coming back to the same sentence for weeks afterward, telling every new hire who touched the AWS console: "It's not a firewall that blocks the bad guys. It's a firewall that starts by blocking everybody, and you decide who gets an exception." That's really the whole concept, distilled down to one sentence — everything else in this post is just the mechanics of how you write those exceptions correctly.
Revision note. Written September 2026, covering AWS VPC security groups as documented on our AWS official docs at the time of writing, including current quotas, default rule behavior, and connection tracking defaults across Nitro and non-Nitro instance types. This will need a fresh look if AWS changes the default connection tracking timeouts again or updates the quota tables. If you're the person who just got locked out of your own instance for the first time today: you didn't break anything, and you're closer to understanding this than you think.
π‘ Recommended AWS Foundations Reading
Master the core building blocks of AWS infrastructure, networking, and security:
- πΊ️ Regions vs. Availability Zones — The physical map that fixes half of your latency and redundancy bugs.
- π Decoding AWS ARNs — How to read the exact address syntax for any resource across accounts and regions.
- π‘️ Shared Responsibility Model — Who fixes what when an AWS service fails or leaks.
- π Public vs. Private Subnets — Visualizing traffic flow and network isolation in a VPC.
- πͺ Internet Gateway vs. NAT Gateway — Outbound internet routing without hidden cost surprises.
- π§± AWS Security Groups — Stateful firewall rules explained in plain English.
- π Service-Linked Roles — The permissions AWS automatically creates and manages for you.
- π₯️ EC2 Instance Profiles — How EC2 instances access services without hardcoded access keys.
- π¨ Root User vs. IAM User — Why you should lock away root credentials immediately.
- π AWS MFA Setup Guide — Clear the console nagging banner and secure your account in 3 minutes.