OCI Network Internet Gateways Should Not Be Exposed
More Info:
Internet Gateways that are enabled and attached to a VCN provide direct internet connectivity. Unnecessary internet gateways expand the network attack surface.
Risk Level
Medium
Address
Compliance, Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- HIPAA
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- Reserve Bank of India (RBI) Cyber Security Framework
- Reserve Bank of India (RBI) Master Direction – Information Technology Framework
- SOC2
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
Below are step‑by‑step remediation options in the OCI Console for the issue
“OCI Network Internet Gateways Should Not Be Exposed” in the context of OCI Networking / Monitoring (e.g., flagged by Cloud Guard, Network Monitoring, or security posture tools).
1. Identify the Exposed Internet Gateway
- Sign in to the OCI Console.
- In the top-left, open the Navigation menu → Networking → Virtual Cloud Networks.
- Select the compartment where the issue was reported.
- Click the VCN in which the Internet Gateway (IGW) exists.
- In the left panel of the VCN details page, click Internet Gateways.
- Find the Internet Gateway flagged as exposed (or review each IGW):
- Check State (should be “Available”).
- Check if it is attached to route tables with 0.0.0.0/0 pointing to it.
If a security tool (Cloud Guard, etc.) gave you a specific IGW OCID or name, use that to find it.
2. If the Internet Gateway Is Not Needed → Disable or Delete It
A. Disable the Internet Gateway
- From the VCN → Internet Gateways list, click the IGW name.
- Click Edit.
- Uncheck Enable internet gateway.
- Click Save changes.
B. Delete the Internet Gateway (only if you are sure it’s not needed)
- Ensure no route table has this IGW as a target:
- From VCN page, click Route Tables.
- Open each Route Table and remove any rule with Target Type = Internet Gateway pointing to this IGW (see Section 3 below).
- Once no routes use it, go back to Internet Gateways.
- Click the Actions (⋮) menu next to the IGW → Terminate (or Delete).
- Confirm deletion.
3. If the Internet Gateway Must Exist → Remove or Restrict Public Routes
The exposure usually comes from default route 0.0.0.0/0 → Internet Gateway.
A. Remove the 0.0.0.0/0 Route to IGW (Preferred)
- From the VCN page, click Route Tables.
- For each Route Table associated with public subnets:
- Click the route table name.
- Click Edit.
- For any route rule with:
- Destination CIDR Block = 0.0.0.0/0 and
- Target Type = Internet Gateway (your IGW),
- Click the trash icon to remove that rule.
- Optionally, add a more restrictive rule (e.g., specific CIDRs if you must allow certain IP ranges).
- Click Save changes.
If the subnet no longer needs internet access at all, it’s now effectively private.
B. Use NAT Gateway or Service Gateway Instead of IGW (For Private Egress)
If workloads only need outbound access (no inbound from Internet):
- From Navigation menu → Networking → Virtual Cloud Networks → open your VCN.
- In left panel, click NAT Gateways → Create NAT Gateway (if not already present).
- Still in the VCN, go to Route Tables, edit the relevant route table:
- Remove
0.0.0.0/0 → Internet Gateway. - Add
0.0.0.0/0 → NAT Gateway.
- Remove
- Associate that route table with the subnets that should be private but require outbound Internet.
For OCI services (Object Storage, etc.) without public Internet:
- In VCN, click Service Gateways → Create Service Gateway.
- Edit route tables:
- Add route with Destination Type = Service CIDR (All OCI Services or specific service).
- Target Type = Service Gateway.
- Remove any corresponding
0.0.0.0/0 → Internet Gatewayif not required.
4. Tighten Security for Subnets Using IGW (If You Must Keep Public Access)
If you absolutely must keep an IGW and public subnet, limit exposure:
A. Restrict Security Lists or Network Security Groups (NSGs)
- From Networking → Virtual Cloud Networks → open your VCN.
- For Security Lists:
- Click Security Lists, open the list associated with the public subnet.
- Edit Ingress Rules:
- Remove or narrow any 0.0.0.0/0 rules, especially with wide ports (e.g., 0–65535).
- Add only the minimal required IP ranges and ports (e.g., SSH from your office IP only).
- Edit Egress Rules similarly, restricting if possible.
- For NSGs (recommended over security lists):
- Click Network Security Groups.
- Open the NSG associated with your instances.
- Reduce rules from
0.0.0.0/0to specific source CIDRs and ports.
5. Validate via Networking / Monitoring / Cloud Guard
- If using Cloud Guard:
- Go to Navigation menu → Identity & Security → Cloud Guard.
- Check Detections.
- Confirm that the “Network Internet Gateways Should Not Be Exposed” problem is Resolved after your changes (may take a few minutes).
- If using Network Monitoring / VCN Flow Logs:
- Verify that no unexpected inbound traffic from unknown internet IPs is reaching formerly exposed subnets.
- Optionally run an updated Security Assessment / Vulnerability scan to confirm no open/public endpoints remain unintentionally exposed.
Summary remediation pattern (OCI Console):
- If IGW unnecessary → Disable or Delete it.
- If IGW required → remove 0.0.0.0/0 routes or move subnets to NAT/Service Gateway.
- Where IGW and public subnets must exist → strict Security Lists/NSGs and narrow routes.
Using CLI
To “remediate” exposed Internet Gateways (IGs) in OCI via CLI, you typically:
- Identify all Internet Gateways and which are “exposed”
- Stop exposure by:
- Disabling or deleting the IG, and/or
- Removing 0.0.0.0/0 routes that point to the IG
Below are step‑by‑step OCI CLI commands you can run.
0. Set up common variables
# Replace with your values
COMPARTMENT_OCID="<your_compartment_ocid>"
VCN_OCID="<your_vcn_ocid>" # optional if you want to scope to a VCN
1. List Internet Gateways in a compartment
oci network internet-gateway list \
--compartment-id "$COMPARTMENT_OCID" \
--all
Look for:
"is-enabled": true- Attached
"vcn-id": "..."
If you want to filter by VCN:
oci network internet-gateway list \
--compartment-id "$COMPARTMENT_OCID" \
--vcn-id "$VCN_OCID" \
--all
Note each internet-gateway-id that should not be exposed.
2. Find route tables that expose these IGs
For each IG:
IG_OCID="<internet_gateway_ocid>"
oci network route-table list \
--compartment-id "$COMPARTMENT_OCID" \
--all \
--output json
Inspect the JSON for any route-rules with:
"destination": "0.0.0.0/0""network-entity-id": "<IG_OCID>"
To narrow with jq:
oci network route-table list \
--compartment-id "$COMPARTMENT_OCID" \
--all \
--output json | \
jq --arg IG "$IG_OCID" '
.data[] |
select(.["route-rules"][]? |
.["network-entity-id"] == $IG and .destination == "0.0.0.0/0") |
{ "routeTableId": .id, "displayName": .["display-name"], "routeRules": .["route-rules"] }
'
Any returned route tables are exposing the IG to the internet.
3. Remove 0.0.0.0/0 routes to the Internet Gateway
For each exposed route table, fetch its full config:
RT_OCID="<route_table_ocid>"
oci network route-table get \
--rt-id "$RT_OCID" \
--output json > rt.json
Edit rt.json and remove or change any rule like:
{
"cidrBlock": "0.0.0.0/0",
"networkEntityId": "<internet_gateway_ocid>"
}
or (for newer APIs):
{
"destination": "0.0.0.0/0",
"destinationType": "CIDR_BLOCK",
"networkEntityId": "<internet_gateway_ocid>"
}
Keep only the desired rules.
Then update the route table:
# Prepare only the route-rules array from rt.json
jq '.data."route-rules"' rt.json > route-rules.json
oci network route-table update \
--rt-id "$RT_OCID" \
--route-rules file://route-rules.json \
--force
Repeat for all route tables exposing the IG.
4. Disable or delete unused Internet Gateways
If the IG should no longer be used at all:
Option A – Disable the Internet Gateway (safer)
IG_OCID="<internet_gateway_ocid>"
oci network internet-gateway update \
--ig-id "$IG_OCID" \
--is-enabled false \
--force
This leaves the object but stops traffic.
Option B – Delete the Internet Gateway
Make sure no route table still references it.
oci network internet-gateway delete \
--ig-id "$IG_OCID" \
--force \
--wait-for-state TERMINATED
5. (Optional) Verify that no IG is exposing 0.0.0.0/0
Quick cross-check:
oci network route-table list \
--compartment-id "$COMPARTMENT_OCID" \
--all \
--output json | \
jq '
.data[] |
. as $rt |
.["route-rules"][]? |
select(.destination == "0.0.0.0/0" and .["network-entity-id"] | contains("internetGateway")) |
{routeTableId: $rt.id, displayName: $rt["display-name"], rule: .}
'
If this returns nothing, there are no 0.0.0.0/0 routes via Internet Gateways in the compartment.
If you share a sample Cloud Guard / Monitoring finding (OCID or JSON), I can translate it to exact CLI commands for that specific IG and route table.
Using Python
To “not expose” OCI Internet Gateways (IGWs), you generally need to:
- Detect IGWs in a tenancy/compartment.
- Find route tables that send
0.0.0.0/0(and::/0for IPv6) to those IGWs. - Either:
- Remove or modify those route rules, or
- Disable/delete the IGW if not needed.
Below is a concise, step‑by‑step approach and a Python example using the OCI SDK.
1. Prerequisites
- Install SDK:
pip install oci
- Configure
~/.oci/configwith at least:tenancyuserfingerprintkey_fileregion
Example profile [DEFAULT] is assumed.
2. Decide What “Not Exposed” Means for Your Policy
Pick your policy, for example:
- Strict: No route rule anywhere with
0.0.0.0/0or::/0using an Internet Gateway. - Conditional: Only allow from specific VCNs/compartments; everything else is remediated.
In the example below, we:
- Flag any route rule with:
cidr_block == "0.0.0.0/0"ordestination == "0.0.0.0/0"destination_type == "CIDR_BLOCK"network_entity_id== an IGW OCID
- And delete those route rules.
You can adapt to instead:
- Replace the IGW with a NAT Gateway, or
- Narrow the CIDR to a specific external subnet, etc.
3. Python Script – Monitor and Remediate IGW Exposure
import oci
PROFILE = "DEFAULT" # OCI config profile name
COMPARTMENT_OCID = "<your_compartment_ocid>" # or tenancy OCID for full scan
DRY_RUN = True # set to False to actually remediate
def get_all_vcns(network_client, compartment_id):
vcns = []
list_vcns_resp = oci.pagination.list_call_get_all_results(
network_client.list_vcns,
compartment_id=compartment_id
)
vcns.extend(list_vcns_resp.data)
return vcns
def get_all_igws(network_client, compartment_id, vcn_ids=None):
igws = []
kwargs = {}
if vcn_ids:
# If you want to limit to selected VCNs
for vcn_id in vcn_ids:
resp = oci.pagination.list_call_get_all_results(
network_client.list_internet_gateways,
compartment_id=compartment_id,
vcn_id=vcn_id
)
igws.extend(resp.data)
else:
resp = oci.pagination.list_call_get_all_results(
network_client.list_internet_gateways,
compartment_id=compartment_id
)
igws.extend(resp.data)
return igws
def get_all_route_tables(network_client, compartment_id, vcn_ids=None):
rts = []
if vcn_ids:
for vcn_id in vcn_ids:
resp = oci.pagination.list_call_get_all_results(
network_client.list_route_tables,
compartment_id=compartment_id,
vcn_id=vcn_id
)
rts.extend(resp.data)
else:
resp = oci.pagination.list_call_get_all_results(
network_client.list_route_tables,
compartment_id=compartment_id
)
rts.extend(resp.data)
return rts
def is_default_anywhere_route(rule):
# IPv4 & IPv6 default routes
dest = getattr(rule, "destination", None) or getattr(rule, "cidr_block", None)
return dest in ["0.0.0.0/0", "::/0"]
def main():
config = oci.config.from_file("~/.oci/config", PROFILE)
network_client = oci.core.VirtualNetworkClient(config)
# 1. Get all VCNs in compartment
vcns = get_all_vcns(network_client, COMPARTMENT_OCID)
vcn_ids = [vcn.id for vcn in vcns]
# 2. Get all Internet Gateways
igws = get_all_igws(network_client, COMPARTMENT_OCID, vcn_ids=vcn_ids)
igw_ids = {igw.id for igw in igws}
if not igw_ids:
print("No Internet Gateways found; nothing to remediate.")
return
print(f"Found IGWs: {igw_ids}")
# 3. Get all route tables in those VCNs
route_tables = get_all_route_tables(network_client, COMPARTMENT_OCID, vcn_ids=vcn_ids)
for rt in route_tables:
# Identify rules to remove
rules_to_keep = []
rules_to_remove = []
for rule in rt.route_rules:
# Check if rule points to an IGW and is 0.0.0.0/0 or ::/0
if (rule.network_entity_id in igw_ids) and is_default_anywhere_route(rule):
rules_to_remove.append(rule)
else:
rules_to_keep.append(rule)
if not rules_to_remove:
continue
print(f"\nRoute Table: {rt.display_name} ({rt.id})")
for r in rules_to_remove:
dest = getattr(r, "destination", None) or getattr(r, "cidr_block", None)
print(f" Will remove rule: {dest} -> {r.network_entity_id}")
if DRY_RUN:
print(" DRY_RUN=True, not making changes.")
continue
# 4. Update the route table (remove insecure rules)
update_details = oci.core.models.UpdateRouteTableDetails(
route_rules=rules_to_keep
)
try:
resp = network_client.update_route_table(
rt.id,
update_route_table_details=update_details
)
print(f" Updated route table {rt.id}, removed {len(rules_to_remove)} rules.")
except Exception as e:
print(f" ERROR updating route table {rt.id}: {e}")
print("\nCompleted scan/remediation.")
if __name__ == "__main__":
main()
4. Using This for “Monitoring”
To turn this into ongoing monitoring:
-
Keep
DRY_RUN = Trueand:- Run it periodically from:
- OCI Functions (wrapped in a function)
- OCI DevOps/Code pipelines or an external CI
- A cron job on a bastion host
- Send output to:
- OCI Logging / Logging Analytics
- Email / Slack via extra code.
- Run it periodically from:
-
For auto-remediation:
- Set
DRY_RUN = Falsein a controlled environment. - Optionally restrict to specific compartments.
- Set
5. Optional: Hardening IGWs Further
If you want stricter remediation, after cleaning routes you can:
- Disable an IGW (
is_enabled=Falseviaupdate_internet_gateway). - Or delete unused IGWs (
delete_internet_gateway) if no more routes reference them.
If you specify your exact policy (e.g., “no IGW at all in compartment X”), I can adjust the code to enforce that explicitly.
Using Terraform
resource "oci_core_internet_gateway" "this" {
# REQUIRED: replace with your compartment OCID
compartment_id = "OCID_OF_COMPARTMENT"
# REQUIRED: replace with your VCN OCID
vcn_id = "OCID_OF_VCN"
display_name = "NON_INTERNET_EXPOSED_IGW"
# Remediation: disable the Internet Gateway so it no longer provides internet connectivity
enabled = false
# OPTIONAL: add tags as appropriate
freeform_tags = {
"Environment" = "ENVIRONMENT_NAME"
"Owner" = "TEAM_OR_OWNER"
}
}
Disabling enabled is an in‑place update on oci_core_internet_gateway and does not force replacement of the gateway (no outage from the resource being recreated, but any existing routes to it will stop providing internet connectivity).
To verify, terraform plan should show only an in-place update on oci_core_internet_gateway.this with enabled changing from true to false and no resources marked -/+ (replace) or - (destroy) unless you intentionally removed other configuration.