OCI, Terraform & IaC: Creating Compartments for CIS Foundation Architecture
Contents
In this third blog post series, we will be creating four main compartments
- Security Compartment
- Network Compartment
- App/Dev Compartment
- Database Compartment
The compartments above are based on the CIS Foundation Architecture, which is an architecture that starts with the compartment design for the tenancy along with groups and policies for the segregation of duties.
We will be using what we created in the past blog post, and we will just build on that.
The first thing I did was now instead of using a set value for the compartment resource, I use the for_each Meta-Argument. Terraform will create one instance of the resource for each member of that map or set. With the exception of the var.compartment_ocid, I will be grabbing the values from var.compartments object map.
resource "oci_identity_compartment" "cmpts" {
for_each = var.compartments
name = each.value.name
description = each.value.description
enable_delete = each.value.enable_delete
compartment_id = var.compartment_ocid
provisioner "local-exec" {
command = "sleep 60"
}
}
The other change that I made, was in the variables.tf, which was to add a complex datatype variable object map called compartments.
A map is a data structure that allows you to store and manage a collection of key-value pairs. Maps are often used to define input variables, output values, and resource configurations. An object is a structural type that can hold several types of values. It is a set of named attributes, each with its own type.
I did it this way, as later on I will be setting the default values out of the object, but for now, this is just to show that we can create. I used the names and descriptions from the actual CIS Foundation Landing Zone, no need to reinvent the wheel.
variable "compartments" {
type = map(object({
name = string
description = string
enable_delete = string
}))
default = {
key1 = {
name = "network-cmp"
description ="CIS Landing Zone compartment for all network related resources: VCNs, subnets, network gateways, security lists, NSGs, load balancers, VNICs, and others."
enable_delete = "false"
}
key2 = {
name = "security-cmp"
description = "CIS Landing Zone compartment for all security related resources: vaults, topics, notifications, logging, scanning, and others."
enable_delete = "false"
}
key3 = {
name = "appdev-cmp"
description= "CIS Landing Zone compartment for all security related resources: vaults, topics, notifications, logging, scanning, and others."
enable_delete = "true"
}
key4 = {
name = "database-cmp"
description= "CIS Landing Zone compartment for all database related resources."
enable_delete = "true"
}
}
}
Last, we will modify the outputs.tf so that we can show the result of each compartment resource we created. We use a for Expression, which its input can be a list, a set, a tuple, a map, or an object. It is important to note that
The type of brackets around the for
expression decides what type of result it produces. The [
and ]
, produces a tuple. If you use {
and }
instead, the result is an object and you must provide two result expressions that are separated by the =>
symbol, this expression produces an object whose attributes are the original elements.
output "compartments" {
description = "The compartments, indexed by keys in var.compartments."
value = {for k, v in var.compartments : k => oci_identity_compartment.cmpts[k]}
}
The result of the changes we have mentioned so creates 4 compartments and below is the output.
[opc@oracle-rene-cloud-ace vol02_compartment_cis]$ terraform apply
data.oci_identity_availability_domains.ADs: Reading...
data.oci_identity_region_subscriptions.home_region_subscriptions: Reading...
data.oci_identity_availability_domains.ADs: Read complete after 0s [id=IdentityAvailabilityDomainsDataSource-2545584872]
data.oci_identity_region_subscriptions.home_region_subscriptions: Read complete after 0s [id=IdentityRegionSubscriptionsDataSource-2545584872]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# oci_identity_compartment.these["key1"] will be created
+ resource "oci_identity_compartment" "these" {
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ defined_tags = (known after apply)
+ description = "CIS Landing Zone compartment for all network related resources: VCNs, subnets, network gateways, security lists, NSGs, load balancers, VNICs, and others."
+ enable_delete = false
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ inactive_state = (known after apply)
+ is_accessible = (known after apply)
+ name = "network-cmp"
+ state = (known after apply)
+ time_created = (known after apply)
}
...
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
oci_identity_compartment.these["key1"]: Creating...
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
compartments = {
"key1" = {
"compartment_id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"defined_tags" = tomap({
"Oracle-Tags.CreatedBy" = "default/ra@ace.com"
"Oracle-Tags.CreatedOn" = "2024-02-15T19:33:47.798Z"
})
"description" = "CIS Landing Zone compartment for all network related resources: VCNs, subnets, network gateways, security lists, NSGs, load balancers, VNICs, and others."
"enable_delete" = false
"freeform_tags" = tomap({})
"id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"inactive_state" = tostring(null)
"is_accessible" = true
"name" = "network-cmp"
"state" = "ACTIVE"
"time_created" = "2024-02-15 19:33:47.863 +0000 UTC"
"timeouts" = null /* object */
}
"key2" = {
"compartment_id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"defined_tags" = tomap({
"Oracle-Tags.CreatedBy" = "default/ra@ace.com"
"Oracle-Tags.CreatedOn" = "2024-02-15T19:33:47.796Z"
})
"description" = "CIS Landing Zone compartment for all security related resources: vaults, topics, notifications, logging, scanning, and others."
"enable_delete" = false
"freeform_tags" = tomap({})
"id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"inactive_state" = tostring(null)
"is_accessible" = true
"name" = "security-cmp"
"state" = "ACTIVE"
"time_created" = "2024-02-15 19:33:48.258 +0000 UTC"
"timeouts" = null /* object */
}
"key3" = {
"compartment_id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"defined_tags" = tomap({
"Oracle-Tags.CreatedBy" = "default/ra@ace.com"
"Oracle-Tags.CreatedOn" = "2024-02-15T19:33:47.822Z"
})
"description" = "CIS Landing Zone compartment for all security related resources: vaults, topics, notifications, logging, scanning, and others."
"enable_delete" = true
"freeform_tags" = tomap({})
"id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"inactive_state" = tostring(null)
"is_accessible" = true
"name" = "appdev-cmp"
"state" = "ACTIVE"
"time_created" = "2024-02-15 19:33:49.203 +0000 UTC"
"timeouts" = null /* object */
}
"key4" = {
"compartment_id" = "ocid1.compartment.oc1.. aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"defined_tags" = tomap({
"Oracle-Tags.CreatedBy" = "default/ra@ace.com"
"Oracle-Tags.CreatedOn" = "2024-02-15T19:33:47.802Z"
})
"description" = "CIS Landing Zone compartment for all database related resources."
"enable_delete" = true
"freeform_tags" = tomap({})
"id" = "ocid1.compartment.oc1..aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"inactive_state" = tostring(null)
"is_accessible" = true
"name" = "database-cmp"
"state" = "ACTIVE"
"time_created" = "2024-02-15 19:33:48.659 +0000 UTC"
"timeouts" = null /* object */
}
}
Conclusion
In this blog post, we discussed the CIS Foundations Landing Zone, and how to use complex data types and Expressions. In the next series, we will delve into creating a VCN and start having more fun with Terraform.