From 738fe7aa8795c151a32cdadc31c3937537336467 Mon Sep 17 00:00:00 2001
From: jason-chong <jason.c.chong@oracle.com>
Date: Wed, 8 Mar 2023 14:46:44 -0500
Subject: [PATCH] orm-update

---
 README.md                                     |   17 +
 .../enterprise-landing-zone/destroy_lz.py     |  290 ++++
 .../network-extension-variables.tf            |    2 +
 templates/enterprise-landing-zone/schema.yaml | 1184 +++++++++++++++++
 test/pytest.ini                               |    1 +
 test/terraform/network/compartment/main.tf    |   21 +
 test/terraform/network/compartment/outputs.tf |    8 +
 .../network/compartment/variables.tf          |   26 +
 test/terraform/network/main.tf                |   70 +-
 test/terraform/network/variables.tf           |    6 +
 test/test_security_vault.py                   |    1 +
 11 files changed, 1620 insertions(+), 6 deletions(-)
 create mode 100644 templates/enterprise-landing-zone/destroy_lz.py
 create mode 100644 templates/enterprise-landing-zone/schema.yaml
 create mode 100644 test/terraform/network/compartment/main.tf
 create mode 100644 test/terraform/network/compartment/outputs.tf
 create mode 100644 test/terraform/network/compartment/variables.tf

diff --git a/README.md b/README.md
index 8aee433d..5b37b275 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,23 @@ The Enterprise Scale Baseline Landing Zone v2.0 (ESBLZ v2.0) deploys a typical a
 - [Implementation Guide](./templates/enterprise-landing-zone/IMPLEMENTATION.md)
 - [Configuration Guide](./templates/enterprise-landing-zone/CONFIGURATION.md)
 
+## Deploy Using Oracle Resource Manager
+1. Click to deploy the stack
+
+[![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/oracle-quickstart/oci-landing-zones/archive/refs/tags/v2.0.0.zip)
+
+    If you aren't already signed in, when prompted, enter the tenancy and user credentials. Review and accept the terms and conditions.
+
+
+2. Select the region where you want to deploy the stack.
+3. For Working directory, select `templates/enterprise-landing-zone`
+4. Follow the on-screen prompts and instructions to create the stack.
+5. After creating the stack, click Terraform Actions, and select Plan.
+6. Wait for the job to be completed, and review the plan.
+7. To make any changes, return to the Stack Details page, click Edit Stack, and make the required changes. Then, run the Plan action again.
+8. If no further changes are necessary, return to the Stack Details page, click Terraform Actions, and select Apply.
+
+
 ## The Team
 
 This repository is developed and supported by the Oracle OCI Landing Zones team.
diff --git a/templates/enterprise-landing-zone/destroy_lz.py b/templates/enterprise-landing-zone/destroy_lz.py
new file mode 100644
index 00000000..d51a112e
--- /dev/null
+++ b/templates/enterprise-landing-zone/destroy_lz.py
@@ -0,0 +1,290 @@
+import argparse
+import os
+from concurrent.futures import ThreadPoolExecutor
+from datetime import datetime
+from typing import List, Dict
+import subprocess
+
+import oci
+from tqdm import tqdm
+
+
+class DestroyLandingZone:
+    def __init__(self, parent_cmp: str, region_key: str, env_prefixes: List[str],  oci_config: str, profile_name: str):
+        '''
+        Inputs include parent compartment as its name can be overridden via tfvar.
+        Region key and Environment prefix are variables used in compartment naming as well.
+        '''
+
+        self._conf_file = oci_config
+        self.config = oci.config.from_file(
+            file_location=self.config_filename,
+            profile_name=profile_name
+        )
+
+        self.identity_client = oci.identity.IdentityClient(self.config)
+        self.os_client = oci.object_storage.ObjectStorageClient(self.config)
+        self.log_analytics_client = oci.log_analytics.LogAnalyticsClient(
+            self.config)
+        self.identity_client = oci.identity.IdentityClient(self.config)
+        self.key_management_client = oci.key_management.KmsVaultClient(
+            self.config)
+        print("finished initializing oci clients")
+
+        self.tenancy_id = self.config["tenancy"]
+        self.parent_cmp = parent_cmp
+        self.os_namespace = self.get_os_namespace()
+        self.region_key = region_key
+        self.env_prefixes = env_prefixes
+
+    @property
+    def config_filename(self):
+        fn = os.path.join(os.environ["HOME"], self._conf_file)
+        return fn
+
+    def get_cmps(self, env_prefix: str) -> Dict[str, str]:
+        parent_cmps_response = self.identity_client.list_compartments(
+            compartment_id=self.tenancy_id,
+            name=self.parent_cmp
+        )
+        parent_cmp_id = parent_cmps_response.data[0].id
+
+        env_cmp_name = f"OCI-ELZ-{env_prefix}-CMP"
+        env_cmps_response = self.identity_client.list_compartments(
+            compartment_id=parent_cmp_id,
+            name=env_cmp_name
+        )
+        env_cmp_id = env_cmps_response.data[0].id
+
+        log_cmp_name = f"OCI-ELZ-{env_prefix}-LOG-{self.region_key}"
+        log_cmps_response = self.identity_client.list_compartments(
+            compartment_id=env_cmp_id,
+            name=log_cmp_name
+        )
+        log_cmp_id = log_cmps_response.data[0].id
+
+        shared_cmp_name = f"OCI-ELZ-{env_prefix}-SRD-CMP-{self.region_key}"
+        shared_cmps_response = self.identity_client.list_compartments(
+            compartment_id=env_cmp_id,
+            name=shared_cmp_name
+        )
+        shared_cmp_id = shared_cmps_response.data[0].id
+
+        security_cmp_name = f"OCI-ELZ-{env_prefix}-SRD-SEC"
+        security_cmps_response = self.identity_client.list_compartments(
+            compartment_id=shared_cmp_id,
+            name=security_cmp_name
+        )
+        security_cmp_id = security_cmps_response.data[0].id
+
+        cmp_map = {
+            "parent": parent_cmp_id,
+            "env": env_cmp_id,
+            "log": log_cmp_id,
+            "shared": shared_cmp_id,
+            "security": security_cmp_id
+        }
+
+        return cmp_map
+
+    def get_os_namespace(self):
+        os_namespace = self.os_client.get_namespace()
+        return os_namespace.data
+
+    def get_bucket_names(self, cmp_id: str) -> List[str]:
+        buckets_response = self.os_client.list_buckets(
+            compartment_id=cmp_id,
+            namespace_name=self.os_namespace
+        )
+
+        bucket_names = [d.name for d in buckets_response.data]
+        return bucket_names
+
+    def delete_retention_rules(self, bucket_name: str):
+        retention_rule_response = self.os_client.list_retention_rules(
+            namespace_name=self.os_namespace,
+            bucket_name=bucket_name
+        )
+        retention_rules = retention_rule_response.data.items
+
+        for rule in retention_rules:
+            retention_rule_response = self.os_client.delete_retention_rule(
+                namespace_name=self.os_namespace,
+                bucket_name=bucket_name,
+                retention_rule_id=rule.id
+            )
+
+    def delete_bucket_contents(self, bucket_name: str):
+        bucket_files = []
+        next_start_with = ""
+        while next_start_with != None:
+            list_files = self.os_client.list_objects(
+                self.os_namespace,
+                bucket_name,
+                start=next_start_with
+            )
+
+            next_start_with = list_files.data.next_start_with
+            if not list_files.data.objects:
+                break
+            bucket_files += list_files.data.objects
+
+        for filenames in tqdm(bucket_files, desc=f'bucket {bucket_name}'):
+            self.os_client.delete_object(
+                self.os_namespace,
+                bucket_name,
+                filenames.name
+            )
+
+    def delete_bucket(self, bucket_name: str):
+        delete_bucket_response = self.os_client.delete_bucket(
+            namespace_name=self.os_namespace,
+            bucket_name=bucket_name
+        )
+
+    def delete_bucket_all(self, bucket_name: str):
+        self.delete_retention_rules(bucket_name)
+        self.delete_bucket_contents(bucket_name)
+        self.delete_bucket(bucket_name)
+
+    def purge_log_analytics(self, cmp_id: str):
+        purge_storage_data_response = self.log_analytics_client.purge_storage_data(
+            namespace_name=self.os_namespace,
+            purge_storage_data_details=oci.log_analytics.models.PurgeStorageDataDetails(
+                compartment_id=cmp_id,
+                time_data_ended=datetime.now().strftime(
+                    "%Y-%m-%dT%H:%M:%S.%fZ"),
+                compartment_id_in_subtree=True),
+            # wait_for_states=["SUCCEEDED"]
+        )
+        # purge_storage_data_response = oci.log_analytics.LogAnalyticsClientCompositeOperations(self.log_analytics_client).purge_storage_data_and_wait_for_state(
+        #     namespace_name=self.os_namespace,
+        #     purge_storage_data_details=oci.log_analytics.models.PurgeStorageDataDetails(
+        #         compartment_id=cmp_id,
+        #         time_data_ended=datetime.now().strftime(
+        #             "%Y-%m-%dT%H:%M:%S.%fZ"),
+        #         compartment_id_in_subtree=True),
+        #     wait_for_states=["SUCCEEDED"]
+        # )
+
+    def delete_log_analytics_group(self, cmp_id: str):
+        list_log_analytics_log_groups_response = self.log_analytics_client.list_log_analytics_log_groups(
+            namespace_name=self.os_namespace,
+            compartment_id=cmp_id
+        )
+        log_groups = list_log_analytics_log_groups_response.data.items
+
+        for group in log_groups:
+            delete_log_analytics_log_group_response = self.log_analytics_client.delete_log_analytics_log_group(
+                namespace_name=self.os_namespace,
+                log_analytics_log_group_id=group.id
+            )
+            print(delete_log_analytics_log_group_response.data)
+
+    def move_vaults(self, cmp_id):
+        list_vaults_response = self.key_management_client.list_vaults(
+            compartment_id=cmp_id
+        )
+        vaults = list_vaults_response.data
+
+        for vault in vaults:
+            if vault.lifecycle_state != "CREATED":
+                print(
+                    f"ignoring vault {vault.display_name} not in created state")
+                continue
+
+            change_vault_compartment_response = self.key_management_client.change_vault_compartment(
+                vault_id=vault.id,
+                change_vault_compartment_details=oci.key_management.models.ChangeVaultCompartmentDetails(
+                    compartment_id=self.tenancy_id
+                )
+            )
+
+    def update_terraform_state(self):
+        process = subprocess.run(["terraform state rm module.nonprod_environment.module.security.module.vault.oci_kms_vault.vault"],
+                                 stdout=subprocess.PIPE,
+                                 universal_newlines=True,
+                                 shell=True)
+        process = subprocess.run(["terraform state rm module.prod_environment.module.security.module.vault.oci_kms_vault.vault"],
+                                 stdout=subprocess.PIPE,
+                                 universal_newlines=True,
+                                 shell=True)
+
+    def deactivate_domains(self, cmp_id):
+        list_domains_response = self.identity_client.list_domains(
+            compartment_id=cmp_id
+        )
+        domains = list_domains_response.data
+
+        for domain in domains:
+            deactivate_domain_response = self.identity_client.deactivate_domain(
+                domain_id=domain.id
+            )
+
+    def delete_environment(self, env_prefix: str):
+        print(f"beginning env {env_prefix} destroy")
+
+        print("fetching compartment ids")
+        compartments = self.get_cmps(env_prefix)
+        bucket_cmps = [compartments["parent"], compartments["log"]]
+
+        print("beginning bucket destroy")
+        bucket_names = []
+        for cmp in bucket_cmps:
+            bucket_names += self.get_bucket_names(cmp)
+
+        print(bucket_names)
+        with ThreadPoolExecutor(max_workers=4) as p:
+            p.map(self.delete_bucket_all, bucket_names)
+
+        print("beginning log analytics destroy")
+        self.purge_log_analytics(compartments["security"])
+        self.delete_log_analytics_group(compartments["security"])
+
+        print("beginning vault move")
+        self.move_vaults(compartments["security"])
+        # self.update_terraform_state()
+
+        print("deactivating domains")
+        self.deactivate_domains(compartments["security"])
+
+        print("finished destroying ___\n\n")
+
+    def run_all(self):
+        for env in self.env_prefixes:
+            self.delete_environment(env)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description="Destroy Landing Zone Lingering Resources",
+        epilog="python destroy_lz.py -r IAD -e P N")
+
+    parser.add_argument("-c", "--cmp",
+                        default="OCI-ELZ-CMP-HOME",
+                        help="Name of the parent cmp")
+
+    parser.add_argument("-r", "--region_key",
+                        help="Region Key used in compartment naming eg. IAD, PHX")
+
+    parser.add_argument("-e", "--env_prefixes", nargs="+",
+                        default=["P", "N"],
+                        help="Environment prefix used in compartment naming")
+
+    parser.add_argument("--profile",
+                        default="DEFAULT",
+                        help="OCI profile you want to use in the specified region")
+
+    parser.add_argument("--oci_config",
+                        default=".oci/config",
+                        help="Path to the OCI Configuration file")
+
+    args = parser.parse_args()
+    generate_schema = DestroyLandingZone(
+        parent_cmp=args.cmp,
+        region_key=args.region_key,
+        env_prefixes=args.env_prefixes,
+        oci_config=args.oci_config,
+        profile_name=args.profile
+    )
+    generate_schema.run_all()
diff --git a/templates/enterprise-landing-zone/network-extension-variables.tf b/templates/enterprise-landing-zone/network-extension-variables.tf
index 38176958..56a5a87d 100644
--- a/templates/enterprise-landing-zone/network-extension-variables.tf
+++ b/templates/enterprise-landing-zone/network-extension-variables.tf
@@ -7,11 +7,13 @@ variable "enable_vpn_or_fastconnect" {
 variable "prod_enable_vpn" {
   type        = bool
   description = "Enable VPN in prod environment"
+  default     = false
 }
 
 variable "nonprod_enable_vpn" {
   type        = bool
   description = "Enable VPN in non prod environment"
+  default     = false
 }
 
 variable "prod_cpe_display_name" {
diff --git a/templates/enterprise-landing-zone/schema.yaml b/templates/enterprise-landing-zone/schema.yaml
new file mode 100644
index 00000000..0936d29e
--- /dev/null
+++ b/templates/enterprise-landing-zone/schema.yaml
@@ -0,0 +1,1184 @@
+title: Enterprise Scale Baseline Landing Zone 2.0
+description: Enterprise Scale Baseline Landing Zone 2.0 developed by OCI
+schemaVersion: 1.0.0
+version: "1.0.0"
+locale: en
+variableGroups:
+  - title: Provider Variables
+    visible: false
+    variables:
+      - api_fingerprint
+      - api_private_key_path
+      - api_private_key
+      - region
+      - tenancy_ocid
+      - current_user_ocid
+  - title: IAM Variables
+    visible: true
+    variables:
+      - resource_label
+      - home_compartment_name
+      - prod_domain_admin_email
+      - nonprod_domain_admin_email
+      - enable_compartment_delete
+      - break_glass_user_email_list
+      - show_extra_group_names
+      - prod_network_admin_group_name
+      - prod_security_admin_group_name
+      - prod_iam_admin_group_name
+      - prod_platform_admin_group_name
+      - prod_ops_admin_group_name
+      - prod_log_admin_group_name
+      - prod_workload_admin_group_name
+      - prod_application_admin_group_name
+      - prod_database_admin_group_name
+      - nonprod_network_admin_group_name
+      - nonprod_security_admin_group_name
+      - nonprod_iam_admin_group_name
+      - nonprod_platform_admin_group_name
+      - nonprod_ops_admin_group_name
+      - nonprod_log_admin_group_name
+      - nonprod_workload_admin_group_name
+      - nonprod_application_admin_group_name
+      - nonprod_database_admin_group_name
+  - title: Security Variables
+    visible: true
+    variables:
+      - enable_cloud_guard
+      - cloud_guard_target_tenancy
+      - prod_enable_bastion
+      - prod_bastion_client_cidr_block_allow_list
+      - nonprod_enable_bastion
+      - nonprod_bastion_client_cidr_block_allow_list
+  - title: Budget Variables
+    visible: true
+    variables:
+      - prod_enable_budget
+      - prod_budget_alert_rule_message
+      - prod_budget_alert_rule_recipients
+      - prod_budget_alert_rule_threshold
+      - prod_budget_amount
+      - nonprod_enable_budget
+      - nonprod_budget_alert_rule_message
+      - nonprod_budget_alert_rule_recipients
+      - nonprod_budget_alert_rule_threshold
+      - nonprod_budget_amount
+  - title: Network Variables
+    visible: true
+    variables:
+      - prod_enable_internet_gateway_hub
+      - prod_enable_nat_gateway_hub
+      - prod_enable_service_gateway_hub
+      - prod_enable_nat_gateway_spoke
+      - prod_enable_service_gateway_spoke
+      - prod_hub_vcn_cidr_block
+      - prod_hub_public_subnet_cidr_block
+      - prod_hub_private_subnet_cidr_block
+      - prod_spoke_vcn_cidr
+      - prod_spoke_subnet_web_cidr_block
+      - prod_spoke_subnet_app_cidr_block
+      - prod_spoke_subnet_db_cidr_block
+      - nonprod_enable_internet_gateway_hub
+      - nonprod_enable_nat_gateway_hub
+      - nonprod_enable_service_gateway_hub
+      - nonprod_enable_nat_gateway_spoke
+      - nonprod_enable_service_gateway_spoke
+      - nonprod_hub_vcn_cidr_block
+      - nonprod_hub_public_subnet_cidr_block
+      - nonprod_hub_private_subnet_cidr_block
+      - nonprod_spoke_vcn_cidr
+      - nonprod_spoke_subnet_web_cidr_block
+      - nonprod_spoke_subnet_app_cidr_block
+      - nonprod_spoke_subnet_db_cidr_block
+  - title: Tagging Variables
+    visible: true
+    variables:
+      - prod_enable_tagging
+      - prod_cost_center_tagging
+      - prod_geo_location_tagging
+      - nonprod_enable_tagging
+      - nonprod_cost_center_tagging
+      - nonprod_geo_location_tagging
+  - title: Logging Variables
+    visible: true
+    variables:
+      - archive_log_retention_policy_duration_amount
+      - archive_log_retention_policy_duration_time_unit
+      - prod_retention_policy_duration_amount
+      - prod_retention_policy_duration_time_unit
+      - nonprod_retention_policy_duration_amount
+      - nonprod_retention_policy_duration_time_unit
+  - title: Monitoring Variables
+    visible: true
+    variables:
+      - onboard_log_analytics
+      - prod_network_topic_endpoints
+      - prod_secops_topic_endpoints
+      - prod_platform_topic_endpoints
+      - prod_identity_topic_endpoints
+      - prod_workload_topic_endpoints
+      - nonprod_network_topic_endpoints
+      - nonprod_secops_topic_endpoints
+      - nonprod_platform_topic_endpoints
+      - nonprod_identity_topic_endpoints
+      - nonprod_workload_topic_endpoints
+      - prod_enable_security_monitoring_alarms
+      - prod_enable_network_monitoring_alarms
+      - prod_enable_workload_monitoring_alarms
+      - nonprod_enable_security_monitoring_alarms
+      - nonprod_enable_network_monitoring_alarms
+      - nonprod_enable_workload_monitoring_alarms
+  - title: Network Extension Variables
+    visible: true
+    variables:
+      - enable_vpn_or_fastconnect
+      - show_vpn_variables
+      - prod_enable_vpn
+      - nonprod_enable_vpn
+      - prod_cpe_display_name
+      - nonprod_cpe_display_name
+      - prod_cpe_ip_address
+      - nonprod_cpe_ip_address
+      - prod_ipsec_display_name
+      - nonprod_ipsec_display_name
+      - prod_ipsec_connection_static_routes
+      - nonprod_ipsec_connection_static_routes
+      - prod_cpe_vendor
+      - nonprod_cpe_vendor
+      - prod_ipsec_routing_type
+      - prod_tunnel_a_display_name
+      - prod_customer_bgp_asn
+      - prod_bgp_cust_tunnela_ip
+      - prod_bgp_oci_tunnela_ip
+      - prod_shared_secret
+      - prod_tunnel_b_display_name
+      - nonprod_ipsec_routing_type
+      - nonprod_tunnel_a_display_name
+      - nonprod_customer_bgp_asn
+      - nonprod_bgp_cust_tunnela_ip
+      - nonprod_bgp_oci_tunnela_ip
+      - nonprod_shared_secret
+      - nonprod_tunnel_b_display_name
+      - show_fastconnect_variables
+      - fastconnect_provider
+      - virtual_circuit_bandwidth_shape
+      - virtual_circuit_display_name
+      - provider_service_key_name
+      - fastconnect_routing_policy
+      - virtual_circuit_type
+      - customer_primary_bgp_peering_ip
+      - oracle_primary_bgp_peering_ip
+      - customer_secondary_bgp_peering_ip
+      - oracle_secondary_bgp_peering_ip
+      - virtual_circuit_customer_asn
+      - virtual_circuit_is_bfd_enabled
+      - bgp_md5auth_key
+      - customer_onprem_ip_cidr
+  - title: Invisible Variables
+    visible: false
+    variables:
+      - igw_hub_check
+      - nat_gw_hub_check
+      - nat_gw_spoke_check
+      - service_gw_hub_check
+      - service_gw_spoke_check
+      - nonprod_create_master_encryption_key
+      - nonprod_enable_vault_replication
+      - nonprod_vault_replica_region
+      - nonprod_vault_type
+      - prod_create_master_encryption_key
+      - prod_enable_vault_replication
+      - prod_vault_replica_region
+      - prod_vault_type
+      - nonprod_enable_fastconnect
+      - prod_enable_fastconnect
+
+
+variables:
+  #Provider Variables
+  api_fingerprint:
+    type: string
+    description: The fingerprint of API
+    default: "Value not required in Oracle Resource Manager."
+    title: Api Fingerprint
+  api_private_key_path:
+    type: string
+    description: The local path to the API private key
+    default: "Value not required in Oracle Resource Manager."
+    title: Api Private Key Path
+  region:
+    type: string
+    description: the OCI region LZ is deployed to.
+    title: Region
+    required: true
+  tenancy_ocid:
+    type: string
+    description: The OCID of tenancy
+    title: Tenancy OCID
+  current_user_ocid:
+    type: string
+    description: OCID of the current user
+    title: Current User OCID
+
+  # IAM variables
+  resource_label:
+    type: string
+    description: "The prefix used to avoid naming conflict"
+    default: ""
+    required: true
+    title: Resource Label
+  home_compartment_name:
+    type: string
+    description: "The name of the Landing Zone home compartment"
+    default: "OCI-ELZ-CMP-HOME"
+    required: true
+    title: Home Compartment Name
+  prod_domain_admin_email:
+    type: string
+    description: "The email address for the prod identity domain admin"
+    required: true
+    title: Domain Admin Email in Prod
+  nonprod_domain_admin_email:
+    type: string
+    description: "The email address for the non-prod identity domain admin"
+    required: true
+    title: Domain Admin Email in Non-Prod
+  enable_compartment_delete:
+    type: boolean
+    description: "Set to true to allow the compartments to delete on terraform destroy."
+    required: true
+    title: Enable Compartment Delete
+  break_glass_user_email_list:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description:
+      "Unique list of break glass user email addresses that do not exist. These users are added to the Administrator group.
+      in the tenancy"
+    required: true
+    title: Break Glass User Email List
+  show_extra_group_names:
+    type: boolean
+    default: false
+    required: false
+    title: Override default group names
+  prod_network_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Network Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Network Admin Group Name in Prod
+  prod_security_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Security Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Security Admin Group Name in Prod
+  prod_iam_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone IAM Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: IAM Admin Group Name in Prod
+  prod_platform_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Platform Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Platform Admin Group Name in Prod
+  prod_ops_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Ops Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Ops Admin Group Name in Prod
+  prod_log_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Log Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Log Admin Group Name in Prod
+  prod_workload_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Workload Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Workload Admin Group Name in Prod
+  prod_application_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Application Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Application Admin Group Name in Prod
+  prod_database_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Database Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Database Admin Group Name in Prod
+  nonprod_network_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Network Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Network Admin Group Name in Non-Prod
+  nonprod_security_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Security Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Security Admin Group Name in Non-Prod
+  nonprod_iam_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone IAM Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: IAM Admin Group Name in Non-Prod
+  nonprod_platform_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Platform Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Platform Admin Group Name in Non-Prod
+  nonprod_ops_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Ops Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Ops Admin Group Name in Non-Prod
+  nonprod_log_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Log Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Log Admin Group Name in Non-Prod
+  nonprod_workload_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Workload Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Workload Admin Group Name in Non-Prod
+  nonprod_application_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Application Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Application Admin Group Name in Non-Prod
+  nonprod_database_admin_group_name:
+    type: string
+    description: "The group name for the OCI Landing Zone Database Administrators Group"
+    required: false
+    default: ""
+    visible: show_extra_group_names
+    pattern: ^([\w\.-]){1,100}$
+    title: Database Admin Group Name in Non-Prod
+
+  # Security Variables
+  enable_cloud_guard:
+    type: boolean
+    description: "true if you don't have cloud guard enabled, false if you've already have cloud guard enabled."
+    default: true
+    required: true
+    title: Enable Cloud Guard
+  cloud_guard_target_tenancy:
+    type: boolean
+    description: "true if cloud guard targets to tenancy, false if cloud guard targets to Landing Zone home compartment."
+    default: false
+    required: true
+    title: Cloud Guard Target Tenancy
+  prod_enable_bastion:
+    type: boolean
+    description: "Option to enable bastion service in prod"
+    default: true
+    required: true
+    title: Enable Bastion in Prod
+  prod_bastion_client_cidr_block_allow_list:
+    type: array
+    items:
+      type: string
+      pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    description: "A list of address ranges in CIDR notation that bastion is allowed to connect"
+    required: true
+    visible: prod_enable_bastion
+    title: Bastion Client CIDR Block Allow List in Prod
+  nonprod_enable_bastion:
+    type: boolean
+    description: "Option to enable bastion service in non-prod"
+    default: true
+    required: true
+    title: Enable Bastion in Non-Prod
+  nonprod_bastion_client_cidr_block_allow_list:
+    type: array
+    items:
+      type: string
+      pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    description: "A list of address ranges in CIDR notation that bastion is allowed to connect"
+    required: true
+    visible: nonprod_enable_bastion
+    title: Bastion Client CIDR Block Allow List in Non-Prod
+  # Budget Variables
+  prod_enable_budget:
+    type: boolean
+    description: "Option to enable budget service in prod."
+    default: true
+    required: true
+    title: Enable Budget Service in Prod
+  prod_budget_alert_rule_message:
+    type: string
+    description: "The alert message for budget alerts."
+    required: false
+    default: ""
+    visible: prod_enable_budget
+    title: Budget Alert Rule Message in Prod
+  prod_budget_alert_rule_recipients:
+    type: string
+    description: "The delimited list of email addresses to receive the alert when it triggers. Delimiter characters can be a comma, space, TAB, or semicolon"
+    required: false
+    default: ""
+    visible: prod_enable_budget
+    title: Budget Alert Rule Recipients in Prod
+  prod_budget_alert_rule_threshold:
+    type: string
+    description: "The threshold for the budget alert."
+    required: false
+    default: ""
+    visible: prod_enable_budget
+    title: Budget Alert Rule Threshold in Prod
+  prod_budget_amount:
+    type: string
+    description: "The amount of the budget expressed as a whole number in the currency of the customer's rate card."
+    required: false
+    default: ""
+    visible: prod_enable_budget
+    title: Budget Amount in Prod
+  nonprod_enable_budget:
+    type: boolean
+    description: "Option to enable budget service in non-prod."
+    default: true
+    required: true
+    title: Enable Budget Service in Non-Prod
+  nonprod_budget_alert_rule_message:
+    type: string
+    description: "The alert message for budget alerts."
+    required: false
+    default: ""
+    visible: nonprod_enable_budget
+    title: Budget Alert Rule Message in Non-Prod
+  nonprod_budget_alert_rule_recipients:
+    type: string
+    description: "The delimited list of email addresses to receive the alert when it triggers. Delimiter characters can be a comma, space, TAB, or semicolon"
+    required: false
+    default: ""
+    visible: nonprod_enable_budget
+    title: Budget Alert Rule Recipients in Non-Prod
+  nonprod_budget_alert_rule_threshold:
+    type: string
+    description: "The threshold for the budget alert."
+    required: false
+    default: ""
+    visible: nonprod_enable_budget
+    title: Budget Alert Rule Threshold in Non-Prod
+  nonprod_budget_amount:
+    type: string
+    description: "The amount of the budget expressed as a whole number in the currency of the customer's rate card."
+    required: false
+    default: ""
+    visible: nonprod_enable_budget
+    title: Budget Amount in Non-Prod
+
+  # Tagging Variables
+  prod_enable_tagging:
+    type: boolean
+    description: "Option to enable tagging service in prod."
+    default: true
+    required: true
+    title: Enable Tagging Service in Prod
+  prod_cost_center_tagging:
+    type: string
+    description: "Cost center tagging in prod."
+    required: true
+    title: Cost Center Tagging in Prod
+  prod_geo_location_tagging:
+    type: string
+    description: "Geo location tagging in prod."
+    required: true
+    title: Geo Location Tagging in Prod
+  nonprod_enable_tagging:
+    type: boolean
+    description: "Option to enable tagging service in non-prod."
+    default: true
+    required: true
+    title: Enable Tagging Service in Prod
+  nonprod_cost_center_tagging:
+    type: string
+    description: "Cost center tagging in non-prod."
+    required: true
+    title: Cost Center Tagging in Non-Prod
+  nonprod_geo_location_tagging:
+    type: string
+    description: "Geo location tagging in non-prod."
+    required: true
+    title: Geo Location Tagging in Non-Prod
+
+  # Logging Variables
+  archive_log_retention_policy_duration_amount:
+    type: string
+    description: "The timeAmount is interpreted in units defined by the timeUnit parameter, and is calculated in relation to each object's Last-Modified timestamp"
+    required: true
+    default: "1"
+    title: Retention Policy Duration Amount for Archive Log Bucket
+  archive_log_retention_policy_duration_time_unit:
+    type: string
+    description: "The unit that should be used to interpret timeAmount. Options: DAYS, YEARS"
+    required: true
+    default: "DAYS"
+    title: Retention Policy Duration Time Unit for Archive Log Bucket
+  prod_retention_policy_duration_amount:
+    type: string
+    description: "The timeAmount is interpreted in units defined by the timeUnit parameter, and is calculated in relation to each object's Last-Modified timestamp"
+    required: true
+    default: "1"
+    title: Retention Policy Duration Amount for Standard Log Bucket in Prod
+  prod_retention_policy_duration_time_unit:
+    type: string
+    description: "The unit that should be used to interpret timeAmount. Options: DAYS, YEARS"
+    required: true
+    default: "DAYS"
+    title: Retention Policy Duration Time Unit for Standard Log Bucket in Prod
+  nonprod_retention_policy_duration_amount:
+    type: string
+    description: "The timeAmount is interpreted in units defined by the timeUnit parameter, and is calculated in relation to each object's Last-Modified timestamp"
+    required: true
+    default: "1"
+    title: Retention Policy Duration Amount for Standard Log Bucket in Non-Prod
+  nonprod_retention_policy_duration_time_unit:
+    type: string
+    description: "The unit that should be used to interpret timeAmount. Options: DAYS, YEARS"
+    required: true
+    default: "DAYS"
+    title: Retention Policy Duration Time Unit for Standard Log Bucket in Non-Prod
+
+  # Monitoring Variables
+  onboard_log_analytics:
+    type: boolean
+    description: "Set to true to onboard log analytics service. Set to false if it's already onboarded"
+    default: true
+    required: true
+    title: Onboard Log Analytics
+  prod_network_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Network Warning and Critical notifications."
+    required: false
+    default: []
+    title: Network Warning and Critical Notification Recipient Email List in Prod"
+  prod_secops_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for SecOps Warning and Critical notifications."
+    required: false
+    default: []
+    title: SecOps Warning and Critical Notification Recipient Email List in Prod"
+  prod_platform_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Platform notifications."
+    required: false
+    default: []
+    title: Platform Notification Recipient Email List in Prod"
+  prod_identity_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Identity notifications."
+    required: false
+    default: []
+    title: Identity Notification Recipient Email List in Prod"
+  prod_workload_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Workload notifications."
+    required: false
+    default: []
+    title: Workload Notification Recipient Email List in Prod"
+  nonprod_network_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Network Warning and Critical notifications."
+    required: false
+    default: []
+    title: Network Warning and Critical Notification Recipient Email List in Non-Prod"
+  nonprod_secops_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for SecOps Warning and Critical notifications."
+    required: false
+    default: []
+    title: SecOps Warning and Critical Notification Recipient Email List in Non-Prod"
+  nonprod_platform_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Platform notifications."
+    required: false
+    default: []
+    title: Platform Notification Recipient Email List in Non-Prod"
+  nonprod_identity_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Identity notifications."
+    required: false
+    default: []
+    title: Identity Notification Recipient Email List in Non-Prod"
+  nonprod_workload_topic_endpoints:
+    type: array
+    items:
+      type: string
+      pattern: ^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$
+    description: "List of email addresses for Workload notifications."
+    required: false
+    default: []
+    title: Workload Notification Recipient Email List in Non-Prod"
+  prod_enable_security_monitoring_alarms:
+    type: boolean
+    description: "Enable Security Monitoring Alarms in Production Security Compartment."
+    default: false
+    required: true
+    title: Enable Security Monitoring Alarms in Prod
+  prod_enable_network_monitoring_alarms:
+    type: boolean
+    description: "Enable Network Monitoring Alarms in Production Network Compartment."
+    default: false
+    required: true
+    title: Enable Network Monitoring Alarms in Prod
+  prod_enable_workload_monitoring_alarms:
+    type: boolean
+    description: "Enable Workload Monitoring Alarms in Production Workload Compartment."
+    default: false
+    required: true
+    title: Enable Workload Monitoring Alarms in Prod
+  nonprod_enable_security_monitoring_alarms:
+    type: boolean
+    description: "Enable Security Monitoring Alarms in Non-Production Security Compartment."
+    default: false
+    required: true
+    title: Enable Security Monitoring Alarms in Non-Prod
+  nonprod_enable_network_monitoring_alarms:
+    type: boolean
+    description: "Enable Network Monitoring Alarms in Non-Production Network Compartment."
+    default: false
+    required: true
+    title: Enable Network Monitoring Alarms in Non-Prod
+  nonprod_enable_workload_monitoring_alarms:
+    type: boolean
+    description: "Enable Workload Monitoring Alarms in Non-Production Workload Compartment."
+    default: false
+    required: true
+    title: Enable Workload Monitoring Alarms in Non-Prod
+
+  # Network Variables
+  prod_enable_internet_gateway_hub:
+    type: boolean
+    description: "Option to enable internet gateway in prod hub"
+    default: true
+    required: true
+    title: Enable Internet Gateway in Prod Hub
+  prod_enable_nat_gateway_hub:
+    type: boolean
+    description: "Option to enable nat gateway in prod hub"
+    default: true
+    required: true
+    title: Enable NAT Gateway in Prod Hub
+  prod_enable_service_gateway_hub:
+    type: boolean
+    description: "Option to enable service gateway in prod hub"
+    default: true
+    required: true
+    title: Enable Service Gateway in Prod Hub
+  prod_enable_nat_gateway_spoke:
+    type: boolean
+    description: "Option to enable nat gateway in prod spoke"
+    default: true
+    required: true
+    title: Enable NAT Gateway in Prod Spoke
+  prod_enable_service_gateway_spoke:
+    type: boolean
+    description: "Option to enable service gateway in prod spoke"
+    default: true
+    required: true
+    title: Enable Service Gateway in Prod Spoke
+  prod_hub_vcn_cidr_block:
+    type: string
+    description: "Vcn CIDR block in Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Vcn CIDR Block in Prod Hub
+  prod_hub_public_subnet_cidr_block:
+    type: string
+    description: "Public subnet CIDR block in Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Public Subnet CIDR Block in Prod Hub
+  prod_hub_private_subnet_cidr_block:
+    type: string
+    description: "Private subnet CIDR block in Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Private Subnet CIDR Block in Prod Hub
+  prod_spoke_vcn_cidr:
+    type: string
+    description: "Vcn CIDR block in Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Vcn CIDR Block in Prod Spoke
+  prod_spoke_subnet_web_cidr_block:
+    type: string
+    description: "Web subnet CIDR block in Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Web Subnet CIDR Block in Prod Spoke
+  prod_spoke_subnet_app_cidr_block:
+    type: string
+    description: "App subnet CIDR block in Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: App Subnet CIDR Block in Prod Spoke
+  prod_spoke_subnet_db_cidr_block:
+    type: string
+    description: "Database subnet CIDR block in Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Database Subnet CIDR Block in Prod Spoke
+  nonprod_enable_internet_gateway_hub:
+    type: boolean
+    description: "Option to enable internet gateway in Non-prod hub"
+    default: true
+    required: true
+    title: Enable Internet Gateway in Non-Prod Hub
+  nonprod_enable_nat_gateway_hub:
+    type: boolean
+    description: "Option to enable nat gateway in Non-prod hub"
+    default: true
+    required: true
+    title: Enable NAT Gateway in Non-Prod Hub
+  nonprod_enable_service_gateway_hub:
+    type: boolean
+    description: "Option to enable service gateway in Non-prod hub"
+    default: true
+    required: true
+    title: Enable Service Gateway in Non-Prod Hub
+  nonprod_enable_nat_gateway_spoke:
+    type: boolean
+    description: "Option to enable nat gateway in Non-prod spoke"
+    default: true
+    required: true
+    title: Enable NAT Gateway in Non-Prod Spoke
+  nonprod_enable_service_gateway_spoke:
+    type: boolean
+    description: "Option to enable service gateway in Non-prod spoke"
+    default: true
+    required: true
+    title: Enable Service Gateway in Non-Prod Spoke
+  nonprod_hub_vcn_cidr_block:
+    type: string
+    description: "Vcn CIDR block in Non-Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Vcn CIDR Block in Non-Prod Hub
+  nonprod_hub_public_subnet_cidr_block:
+    type: string
+    description: "Public subnet CIDR block in Non-Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Public Subnet CIDR Block in Non-Prod Hub
+  nonprod_hub_private_subnet_cidr_block:
+    type: string
+    description: "Private subnet CIDR block in Non-Prod Hub"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Private Subnet CIDR Block in Non-Prod Hub
+  nonprod_spoke_vcn_cidr:
+    type: string
+    description: "Vcn CIDR block in Non-Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Vcn CIDR Block in Non-Prod Spoke
+  nonprod_spoke_subnet_web_cidr_block:
+    type: string
+    description: "Web subnet CIDR block in Non-Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Web Subnet CIDR Block in Non-Prod Spoke
+  nonprod_spoke_subnet_app_cidr_block:
+    type: string
+    description: "App subnet CIDR block in Non-Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: App Subnet CIDR Block in Non-Prod Spoke
+  nonprod_spoke_subnet_db_cidr_block:
+    type: string
+    description: "Database subnet CIDR block in Non-Prod Spoke"
+    required: true
+    pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    title: Database Subnet CIDR Block in Non-Prod Spoke
+
+  # Network Extension Variables
+  enable_vpn_or_fastconnect:
+    type: enum
+    description: "Enable VPN or FASTCONNECT. Options: NONE, VPN, FASTCONNECT"
+    enum:
+      - "NONE"
+      - "VPN"
+      - "FASTCONNECT"
+    required: true
+    default: "NONE"
+    title: Enable VPN or Fastconnect
+  show_vpn_variables:
+    type: boolean
+    description: "Show VPN related variables"
+    required: false
+    title: Show VPN Related Variables
+  prod_enable_vpn:
+    type: boolean
+    description: "Enable VPN in prod environment"
+    required: false
+    default: false
+    visible: show_vpn_variables
+    title: Enable VPN in Prod
+  prod_cpe_display_name:
+    type: string
+    description: "Customer Premises Equipment name in prod. Recommendation: OCI-ELZ-CPE-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: CPE Display Name in Prod
+  prod_cpe_ip_address:
+    type: string
+    description: "Customer Premises Equipment IP address in prod. Recommendation: OCI-ELZ-CPE-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: CPE IP Address in Prod
+  prod_ipsec_display_name:
+    type: string
+    description: "IPsec display name in prod. Recommendation: OCI-ELZ-IPS-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: IPsec Display Name in Prod
+  prod_ipsec_connection_static_routes:
+    type: array
+    items:
+      type: string
+    description: "IPsec Connection Static Routes in prod"
+    required: false
+    default: [""]
+    visible: show_vpn_variables
+    title: IPsec Connection Static Routes in Prod
+  prod_cpe_vendor:
+    type: number
+    description: "Type corresponding number as your CPE vendor: Yamaha-RTX1210 0, Other 1, Cisco-9.7.1-or-later 2, Yamaha-RTX830 3, Libreswan 4, Fortinet 5, NEC 6, Cisco-8.5+ 7, Cisco-IOS 8, WatchGuard 9, Juniper-MX 10, Juniper-SRX 11, Furukawa 12, Check_Point 13, Palo_Alto 14"
+    required: false
+    default: 0
+    visible: show_vpn_variables
+    title: CPE Vendor in Prod
+  prod_ipsec_routing_type:
+    type: string
+    description: "BGP dynamic routing, STATIC routing. Type BGP or STATIC"
+    required: false
+    default: STATIC
+    visible: show_vpn_variables
+    title: IPsec Routing Type in Prod
+  prod_tunnel_a_display_name:
+    type: string
+    description: "Tunnel A display name in prod."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Tunnel A Display Name in Prod
+  prod_customer_bgp_asn:
+    type: string
+    description: "ASN is required and used for the tunnel's BGP session"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Customer BGP ASN in Prod
+  prod_bgp_cust_tunnela_ip:
+    type: string
+    description: "The IP address for the CPE end of the inside tunnel interface."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: BGP Customer End IP in Prod
+  prod_bgp_oci_tunnela_ip:
+    type: string
+    description: "The IP address for the Oracle end of the inside tunnel interface."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: BGP Oracle End IP in Prod
+  prod_shared_secret:
+    type: string
+    description: "The shared secret (pre-shared key) to use for the IPSec tunnel"
+    required: false
+    default: "example"
+    visible: show_vpn_variables
+    title: IPsec Shared Secret in Prod
+  prod_tunnel_b_display_name:
+    type: string
+    description: "Tunnel B display name in prod"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Tunnel B Display Name in Prod
+  nonprod_enable_vpn:
+    type: boolean
+    description: "Enable VPN in Non-prod environment"
+    required: false
+    default: false
+    visible: show_vpn_variables
+    title: Enable VPN in Non-Prod
+  nonprod_cpe_display_name:
+    type: string
+    description: "Customer Premises Equipment name in Non-prod. Recommendation: OCI-ELZ-CPE-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: CPE Display Name in Non-Prod
+  nonprod_cpe_ip_address:
+    type: string
+    description: "Customer Premises Equipment IP address in Non-prod. Recommendation: OCI-ELZ-CPE-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: CPE IP Address in Non-Prod
+  nonprod_ipsec_display_name:
+    type: string
+    description: "IPsec display name in Non-prod. Recommendation: OCI-ELZ-IPS-[Environment]-HUB-[Region] 001"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: IPsec Display Name in Non-Prod
+  nonprod_ipsec_connection_static_routes:
+    type: array
+    items:
+      type: string
+      pattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1][0-9]|[2][0-9]))$
+    description: "IPsec Connection Static Routes in Non-prod"
+    required: false
+    default: [""]
+    visible: show_vpn_variables
+    title: IPsec Connection Static Routes in Non-Prod
+  nonprod_cpe_vendor:
+    type: number
+    description: "Type corresponding number as your CPE vendor: Yamaha-RTX1210 0, Other 1, Cisco-9.7.1-or-later 2, Yamaha-RTX830 3, Libreswan 4, Fortinet 5, NEC 6, Cisco-8.5+ 7, Cisco-IOS 8, WatchGuard 9, Juniper-MX 10, Juniper-SRX 11, Furukawa 12, Check_Point 13, Palo_Alto 14"
+    required: false
+    default: 0
+    visible: show_vpn_variables
+    title: CPE Vendor in Non-Prod
+  nonprod_ipsec_routing_type:
+    type: string
+    description: "BGP dynamic routing, STATIC routing. Type BGP or STATIC"
+    required: false
+    default: STATIC
+    visible: show_vpn_variables
+    title: IPsec Routing Type in Non-Prod
+  nonprod_tunnel_a_display_name:
+    type: string
+    description: "Tunnel A display name in Non-prod."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Tunnel A Display Name in Non-Prod
+  nonprod_customer_bgp_asn:
+    type: string
+    description: "ASN is required and used for the tunnel's BGP session"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Customer BGP ASN in Non-Prod
+  nonprod_bgp_cust_tunnela_ip:
+    type: string
+    description: "The IP address for the CPE end of the inside tunnel interface."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: BGP Customer End IP in Non-Prod
+  nonprod_bgp_oci_tunnela_ip:
+    type: string
+    description: "The IP address for the Oracle end of the inside tunnel interface."
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: BGP Oracle End IP in Non-Prod
+  nonprod_shared_secret:
+    type: string
+    description: "The shared secret (pre-shared key) to use for the IPSec tunnel"
+    required: false
+    default: "example"
+    visible: show_vpn_variables
+    title: IPsec Shared Secret in Non-Prod
+  nonprod_tunnel_b_display_name:
+    type: string
+    description: "Tunnel B display name in Non-prod"
+    required: false
+    default: ""
+    visible: show_vpn_variables
+    title: Tunnel B Display Name in Non-Prod
+  show_fastconnect_variables:
+    type: boolean
+    description: "Show FastConnect related variables"
+    required: false
+    title: Show FastConnect Related Variables
+  fastconnect_provider:
+    type: string
+    description: "Fastconnect provider. Please choose from: AT&T, Azure, Megaport, QTS, CEintro, Cologix, CoreSite, Digitial Realty, EdgeConneX, Epsilon, Equinix, InterCloud, Lumen, Neutrona, OMCS, OracleL2ItegDeployment, OracleL3ItegDeployment, Orange, Verizon, Zayo"
+    required: false
+    visible: show_fastconnect_variables
+    title: FastConnect Provider
+  virtual_circuit_bandwidth_shape:
+    type: string
+    description: "The provisioned data rate of the connection"
+    required: false
+    default: "1500"
+    visible: show_fastconnect_variables
+    title: Virtual Circuit Bandwidth Shape
+  virtual_circuit_display_name:
+    type: string
+    description: "The display name of this virtual circuit. Recommendation: OCI-ELZ-FCN-P-HUB-[REGION] 001"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Virtual Circuit Display Name
+  provider_service_key_name:
+    type: string
+    description: "The provider service key that the provider gives you when you set up a virtual circuit connection from the provider to OCI"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Provider Service Key Name
+  fastconnect_routing_policy:
+    type: array
+    items:
+      type: string
+    description: "Available FastConnect routing policies: ORACLE_SERVICE_NETWORK, REGIONAL, MARKET_LEVEL, GLOBAL"
+    required: false
+    default: []
+    visible: show_fastconnect_variables
+    title: FastConnect Routing Policy
+  virtual_circuit_type:
+    type: string
+    description: "The type of IP addresses used in this virtual circuit. PRIVATE or PUBLIC"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Virtual Circuit Type
+  customer_primary_bgp_peering_ip:
+    type: string
+    description: "The primary BGP IPv4 address of the customer's router"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Customer Primary BGP Peering IP
+  oracle_primary_bgp_peering_ip:
+    type: string
+    description: "The primary BGP IPv4 address of the oracle's router"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Oracle Primary BGP Peering IP
+  customer_secondary_bgp_peering_ip:
+    type: string
+    description: "[Optional] The secondary BGP IPv4 address of the customer's router"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Customer Secondary BGP Peering IP
+  oracle_secondary_bgp_peering_ip:
+    type: string
+    description: "[Optional] The secondary BGP IPv4 address of the oracle's router"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: Oracle Secondary BGP Peering IP
+  virtual_circuit_customer_asn:
+    type: string
+    description: "The BGP ASN of the network at the other end of the BGP session from Oracle"
+    required: false
+    default: "0"
+    visible: show_fastconnect_variables
+    title: Virtual Circuit Customer ASN
+  virtual_circuit_is_bfd_enabled:
+    type: boolean
+    description: "Set to true to enable BFD for IPv4 BGP peering, or set to false to disable BFD"
+    required: false
+    default: false
+    visible: show_fastconnect_variables
+    title: Enable BFD in Virtual Circuit
+  bgp_md5auth_key:
+    type: string
+    description: "The key for BGP MD5 authentication. Only applicable if your system requires MD5 authentication"
+    required: false
+    default: ""
+    visible: show_fastconnect_variables
+    title: BGP Md5Auth Key
+  customer_onprem_ip_cidr:
+    type: array
+    items:
+      type: string
+    description: "Customer Onprem IP CIDR"
+    required: false
+    default: [ ]
+    visible: show_fastconnect_variables
+    title: Customer Onprem IP CIDR
\ No newline at end of file
diff --git a/test/pytest.ini b/test/pytest.ini
index e5e5a28e..d6c18430 100644
--- a/test/pytest.ini
+++ b/test/pytest.ini
@@ -5,3 +5,4 @@ markers =
     integration: integration tests
     tf: terraform
     slow: slow tests
+    expensive: Tests using expensive or difficult to clean up resources 
diff --git a/test/terraform/network/compartment/main.tf b/test/terraform/network/compartment/main.tf
new file mode 100644
index 00000000..61feba76
--- /dev/null
+++ b/test/terraform/network/compartment/main.tf
@@ -0,0 +1,21 @@
+terraform {
+  required_version = ">= 1.0.0"
+
+  required_providers {
+    oci = {
+      source = "oracle/oci"
+    }
+  }
+}
+
+resource "oci_identity_compartment" "compartment" {
+  compartment_id = var.compartment_parent_id
+  description    = var.compartment_description
+  name           = var.compartment_name
+  enable_delete  = var.enable_compartment_delete
+}
+
+resource "time_sleep" "compartment_replication_delay" {
+  depends_on      = [oci_identity_compartment.compartment]
+  create_duration = var.compartment_replication_delay
+}
diff --git a/test/terraform/network/compartment/outputs.tf b/test/terraform/network/compartment/outputs.tf
new file mode 100644
index 00000000..43fd128a
--- /dev/null
+++ b/test/terraform/network/compartment/outputs.tf
@@ -0,0 +1,8 @@
+output "compartment_id" {
+  value       = oci_identity_compartment.compartment.id
+  description = "The OCID of the compartment created"
+  depends_on = [
+    time_sleep.compartment_replication_delay
+  ]
+}
+
diff --git a/test/terraform/network/compartment/variables.tf b/test/terraform/network/compartment/variables.tf
new file mode 100644
index 00000000..02e245d1
--- /dev/null
+++ b/test/terraform/network/compartment/variables.tf
@@ -0,0 +1,26 @@
+variable "compartment_parent_id" {
+  type        = string
+  description = "OCID of the parent compartment."
+}
+
+variable "compartment_name" {
+  type        = string
+  description = "Name of the compartment to create."
+}
+
+variable "compartment_description" {
+  type        = string
+  description = "Description of the compartment to create."
+}
+
+variable "enable_compartment_delete" {
+  type        = bool
+  description = "Allows the compartment to delete on terraform destroy."
+  default = false
+}
+
+variable "compartment_replication_delay" {
+  type         = string
+  description  =  "delay to allow compartments to replicate"
+  default      = "90s"
+}
\ No newline at end of file
diff --git a/test/terraform/network/main.tf b/test/terraform/network/main.tf
index 8cce39b3..043ebe88 100644
--- a/test/terraform/network/main.tf
+++ b/test/terraform/network/main.tf
@@ -1,8 +1,54 @@
 locals {
   availability_domains = data.oci_identity_availability_domains.ad.availability_domains
   test_compartment_ocid = var.compartment_ocid != "" ? var.compartment_ocid : var.tenancy_ocid
+  network_compartment_name = "Test_net_compartment"
+  workload_compartment_name = "Test_wrk_compartment"
 }
 
+# ---------------------------------------------------------------------------------------------------------------------
+# Create compartments
+# ---------------------------------------------------------------------------------------------------------------------
+
+module "environment_compartment" {
+  source = "./compartment"
+
+  compartment_parent_id     = local.test_compartment_ocid
+  compartment_name          = "Test_net_env_compartment"
+  compartment_description   = "Test environment comaprtment for network tests"
+  compartment_replication_delay = var.compartment_replication_delay
+
+  providers = {
+    oci = oci.home_region
+  }
+} 
+
+module "network_compartment" {
+  source = "./compartment"
+
+  compartment_parent_id     = module.environment_compartment.compartment_id
+  compartment_name          = local.network_compartment_name
+  compartment_description   = "Test Network comaprtment for Net tests"
+  compartment_replication_delay = var.compartment_replication_delay
+
+  providers = {
+    oci = oci.home_region
+  }
+}
+
+module "workload_compartment" {
+  source = "./compartment"
+
+  compartment_parent_id     = module.environment_compartment.compartment_id
+  compartment_name          = local.workload_compartment_name
+  compartment_description   = "Test Workload comaprtment for Net tests"
+  compartment_replication_delay = var.compartment_replication_delay
+
+  providers = {
+    oci = oci.home_region
+  }
+}
+
+
 # ---------------------------------------------------------------------------------------------------------------------
 # Call network module to set up hub and spoke network here:
 # ---------------------------------------------------------------------------------------------------------------------
@@ -13,11 +59,12 @@ module "network" {
   tenancy_ocid = var.tenancy_ocid
   region = var.region
   environment_prefix = var.environment_prefix
-  enable_internet_gateway = true
-  enable_nat_gateway = true
-  enable_service_gateway = true
 
-  network_compartment_id = local.test_compartment_ocid
+  enable_internet_gateway_hub = "true"
+  enable_nat_gateway_hub = "true"
+  enable_service_gateway_hub = "true"
+
+  network_compartment_id = module.network_compartment.compartment_id
 
   vcn_cidr_block = var.vcn_cidr_block
   public_subnet_cidr_block = var.public_subnet_cidr_block
@@ -36,6 +83,17 @@ module "network" {
   enable_vpn_on_environment = false
   enable_fastconnect_on_environment = false
   
+  nat_gw_hub_check = [""]
+  service_gw_hub_check = [""]
+  nat_gw_spoke_check = [""]
+  igw_hub_check = [""]
+  service_gw_spoke_check = [""]
+
+
+  workload_compartment_name = local.workload_compartment_name
+  workload_compartment_id = module.workload_compartment.compartment_id
+  network_compartment_name = local.network_compartment_name
+
   providers = {
     oci             = oci
     oci.home_region = oci.home_region
@@ -61,7 +119,7 @@ locals {
 # ---------------------------------------------------------------------------------------------------------------------
 module "bastion" {
   source               = "./test_instance"
-  compartment_ocid     = local.test_compartment_ocid
+  compartment_ocid     = module.workload_compartment.compartment_id
   hostname             = "hub-bastion"
   ssh_public_keys      = join("\n", var.ssh_public_key_list)
   subnet_id            = local.pub_subnet
@@ -77,7 +135,7 @@ module "bastion" {
 module "test_nodes" {
   source               = "./test_instance"
   count                = length(local.priv_subnets)
-  compartment_ocid     = local.test_compartment_ocid
+  compartment_ocid     = module.workload_compartment.compartment_id
 
   hostname             = "spoke-${count.index + 1}-test"
   ssh_public_keys      = join("\n", var.ssh_public_key_list)
diff --git a/test/terraform/network/variables.tf b/test/terraform/network/variables.tf
index 5063fdf2..c71309d4 100644
--- a/test/terraform/network/variables.tf
+++ b/test/terraform/network/variables.tf
@@ -11,6 +11,12 @@ variable "compartment_ocid" {
   default = ""
 }
 
+variable "compartment_replication_delay" {
+  type         = string
+  description  =  "delay to allow compartments to replicate"
+  default      = "90s"
+}
+
 variable "ssh_public_key_list" {
   type        = list(string)
   description = "The list of ssh public keys"
diff --git a/test/test_security_vault.py b/test/test_security_vault.py
index 0a8e666b..12454e33 100644
--- a/test/test_security_vault.py
+++ b/test/test_security_vault.py
@@ -8,6 +8,7 @@
 #unit tests for vault/key portion of the security module
 @pytest.mark.skip(reason="Skipped until we can better deal with vault cleanup. ")
 @pytest.mark.unit
+@pytest.mark.expensive
 @terraform("security_vault", scope="session")
 def test_master_encryption_key_created(security_vault):
     conf = get_test_config()