Cross-region DataGuard in OCI coded with Terraform

In one of the latest lessons of my tutorial I have shown how to setup DataGuard locally within the same region. I guess this is some sort of database protection, but in case of the whole region failure it will not help at all. So it is worth to consider the cross-region solution for database security. In this additional lesson I am trying to showcase how to deploy remote DataGuard Association with the usage of Terraform code.

Pic. Topology Diagram

The database archivelogs will be send directly via DRGs and OCI backbone. I hope you will find this dish tasty and it will be somehow useful for your work with the cloud solutions. Let me know if you have any kind of feedback. ๐Ÿ™‚

Bon Appetit,

Martin, The Cook.

Subscribe to get access

For now video is blocked, but you can watch it immediately when you subscribe!

USE OCI OBJECT STORAGE TO STORE TERRAFORM STATE FILES

download.png

Introduction

Terraform allows you to deploy infrastructure very quickly, and you can find thousands of script/modules/snippets on the web to get you started in a snap.

Once you move from the “Let’s try this at home” phase to a more “Let’s do this for a real environment” oriented phase you will have to make a lot of decisions about how you are going to maintain your infrastructure and how you are going to manage change, possibly in a non destructive way.

Nothing like dropping a production environment on a Friday evening while you are testing a small change in your dev environment will make you realise how badly you need this when moving past the Terraform learning phase.

One important decision during this transition to real world use of terraform is the location where you are going to store a Terraform project state file.

In this tutorial you will learn how to configure OCI Object storage as a remote backend for a sample terraform project, this will allow you to replicate the setup for your projects.

What is a terraform state file?

Terraform must store state information about your managed infrastructure and configuration. This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures.

This state is stored by default in a local file named “terraform.tfstate”, but it can also be stored remotely, which is essential when more than one person is working on the same project. Withย remote state, Terraform writes the state data to a remote data store, which can then be shared between all members of a team, encrypted, versioned and secured. Terraform supports storing state in Terraform Cloud,ย HashiCorp Consul, Amazon S3, Alibaba Cloud OSS, and other providers.

If you want to dig deeper into why Terraform needs a state file to work you can have a look here: https://www.terraform.io/docs/state/purpose.html

Terraform remote state file and OCI support

OCI object storage is not supported natively for storing state files, but since it has an AWS S3 compatibility layer we can use it all the same

Requirements

An Active Oracle Cloud Tenancy

If you do not have one, you can enroll here for a trial subscription that includes $300 of free credits

An Oracle Cloud Shell Instance

The OCI Cloud Shell is a web browser-based terminal accessible from the Oracle Cloud Console. Cloud Shell is free to use (within monthly tenancy limits), and provides access to a Linux shell, with a pre-authenticated Oracle Cloud Infrastructure CLI and other useful tools for following Oracle Cloud Infrastructure service tutorials and labs. Cloud Shell is a feature available to all OCI users, accessible from the Console. Your Cloud Shell will appear in the Oracle Cloud Console as a persistent frame of the Console and will stay active as you navigate to different pages of the Console. You can find detailed instructions on how to get started with the OCI Cloud Shell here

cloudshell-1.png

Create an initial working dir:

mkdir fk-terraform-objectstorage
cd fk-terraform-objectstorage/

A test terraform project

git clone https://github.com/mattiarossi/terraform-oci-default-vcn/


Cloning into 'terraform-oci-default-vcn'...
remote: Enumerating objects: 61, done.
remote: Counting objects: 100% (61/61), done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 75 (delta 27), reused 44 (delta 14), pack-reused 14
Unpacking objects: 100% (75/75), done.


cd terraform-oci-default-vcn/examples/vcn_default/

The test project will deploy a simple VCN in a compartment of your choice, configurable in the project variables, and will store the state file in an OCI Object storage Bucket that needs to be created in advance

An OCI Object Storage Bucket

The bucket needs to be created in the Compartment that is designated on OCI to be the target for the AWS S3 compatibility layer. You can check the active S3 compartment by using the following command:

oci os ns  get-metadata --output=table
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+
| default-s3-compartment-id                                                           | default-swift-compartment-id                                                        | namespace |
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+
| ocid1.compartment.oc1..aaaaaaa...4nxhlvbbbbbbb3kpmffof6vba                          | ocid1.compartment.oc1..aaaaaaa...hlvbbbbbbbbpmffof6vba                              | mytenancy |
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+

We will be using a bucket named tf-fk-test-01

This command will create a bucket named tf-fk-test-01 in the AWS s3 compatibility layer compartment:

oci os bucket create --compartment-id ocid1.compartment.oc1..aaaaaaa...4nxhlvb3luoh3kpmffof6vba --name tf-fk-test-01

A properly configured AWS S3 compatibility environment

In order to be able to access the Object Storage bucket using the S3 compatibility layer, you need to generate a set of access credentials, and the oci cli command needed for creating these needs to know the current user ocid:

export ME=mattia.rossi@myemail.com (my tenancy username)
oci iam user list --query "data[?\"name\"=='$ME']".{"name:\"name\",id:\"id\""} --output table

+------------------------------------------------------------------------------+--------------------------+
| id                                                                           | name                     |
+------------------------------------------------------------------------------+--------------------------+
| ocid1.user.oc1..aaaaaaa..................................tojgy2qybdkcayvnxsq | mattia.rossi@myemail.com |
+------------------------------------------------------------------------------+--------------------------+

export OCIUID=ocid1.user.oc1..aaaaaaa..................................tojgy2qybdkcayvnxsq

The following command will reuse the ocid variable to create the credentials needed to setup the AWS compatibility layer (please note that these are examples only and you will need to insert the proper secrets generated by the oci cli in the export command

oci iam customer-secret-key create --user-id $OCIUID --display-name 'key-tf-test' --query "data".{"AWS_ACCESS_KEY_ID:\"id\",AWS_SECRET_ACCESS_KEY:\"key\""} --output=table

+------------------------------------------+----------------------------------------------+
| AWS_ACCESS_KEY_ID                        | AWS_SECRET_ACCESS_KEY                        |
+------------------------------------------+----------------------------------------------+
| fd9bcbb0.........................93e7139 | kS/...............................PRDoGX1NY= |
+------------------------------------------+----------------------------------------------+

export AWS_ACCESS_KEY_ID=fd9bcbb0.........................93e7139
export AWS_SECRET_ACCESS_KEY=kS/...............................PRDoGX1NY=

Environment variables

The only other environment variable needed by the project for authenticating is the tenancy ocid, that can be set up using this command:

export TF_VAR_tenancy_ocid=`cat /etc/oci/config  | grep tenancy | uniq | cut -d '=' -f 2`

Terraform project config

Prepare one variable file named “terraform.tfvars” with the configuration information. The content of “terraform.tfvars” should look something like the following:

$ cat terraform.tfvars
# Region
region = "eu-frankfurt-1"

# Compartment
compartment_ocid = ""

# VCN Configurations
vcn_display_name = "testVCN"
vcn_cidr = "10.0.0.0/16"

Use the following script to retrieve the ocid of the compartment where you want to deploy the test VCN:

export COMPARTMENT=my-compartment
oci iam compartment list --query "data[?\"name\"=='$COMPARTMENT']".{"name:\"name\",id:\"id\""} --output=table
+-------------------------------------------------------------------------------------+-----------------------+
| id                                                                                  | name                  |
+-------------------------------------------------------------------------------------+-----------------------+
| ocid1.compartment.oc1..aaaaaaaabmc54lgslm..........................3hygseg6qeh5pvwq | my-compartment        |
+-------------------------------------------------------------------------------------+-----------------------+

Edit the file vcn_default.tf, and update the terraform backend section to match your OCI setup:

terraform {
  backend "s3" {
    endpoint                    = "https://__mytenancy__.compat.objectstorage.__region__.oraclecloud.com"
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
    skip_credentials_validation = true
    bucket                      = "__mybucket__"
    key                         = "__key__"
    region                      = "__region__"
  }
}

where:

  • __mytenancy__ is your tenancy name
  • __region__ is the region where you created the Object Storage bucket
  • __mybucket__ is the name of the bucket you created
  • key is the name of the bucket entry that will hold your terraform state file (for example: terraform/state/oci/vcn/testVCN/terraform.tfstate)

Then apply the example using the following commands:

terraform init
terraform plan
terraform apply

Init:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform init
Initializing modules...
- vcn in ../..

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "oci" (hashicorp/oci) 3.74.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.oci: version = "~> 3.74"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Plan:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.vcn.data.oci_identity_availability_domains.this: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# module.vcn.oci_core_default_route_table.this will be created
+ resource "oci_core_default_route_table" "this" {
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ manage_default_resource_id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)

+ route_rules {
+ cidr_block = (known after apply)
+ description = (known after apply)
+ destination = "0.0.0.0/0"
+ destination_type = (known after apply)
+ network_entity_id = (known after apply)
}
}

# module.vcn.oci_core_internet_gateway.this will be created
+ resource "oci_core_internet_gateway" "this" {
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ enabled = true
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
}

# module.vcn.oci_core_subnet.this[0] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-1"
+ cidr_block = "192.168.0.0/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-1"
+ dns_label = "subnet1"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[1] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-2"
+ cidr_block = "192.168.0.16/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-2"
+ dns_label = "subnet2"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[2] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-3"
+ cidr_block = "192.168.0.32/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-3"
+ dns_label = "subnet3"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_vcn.this will be created
+ resource "oci_core_vcn" "this" {
+ cidr_block = "192.168.0.0/25"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ default_dhcp_options_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_list_id = (known after apply)
+ defined_tags = (known after apply)
+ display_name = "TEST-FK-VCN"
+ dns_label = "vcn"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ is_ipv6enabled = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_domain_name = (known after apply)
}

Plan: 6 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Apply:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform apply
module.vcn.data.oci_identity_availability_domains.this: Refreshing state...

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# module.vcn.oci_core_default_route_table.this will be created
+ resource "oci_core_default_route_table" "this" {
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ manage_default_resource_id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)

+ route_rules {
+ cidr_block = (known after apply)
+ description = (known after apply)
+ destination = "0.0.0.0/0"
+ destination_type = (known after apply)
+ network_entity_id = (known after apply)
}
}

# module.vcn.oci_core_internet_gateway.this will be created
+ resource "oci_core_internet_gateway" "this" {
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ enabled = true
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
}

# module.vcn.oci_core_subnet.this[0] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-1"
+ cidr_block = "192.168.0.0/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-1"
+ dns_label = "subnet1"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[1] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-2"
+ cidr_block = "192.168.0.16/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-2"
+ dns_label = "subnet2"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[2] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-3"
+ cidr_block = "192.168.0.32/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-3"
+ dns_label = "subnet3"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_vcn.this will be created
+ resource "oci_core_vcn" "this" {
+ cidr_block = "192.168.0.0/25"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ default_dhcp_options_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_list_id = (known after apply)
+ defined_tags = (known after apply)
+ display_name = "TEST-FK-VCN"
+ dns_label = "vcn"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ is_ipv6enabled = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_domain_name = (known after apply)
}

Plan: 6 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.

Enter a value: yes

module.vcn.oci_core_vcn.this: Creating...
module.vcn.oci_core_vcn.this: Creation complete after 0s [id=ocid1.vcn.oc1.eu-frankfurt-1.amaaaaaavyxeuaqaavuidjkp2un5v7fgodw63pytlkaxvrfs5coucgfqmgfa]
module.vcn.oci_core_internet_gateway.this: Creating...
module.vcn.oci_core_subnet.this[2]: Creating...
module.vcn.oci_core_subnet.this[1]: Creating...
module.vcn.oci_core_subnet.this[0]: Creating...
module.vcn.oci_core_subnet.this[0]: Creation complete after 0s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaa2feksp66yxjrj2twxypjbuk5blefju2ghkk34z4hvex57obkxzqa]
module.vcn.oci_core_subnet.this[2]: Creation complete after 1s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaadqbslze7krqigudqg6ajhxhxddpmhvaottievimyk6jdxz754pta]
module.vcn.oci_core_subnet.this[1]: Creation complete after 1s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaoqrhcrv743sdt6norse7wql7rmin3ca6amoigqonvsejuoavnjtq]
module.vcn.oci_core_internet_gateway.this: Creation complete after 2s [id=ocid1.internetgateway.oc1.eu-frankfurt-1.aaaaaaaau4sdjijm4b3miu2hwf5lcbkyb7eaea62qg7dpaar2udn4u4zhfnq]
module.vcn.oci_core_default_route_table.this: Creating...
module.vcn.oci_core_default_route_table.this: Creation complete after 0s [id=ocid1.routetable.oc1.eu-frankfurt-1.aaaaaaaa5ag3j4kbkb763c3qorcowy5r3swyileytlyhagkv7mqragxysgma]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

Outputs:

default_dhcp_options_id = ocid1.dhcpoptions.oc1.eu-frankfurt-1.aaaaaaaabzs2tgdpnq6jrd2p67lks44qovk272uxuoi3kgciib62fyflgyja
default_route_table_id = ocid1.routetable.oc1.eu-frankfurt-1.aaaaaaaa5ag3j4kbkb763c3qorcowy5r3swyileytlyhagkv7mqragxysgma
default_security_list_id = ocid1.securitylist.oc1.eu-frankfurt-1.aaaaaaaadm7oi73fwjx2kiiqbc7ucsuvqcmxfjis27at4p3tyhuopod5tqoq
internet_gateway_id = ocid1.internetgateway.oc1.eu-frankfurt-1.aaaaaaaau4sdjijm4b3miu2hwf5lcbkyb7eaea62qg7dpaar2udn4u4zhfnq
subnet_ids = [
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaa2feksp66yxjrj2twxypjbuk5blefju2ghkk34z4hvex57obkxzqa",
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaoqrhcrv743sdt6norse7wql7rmin3ca6amoigqonvsejuoavnjtq",
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaadqbslze7krqigudqg6ajhxhxddpmhvaottievimyk6jdxz754pta",
]
vcn_id = ocid1.vcn.oc1.eu-frankfurt-1.amaaaaaavyxeuaqaavuidjkp2un5v7fgodw63pytlkaxvrfs5coucgfqmgfa

Now let’s check the local terraform state file:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ cat .terraform/terraform.tfstate 
{
"version": 3,
"serial": 1,
"lineage": "1250a1d2-3e20-124b-7c25-524f67566052",
"backend": {
"type": "s3",
"config": {
"access_key": null,
"acl": null,
"assume_role_policy": null,
"bucket": "tf-fk-test-01",
"dynamodb_endpoint": null,
"dynamodb_table": null,
"encrypt": null,
"endpoint": "https://mytenancy.compat.objectstorage.eu-frankfurt-1.oraclecloud.com",
"external_id": null,
"force_path_style": true,
"iam_endpoint": null,
"key": "terraform/state/oci/vcn/testVCN/terraform.tfstate",
"kms_key_id": null,
"lock_table": null,
"max_retries": null,
"profile": null,
"region": "eu-frankfurt-1",
"role_arn": null,
"secret_key": null,
"session_name": null,
"shared_credentials_file": null,
"skip_credentials_validation": true,
"skip_get_ec2_platforms": null,
"skip_metadata_api_check": true,
"skip_region_validation": true,
"skip_requesting_account_id": null,
"sse_customer_key": null,
"sts_endpoint": null,
"token": null,
"workspace_key_prefix": null
},
"hash": 1758364997
},
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
}

And let’s check the Object storage bucket:

oci os object list -bn tf-fk-test-01 --output=table
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
| etag | md5 | name | size | time-created | time-modified |
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
| None | PRXsobIN......efUorHfg== | terraform/state/oci/vcn/testVCN/terraform.tfstate | 14161 | 2020-05-08T18:43:19.428000+00:00 | None |
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
prefixes: []

.. and we’re done, you have configured terraform to store state files remotely on OCI.

If you want to use the same pattern outside the OCI cloud shell you will need to configure the oci provider to use the usual API key/fingerprint combo

Have Fun!

Mattia

OCI File Storage Service + Network Security Groups (NSG) with Terraform

What is the topic for today? Network security of your OCI cloud infrastructure! Honestly speaking always an important topic, right? The basics of Network Security Groups (NSG), for the first time I have described in this blog post. Recently I have found in OCI Release Notes, that OCI File Storage Services supports now NSG. Immediately I have checked Terraform OCI Provider, just to confirm my favorite automation runtime also supports it. And guess what? Terraform OCI Provider in version 3.55.0 fully covers this feature. That is really amazing! Just one week later, after OCI release, Terraform Provider codebase has been updated! That is why I have decided to test it and add this stuff to my Terraform+OCI tutorial as a lesson 5a. I hope you will find it interesting! If it is true I really encourage you to subscribe to our YouTube Channel ๐Ÿ™‚ One more thing – File Storage Service UDP and TCP ports for NSGs and Security Lists have been documented here.

Bon Appetit,

Martin, The Cook.

How to create shared block volume in OCI with Terraform

Yeah! That is the feature which I really like. Shared block volume attached to more than one compute instances. This feature has been announced in OCI in the middle of December 2019. One month later I have decided to test it with Terraform. I was hoping it would work not only in the OCI Console but also with my favorite automation runtime. So I have written this simple repo in GitHub. Worth to add I am not finishing the code at the moment of attachment between compute instances and volume block resource. I am including Terraform files that execute null_resources which are building OCFS2 on top of the volume which is visible as a device via iSCSI protocol. Most of the knowledge of how to do it have incorporated from this blog post. I think you can find my dish tasty and you can somehow reutilize this code in the future ๐Ÿ™‚

Bon Appetit,

Martin, The Cook.