Hey engineers! 👋
In the previous article, we answered a fundamental question:
How does one server find another server?
We explored DNS, Private DNS, and Service Discovery the mechanisms that turn something like:
postgres.internal.company
into a reachable destination inside a network.
But finding a server is only half of the story.
Knowing where a server is doesn't automatically mean you're allowed to connect to it.
That leads us to a more interesting question.
Most developers eventually learn this architecture:
User
↓
Application
↓
Database
But how does this actually work at the network level?
If the application can connect to PostgreSQL, why can't someone on the Internet connect to the same database?
This sounds like a simple networking question.
It isn't.
The answer involves:
- Network routing
- Public and private subnets
- VPCs
- Security groups
- Firewall rules
- Network isolation
- Access boundaries
- Defense in depth
And these concepts ultimately determine something much bigger:
Which systems are allowed to talk to which other systems?
That's one of the most important questions in production infrastructure.
Because there is a critical difference between:
Can I find the server?
and:
Can I reach the server?
And an even more important difference between:
Can I reach the server?
and:
Am I allowed to connect?
In the previous article, we focused on finding the destination.
In this article, we'll focus on controlling access to that destination.
Let's break it down.
The Architecture We Usually See
Imagine a typical SaaS application:
Internet
│
▼
Load Balancer
│
▼
Application
│
▼
PostgreSQL
The application needs the database.
Customers don't.
That distinction is extremely important.
The customer needs:
Internet
↓
Application
The application needs:
Application
↓
Database
But there should usually be no direct path like this:
Internet
↓
Database
This is where cloud networking starts becoming interesting.
The First Principle: Not Everything Needs to Be Reachable
A common mistake in infrastructure design is thinking:
If a service needs to work,
it should be reachable.
Modern infrastructure follows almost the opposite principle:
Make only what needs to be reachable,
reachable.
For example:
Public
│
├── Load Balancer
│
└── API Gateway
Private
│
├── Application Servers
├── Background Workers
├── Redis
└── PostgreSQL
The database doesn't need to accept connections from the public Internet.
So why expose it?
You don't.
This simple decision dramatically reduces the attack surface.
Public Subnet vs Private Subnet
Inside a cloud network such as a VPC, resources are commonly organized into different network boundaries.
Two of the most important concepts are:
Public Subnet
Private Subnet
Think about a building.
There might be:
Public Area
↓
Reception
Meeting Room
Waiting Area
And deeper inside:
Restricted Area
↓
Operations
Finance
Infrastructure
Records
Not everyone who can enter the building should be able to enter every room.
Cloud networks work with a similar principle.
What Is a Public Subnet?
A public subnet is a subnet whose routing configuration provides a path toward an Internet Gateway.
Resources placed there can be Internet-facing when their own network configuration also permits it for example, when they have a public IP or are exposed through a public load balancer.
Typical examples include:
Load Balancers
Reverse Proxies
Internet-facing Web Servers
Bastion Hosts
A simplified architecture might look like:
Internet
│
▼
Internet Gateway
│
▼
Public Subnet
│
▼
Load Balancer
This is where Internet-facing traffic enters the system.
What Is a Private Subnet?
A private subnet is designed for resources that should not be directly reachable from the public Internet.
Typical resources include:
Application Servers
PostgreSQL
MySQL
Redis
RabbitMQ
Kafka
Background Workers
Internal Services
A simplified architecture:
Internet
✖
│
▼
Private Subnet
│
├── Application
├── Redis
└── PostgreSQL
The important idea is not:
"Nobody can access these machines."
It is:
"They are not directly reachable from the public Internet."
That distinction matters.
Private Does Not Mean Isolated
This is one of the most common misunderstandings.
Many developers hear:
Private Subnet
and think:
Nothing can connect to it.
Not true.
A private subnet can communicate with other resources inside the same VPC.
For example:
Application Server
10.0.1.10
│
▼
PostgreSQL
10.0.2.20
Both resources may exist inside:
VPC
10.0.0.0/16
The traffic can remain inside the cloud network.
It doesn't need to travel across the public Internet.
So How Does the App Reach the Database?
Suppose:
Application Server
10.0.1.10
needs to connect to:
PostgreSQL
10.0.2.20:5432
The application creates a TCP connection:
10.0.1.10
│
│ TCP :5432
▼
10.0.2.20
The VPC routing system determines how packets should move between those network destinations.
If the route exists and the relevant security controls permit the traffic, the connection succeeds.
There is no requirement for the database to have a public IP.
In fact, keeping the database private is usually the safer design.
Then What Stops Everyone Else?
This is where Security Groups become important.
Routing answers:
Where should this packet go?
Security controls answer:
Is this traffic allowed?
These are different questions.
Security Groups: The Access Control Layer
In AWS, a Security Group acts as a stateful virtual firewall associated with resources such as EC2 instances and certain managed services.
Imagine a building.
The subnet is the area of the building.
The security group is the access control at the door.
The database exists.
The network path may exist.
But access can still be restricted.
For PostgreSQL, the standard port is:
5432
A dangerous rule might look like:
Inbound
Port: 5432
Source: 0.0.0.0/0
That effectively allows connection attempts from anywhere that can reach the database.
That is rarely what you want for a production database.
The Better Rule
Instead of:
Allow everyone
define:
Allow application servers
For example:
Database Security Group
│
└── Inbound
│
├── Protocol: TCP
├── Port: 5432
└── Source: App Security Group
Now the access relationship becomes:
Internet User
✖
Random Server
✖
Unrelated Service
✖
Application Server
✔
This is much more meaningful than simply allowing a large IP range.
Why Security Group References Matter
Consider an application running on multiple servers.
Initially:
10.0.1.10
So someone might configure:
Allow 10.0.1.10 → PostgreSQL:5432
Then autoscaling happens.
Now there are:
10.0.1.10
10.0.1.11
10.0.1.12
10.0.1.13
Tomorrow there may be twenty.
The infrastructure is dynamic.
Hardcoding individual IP addresses creates unnecessary operational complexity.
Instead, define an application security group:
app-sg
Attach it to application servers.
Then configure the database:
db-sg
Inbound:
5432
Source:
app-sg
Now the rule expresses the actual architectural relationship:
Application Layer
│
│ allowed
▼
Database Layer
The exact server IP becomes less important.
Network Access Is a Chain of Decisions
A database connection isn't simply:
Can I ping the database?
Multiple layers can influence whether traffic succeeds.
Conceptually:
Application
│
▼
DNS Resolution
│
▼
Route
│
▼
Network ACL
│
▼
Security Group
│
▼
Database Listener
│
▼
PostgreSQL
If any required layer is incorrectly configured, the connection can fail.
This is why production networking can feel confusing.
There isn't always one single "firewall."
There are multiple boundaries.
A Production-Style Architecture
A more realistic architecture might look like this:
Internet
│
▼
┌─────────────────┐
│ Load Balancer │
│ Public │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Application │
│ Servers │
│ Private │
└────────┬────────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Redis │ │ PostgreSQL │
│ Private │ │ Private │
└──────────────┘ └──────────────┘
Notice the boundaries.
The Internet can reach the load balancer.
The load balancer can reach the application.
The application can reach PostgreSQL.
But the Internet does not get a direct path to PostgreSQL.
This Is Defense in Depth
Now imagine the application itself contains a vulnerability.
An attacker manages to compromise a public-facing component.
A poorly designed network might look like:
Compromised Server
│
├── Database ✔
├── Redis ✔
├── Internal APIs ✔
└── Everything Else ✔
The blast radius becomes enormous.
A better architecture might look like:
Compromised Server
│
├── Database ✔
├── Redis ✖
├── Internal Service ✖
└── Other Systems ✖
The attacker may still have compromised one component.
But the compromise doesn't automatically become a compromise of the entire environment.
That is the value of segmentation.
Security Is About Blast Radius
One of the most useful ways to think about infrastructure security is:
What happens if one component is compromised?
Not:
Can anything ever be hacked?
That second question is unrealistic.
Production systems should be designed with the assumption that individual components can fail or become compromised.
The goal is to limit the damage.
For example:
Internet
│
▼
Public Service
│
▼
Private Application
│
▼
Private Database
Each layer has a limited set of allowed relationships.
This creates smaller blast radiuses.
Why This Matters Beyond Security
Network isolation isn't only about preventing attackers.
It also improves operational control.
Suppose a database is publicly accessible.
Then many different systems can potentially attempt to connect:
Internet
│
├── Bots
├── Scanners
├── Attackers
├── Unknown Services
└── Legitimate Clients
Now the database must deal with traffic it never needed in the first place.
A private database changes the model:
Application Layer
│
▼
Database
The allowed communication becomes explicit.
That improves:
- Security
- Reliability
- Troubleshooting
- Operational visibility
- Compliance
- Change management
The Business Impact Is Hidden in the Architecture
A network diagram may look purely technical.
But every boundary represents a business decision.
Consider a database containing:
Customer Accounts
Payment Records
Orders
Personal Information
Internal Business Data
If that database is accidentally exposed, the consequences can extend far beyond engineering:
Misconfiguration
↓
Unauthorized Access
↓
Data Exposure
↓
Incident Response
↓
Downtime / Investigation
↓
Customer Impact
↓
Financial & Reputation Cost
The infrastructure decision happened at the technical layer.
The consequences don't stay there.
This is why architecture is ultimately connected to business continuity.
"Nobody Knows the Database IP" Is Not Security
Another common assumption is:
Nobody knows my database IP.
Therefore:
I'm safe.
That's security through obscurity.
A better assumption is:
Assume the attacker knows the address.
Then ask:
Can they establish a connection?
If the answer is:
No route
+
No public exposure
+
Security group denies access
then knowing the address doesn't help much.
The important boundary is not secrecy.
It is reachability and authorization.
Public Exposure vs Private Access
Let's compare the two models.
Public Database
Internet
│
▼
Public IP
│
▼
PostgreSQL:5432
The database is directly exposed to Internet traffic.
Even if authentication is strong, the attack surface is unnecessarily large.
Private Database
Internet
│
✖
│
▼
Private Network
│
▼
PostgreSQL:5432
And:
Application
│
✔
▼
PostgreSQL:5432
The database only needs to serve the application.
So the network should reflect that requirement.
A Simple Mental Model
Think of your infrastructure as a building.
STREET
│
▼
Public Lobby
│
▼
Employee Area
│
▼
Vault
The public can enter the lobby.
Employees can enter restricted areas.
Only authorized systems can reach the vault.
Now translate that into cloud architecture:
Internet
│
▼
Public Subnet
│
▼
Private Application Layer
│
▼
Private Database Layer
And Security Groups define:
Who can move between the layers.
That's the mental model worth remembering.
The Bigger Engineering Principle
A strong production architecture doesn't ask:
How do we make everything communicate?
It asks:
What actually needs to communicate?
Then it creates the smallest set of allowed paths.
For example:
Load Balancer
│
▼
Application
│
├──────► PostgreSQL
│
└──────► Redis
But:
Internet ─────X────► PostgreSQL
Internet ─────X────► Redis
Redis ─────────X────► PostgreSQL
unless those connections are explicitly required.
This is the principle of least privilege applied to networking.
Frequently Asked Questions
What is a public subnet?
A public subnet is a subnet whose routing configuration provides a path toward an Internet Gateway. Resources in it can be made Internet-facing when their own configuration permits public connectivity.
What is a private subnet?
A private subnet is designed for resources that should not be directly reachable from the public Internet.
Common examples include:
- Application servers
- Databases
- Redis
- Message brokers
- Background workers
- Internal services
Can an application connect to a database in a private subnet?
Yes.
Private does not mean isolated.
If the appropriate network routes exist and security controls permit the connection, an application in one private subnet can communicate with a database in another private subnet.
Why shouldn't a database normally be publicly accessible?
A public database unnecessarily increases the attack surface.
Instead of:
Internet
↓
Database
a safer architecture is usually:
Internet
↓
Load Balancer
↓
Application
↓
Database
The database only needs to accept connections from systems that actually use it.
What is a Security Group?
A Security Group is a virtual, stateful network firewall used to control allowed traffic to and from supported cloud resources.
For example:
Database Security Group
Inbound:
TCP 5432
Source:
Application Security Group
This allows PostgreSQL traffic from the application layer while denying unrelated sources.
Why use a Security Group instead of an IP address?
Infrastructure is dynamic.
Application servers may be created, destroyed, replaced, or scaled automatically.
Instead of maintaining:
10.0.1.10
10.0.1.11
10.0.1.12
a security-group relationship can express:
Application Layer
↓
Database Layer
This better represents the intended architecture.
Does a private database need a public IP?
No.
A database can be reachable from private application servers using private networking without having a public IP address.
What happens if an attacker compromises an application server?
That depends on the network architecture.
If the application server has unrestricted access to the environment, the attacker may be able to move laterally.
With segmentation and least-privilege access, the attacker may encounter multiple boundaries:
Compromised Application
│
├── Required Database ✔
├── Internal Service ✖
├── Other Database ✖
└── Management Systems ✖
This limits the potential blast radius.
What is defense in depth?
Defense in depth means relying on multiple independent security layers rather than a single control.
For example:
Network Isolation
↓
Private Subnet
↓
Security Group
↓
Application Authentication
↓
Database Authentication
If one layer fails, other layers can still provide protection.
Is hiding the database IP enough to secure it?
No.
Security through obscurity is not a reliable security strategy.
A stronger model assumes the address or infrastructure details may eventually become known and asks:
Can an unauthorized system actually reach it?
What is the difference between routing and security groups?
They solve different problems.
Routing determines where traffic can go:
Where should the packet go?
Security controls determine whether the traffic is allowed:
Is this traffic permitted?
Both can be required for a successful connection.
What is least privilege in networking?
Least privilege means giving a system only the network access it actually needs.
For example:
Application
│
├── PostgreSQL:5432 ✔
├── Redis:6379 ✔
└── Everything else ✖
The goal is to minimize unnecessary communication paths.
Why is network segmentation important?
Segmentation limits how far an attacker, malfunctioning service, or misconfigured application can reach.
Without segmentation:
One Compromise
↓
Entire Environment
With segmentation:
One Compromise
↓
Limited Access
↓
Limited Blast Radius
Should application servers also be public?
Not necessarily.
A common architecture is:
Internet
↓
Public Load Balancer
↓
Private Application Servers
↓
Private Database
The application servers don't need to be directly exposed when the load balancer is responsible for receiving Internet traffic.
What should developers understand about cloud networking?
Developers working with production systems should understand at least:
- IP addressing
- CIDR ranges
- VPCs
- Subnets
- Routing
- Internet Gateways
- NAT
- Security Groups
- Network ACLs
- DNS
- Private networking
- Service discovery
- Load balancing
You don't need to become a network engineer to build applications.
But you should understand how your application actually reaches the systems it depends on.
Key Takeaways
- Public does not automatically mean insecure, and private does not automatically mean secure.
- Public exposure should exist only where there is a real requirement.
- Private networking reduces unnecessary Internet exposure.
- Routing determines possible network paths.
- Security Groups determine whether specific traffic is allowed.
- Least privilege applies to networks just as it applies to application permissions.
- Segmentation reduces blast radius.
- Infrastructure security is fundamentally about controlling communication paths.
- The strongest architecture is often the one with the fewest unnecessary paths.
About the Author
Anik Sikder is a Software Engineer specializing in Backend Systems, DevOps, Cloud Infrastructure, and Software Architecture.
He writes about Python, Django, FastAPI, JavaScript, System Design, distributed systems, cloud infrastructure, and scalable software engineering practices.



