Oracle Cloud Infrastructure: using Network Security Groups and the caveat with the subnet’s default security list

This is going to be one of these posts I’m mainly writing to myself, in the hope that a) I don’t forget about that topic too soon and b) someone might have the same question and doesn’t want to spin up an environment to find out.

Broadly speaking Oracle Cloud Infrastructure (and some other cloud providers) give you 2 different means of securing the Virtual Cloud Network at the VCN level:

After I got to grips with the latter when Oracle released them, I have used them a lot, for reasons outlined in the documentation. So why this post? It’s to raise awareness that you might feel secure thanks to a Network Security Group (NSG) when in fact you aren’t.

Obligatory Cloud Post Warning: if you create resources described in this post you might incur cost.

It’s easier to show with an example

Assume you created a VCN with 1 public, regional subnet for your admin host, running Oracle Linux 7. You didn’t create a VPN to connect to the VCN yet. However, you created a NSG for the admin host only allowing your IP to access the admin host. The admin host’s VNIC is assigned to the NSG. Like in this Terraform example, shortened to include only the necessary resources:

#
# VCN
#
resource "oci_core_vcn" "simplevm_vcn" {

  cidr_block     = var.simplevm_vcn_cidr_block
  compartment_id = var.compartment_ocid
  display_name   = "simplevm VCN"
  dns_label      = "simplevm"

  defined_tags   = { "project.name" = "simple-vm" }
}

#
# NSG + SSH rule
#
resource "oci_core_network_security_group" "simplevm_bastion_nsg" {
  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.simplevm_vcn.id
  display_name   = "Simple VM bastion NSG"
  defined_tags   = { "project.name" = "simple-vm" }
}

resource "oci_core_network_security_group_security_rule" "simplevm_bastion_nsg_ssh_rule" {
  network_security_group_id = oci_core_network_security_group.simplevm_bastion_nsg.id
  description               = "ssh"
  direction                 = "INGRESS"
  protocol                  = 6
  source_type               = "CIDR_BLOCK"
  source                    = var.controlhost

  tcp_options {
    destination_port_range {
      min = 22
      max = 22
    }
  }
}

#
# Subnet
#
resource "oci_core_subnet" "simplevm_vcn_bastion_sn" {
  cidr_block     = var.simplevm_vcn_bastion_sn_cidr_block
  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.simplevm_vcn.id

  display_name   = "Simple VM bastion SN"
  dns_label      = "simplevm"

  defined_tags   = { "project.name" = "simple-vm" }

  prohibit_public_ip_on_vnic = false
  route_table_id             = oci_core_route_table.simplevm_igw_rt.id

} 

The big question must be: is the admin host accessible via SSH from everywhere, or merely from whatever is the value stored in var.controlhost? You’ll have to take my word for it, it’s a /32 address ;)

#
# simple VM
#
resource "oci_core_instance" "simplevm" {
  availability_domain = var.availability_domain
  compartment_id      = var.compartment_ocid
  shape               = "VM.Standard.E2.1.Micro"

  defined_tags        = { "project.name" = "simple-vm" }

  create_vnic_details {

    assign_public_ip = true
    display_name     = "simplevm"
    hostname_label   = "simplevm"
    nsg_ids = [
      oci_core_network_security_group.simplevm_bastion_nsg.id
    ]
    subnet_id = oci_core_subnet.simplevm_vcn_bastion_sn.id
  }

...

} 

Unfortunately “simplevm” is accessible from everywhere, thanks to the Default Security List implicitly created with the public subnet. It opens port 22 to the world for incoming traffic. The way Security Lists and Network Security work, is described in the Security Rules section of the documentation:

A packet in question is allowed if any rule in any of the relevant lists and groups allows the traffic…

— aforementioned Oracle Cloud Infrastructure documentation

Clearly the default security list matches with its ingress rule of 0.0.0.0/0 to port 22, and traffic is allowed to reach the VM.

Summary

So with that said, in scenarios like the one shown above, please ensure you either change the default security list, or create a separate one and assign it to the subnet.

Better still, ensure you use a more secure approach to accessing your cloud network. There are many ways to do so, in the case of Oracle you find a dedicated module in the free OCI foundation training. Under “Connectivity” you will find both a video as well as slides.

The use of bastion hosts is frowned upon in some circles, and that sounds about right to me.