Engineers configuring security groups and firewalls tend to focus on inbound/ingress rules to restrict the networks from which requests to their applications can originate. A common best practice has long been to prevent the use of the CIDR — and aliases for it — that would allow inbound access from any IP.

However, the recent 2020 United States federal government data breach reminded me that it is also important to restrict outbound access. After all, the code originally loaded by supply chain attacks against SolarWinds and Microsoft software could not have sent any information to the Russian intelligence agencies behind the hacks and could not have downloaded and installed additional malware unless the federal security groups and firewalls allowed arbitrary outbound access.

Properly configured security groups and firewalls block outbound access to the CIDR in the same way that they block inbound access to it.

At this point, I want to confess that I have also been negligent in this area. As a field expert in the use of HashiCorp’s policy as code solution, Sentinel, I have written many example Sentinel policies including some that restrict inbound access in security groups and firewalls created by Terraform in AWS, Azure, and GCP. But I had not previously created policies that restricted outbound access.

I rectified that today by writing 3 new Sentinel policies that do prevent security groups and firewalls from using in outbound/egress rules.

How to Restrict Inbound/Ingress Access

I’ll describe my new outbound/egress rules in more detail below, but I would first like to mention the 3 existing policies that restricted inbound/ingress rules:

How to Restrict Outbound/Egress Access

It was quite easy for me to create the 3 new Sentinel policies that restrict outbound access from the 3 policies listed above.

For AWS, I wrote restrict-egress-sg-rule-cidr-blocks.sentinel by changing the type of security group rules from ingress to egress and examined egress blocks of security groups instead of their ingress blocks. I also changed the names of various variables to use “Egress” instead of “Ingress”.

For Azure, I wrote restrict-outbound-destination-address-prefixes.sentinel by changing the direction of network security rules from Inbound to Outbound and checking the destination_address_prefix and destination_address_prefixes attributes of network security groups and network security rules instead of their source_address_prefix and source_address_prefixes attributes. I also changed the names of various variables to use “Outbound” instead of “Inbound”.

For GCP, I wrote restrict-egress-firewall-destination-ranges.sentinel by changing the direction of compute firewalls from INGRESS to EGRESS and checking their destination_ranges attribute instead of their source_ranges attribute. I also renamed the ingressFirewalls variable to egressFirewalls.

I was able to write and test all 3 of the new policies as well as new test cases and mock files for them in 90 minutes. I copied the test cases and mock files from the original policies and then edited the mock files by hand to convert inbound/ingress rules to outbound/egress rules. I tested the new policies with the test command of the Sentinel CLI.

Potential Inconveniences

Restricting outbound security group and firewall rules can be inconvenient. For example, if you are downloading software with tools like curl and wget, this will only be allowed from specific networks. That means you can no longer simply clone a public GitHub repository. After all, if you allowed outbound access to GitHub, you would be allowing cloning from all public repositories, not just the ones you want! Instead, you need to copy the code from desired public repositories into a private registry on a controlled network to which your security group or firewall rules allow egress.

But any inconvenience for the developers of applications is worth the extra security derived from restricting outbound access to the entire internet.