OCI Bastion Service Part II: Create Bastion Service Using OCI CLI and Terraform

Share on:



In part II, and after demonstrating how to use OCI Bastion Service using the Console (see part I) we will cover how to create Bastion Service using automation tools like OCI CLI and Terraform as I didn’t want all these approaches to be lumped in one post.

A quick table of contents

– Create Bastion Service using OCI CLI
– Create Bastion Service using Terraform

As described in part I The Bastion Service is linked to the target subnet and a bastion session will define the port forwarding to the target instance.
 Our environment :
   VCN vcnterra has the private subnet db-sub with a CIDR of
DB instance IP is


I. Create Bastion Service from OCI CLI

     OCI CLI is perfect for quickly automating Bastion Service creation with many sessions/ports

  • Install and configure OCI CLI as described here. Assuming your default profile will be the target tenancy


1. Create the Bastion  

By specifying the compartment and subnet ids from the previous example

$ export comp_id=ocid1.compartment.oc1..a***q 
$ export subnet_id=ocid1.subnet.oc1.ca-toronto-1.a**q

-- Create the Bastion -- 
$ oci bastion bastion create --bastion-type Standard --compartment-id $comp_id --target-subnet-id $subnet_id --client-cidr-list '[""]'

-- describe the Bastion Service -- 
$ export bastion_id=$(oci bastion bastion list --compartment-id  $comp_id --all --query "data[0].id" --raw-output)

$ oci bastion bastion get --bastion-id $bastion_id  --query "data.{Name:name,bastion_type:\"bastion-type\",state:\"lifecycle-state\",allow_list:\"client-cidr-block-allow-list\",jump_ip:\"private-endpoint-ip-address\",timeout:\"max-session-ttl-in-seconds\"}"   --output table

| Name      | allow_list  |bastion_type | jump_ip       | state  | timeout |
| bastion2* |['']| STANDARD    | | ACTIVE | 10800   |


2. Create Port forwarding Bastion Session

We will use $bastion_id and other required attributes we inserted in the console earlier

$ oci bastion session create-port-forwarding  --display-name bastiontoDBSession --bastion-id $bastion_id --key-type PUB --ssh-public-key-file id_rsa_oci.pub --target-port 22 --target-private-ip --wait-for-state SUCCEEDED 
  • export the bastion session OCID 
$ session_id=$(oci bastion session list --bastion-id $bastion_id --session-lifecycle-state ACTIVE --sort-order asc --all --query "data[0].id" --raw-output) 
  • Display the ssh proxy command details from the bastion session resource 
$ oci bastion session get --session-id $session_id --query "data.\"ssh-metadata\".command" --raw-output

ssh -i <privateKey> -N -L <localPort>: -p 22 ocid1.bastionsession.oc1.ca-toronto-1.ama**@host.bastion.ca-toronto-1.oci.oraclecloud.com


II. Create Bastion Service from Terraform

This is also super cool to have, especially when deploying a full stack and needing to connect to private resources right away
The SSH Command can even be extracted from the output (we’ll use the same environment)

3 x Configuration files

  • Bastion.tf for both Bastion and Bastion session
$ vi bastion.tf

resource "oci_bastion_bastion" "mybastion" {
    bastion_type = "standard"
    compartment_id = var.compartment_ocid
    target_subnet_id = oci_core_subnet.terraDB.id   #CHANGE ME
     name = var.bastion_name
    client_cidr_block_allow_list = [var.bastion_cidr_block_allow_list]
#    Bastion Session

resource "oci_bastion_session" "mybastion_session" {
    bastion_id = oci_bastion_bastion.mybastion.id
    key_details {
        public_key_content = var.ssh_public_key
    target_resource_details {
        session_type = var.bastion_session_type
        target_resource_port = "22" 
        target_resource_private_ip_address = "" 
    display_name = var.bastion_session_name   
    key_type = "PUB"
    session_ttl_in_seconds = "10800"  
  • variables.tf
$ vi variable.tf
variable "bastion_cidr_block_allow_list" { default= ""}
variable "bastion_name" { default = "BastionMyDB"}
variable "bastion_session_type" {default = "PORT_FORWARDING"}
variable "bastion_session_name" {default = "Session-Mybastion" } 
  • output.tf to extract all necessary information including the SSH command
$ vi output.tf
 output "bastion_session_state" {
           value = oci_bastion_session.mybastion_session.state}
output "bastion_session_target_resource_details" {
           value = oci_bastion_session.mybastion_session.target_resource_details}
output "bastion_session_ssh_connection" {
           value = oci_bastion_session.mybastion_session.ssh_metadata.command}  
  • After setting the Subnet/compartment ids, terraform apply will create the Bastion and Display something like the below



SSH Connection Usage

  • The final result will look like this, notice I added and run it in the background, so I won’t have to open another session to login to the Private DB Instance
# ssh -i ~/.ssh/id_rsa_oci -N -L 22: -p 22 ocid1.bastionsession.oc1.ca-toronto-1.amaaaaaavr**a@host.bastion.ca-toronto-1.oci.oraclecloud.com &
  • Run the final SSH Command to access the target resource using a sort of loopback where localhost is forwarded into the target instance IP through the opened proxy tunnel
# ssh -i  ~/.ssh/id_rsa_dbcs opc@localhost
[opc@hopsdb-oci ~]$ cat /etc/redhat-release --- target instance
Red Hat Enterprise Linux Server release 7.9 (Maipo)
[opc@hopsdb-oci ~]$ ifconfig  ens3
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9000
inet  netmask  broadcast
 Warning: Beware as It’s important to distinguish between:
    • SSH Keypair used to build the Bastion Session
    • SSH Keypair used in the target VM (our DB Instance) upon creation
  • The first is used when we run the bastion command, the second is used when connecting as opc@locahost.



In this article, we learned

  • How to create OCI Bastion service using  OCI CLI, and finally Terraform.
  • With the above, there is no excuse not to try this super cool feature that is absolutely FREE.
Share on:
Back to Top