OCI Bastion and jump-host build with DRG using terraform code


 

Overview

 

BASTION

Provide restricted and time-limited secure access to resources that don not have public endpoints and require strict resource access controls. Examples include compute instances, bare metal and virtual machines, MySQL, ATP, OKE, and any other resource that allows Secure Shell Protocol (SSH) access. For more details see oci bastion documentation

OCI Bastion removes the need for a public IP for bastion access, eliminating the hassle and potential attack surface from remote access.

See bastion concept using Transit routing in figure 1.0.

 

Figure1.0:



 

 

SESSION

The Bastion service recognizes three types of sessions. The type of session you create, or choose to connect to, depends on the type of target resource. Recommended to use ssh port forwarding session. For more details see: link

 

 

Overview of Dynamic Routing Gateways and remote VCN peering

A DRG acts as a virtual router, providing a path for traffic between your on-premises networks and VCNs, and can also be used to route traffic between VCNs. Using different types of attachments, custom network topologies can be constructed using components in different regions and tenancies. Each DRG attachment has an associated route table which is used to route packets entering the DRG to their next hop. In addition to static routes, routes from the attached networks are dynamically imported into DRG route tables using optional import route distributions.

Remote VCN peering is the process of connecting two VCNs in different regions (but the same tenancy ). The peering allows the VCNs' resources to communicate using private IP addresses without routing the traffic over the internet or through your on-premises network. Without peering, a given VCN would need an internet gateway and public IP addresses for the instances that need to communicate with another VCN in a different region.

For more details see: link

Note: the CIDR range would not be overlapping.

See Figure1.1:

 

 

Terraform code

 

#Setup local’s variable that are repeatedly using in code.

locals {

  # Jump Host properties

  jump_host_compartment_ocid          = ""

  jump_host_vcn_cidr                  = "192.168.0.0/29"

  jump_host_vcn_name                  = ""

  jump_host_subnet_cidr               = "192.168.0.0/29"

  jump_host_subnet_name               = ""

  jump_host_subnet_security_list_name = ""

  jump_host_subnet_route_table_name   = ""

  jump_host_to_service_lpg_name       = ""

  jump_host_service_gateway_name      = ""

  jump_nat_gateway_name               = ""

 

 

  #MS service properties

  service_ms_compartment_ocid                        = ""

  service_ms_vpn_ocid                                = ""

  service_ms_vcn_cidr                                = "10.0.0.0/24"

  service_ms_vcn_name                                = ""

  service_ms_control_plane_subnet_cidr               = "10.0.0.0/24"

  service_ms_control_plane_subnet_name               = ""

  service_ms_control_plane_subnet_security_list_name = ""

  service_ms_control_plane_subnet_route_table_name   = ""

  service_ms_to_jump_host_lpg_name                   = ""

  service_ms_vcn_service_ms_gateway_name             = ""

  service_ms_nat_gateway_name                        = ""

 

 

  # Common Networking properties

  TCP                = "6"

  CIDR_BLOCK         = "CIDR_BLOCK"

  SERVICE_CIDR_BLOCK = "SERVICE_CIDR_BLOCK"

  oci_service_id     = data.oci_core_services.oci.services[0].id

  oci_service_cidr  = data.oci_core_services.oci.services[0].cidr_block

 

  # Common Compute Instance properties

  compute_instance_shape  = "VM.Standard1.1"

  ad                      = "EU-FRANKFURT-1-AD-1"

  image_ocid              = ""

  boot_volume_size_in_gbs = 75

  ssh_public_key         = ""

  InstanceShape.         = ""

 

  # Bastion properties

  bastion_name     =  ""

  phone_book_entry = ""

  allow_list = ""

 

 

#Stage1

#Creation of separate VCN in CIDR range (192.168.0.0/29) that would host OCI bastion and jump-hosts. /29 CIDR range support 8 Ip’s and that will be sufficient for setups bastion and backend jump-hosts.

 

resource "oci_core_vcn" jump_host_vcn {

  compartment_id = local.jump_host_compartment_ocid

  cidr_block     = local.jump_host_vcn_cidr

  display_name   = local.jump_host_vcn_name

}

 

 

 

 

 

#Stage2

#Creation of DRG for the jump-host VCN network and attach DRG in the same VCN and then initiate remote peering. Inf the below example I am creating a connection from Frankfurt to Ashburn region.

 

 

resource oci_core_drg FRA-to-ASH-DRG {

  compartment_id = local.jump_host_compartment_ocid

  defined_tags = {

  }

  display_name = "FRA-to-ASH-DRG"

}

 

resource "oci_core_drg_attachment" "FRA-to-ASH-ATTACH-DRG" {

  drg_id       = oci_core_drg.FRA-to-ASH-DRG.id

  display_name = "FRA-to-ASH-ATTACH-DRG"

  vcn_id       = oci_core_vcn.jump_host_vcn.id

}

 

 

resource oci_core_remote_peering_connection FRA-to-ASH-RPC-DRG {

  compartment_id = local.jump_host_compartment_ocid

  display_name   = "FRA-to-ASH-RPC-DRG"

  drg_id         = oci_core_drg.FRA-to-ASH-DRG.id

}

 

 

#Stage3

#Creation and attachment of DRG in another region (Ashburn) VCN.

 

resource oci_core_drg MS-ASH-to-JUMP-FRA-DRG-POC {

  provider       = oci.us-ashburn-1

  compartment_id = local.service_ms_compartment_ocid

  display_name   = "MS-ASH-to-JUMP-FRA-DRG-POC"

}

 

resource "oci_core_drg_attachment" "MS-ASH-to-JUMP-FRA-ATTACH-DRG-POC" {

  provider     = oci.us-ashburn-1

  drg_id       = oci_core_drg.MS-ASH-to-JUMP-FRA-DRG-POC.id

  display_name = "MS-ASH-to-JUMP-FRA-ATTACH-DRG-POC"

  vcn_id       = local.service_ms_vcn_cidr

}

 

resource oci_core_remote_peering_connection MS-ASH-to-JUMP-FRA-DRG-POC {

  provider         = oci.us-ashburn-1

  compartment_id   = local.service_ms_compartment_ocid

  display_name     = "FRA-to-ASH-RPC-DRG-POC"

  drg_id           = oci_core_drg.MS-ASH-to-JUMP-FRA-DRG-POC.id

  peer_id          = oci_core_remote_peering_connection.FRA-to-ASH-RPC-DRG-POC.id

  peer_region_name = "eu-frankfurt-1"

}

 

 

#Stage4

#Create a Service gateway, NAT gateway, Security list , route table and subnets for Jump-host VCN

 

#Discover service gateway

data "oci_core_services" oci {

  filter {

    name   = "name"

    values = ["All.*Oracle.*Services"]

    regex  = true

  }

}

 

resource "oci_core_security_list" jump_host_subnet_security_list {

  compartment_id = local.jump_host_compartment_ocid

  vcn_id         = oci_core_vcn.jump_host_vcn.id

  display_name   = local.jump_host_subnet_security_list_name

 

 

  #allow egress traffic to flow to service vcn cidr

  egress_security_rules {

    description      = "egress for overlayhost connection"

    destination      = "0.0.0.0/0"

    destination_type = "CIDR_BLOCK"

    protocol         = "6"

    stateless        = false

  }

 

  # all ingress traffic from all IP addresses of this subnet to all other IP addresses within the subnet

  ingress_security_rules {

    source_type = local.CIDR_BLOCK

    source      = local.jump_host_vcn_cidr

    protocol    = local.TCP

    tcp_options {

      min = 22

      max = 22

    }

    description = "From other IP Addresses within subnet via TCP"

  }

 

  # all ingress traffic from all IP addresses from MS subnet.

  ingress_security_rules {

    source_type = local.CIDR_BLOCK

    source      = local.service_ms_control_plane_subnet_cidr

    protocol    = local.TCP

    tcp_options {

      min = 22

      max = 22

    }

    description = "From MS IP Addresses within subnet via TCP"

  }

 

 

  # all egress traffic from all IP addresses of this subnet to all other IP addresses within the subnet

  egress_security_rules {

    destination_type = local.CIDR_BLOCK

    destination      = local.jump_host_subnet_cidr

    protocol         = local.TCP

    tcp_options {

      min = 22

      max = 22

    }

    description = "To other IP Addresses within subnet via TCP"

  }

}

 

# service gatway

resource "oci_core_service_gateway" jump_host_sgw {

  compartment_id = local.jump_host_compartment_ocid

  vcn_id         = oci_core_vcn.jump_host_vcn.id

  display_name   = local.jump_host_service_gateway_name

  services {

    service_id = local.oci_service_id

  }

}

 

# NAT gatway

 

resource "oci_core_nat_gateway" "test_nat_gateway" {

  compartment_id = local.jump_host_compartment_ocid

  vcn_id         = oci_core_vcn.jump_host_vcn.id

  display_name   = local.jump_nat_gateway_name

}

 

# attaching rules to route table

 

resource "oci_core_route_table" "test_route_table" {

  compartment_id = local.jump_host_compartment_ocid

  vcn_id         = oci_core_vcn.jump_host_vcn.id

  display_name   = local.jump_host_subnet_route_table_name

 

  route_rules {

    description       = "Add DRG route to subnet"

    destination       = local.service_ms_control_plane_subnet_cidr

    destination_type  = "CIDR_BLOCK"

    network_entity_id = oci_core_drg.FRA-to-ASH-DRG.id

  }

 

  route_rules {

    description       = "Add service GW route to subnet"

    destination       = local.oci_service_cidr

    destination_type  = "SERVICE_CIDR_BLOCK"

    network_entity_id = oci_core_service_gateway.jump_host_sgw.id

  }

  route_rules {

    description       = "Add NAT gatway to subnet"

    destination       = "0.0.0.0/0"

    destination_type  = "CIDR_BLOCK"

    network_entity_id = oci_core_nat_gateway.test_nat_gateway.id

  }

 

}

 

 

#Creation of subnet at jumphost vcn

 

resource "oci_core_subnet" jump_host_subnet {

  compartment_id             = local.jump_host_compartment_ocid

  vcn_id                     = oci_core_vcn.jump_host_vcn.id

  cidr_block                 = local.jump_host_subnet_cidr

  prohibit_public_ip_on_vnic = true

  prohibit_internet_ingress  = "true"

  display_name               = local.jump_host_subnet_name

  route_table_id             = oci_core_route_table.test_route_table.id

  security_list_ids          = [oci_core_security_list.jump_host_subnet_security_list.id]

}

 

 

#Stage5

#REPEATE Stage4 AND ADD ROUTING TABLE AND OPEN SECURULES/NSG CONNECTION FOR  MANAGED SERVICES IN OTHER REGION.

 

 

 

#Stage6

 #Creation a jump-host

 

Creating jump host

 

data "oci_identity_availability_domains" "ads" {

  compartment_id = local.jump_host_compartment_ocid

}

resource "oci_core_instance" "ms-jumphost01" {

  availability_domain  = data.oci_identity_availability_domains.ads.availability_domains[0].name

  compartment_id       = local.jump_host_compartment_ocid

  display_name         = "ms-jumphost01"

  shape                = local.InstanceShape

  subnet_id            = oci_core_subnet.jump_host_subnet.id

  preserve_boot_volume = "false"

 

  create_vnic_details {

    assign_public_ip = "false"

  }

 

  source_details {

    source_type             = "image"

    source_id               = local.image_ocid

    boot_volume_size_in_gbs = local.boot_volume_size_in_gbs

  }

  metadata = {

    ssh_authorized_keys = local.ssh_public_key

    hostclass           = local.hostclass

  }

  # You need to ignore the source details if you don't want to apply any changes to old instances.

  lifecycle {

    ignore_changes = [

      source_details

    ]

  }

}

 

#Stage7

#Repeat Stage6 for second jump-host creation

 

#Stage8

#OCI Bastion creation. For more details see link

 

resource "oci_bastion_bastion" "test_bastion" {

    bastion_type = "STANDARD"

    client_cidr_block_allow_list = local.allow_list

    compartment_id = local.jump_host_compartment_ocid

    target_subnet_id = oci_core_subnet.jump_host_subnet.id

    name = local.bastion_name

    phone_book_entry = local.phone_book_entry

    static_jump_host_ip_addresses = [oci_core_instance.ms-jumphost01.private_ip, oci_core_instance.ms-jumphost02.private_ip]

}

 

 

#Stage9

#Create a bastion session

resource "oci_bastion_session" "test_session" {
    bastion_id = oci_bastion_bastion.test_bastion.id
    key_details {
        public_key_content = var.session_key_details_public_key_content
    }
    target_resource_details {
        session_type = var.session_target_resource_details_session_type        
    }
    display_name = var.session_display_name   
}

 

 

#Stage10

#Outputs

 

data "oci_bastion_bastion" "test_bastions" {

 

  bastion_id = oci_bastion_bastion.test_bastion.id

} 

output bastions {

  value = data.bastion_internal_bastion.test_bastions.id

}

 

data "oci_bastion_sessions" "test_sessions" {
 
      bastion_id = oci_bastion_bastion.test_bastion.id 
}

output sessions {

  value = data.oci_bastion_sessions.test_sessions

}

 

 

 

 



Comments