Networking Security: Self-Managed / Firewalls for Self-Managed Deployments
Imagine setting up IP binding on your MongoDB server only to discover unauthorized access attempts still hitting your database.
IP binding alone isn't enough to properly secure your MongoDB deployment.
You need defense in-depth, and a properly configured firewall is your next critical security layer. In this lesson, we'll explore what firewalls do for MongoDB security and how to configure iptables on Linux to protect your database.
By the end, you'll know how to create rules that work alongside your IP binding settings for comprehensive protection.
A firewall is a security system that monitors and controls network traffic based on predetermined security rules. Just as a physical firewall in a building prevents fire from spreading between sections, a digital firewall creates a barrier between your trusted MongoDB environment and the untrusted outside world.
It examines each packet of data trying to enter or leave your network and decides whether to allow it through based on your rules.
Firewalls operate at different layers of the network stack, typically filtering traffic by examining source and destination IP addresses, port numbers, network protocols, and connection states.
Each piece of information helps the firewall make decisions about which traffic to allow and which to block. For MongoDB, a firewall adds an extra layer of protection beyond IP binding.
While IP binding restricts which addresses your MongoDB listens on, a firewall controls which external systems can initiate connections to those addresses in the first place.
This dual protection is important because if your firewall configuration has any gaps, the IP binding serves as a second line of defense.
So how do we configure a firewall to protect our MongoDB deployment?
The approach varies depending on your operating system.
Windows servers typically use Windows Defender Firewall, while macOS has its built in firewall.
For our MongoDB servers running on Linux, we'll use iptables for demonstration purposes. Though modern Linux distributions increasingly leverage eBPF based alternatives like Selenium for better performance and observability.
Numerous third party options are also available, so you are not restricted to just the solutions mentioned here. IP tables is a command line firewall tool built into the Linux kernel.
When working with iptables, we'll use terminal commands to define rules that examine packets based on their source, destination, port, and other characteristics.
Each rule we create will either accept legitimate traffic or drop potentially dangerous connections before they ever reach our database service. Now that we understand what IP tables is, let's explore how it organizes rules using chains.
iptables uses the concept of chains to process network traffic based on this direction.
The two main chains we'll focus on for MongoDB security are the input chain, which handles all incoming connections to your MongoDB server, and the output chain, which manages all outgoing connections from your server.
This distinction is important because in a MongoDB replica set, our nodes need to communicate with each other. We need to allow both incoming traffic to each node and outgoing responses from each node.
Let's take a look at a basic example of configuring input and output chains to allow traffic from another MongoDB server to our replica set.
In this first command, we start with iptables to invoke the tool.
"-A INPUT" means that we're adding a rule to the input chain.
With "-s" we specify the source IP address that's allowed to connect to us.
"-p TCP" indicates we're working with the TCP protocol.
"--destination-port 27017" targets MongoDB's default port.
With "-m state --state NEW, ESTABLISHED", we use the state module to match only connections that are either new or already established.
Finally, "-j ACCEPT" tells the firewall to jump to the accept action, allowing this traffic through.
The second command creates a corresponding rule for the output chain.
It allows our server to send data back to the same IP address specified with "-d".
"--source-port 27017" indicates responses coming from our MongoDB port. This rule only permits "-m state --state ESTABLISHED" connections, meaning our server can respond to existing connections but won't initiate new ones from that IP on port 27017.
These complementary rules ensure that MongoDB nodes can receive connections and respond appropriately while maintaining firewall protection.
Beyond allowing our MongoDB replica set members to communicate with each other, we also need to configure our firewall to permit traffic from our application servers.
After all, databases are only useful when applications can't connect to them.
Similar to our previous rules, we need to create specific iptables entries that allow your application server to reach your MongoDB deployment.
The syntax is almost identical, but we'll use the IP address of your application server instead.
Here, we're allowing incoming connections from your application server to MongoDB's port 27017 and permitting MongoDB to send response data back to the same application server.
You would replace IP address with your actual application server's IP address.
But what if you have multiple application servers?
Simply repeat these commands for each server's IP address.
This granular approach ensures that only legitimate application servers can communicate with your database while blocking access to all other sources.
If your application servers are on a common subnet, you can also use CIDR (Classless Inter-Domain Routing) notation to specify a range of IP addresses.
For example, if all your application servers are on the subnet shown on screen, you could just use this notation in your firewall rules or security groups to permit traffic to the entire subnet at once, covering all two hundred and fifty six possible addresses in that range instead of creating individual rules for each server.
This approach maintains strong security while reducing the number of individual rules you'll need to manage.
If you're working with a sharded MongoDB deployment, your firewall configuration becomes significantly more complex.
Sharded clusters involve additional components beyond standard replica sets, each requiring specific firewall rules.
In a sharded environment, you must account for config servers which store metadata about the cluster, shard servers that store the actual data, and query routers or mongos instances which direct client requests.
Each component needs carefully crafted firewall rules.
Config servers must communicate with each other with shard servers and with mongos instances.
Similarly, shard servers need to talk to other shards, to config servers, and to mongos instances.
The mongos instances, in turn, require access to both config servers and all shards. This interconnected nature means you'll need to create multiple iptables rules for each component using their respective ports.
The complexity increases with the size of your sharded cluster.
Remember that missing even one communication path can result in decreed performance or functionality in your MongoDB deployment.
So careful planning and implementation are essential.
Now that we've established specific rules to allow necessary traffic, it's time to strengthen our security posture by updating the default behavior of iptables.
By default, iptables allows all traffic that doesn't match any rules.
This approach is convenient, but it creates a security risk since any traffic we don't explicitly block will be permitted.
Instead, we want to implement a default deny approach where the only traffic we've explicitly allowed can pass through. This is accomplished by changing the default policy for our input and output chains from ACCEPT to DROP.
The "-p" flag stands for policy, and we're setting the default policy for both chains to DROP.
This means that any traffic that doesn't match our previously defined ACCEPT rules will be discarded.
Exercise caution with these commands. Improperly configured rules could lock you out entirely.
Always have a backup access method before altering default policies.
After configuring all our necessary firewall rules, we face one final challenge.
iptables rules are stored in memory by default.
This means that when your server restarts, all your carefully crafted security rules will vanish unless you take steps to make them persistent.
This is where the iptables-save command becomes helpful.
This utility captures your current iptables configuration and outputs it in a format that can be restored later.
We can redirect this output to a configuration file.
This command takes all your current iptables rules and policies and saves them to this file. However, simply saving the rules isn't enough.
We also need to ensure they're restored whenever the system reboots.
Different Linux distributions handle this differently.
On some systems, you might need to create a startup script that runs the restoration command.
Make sure that you verify your rules persist after a reboot. Excellent work.
Let's recap what we covered.
We define firewalls as security barriers that monitor and control network traffic based on predefined rules.
We learned to use iptables on Linux to manage both input chains or incoming traffic and output chains or outgoing responses.
We established the importance of a default deny approach by setting chains to DROP traffic and ensure persistence of our rules by using iptables-save. Remember that firewalls complement IP binding to form a multilayered security strategy.
