This post describes features of CIS Landing Zone Terraform configuration, which is retired as of May 2025. The last release of CIS Landing Zone Terraform configuration is Release 2.8.8.
 

 

If code changes are needed, the Terraform configuration has a single root module and individual modules to provision the resources. This modular pattern enables efficient and consistent code reuse. To add resources to the Terraform configuration (for example, compartments), reuse the existing modules and add the necessary module calls, similar to the existing ones in the root module. Most modules accept a map of resource objects and new objects are just a new element in the map. For example, to add a new compartment, define a new object with the compartment information and add it to the existing compartment’s map. To add objects to an existing container object (for example, to add a subnet to a VCN), add the subnet resources to the existing subnet’s map.

Using Terraform Overrides

Changes on the CIS Landing Zone code should be avoided when ever possible. Once the CIS Landing Zone code is updated, your changes are out of sync and you might not be able to benefit from the new additions.

A good approach is to use Terraform Override Files for customization. Override files are merged with the combined Terraform files and allow to customize the CIS Landing Zone in a very flexible way.

Although most of the CIS Landing Zone modules are designed to allow the customization of most of their parts, the best is to only override the contents of the local block of each .tf file.

Overrides Restrictions

Although overrides work for mostly every part of the Terraform files, there are some restrictions.

  • Only existing values can be used in the override file. If, for example, a new variable should be used, it is required to define it outside of the override file. A good practice is to create a sibling file containing this variable.
  • Resource and data blocks which use depends_on cannot be used within an override file.

Adding Overrides before deployment

If you need advanced customizations for your CIS Landing Zone implementation, Terraform Overrides are an interesting feature.

To use Terraform Overrides, you are able to create override files for each component or just a single file containing all aspects. It is recommended to use a project specific set of files:

  • <project-name>-input.tfvars – Project-specific settings (a copy of the quickstart-input.tfvars).
  • <project-name>_override.tf – Holds all the configuration which override the default settings.
  • <project-name>_locals.tf – An optional file which may contain new variables used in <project-name>_override.tf.

where <project-name> will be your project name. These files need to be in the config directory to be considered by Terraform automatically.

A good practice is to start with creating and modifying these files in a directory at the top-level of the Landing Zone named project-name (you should replace project_name with your actual project name, of course). Following this approach you can group your project specific files in a manageable way and you can have multiple projects in parallel. Your directory structure will look like this:

oci-cis-landing-zone-quickstart/
   config/
   pre-config/
   project-name/

When you’re about to run the usual Terraform steps of init, plan, and apply, you copy your override files to config and start with terraform init.

Example 1: Enabling Compartment Deletion

By default the Landing Zone prohibits the deletion of compartments. This is great for production but bad for testing. We create a small file called vision_test_override.tf with the following content.

locals {
  enable_cmp_delete = true
}

After placing this file into the config directory you are much better prepared for your testing.

Example 2: Using Freeform Tags

In this example, we use freeform tags.

Tag name Tag Value
CostCenter BA23490

Translating this into a Terraform notation the CIS Landing Zone can use, we get the content below. We can assign the set quite easily to all resources.

The override file vision_freeform_override.tf is listed below.

locals {
  all_cost_management_freeform_tags = {"CostCenter" : "BA23490"}
  all_compartments_freeform_tags = local.all_cost_management_freeform_tags
  all_dynamic_groups_freeform_tags = local.all_cost_management_freeform_tags
}

Now, copy the vision_freeform_override.tf into the configdirectory and run terraform init and terraform plan. In the output of terraform plan you’ll find lines like these:

  + freeform_tags = {
      + "cis-landing-zone" = "vision-quickstart"
      + "CostCenter" = "BA23490"
   }

When you’re satisfied with the result, run terraform apply and your freeform tags will be applied to all your components.

Example 3: Defining and Setting Custom Defined Tags

In this example, we create a custom namespace of defined tags for the Vision project. The Vision project requirements expect the following tags to be defined.

Tag namespace Tag name Cost tracking
vision CostCenter Yes
vision DebitorName  
vision ProjectName  

Defining and creating and using defined tags is a two stage process.

  1. Define and create the tag namespace and the tags of the namespace.
  2. Apply the defined tags to the resources.

Translating this into a Terraform notation the Landing Zone can use, we create a file called vision_stage1_override.tf containing the following terraform code.

locals {
  tag_namespace_name    = "vision"
  all_tags = {
    ("CostCenter") = {
      tag_description         = "Tag for Cost Center."
      tag_is_cost_tracking    = true
      tag_is_retired          = false
      make_tag_default        = false
      tag_default_value       = ""
      tag_default_is_required = false
      tag_defined_tags        = null
      tag_freeform_tags       = null
    },
    ("DebitorName") = {
      tag_description         = "Tag for debitor name."
      tag_is_cost_tracking    = false
      tag_is_retired          = false
      make_tag_default        = false
      tag_default_value       = ""
      tag_default_is_required = false
      tag_defined_tags        = null
      tag_freeform_tags       = null
    },
    ("ProjectName") = {
      tag_description         = "Tag for project name."
      tag_is_cost_tracking    = false
      tag_is_retired          = false
      make_tag_default        = false
      tag_default_value       = ""
      tag_default_is_required = false
      tag_defined_tags        = null
      tag_freeform_tags       = null
    }
  }

To run stage 1 you have to copy the file vision_stage1_override.tf to the config and follow the standard Terraform steps, for example:

> terraform init
> terraform plan -var-file vision-input.tfvars -out vision.plan
> terraform apply vision.plan

Now, we need to create a set of defined tags to be used for all resources, but we don’t want to repeat the code. The best way is to create an additional file that holds the new local and not overridden variable. The content for a set of defined tags looks like the code below.

all_alarms_defined_tags = {
  "vision.CostCenter" = "42",
  "vision.ProjectName" = "The Project"
}

Now we can assign the set quite easily to all resources.

all_buckets_defined_tags = local.all_alarm_defined_tags
all_compartments_defined_tags = local.all_alarm_defined_tags
all_cost_management_defined_tags = local.all_alarm_defined_tags
all_dmz_defined_tags = local.all_alarm_defined_tags
all_dynamic_groups_defined_tags = local.all_alarm_defined_tags
all_exacs_vcns_defined_tags = local.all_alarm_defined_tags
all_flow_logs_defined_tags = local.all_alarm_defined_tags
all_groups_defined_tags = local.all_alarm_defined_tags
all_keys_defined_tags = local.all_alarm_defined_tags
all_notifications_defined_tags = local.all_alarm_defined_tags
all_nsgs_defined_tags = local.all_alarm_defined_tags
all_service_connector_defined_tags = local.all_alarm_defined_tags
all_service_policy_defined_tags = local.all_alarm_defined_tags
all_tags_defined_tags = local.all_alarm_defined_tags
all_topics_defined_tags = local.all_alarm_defined_tags
all_vcn_defined_tags = local.all_alarm_defined_tags
all_vss_defined_tags = local.all_alarm_defined_tags

Combining these two fragments we get a stage 2 override file (vision_stage2_override.tf) with this content.

locals {
  all_alarms_defined_tags = {
    "vision.CostCenter" = "42",
    "vision.ProjectName" = "The Project"
  }
  all_buckets_defined_tags = local.all_alarm_defined_tags
  all_compartments_defined_tags = local.all_alarm_defined_tags
  all_cost_management_defined_tags = local.all_alarm_defined_tags
  all_dmz_defined_tags = local.all_alarm_defined_tags
  all_dynamic_groups_defined_tags = local.all_alarm_defined_tags
  all_exacs_vcns_defined_tags = local.all_alarm_defined_tags
  all_flow_logs_defined_tags = local.all_alarm_defined_tags
  all_groups_defined_tags = local.all_alarm_defined_tags
  all_keys_defined_tags = local.all_alarm_defined_tags
  all_notifications_defined_tags = local.all_alarm_defined_tags
  all_nsgs_defined_tags = local.all_alarm_defined_tags
  all_service_connector_defined_tags = local.all_alarm_defined_tags
  all_service_policy_defined_tags = local.all_alarm_defined_tags
  all_tags_defined_tags = local.all_alarm_defined_tags
  all_topics_defined_tags = local.all_alarm_defined_tags
  all_vcn_defined_tags = local.all_alarm_defined_tags
  all_vss_defined_tags = local.all_alarm_defined_tags
}

Now, we’re placing vision_stage2_override.tf into the config directory and run the terraform init, plan, apply cycle again. Before running terraform apply have a look at the output of terraform plan. You will notice lines like these:

   + defined_tags = {
       + "vision.CostCenter" = "42"
       + "vision.ProjectName" = "The Project"
     }

When you run terraform apply the defined tags of your components will be updated accordingly.