diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 7a55b53..914786c 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,9 @@ +# December 04, 2024 Release Notes - 0.1.8 +## Updates in [Compute module](./cis-compute-storage/) +1. Support for ZPR (Zero Trust Packet Routing) attributes on Compute instances and secondary VNICs. See *zpr_attributes* attribute in [Compute module documentation](./cis-compute-storage/README.md#compute-1) for details. +2. Disabled precondition check on platform images supported shapes when the platform image OCID is provided as the Compute image source. + + # October 14, 2024 Release Notes - 0.1.7 ## Updates in [Compute module](./cis-compute-storage/) 1. Marketplace images, platform images and custom images split for clarity in module interface. @@ -5,11 +11,13 @@ 3. Marketplace images configured with automatic Marketplace agreements. 4. Module now validates whether provided shape is compatible with provided marketplace or platform image. + # August 28, 2024 Release Notes - 0.1.6 ## Updates 1. All modules now require Terraform binary equal or greater than 1.3.0. 2. *cislz-terraform-module* tag renamed to *ocilz-terraform-module*. + # July 25, 2024 Release Notes - 0.1.5 ## Updates 1. Aligned README.md structure to Oracle's GitHub organizations requirements. diff --git a/cis-compute-storage/README.md b/cis-compute-storage/README.md index e14da46..2634e1f 100644 --- a/cis-compute-storage/README.md +++ b/cis-compute-storage/README.md @@ -161,7 +161,7 @@ The CIS Benchmark profile levels drive some aspects of Compute and Storage. In t ##### CIS profile level "2": - encryption at rest with customer managed keys is enforced. -### Compute +### Compute Compute instances are managed using the **instances_configuration** variable. It contains a set of attributes starting with the prefix **default_** and one attribute named **instances**. The **default_** attribute values are applied to all instances within **instances**, unless overridden at the instance level. @@ -232,12 +232,25 @@ The instances themselves are defined within the **instances** attribute, In Terr - **network_security_groups** – (Optional) List of network security groups the VNIC should be placed into. - **skip_source_dest_check** – (Optional) Whether the source/destination check is disabled on the VNIC. If true, the VNIC is able to forward the packet. Default is false. - **nic_index** – (Optional) The physical network interface card (NIC) the VNIC will use. Defaults to 0. Certain bare metal instance shapes have two active physical NICs (0 and 1). + - **security** – (Optional) Security settings for the VNIC, currently only for ZPR (Zero Trust Packet Routing) attributes. + - **zpr_attributes** – (Optional) List of objects representing ZPR attributes. + - **namespace** – (Optional) ZPR namespace. Default is *oracle-zpr*, a default namespace created by Oracle and available in all tenancies. + - **attr_name** – ZPR attribute name. It must exist in the specified namespace. + - **attr_value** – ZPR attribute value. + - **mode** – (Optional) ZPR mode. Default value is *enforce*. - **secondary_ips** – (Optional) Map of secondary private IP addresses for the VNIC. - **display_name** – (Optional) Secondary IP display name. - **hostname** – (Optional) Secondary IP host name. - **private_ip** – (Optional) Secondary IP address. If not provided, an IP address from the subnet is randomly chosen. - **defined_tags** – (Optional) Secondary IP defined_tags. default_defined_tags is used if undefined. - **freeform_tags** – (Optional) Secondary IP freeform_tags. default_freeform_tags is used if undefined. +- **security** – (Optional) Security settings for the instance, currently only for ZPR (Zero Trust Packet Routing) attributes. + - **apply_to_primary_vnic_only** – (Optional) Whether ZPR attributes are applied to the instance primary VNIC only. The default value is false, meaning ZPR attributes are applied to the instance itself (a.k.a. parent resource),thus inherited by all VNICs that are attached to the instance. Set this value to true to stop the inheritance, thus making ZPR attributes applied to the instance primary VNIC only. + - **zpr_attributes** – (Optional) List of objects representing ZPR attributes. + - **namespace** – (Optional) ZPR namespace. Default is *oracle-zpr*, a default namespace created by Oracle and available in all tenancies. + - **attr_name** – ZPR attribute name. It must exist in the specified namespace. + - **attr_value** – ZPR attribute value. + - **mode** – (Optional) ZPR mode. Default value is *enforce*. - **encryption** – (Optional) Encryption settings. See section [In Transit Encryption](#in-transit-encryption) for important information. - **kms_key_id** – (Optional) The encryption key for boot volume encryption. *default_kms_key_id* is used if undefined. Required if *cis_level* or *default_cis_level* is "2". - **encrypt_in_transit_on_instance_create** – (Optional) Whether to enable in-transit encryption for the data volume's paravirtualized attachment. Default is false. Applicable during instance **creation** time only. Note that some platform images do not allow instances overriding the image configuration for in-transit encryption at instance creation time. In such cases, for enabling in-transit encryption, use *encrypt_in_transit_on_instance_update* attribute. First run ```terraform apply``` with it set to false, then run ```terraform apply``` again with it set to true. @@ -342,7 +355,7 @@ The defined **default_** attributes are the following: - **default_defined_tags** – (Optional) The default defined tags for all storage units. It can be overridden by *defined_tags* attribute in each unit. - **default_freeform_tags** – (Optional) the default freeform tags for all storage units. It can be overridden by *freeform_tags* attribute in each unit. -#### Block Volumes +#### Block Volumes Block volumes are defined using the optional **block_volumes** attribute. In Terraform terms, it is a map of objects, where each object is referred by an identifying key. The following attributes are supported: - **compartment_id** – (Optional) The volume compartment. The *default_compartment_id* is used if undefined. This attribute is overloaded. It can be assigned either a literal OCID or a reference (a key) to an OCID in *compartments_dependency* variable. See [External Dependencies](#ext-dep) for details. - **cis_level** – (Optional) The CIS OCI Benchmark profile level to apply. The *default_cis_level* is used if undefined. @@ -562,7 +575,7 @@ sdb 8:16 0 60G 0 disk For more information on mounting block volumes without consistent device path see [Traditional fstab Options](https://docs.oracle.com/en-us/iaas/Content/Block/References/fstaboptions.htm#Traditional_fstab_Options). -#### File Storage +#### File Storage The **file_storage** attribute defines the file systems, mount targets and snapshot policies for OCI File Storage service. The optional attribute **default_subnet_id** applies to all mount targets, unless overridden by **subnet_id** attribute in each mount target. Attribute **subnet_id** is overloaded. It can be assigned either a literal OCID or a reference (a key) to an OCID in *network_dependency* variable. See [External Dependencies](#ext-dep) for details. ##### File Systems diff --git a/cis-compute-storage/SPEC.md b/cis-compute-storage/SPEC.md index 388a6ab..ae9fa61 100644 --- a/cis-compute-storage/SPEC.md +++ b/cis-compute-storage/SPEC.md @@ -74,7 +74,7 @@ No modules. | [compartments\_dependency](#input\_compartments\_dependency) | A map of objects containing the externally managed compartments this module may depend on. All map objects must have the same type and must contain at least an 'id' attribute (representing the compartment OCID) of string type. |
map(object({| `null` | no | | [enable\_output](#input\_enable\_output) | Whether Terraform should enable the module output. | `bool` | `true` | no | | [file\_system\_dependency](#input\_file\_system\_dependency) | A map of objects containing the externally managed file storage resources this module may depend on. This is used when setting file system replication using target file systems managed in another Terraform configuration. All map objects must have the same type and must contain at least an 'id' attribute (representing the file system OCID) of string type. |
id = string # the compartment OCID
}))
map(object({| `null` | no | -| [instances\_configuration](#input\_instances\_configuration) | Compute instances configuration attributes. |
id = string # the file system OCID.
}))
object({| `null` | no | +| [instances\_configuration](#input\_instances\_configuration) | Compute instances configuration attributes. |
default_compartment_id = string, # the default compartment where all resources are defined. It's overriden by the compartment_ocid attribute within each object.
default_subnet_id = optional(string), # the default subnet where all Compute instances are defined. It's overriden by the subnet_id attribute within each Compute instance.
default_ssh_public_key_path = optional(string), # the default ssh public key path used to access the Compute instance. It's overriden by the ssh_public_key attribute within each Compute instance.
default_kms_key_id = optional(string), # the default KMS key to assign as the master encryption key. It's overriden by the kms_key_id attribute within each object.
default_cis_level = optional(string) # the CIS OCI Benchmark profile level. Level "1" is be practical and prudent. Level "2" is intended for environments where security is more critical than manageability and usability. Default is "1".
default_defined_tags = optional(map(string)), # the default defined tags. It's overriden by the defined_tags attribute within each object.
default_freeform_tags = optional(map(string)), # the default freeform tags. It's overriden by the freeform_tags attribute within each object.
default_cloud_init_heredoc_script = optional(string), # the default cloud-init script in Terraform heredoc style that is applied to all instances. It has precedence over default_cloud_init_script_file.
default_cloud_init_script_file = optional(string), # the default cloud-init script file that is applied to all instances.
instances = map(object({ # the instances to manage in this configuration.
cis_level = optional(string)
compartment_id = optional(string) # the compartment where the instance is created. default_compartment_ocid is used if this is not defined.
shape = string # the instance shape.
name = string # the instance display name.
platform_type = optional(string) # the platform type. Assigning this variable enables various platform security features in the Compute service. Valid values: "AMD_MILAN_BM", "AMD_MILAN_BM_GPU", "AMD_ROME_BM", "AMD_ROME_BM_GPU", "AMD_VM", "GENERIC_BM", "INTEL_ICELAKE_BM", "INTEL_SKYLAKE_BM", "INTEL_VM".
cluster_id = optional(string) # the Compute cluster the instance is added to. It can take either a literal cluster OCID or cluster key defined in the clusters_configuration variable.
marketplace_image = optional(object({ # the marketplace image. You must provider the name, and optionally the version. If version is not provided, the latest available version is used.
name = string # the marketplace image name.
version = optional(string) # the marketplace image version.
}))
platform_image = optional(object({ # the platform image. You must provider the name and assign the tenancy_ocid variable.
ocid = optional(string) # the platform image ocid. It takes precedence over name.
name = optional(string) # the platform image name.
}))
custom_image = optional(object({ # the custom image. You must provider either the ocid or name and compartment_id.
ocid = optional(string) # the custom image ocid. It takes precedence over name.
name = optional(string) # the custom image name.
compartment_id = optional(string) # the custom image compartment. Required if name is used.
}))
placement = optional(object({ # placement settings
availability_domain = optional(number,1) # the instance availability domain. Default is 1.
fault_domain = optional(number,1) # the instance fault domain. Default is 1.
}))
boot_volume = optional(object({ # boot volume settings
type = optional(string,"paravirtualized") # boot volume emulation type. Valid values: "paravirtualized" (default for platform images), "scsi", "iscsi", "ide", "vfio".
firmware = optional(string) # firmware used to boot the VM. Valid options: "BIOS" (compatible with both 32 bit and 64 bit operating systems that boot using MBR style bootloaders), "UEFI_64" (default for platform images).
size = optional(number,50) # boot volume size. Default is 50GB (minimum allowed by OCI).
preserve_on_instance_deletion = optional(bool,true) # whether to preserve boot volume after deletion. Default is true.
secure_boot = optional(bool, false) # prevents unauthorized boot loaders and operating systems from booting.
measured_boot = optional(bool, false) # enhances boot security by taking and storing measurements of boot components, such as bootloaders, drivers, and operating systems. Bare metal instances do not support Measured Boot.
trusted_platform_module = optional(bool, false) # used to securely store boot measurements.
backup_policy = optional(string,"bronze") # the Oracle managed backup policy. Valid values: "gold", "silver", "bronze". Default is "bronze".
}))
volumes_emulation_type = optional(string,"paravirtualized") # Emulation type for attached storage volumes. Valid values: "paravirtualized" (default for platform images), "scsi", "iscsi", "ide", "vfio". Module supported values for automated attachment: "paravirtualized", "iscsi".
networking = optional(object({ # networking settings
type = optional(string,"paravirtualized") # emulation type for the physical network interface card (NIC). Valid values: "paravirtualized" (default), "e1000", "vfio".
private_ip = optional(string) # a private IP address of your choice to assign to the primary VNIC.
hostname = optional(string) # the primary VNIC hostname.
assign_public_ip = optional(bool) # whether to assign the primary VNIC a public IP. Defaults to whether the subnet is public or private.
subnet_id = optional(string) # the subnet where the primary VNIC is created. default_subnet_id is used if this is not defined.
network_security_groups = optional(list(string)) # list of network security groups the primary VNIC should be placed into.
skip_source_dest_check = optional(bool,false) # whether the source/destination check is disabled on the primary VNIC. Default is false.
secondary_ips = optional(map(object({ # list of secondary private IP addresses for the primary VNIC.
display_name = optional(string) # Secondary IP display name.
hostname = optional(string) # Secondary IP host name.
private_ip = optional(string) # Secondary IP address. If not provided, an IP address from the subnet is randomly chosen.
defined_tags = optional(map(string)) # Secondary IP defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # Secondary IP freeform_tags. default_freeform_tags is used if this is not defined.
})))
secondary_vnics = optional(map(object({
display_name = optional(string) # the VNIC display name.
private_ip = optional(string) # a private IP address of your choice to assign to the VNIC.
hostname = optional(string) # the VNIC hostname.
assign_public_ip = optional(bool) # whether to assign the VNIC a public IP. Defaults to whether the subnet is public or private.
subnet_id = optional(string) # the subnet where the VNIC is created. default_subnet_id is used if this is not defined.
network_security_groups = optional(list(string)) # list of network security groups the VNIC should be placed into.
skip_source_dest_check = optional(bool,false) # whether the source/destination check is disabled on the VNIC. Default is false.
nic_index = optional(number,0) # the physical network interface card (NIC) the VNIC will use. Defaults to 0. Certain bare metal instance shapes have two active physical NICs (0 and 1).
secondary_ips = optional(map(object({ # list of secondary private IP addresses for the VNIC.
display_name = optional(string) # Secondary IP display name.
hostname = optional(string) # Secondary IP host name.
private_ip = optional(string) # Secondary IP address. If not provided, an IP address from the subnet is randomly chosen.
defined_tags = optional(map(string)) # Secondary IP defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # Secondary IP freeform_tags. default_freeform_tags is used if this is not defined.
})))
defined_tags = optional(map(string)) # VNIC defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # VNIC freeform_tags. default_freeform_tags is used if this is not defined.
})))
}))
encryption = optional(object({ # encryption settings
kms_key_id = optional(string) # the KMS key to assign as the master encryption key. default_kms_key_id is used if this is not defined.
encrypt_in_transit_on_instance_create = optional(bool,null) # whether to enable in-transit encryption for the instance. Default is set by the underlying image. Applicable at instance creation time only.
encrypt_in_transit_on_instance_update = optional(bool,null) # whether to enable in-transit encryption for the instance. Default is set by the underlying image. Applicable at instance update time only.
encrypt_data_in_use = optional(bool, false) # whether the instance encrypts data in-use (in memory) while being processed. A.k.a confidential computing.
}))
flex_shape_settings = optional(object({ # flex shape settings
memory = optional(number,16) # the instance memory for Flex shapes. Default is 16GB.
ocpus = optional(number,1) # the instance ocpus number for Flex shapes. Default is 1.
}))
cloud_agent = optional(object({ # Cloud Agent settings
disable_management = optional(bool,false) # whether the management plugins should be disabled. These plugins are enabled by default in the Compute service.
disable_monitoring = optional(bool,false) # whether the monitoring plugins should be disabled. These plugins are enabled by default in the Compute service.
plugins = optional(list(object({ # list of plugins
name = string # the plugin name. It must be a valid plugin name. The plugin names are available in https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/manage-plugins.htm and in compute-only example(./examples/compute-only/input.auto.tfvars.template) as well.
enabled = bool #Whether or not the plugin should be enabled. In order to disable a previously enabled plugin, set this value to false. Simply removing the plugin from the list will not disable it.
})))
}))
cloud_init = optional(object({
heredoc_script = optional(string) # the cloud-init script in Terraform heredoc style that is applied to the instance. It has precedence over script_file.
script_file = optional(string) # the cloud-init script file that is applied to the instance.
}))
ssh_public_key_path = optional(string) # the SSH public key path used to access the instance.
defined_tags = optional(map(string)) # instances defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # instances freeform_tags. default_freeform_tags is used if this is not defined.
}))
})
object({| `null` | no | | [instances\_dependency](#input\_instances\_dependency) | A map of objects containing the externally managed Compute instances this module may depend on. The objects, when defined, must contain at least an 'id' attribute (representing the instance OCID) of string type. |
default_compartment_id = string, # the default compartment where all resources are defined. It's overriden by the compartment_ocid attribute within each object.
default_subnet_id = optional(string), # the default subnet where all Compute instances are defined. It's overriden by the subnet_id attribute within each Compute instance.
default_ssh_public_key_path = optional(string), # the default ssh public key path used to access the Compute instance. It's overriden by the ssh_public_key attribute within each Compute instance.
default_kms_key_id = optional(string), # the default KMS key to assign as the master encryption key. It's overriden by the kms_key_id attribute within each object.
default_cis_level = optional(string) # the CIS OCI Benchmark profile level. Level "1" is be practical and prudent. Level "2" is intended for environments where security is more critical than manageability and usability. Default is "1".
default_defined_tags = optional(map(string)), # the default defined tags. It's overriden by the defined_tags attribute within each object.
default_freeform_tags = optional(map(string)), # the default freeform tags. It's overriden by the freeform_tags attribute within each object.
default_cloud_init_heredoc_script = optional(string), # the default cloud-init script in Terraform heredoc style that is applied to all instances. It has precedence over default_cloud_init_script_file.
default_cloud_init_script_file = optional(string), # the default cloud-init script file that is applied to all instances.
instances = map(object({ # the instances to manage in this configuration.
cis_level = optional(string)
compartment_id = optional(string) # the compartment where the instance is created. default_compartment_ocid is used if this is not defined.
shape = string # the instance shape.
name = string # the instance display name.
platform_type = optional(string) # the platform type. Assigning this variable enables various platform security features in the Compute service. Valid values: "AMD_MILAN_BM", "AMD_MILAN_BM_GPU", "AMD_ROME_BM", "AMD_ROME_BM_GPU", "AMD_VM", "GENERIC_BM", "INTEL_ICELAKE_BM", "INTEL_SKYLAKE_BM", "INTEL_VM".
cluster_id = optional(string) # the Compute cluster the instance is added to. It can take either a literal cluster OCID or cluster key defined in the clusters_configuration variable.
marketplace_image = optional(object({ # the marketplace image. You must provider the name, and optionally the version. If version is not provided, the latest available version is used.
name = string # the marketplace image name.
version = optional(string) # the marketplace image version.
}))
platform_image = optional(object({ # the platform image. You must provider the name and assign the tenancy_ocid variable.
ocid = optional(string) # the platform image ocid. It takes precedence over name.
name = optional(string) # the platform image name.
}))
custom_image = optional(object({ # the custom image. You must provider either the ocid or name and compartment_id.
ocid = optional(string) # the custom image ocid. It takes precedence over name.
name = optional(string) # the custom image name.
compartment_id = optional(string) # the custom image compartment. Required if name is used.
}))
placement = optional(object({ # placement settings
availability_domain = optional(number,1) # the instance availability domain. Default is 1.
fault_domain = optional(number,1) # the instance fault domain. Default is 1.
}))
boot_volume = optional(object({ # boot volume settings
type = optional(string,"paravirtualized") # boot volume emulation type. Valid values: "paravirtualized" (default for platform images), "scsi", "iscsi", "ide", "vfio".
firmware = optional(string) # firmware used to boot the VM. Valid options: "BIOS" (compatible with both 32 bit and 64 bit operating systems that boot using MBR style bootloaders), "UEFI_64" (default for platform images).
size = optional(number,50) # boot volume size. Default is 50GB (minimum allowed by OCI).
preserve_on_instance_deletion = optional(bool,true) # whether to preserve boot volume after deletion. Default is true.
secure_boot = optional(bool, false) # prevents unauthorized boot loaders and operating systems from booting.
measured_boot = optional(bool, false) # enhances boot security by taking and storing measurements of boot components, such as bootloaders, drivers, and operating systems. Bare metal instances do not support Measured Boot.
trusted_platform_module = optional(bool, false) # used to securely store boot measurements.
backup_policy = optional(string,"bronze") # the Oracle managed backup policy. Valid values: "gold", "silver", "bronze". Default is "bronze".
}))
volumes_emulation_type = optional(string,"paravirtualized") # Emulation type for attached storage volumes. Valid values: "paravirtualized" (default for platform images), "scsi", "iscsi", "ide", "vfio". Module supported values for automated attachment: "paravirtualized", "iscsi".
networking = optional(object({ # networking settings
type = optional(string,"paravirtualized") # emulation type for the physical network interface card (NIC). Valid values: "paravirtualized" (default), "e1000", "vfio".
private_ip = optional(string) # a private IP address of your choice to assign to the primary VNIC.
hostname = optional(string) # the primary VNIC hostname.
assign_public_ip = optional(bool) # whether to assign the primary VNIC a public IP. Defaults to whether the subnet is public or private.
subnet_id = optional(string) # the subnet where the primary VNIC is created. default_subnet_id is used if this is not defined.
network_security_groups = optional(list(string)) # list of network security groups the primary VNIC should be placed into.
skip_source_dest_check = optional(bool,false) # whether the source/destination check is disabled on the primary VNIC. Default is false.
secondary_ips = optional(map(object({ # list of secondary private IP addresses for the primary VNIC.
display_name = optional(string) # Secondary IP display name.
hostname = optional(string) # Secondary IP host name.
private_ip = optional(string) # Secondary IP address. If not provided, an IP address from the subnet is randomly chosen.
defined_tags = optional(map(string)) # Secondary IP defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # Secondary IP freeform_tags. default_freeform_tags is used if this is not defined.
})))
secondary_vnics = optional(map(object({
display_name = optional(string) # the VNIC display name.
private_ip = optional(string) # a private IP address of your choice to assign to the VNIC.
hostname = optional(string) # the VNIC hostname.
assign_public_ip = optional(bool) # whether to assign the VNIC a public IP. Defaults to whether the subnet is public or private.
subnet_id = optional(string) # the subnet where the VNIC is created. default_subnet_id is used if this is not defined.
network_security_groups = optional(list(string)) # list of network security groups the VNIC should be placed into.
skip_source_dest_check = optional(bool,false) # whether the source/destination check is disabled on the VNIC. Default is false.
nic_index = optional(number,0) # the physical network interface card (NIC) the VNIC will use. Defaults to 0. Certain bare metal instance shapes have two active physical NICs (0 and 1).
secondary_ips = optional(map(object({ # list of secondary private IP addresses for the VNIC.
display_name = optional(string) # Secondary IP display name.
hostname = optional(string) # Secondary IP host name.
private_ip = optional(string) # Secondary IP address. If not provided, an IP address from the subnet is randomly chosen.
defined_tags = optional(map(string)) # Secondary IP defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # Secondary IP freeform_tags. default_freeform_tags is used if this is not defined.
})))
security = optional(object({
zpr_attributes = optional(list(object({
namespace = optional(string,"oracle-zpr")
attr_name = string
attr_value = string
mode = optional(string,"enforce")
})))
}))
defined_tags = optional(map(string)) # VNIC defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # VNIC freeform_tags. default_freeform_tags is used if this is not defined.
})))
}))
security = optional(object({
apply_to_primary_vnic_only = optional(bool, false)
zpr_attributes = optional(list(object({
namespace = optional(string,"oracle-zpr")
attr_name = string
attr_value = string
mode = optional(string,"enforce")
})))
}))
encryption = optional(object({ # encryption settings
kms_key_id = optional(string) # the KMS key to assign as the master encryption key. default_kms_key_id is used if this is not defined.
encrypt_in_transit_on_instance_create = optional(bool,null) # whether to enable in-transit encryption for the instance. Default is set by the underlying image. Applicable at instance creation time only.
encrypt_in_transit_on_instance_update = optional(bool,null) # whether to enable in-transit encryption for the instance. Default is set by the underlying image. Applicable at instance update time only.
encrypt_data_in_use = optional(bool, false) # whether the instance encrypts data in-use (in memory) while being processed. A.k.a confidential computing.
}))
flex_shape_settings = optional(object({ # flex shape settings
memory = optional(number,16) # the instance memory for Flex shapes. Default is 16GB.
ocpus = optional(number,1) # the instance ocpus number for Flex shapes. Default is 1.
}))
cloud_agent = optional(object({ # Cloud Agent settings
disable_management = optional(bool,false) # whether the management plugins should be disabled. These plugins are enabled by default in the Compute service.
disable_monitoring = optional(bool,false) # whether the monitoring plugins should be disabled. These plugins are enabled by default in the Compute service.
plugins = optional(list(object({ # list of plugins
name = string # the plugin name. It must be a valid plugin name. The plugin names are available in https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/manage-plugins.htm and in compute-only example(./examples/compute-only/input.auto.tfvars.template) as well.
enabled = bool #Whether or not the plugin should be enabled. In order to disable a previously enabled plugin, set this value to false. Simply removing the plugin from the list will not disable it.
})))
}))
cloud_init = optional(object({
heredoc_script = optional(string) # the cloud-init script in Terraform heredoc style that is applied to the instance. It has precedence over script_file.
script_file = optional(string) # the cloud-init script file that is applied to the instance.
}))
ssh_public_key_path = optional(string) # the SSH public key path used to access the instance.
defined_tags = optional(map(string)) # instances defined_tags. default_defined_tags is used if this is not defined.
freeform_tags = optional(map(string)) # instances freeform_tags. default_freeform_tags is used if this is not defined.
}))
})
map(object({| `null` | no | | [kms\_dependency](#input\_kms\_dependency) | A map of objects containing the externally managed encryption keys this module may depend on. All map objects must have the same type and must contain at least an 'id' attribute (representing the key OCID) of string type. |
id = string # the instance OCID
}))
map(object({| `null` | no | | [module\_name](#input\_module\_name) | The module name. | `string` | `"cis-compute-storage"` | no | diff --git a/cis-compute-storage/compute.tf b/cis-compute-storage/compute.tf index c51eaaa..5cdd9ea 100644 --- a/cis-compute-storage/compute.tf +++ b/cis-compute-storage/compute.tf @@ -103,6 +103,9 @@ locals { custom_images_by_name = { for i in local.custom_images : "${i.key}.${i.display_name}" => {id = i.id, operating_system = i.operating_system }} platform_types = ["AMD_MILAN_BM", "AMD_MILAN_BM_GPU", "AMD_ROME_BM", "AMD_ROME_BM_GPU", "AMD_VM", "GENERIC_BM", "INTEL_ICELAKE_BM", "INTEL_SKYLAKE_BM", "INTEL_VM"] + + zpr_provided_attributes = {for k, v in (var.instances_configuration != null ? var.instances_configuration["instances"] : {}) : k => [for a in v.security.zpr_attributes : "${a.namespace}.${a.attr_name}"] if try(v.security.zpr_attributes,null) != null} + } resource "oci_core_instance" "these" { @@ -158,11 +161,11 @@ resource "oci_core_instance" "these" { condition = try(each.value.marketplace_image.name,null) != null ? contains(data.oci_core_app_catalog_listing_resource_version.this[each.key].compatible_shapes,each.value.shape) : true error_message = try(each.value.marketplace_image.name,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\": invalid image shape \"${each.value.shape}\" in \"shape\" attribute. Ensure it is spelled correctly. Valid shapes for marketplace image \"${each.value.marketplace_image.name}\" version \"${coalesce(each.value.marketplace_image.version,replace(data.oci_marketplace_listing.this[each.key].default_package_version," ","_"))}\" are: ${join(", ",[for v in data.oci_core_app_catalog_listing_resource_version.this[each.key].compatible_shapes : "\"${v}\""])}." : "__void__" } - # Check 11: Check compatible shapes for given platform image ocid - precondition { - condition = try(each.value.platform_image.ocid,null) != null ? contains(local.platform_images_by_id[each.value.platform_image.ocid].shapes,each.value.shape) : true - error_message = try(each.value.platform_image.ocid,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\": invalid image shape \"${each.value.shape}\" in \"shape\" attribute. Ensure it is spelled correctly. Valid shapes for platform image \"${try(each.value.platform_image.ocid,"")}\" are: ${join(", ",[for v in local.platform_images_by_id[each.value.platform_image.ocid].shapes : "\"${v}\""])}." : "__void__" - } + # Check 11: Check compatible shapes for given platform image ocid - DISABLED because it uses oci_core_images data source that limits images to the latest three per platform. + # precondition { + # condition = try(each.value.platform_image.ocid,null) != null ? contains(local.platform_images_by_id[each.value.platform_image.ocid].shapes,each.value.shape) : true + # error_message = try(each.value.platform_image.ocid,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\": invalid image shape \"${each.value.shape}\" in \"shape\" attribute. Ensure it is spelled correctly. Valid shapes for platform image \"${try(each.value.platform_image.ocid,"")}\" are: ${join(", ",[for v in local.platform_images_by_id[each.value.platform_image.ocid].shapes : "\"${v}\""])}." : "__void__" + # } # Check 12: Check compatible shapes for given platform image name precondition { condition = try(each.value.platform_image.name,null) != null ? contains(local.platform_images_by_name[each.value.platform_image.name].shapes,each.value.shape) : true @@ -178,11 +181,18 @@ resource "oci_core_instance" "these" { # condition = try(each.value.platform_image.name,null) != null && length(regexall("FLEX",upper(each.value.shape))) > 0 && each.value.flex_shape_settings != null ? local.platform_images_by_name[each.value.platform_image.name].min_ocpu <= try(each.value.flex_shape_settings.ocpus,0) && local.platform_images_by_name[each.value.platform_image.name].max_ocpu >= try(each.value.flex_shape_settings.ocpus,0) : true # error_message = try(each.value.platform_image.name,null) != null && length(regexall("FLEX",upper(each.value.shape))) > 0 && each.value.flex_shape_settings != null ? "VALIDATION FAILURE in instance \"${each.key}\": invalid ocpu setting \"${each.value.flex_shape_settings.ocpus}\" in \"flexible_shape_settings.ocpu\" attribute for \"${try(each.value.platform_image.name,"")}\". Number of ocpus range from \"${try(local.platform_images_by_name[each.value.platform_image.name].min_ocpu,"")}\" to \"${try(local.platform_images_by_name[each.value.platform_image.name].max_ocpu,"")}\"." : "__void__" # } + # Check 15: Check ZPR attributes dupes + precondition { + condition = try(each.value.security.zpr_attributes,null) != null ? length(distinct([for a in each.value.security.zpr_attributes : "${a.namespace}.${a.attr_name}"])) == length([for a in each.value.security.zpr_attributes : "${a.namespace}.${a.attr_name}"]): true + error_message = try(each.value.security.zpr_attributes,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\" for \"security.zpr-attributes\" attribute: ZPR attribute assigned more than once. \"namespace/attr_name\" pairs must be unique." : "__void__" + #error_message = try(each.value.security.zpr_attributes,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\" for \"security.zpr-attributes\" attribute: ZPR attribute assigned more than once. ${[for a in each.value.security.zpr_attributes : "${a.namespace}.${a.attr_name}" if contains(local.zpr_provided_attributes[each.key],) ]} \"namespace/attr_name\" pairs must be unique." : "__void__" + } } compartment_id = each.value.compartment_id != null ? (length(regexall("^ocid1.*$", each.value.compartment_id)) > 0 ? each.value.compartment_id : var.compartments_dependency[each.value.compartment_id].id) : (length(regexall("^ocid1.*$", var.instances_configuration.default_compartment_id)) > 0 ? var.instances_configuration.default_compartment_id : var.compartments_dependency[var.instances_configuration.default_compartment_id].id) availability_domain = data.oci_identity_availability_domains.ads[each.key].availability_domains[(each.value.placement != null ? each.value.placement.availability_domain : 1) - 1].name fault_domain = format("FAULT-DOMAIN-%s", each.value.placement != null ? each.value.placement.fault_domain : 1) shape = each.value.shape + security_attributes = try(each.value.security.zpr_attributes,null) != null ? try(each.value.security.apply_to_primary_vnic_only,false) == false ? merge([for a in each.value.security.zpr_attributes : {"${a.namespace}.${a.attr_name}.value" : a.attr_value, "${a.namespace}.${a.attr_name}.mode" : a.mode}]...) : null : null display_name = each.value.name preserve_boot_volume = each.value.boot_volume != null ? each.value.boot_volume.preserve_on_instance_deletion : true defined_tags = each.value.defined_tags != null ? each.value.defined_tags : var.instances_configuration.default_defined_tags @@ -196,6 +206,7 @@ resource "oci_core_instance" "these" { hostname_label = each.value.networking != null ? (coalesce(each.value.networking.hostname,lower(replace(each.value.name," ","")))) : lower(replace(each.value.name," ","")) nsg_ids = each.value.networking != null ? [for nsg in coalesce(each.value.networking.network_security_groups,[]) : (length(regexall("^ocid1.*$", nsg)) > 0 ? nsg : var.network_dependency["network_security_groups"][nsg].id)] : null skip_source_dest_check = each.value.networking != null ? each.value.networking.skip_source_dest_check : false + security_attributes = try(each.value.security.zpr_attributes,null) != null ? try(each.value.security.apply_to_primary_vnic_only,false) == true ? merge([for a in each.value.security.zpr_attributes : {"${a.namespace}.${a.attr_name}.value" : a.attr_value, "${a.namespace}.${a.attr_name}.mode" : a.mode}]...) : null : null } source_details { boot_volume_size_in_gbs = each.value.boot_volume != null ? each.value.boot_volume.size : 50 @@ -298,6 +309,7 @@ locals { network_security_groups = vnic_value.network_security_groups skip_source_dest_check = vnic_value.skip_source_dest_check nic_index = vnic_value.nic_index + security = vnic_value.security defined_tags = vnic_value.defined_tags freeform_tags = vnic_value.freeform_tags } @@ -345,9 +357,17 @@ resource "oci_core_vnic_attachment" "these" { network_security_groups = v.network_security_groups skip_source_dest_check = v.skip_source_dest_check nic_index = v.nic_index + security = v.security defined_tags = v.defined_tags freeform_tags = v.freeform_tags } } + # Check 1: Check ZPR attributes dupes + lifecycle { + precondition { + condition = try(each.value.security.zpr_attributes,null) != null ? length(toset([for a in each.value.security.zpr_attributes : "${a.namespace}.${a.attr_name}"])) == length([for a in each.value.security.zpr_attributes : "${a.namespace}.${a.attr_name}"]): true + error_message = try(each.value.security.zpr_attributes,null) != null ? "VALIDATION FAILURE in instance \"${each.key}\": ZPR security attribute assigned more than once. \"security.zpr-attributes.namespace/security.zpr-attributes.attr_name\" pairs must be unique." : "__void__" + } + } display_name = each.value.display_name instance_id = oci_core_instance.these[each.value.inst_key].id nic_index = each.value.nic_index @@ -359,8 +379,9 @@ resource "oci_core_vnic_attachment" "these" { subnet_id = each.value.subnet_id != null ? (length(regexall("^ocid1.*$", each.value.subnet_id)) > 0 ? each.value.subnet_id : var.network_dependency["subnets"][each.value.subnet_id].id) : (length(regexall("^ocid1.*$", var.instances_configuration.default_subnet_id)) > 0 ? var.instances_configuration.default_subnet_id : var.network_dependency["subnets"][var.instances_configuration.default_subnet_id].id) nsg_ids = [for nsg in coalesce(each.value.network_security_groups,[]) : (length(regexall("^ocid1.*$", nsg)) > 0 ? nsg : var.network_dependency["network_security_groups"][nsg].id)] skip_source_dest_check = each.value.skip_source_dest_check - defined_tags = each.value.defined_tags != null ? each.value.defined_tags : var.instances_configuration.default_defined_tags - freeform_tags = merge(local.cislz_module_tag, each.value.freeform_tags != null ? each.value.freeform_tags : var.instances_configuration.default_freeform_tags) + security_attributes = try(each.value.security.zpr_attributes,null) != null ? merge([for a in each.value.security.zpr_attributes : {"${a.namespace}.${a.attr_name}.value" : a.attr_value, "${a.namespace}.${a.attr_name}.mode" : a.mode}]...) : null + defined_tags = each.value.defined_tags != null ? each.value.defined_tags : var.instances_configuration.default_defined_tags + freeform_tags = merge(local.cislz_module_tag, each.value.freeform_tags != null ? each.value.freeform_tags : var.instances_configuration.default_freeform_tags) } } diff --git a/cis-compute-storage/examples/compute-only-multiple-vnics/README.md b/cis-compute-storage/examples/compute-only-multiple-vnics/README.md index ed99ae6..ad1e18f 100644 --- a/cis-compute-storage/examples/compute-only-multiple-vnics/README.md +++ b/cis-compute-storage/examples/compute-only-multiple-vnics/README.md @@ -12,6 +12,7 @@ This example shows how to deploy Compute instances in OCI using the [OCI Landing - The instance boot volume is encrypted with a customer managed key referred by *encryption.kms_key_id* attribute. - The instance boot volume is set to be backed up per Oracle-managed *bronze* backup policy (enforced by the module by default). - The instance primary VNIC is assigned a primary IP address defined by *networking.private_ip*. The IP address must be available in the VNIC subnet. +- The instance gets two ZPR (Zero Trust Packet Routing) attributes attached to its primary VNIC. - The instance has a secondary IP address attached to the primary VNIC, defined by *networking.secondary-ips* attribute. - The IP address is randomly chosen from available addresses in the subnet, as its *primary_ip* attribute is undefined. - The instance has a secondary VNIC attached, defined by *networking.secondary-vnics* attribute. @@ -20,6 +21,7 @@ This example shows how to deploy Compute instances in OCI using the [OCI Landing - The VNIC is assigned a primary IP address defined by its *private_ip* attribute. The IP address must be available in the VNIC subnet. - The VNIC will forward packets, as *skip_source_dest_check* is true. - The VNIC has a secondary IP address randomly chosen from available addresses in the subnet, as its *primary_ip* attribute is undefined. + - The VNIC gets one ZPR (Zero Trust Packet Routing) attribute attached. See [input.auto.tfvars.template](./input.auto.tfvars.template) for the variables configuration. diff --git a/cis-compute-storage/examples/compute-only-multiple-vnics/input.auto.tfvars.template b/cis-compute-storage/examples/compute-only-multiple-vnics/input.auto.tfvars.template index 42a333a..ef74490 100644 --- a/cis-compute-storage/examples/compute-only-multiple-vnics/input.auto.tfvars.template +++ b/cis-compute-storage/examples/compute-only-multiple-vnics/input.auto.tfvars.template @@ -45,6 +45,13 @@ instances_configuration = { encryption = { kms_key_id = "
id = string # the key OCID.
}))