Home / OCI

OCICheat sheetBeginner

OCI network security groups CLI cheat sheet - rules, VNIC membership and quick audits

Copy-paste OCI CLI commands for network security groups. Create NSGs, add, update and remove rules, attach VNICs and load balancers, and audit who can reach what.

Deepak Bhardwaj6 min read

Applies toOCI Networking (VCN network security groups), OCI CLI 3.x, Compute, Load Balancer

When to use this

You need to open a port, find out why one instance can reach a database and another can't, or clean up NSGs before deleting a VCN. These commands cover the day-to-day work. All of them run as-is in Cloud Shell.

export C=ocid1.compartment.oc1..aaaa...   # compartment
export VCN=ocid1.vcn.oc1..aaaa...
export NSG=ocid1.networksecuritygroup.oc1..aaaa...

Reminder: traffic is allowed if any security list on the subnet or any NSG on the VNIC allows it. NSG rules only apply to the VNICs that are members of the NSG.

Find and inspect NSGs

# All NSGs in a VCN
oci network nsg list --compartment-id $C --vcn-id $VCN --all \
  --query 'data[].{name:"display-name", id:id, state:"lifecycle-state"}' --output table

# One NSG's details
oci network nsg get --nsg-id $NSG

# Rules, flattened to something readable
oci network nsg rules list --nsg-id $NSG --all \
  --query 'data[].{id:id, dir:direction, proto:protocol, src:source, dst:destination, ports:"tcp-options"."destination-port-range", stateless:"is-stateless", desc:description}' \
  --output table

# VNICs that are members of the NSG
oci network nsg vnics list --nsg-id $NSG --all

Protocol values are IANA numbers as strings: "6" TCP, "17" UDP, "1" ICMP, "all" everything.

Add rules

--security-rules takes a JSON list. Get a full template with every field:

oci network nsg rules add --generate-param-json-input security-rules > rule-template.json

Ingress from a CIDR (TCP 443)

oci network nsg rules add --nsg-id $NSG --security-rules '[{
  "direction": "INGRESS",
  "protocol": "6",
  "source": "10.0.1.0/24",
  "sourceType": "CIDR_BLOCK",
  "isStateless": false,
  "tcpOptions": {"destinationPortRange": {"min": 443, "max": 443}},
  "description": "HTTPS from app subnet"
}]'

Ingress from another NSG (app tier to database tier)

APP_NSG=ocid1.networksecuritygroup.oc1..bbbb...
oci network nsg rules add --nsg-id $NSG --security-rules "[{
  \"direction\": \"INGRESS\",
  \"protocol\": \"6\",
  \"source\": \"$APP_NSG\",
  \"sourceType\": \"NETWORK_SECURITY_GROUP\",
  \"tcpOptions\": {\"destinationPortRange\": {\"min\": 1521, \"max\": 1521}},
  \"description\": \"Oracle listener from app NSG\"
}]"

NSG-to-NSG rules follow membership. New app instances added to APP_NSG get access without a rule change.

Egress to Oracle services through the service gateway

oci network nsg rules add --nsg-id $NSG --security-rules '[{
  "direction": "EGRESS",
  "protocol": "6",
  "destination": "all-fra-services-in-oracle-services-network",
  "destinationType": "SERVICE_CIDR_BLOCK",
  "tcpOptions": {"destinationPortRange": {"min": 443, "max": 443}},
  "description": "OCI services via service gateway"
}]'

The service CIDR label includes the region key; list the valid names with oci network service list --query 'data[]."cidr-block"'.

ICMP for path MTU discovery

oci network nsg rules add --nsg-id $NSG --security-rules '[{
  "direction": "INGRESS", "protocol": "1",
  "source": "0.0.0.0/0", "sourceType": "CIDR_BLOCK",
  "icmpOptions": {"type": 3, "code": 4},
  "description": "Fragmentation needed (PMTUD)"
}]'

You can pass up to several rules in one list; check the current per-call and per-NSG rule limits in the Networking service limits documentation.

Update and remove rules

Rule IDs are short hex strings from rules list.

# Change a rule (send the id plus the full rule as it should be)
oci network nsg rules update --nsg-id $NSG --security-rules '[{
  "id": "04ABEC",
  "direction": "INGRESS", "protocol": "6",
  "source": "10.0.2.0/24", "sourceType": "CIDR_BLOCK",
  "tcpOptions": {"destinationPortRange": {"min": 443, "max": 443}},
  "description": "HTTPS from new app subnet"
}]'

# Remove rules
oci network nsg rules remove --nsg-id $NSG --security-rule-ids '["04ABEC"]'

Warning

Removing an ingress rule takes effect on new connections straight away. Save the current rules before you change anything, so you can put them back in seconds: oci network nsg rules list --nsg-id $NSG --all > nsg-backup-$(date +%F-%H%M).json

Attach and detach VNICs

# NSGs on each VNIC of an instance
oci compute instance list-vnics --instance-id $INSTANCE \
  --query 'data[].{vnic:id, ip:"private-ip", nsgs:"nsg-ids"}'

# Set the NSG list on a VNIC
oci network vnic update --vnic-id $VNIC --nsg-ids "[\"$NSG\",\"$APP_NSG\"]" --force

Caution

--nsg-ids replaces the whole list. Passing only the new NSG removes the VNIC from every other NSG, which can cut off SSH, monitoring or database access. Read the current list first and send the old IDs plus the new one. --nsg-ids '[]' removes all.

At launch: oci compute instance launch ... --nsg-ids '["<nsg-ocid>"]'. A VNIC can belong to a limited number of NSGs (check the current limit).

Other resources that use NSGs

Resource Command
Load balancer oci lb nsg update --load-balancer-id $LB --network-security-group-ids '["<nsg>"]'
Network load balancer oci nlb network-load-balancer update --network-load-balancer-id $NLB --nsg-ids '["<nsg>"]'
Autonomous DB (private endpoint), DB systems, OKE, MySQL Set in the resource's network settings; check that service's update options

The same "replace the whole list" behaviour applies.

Quick audits

Rules open to the internet

for id in $(oci network nsg list --compartment-id $C --all --query 'data[].id' --raw-output | jq -r '.[]'); do
  oci network nsg rules list --nsg-id $id --all \
    --query "data[?direction=='INGRESS' && source=='0.0.0.0/0'].{port:\"tcp-options\".\"destination-port-range\".min, proto:protocol, desc:description}" \
    --output json | jq -c --arg id "$id" 'select(length>0) | {nsg:$id, rules:.}'
done

Empty or unused NSGs

for id in $(oci network nsg list --compartment-id $C --all --query 'data[].id' --raw-output | jq -r '.[]'); do
  n=$(oci network nsg vnics list --nsg-id $id --all | jq '.data | length')
  [ "${n:-0}" -eq 0 ] && echo "no VNIC members: $id"
done

An NSG with no VNIC members may still be used by a load balancer or database; check before deleting.

Delete an NSG

oci network nsg delete --nsg-id $NSG --force --wait-for-state TERMINATED

Deletion fails while VNICs or other resources still reference it. Remove the memberships first.

Symptom → cause → fix

Symptom Likely cause Fix
Port open in NSG, still times out VNIC not a member of the NSG instance list-vnics, then vnic update with the full list
Works one way only Stateless rule without the reverse rule Use stateful rules, or add the matching return rule
New app instance can't reach DB Rule uses a CIDR, instance is in another subnet Switch to an NSG-sourced rule
Rules look right, still blocked OS firewall on the instance Check firewall-cmd --list-all / iptables -S
Can't delete NSG Still referenced by VNICs or an LB nsg vnics list, clear memberships

Prevent it next time

  • Manage NSGs and rules in Terraform so changes are reviewed and reverts are a re-apply.
  • Prefer NSG-to-NSG rules over CIDRs for tier-to-tier traffic.
  • Put a description on every rule: who asked and why.
  • Create an Events rule for the Networking service's network security group change events (pick the exact event types in the console's rule builder, since names vary) and send it to Notifications.