Skip to content

Commit

Permalink
feat: added new variable kms_encryption_enabled which now needs to …
Browse files Browse the repository at this point in the history
…be set to `true` to enable KMS encryption<br/>- added support to create KMS auth policy along with variable `skip_iam_authorization_policy` to toggle policy creation on or off<br/>- added extra validation around the use of KMS variables<br/>- added a new FSCloud profile terraform submodule (see `profiles/fscloud`) and an example on how to use it (see `examples/profiles`) (#467)
  • Loading branch information
rajatagarwal-ibm committed Jun 9, 2023
1 parent ff5dc23 commit 8f10810
Show file tree
Hide file tree
Showing 19 changed files with 792 additions and 33 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ You need the following permissions to run this module.
## Examples

- [ End to end example with default values](examples/default)
- [ Financial Services Cloud profile example](examples/fscloud)
<!-- END EXAMPLES HOOK -->

---
Expand All @@ -126,6 +127,7 @@ No modules.

| Name | Type |
|------|------|
| [ibm_iam_authorization_policy.block_storage_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
| [ibm_is_floating_ip.secondary_fip](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_floating_ip) | resource |
| [ibm_is_floating_ip.vsi_fip](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_floating_ip) | resource |
| [ibm_is_instance.vsi](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_instance) | resource |
Expand All @@ -146,10 +148,12 @@ No modules.
| <a name="input_access_tags"></a> [access\_tags](#input\_access\_tags) | A list of access tags to apply to the VSI resources created by the module. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial. | `list(string)` | `[]` | no |
| <a name="input_allow_ip_spoofing"></a> [allow\_ip\_spoofing](#input\_allow\_ip\_spoofing) | Allow IP spoofing on the primary network interface | `bool` | `false` | no |
| <a name="input_block_storage_volumes"></a> [block\_storage\_volumes](#input\_block\_storage\_volumes) | List describing the block storage volumes that will be attached to each vsi | <pre>list(<br> object({<br> name = string<br> profile = string<br> capacity = optional(number)<br> iops = optional(number)<br> encryption_key = optional(string)<br> })<br> )</pre> | `[]` | no |
| <a name="input_boot_volume_encryption_key"></a> [boot\_volume\_encryption\_key](#input\_boot\_volume\_encryption\_key) | CRN of boot volume encryption key | `string` | n/a | yes |
| <a name="input_boot_volume_encryption_key"></a> [boot\_volume\_encryption\_key](#input\_boot\_volume\_encryption\_key) | CRN of boot volume encryption key | `string` | `null` | no |
| <a name="input_create_security_group"></a> [create\_security\_group](#input\_create\_security\_group) | Create security group for VSI. If this is passed as false, the default will be used | `bool` | n/a | yes |
| <a name="input_enable_floating_ip"></a> [enable\_floating\_ip](#input\_enable\_floating\_ip) | Create a floating IP for each virtual server created | `bool` | `false` | no |
| <a name="input_existing_kms_instance_guid"></a> [existing\_kms\_instance\_guid](#input\_existing\_kms\_instance\_guid) | The GUID of the Hyper Protect Crypto Services instance in which the key specified in var.boot\_volume\_encryption\_key is coming from. | `string` | `null` | no |
| <a name="input_image_id"></a> [image\_id](#input\_image\_id) | Image ID used for VSI. Run 'ibmcloud is images' to find available images in a region | `string` | n/a | yes |
| <a name="input_kms_encryption_enabled"></a> [kms\_encryption\_enabled](#input\_kms\_encryption\_enabled) | Set this to true to control the encryption keys used to encrypt the data that for the block storage volumes for VPC. If set to false, the data is encrypted by using randomly generated keys. For more info on encrypting block storage volumes, see https://cloud.ibm.com/docs/vpc?topic=vpc-creating-instances-byok | `bool` | `false` | no |
| <a name="input_load_balancers"></a> [load\_balancers](#input\_load\_balancers) | Load balancers to add to VSI | <pre>list(<br> object({<br> name = string<br> type = string<br> listener_port = number<br> listener_protocol = string<br> connection_limit = number<br> algorithm = string<br> protocol = string<br> health_delay = number<br> health_retries = number<br> health_timeout = number<br> health_type = string<br> pool_member_port = string<br> security_group = optional(<br> object({<br> name = string<br> rules = list(<br> object({<br> name = string<br> direction = string<br> source = string<br> tcp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> udp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> icmp = optional(<br> object({<br> type = number<br> code = number<br> })<br> )<br> })<br> )<br> })<br> )<br> })<br> )</pre> | `[]` | no |
| <a name="input_machine_type"></a> [machine\_type](#input\_machine\_type) | VSI machine type. Run 'ibmcloud is instance-profiles' to get a list of regional profiles | `string` | n/a | yes |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The IBM Cloud platform API key needed to deploy IAM enabled resources | `string` | n/a | yes |
Expand All @@ -161,6 +165,7 @@ No modules.
| <a name="input_secondary_use_vsi_security_group"></a> [secondary\_use\_vsi\_security\_group](#input\_secondary\_use\_vsi\_security\_group) | Use the security group created by this module in the secondary interface | `bool` | `false` | no |
| <a name="input_security_group"></a> [security\_group](#input\_security\_group) | Security group created for VSI | <pre>object({<br> name = string<br> rules = list(<br> object({<br> name = string<br> direction = string<br> source = string<br> tcp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> udp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> icmp = optional(<br> object({<br> type = number<br> code = number<br> })<br> )<br> })<br> )<br> })</pre> | n/a | yes |
| <a name="input_security_group_ids"></a> [security\_group\_ids](#input\_security\_group\_ids) | IDs of additional security groups to be added to VSI deployment primary interface. A VSI interface can have a maximum of 5 security groups. | `list(string)` | `[]` | no |
| <a name="input_skip_iam_authorization_policy"></a> [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all Storage Blocks to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the existing\_kms\_instance\_guid variable. In addition, no policy is created if var.kms\_encryption\_enabled is set to false. | `bool` | `false` | no |
| <a name="input_ssh_key_ids"></a> [ssh\_key\_ids](#input\_ssh\_key\_ids) | ssh key ids to use in creating vsi | `list(string)` | n/a | yes |
| <a name="input_subnets"></a> [subnets](#input\_subnets) | A list of subnet IDs where VSI will be deployed | <pre>list(<br> object({<br> name = string<br> id = string<br> zone = string<br> cidr = string<br> })<br> )</pre> | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | List of tags to apply to resources created by this module. | `list(string)` | `[]` | no |
Expand Down
2 changes: 1 addition & 1 deletion examples/default/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ variable "region" {
variable "prefix" {
description = "The prefix that you would like to append to your resources"
type = string
default = "test-landing-zone-vsi"
default = "slz-vsi"
}

variable "resource_tags" {
Expand Down
15 changes: 15 additions & 0 deletions examples/fscloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Financial Services Cloud profile example

An end-to-end example that uses the [Profile for IBM Cloud Framework for Financial Services](../../profiles/fscloud/) to deploy a VSI.

The example uses the IBM Cloud Terraform provider to create the following infrastructure:
* A resource group, if one is not passed in.
* An SSH Key, if one is not passed in.
* A Secure Landing Zone virtual private cloud (VPC).
* An IBM Cloud VSI instance with Hyper Protect Crypto Services root key that is passed in for encrypting block storage.

:exclamation: **Important:** In this example, only the VSI instance complies with the IBM Cloud Framework for Financial Services. Other parts of the infrastructure do not necessarily comply.

## Before you begin

- You need a Hyper Protect Crypto Services instance and root key available in the region that you want to deploy your VSI instance to.
79 changes: 79 additions & 0 deletions examples/fscloud/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
##############################################################################
# Locals
##############################################################################

locals {
resource_group_id = var.resource_group != null ? data.ibm_resource_group.existing_resource_group[0].id : ibm_resource_group.resource_group[0].id
ssh_key_id = var.ssh_key != null ? data.ibm_is_ssh_key.existing_ssh_key[0].id : ibm_is_ssh_key.ssh_key[0].id
}

##############################################################################
# Resource Group
# (if var.resource_group is null, create a new RG using var.prefix)
##############################################################################

resource "ibm_resource_group" "resource_group" {
count = var.resource_group != null ? 0 : 1
name = "${var.prefix}-rg"
quota_id = null
}

data "ibm_resource_group" "existing_resource_group" {
count = var.resource_group != null ? 1 : 0
name = var.resource_group
}

##############################################################################
# SSH key
##############################################################################
resource "tls_private_key" "tls_key" {
count = var.ssh_key != null ? 0 : 1
algorithm = "RSA"
rsa_bits = 4096
}

resource "ibm_is_ssh_key" "ssh_key" {
count = var.ssh_key != null ? 0 : 1
name = "${var.prefix}-ssh-key"
public_key = tls_private_key.tls_key[0].public_key_openssh
}

data "ibm_is_ssh_key" "existing_ssh_key" {
count = var.ssh_key != null ? 1 : 0
name = var.ssh_key
}

#############################################################################
# Provision VPC
#############################################################################

module "slz_vpc" {
source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc.git?ref=v7.2.0"
resource_group_id = local.resource_group_id
region = var.region
prefix = var.prefix
tags = var.resource_tags
name = var.vpc_name
}

#############################################################################
# Provision VSI
#############################################################################

module "slz_vsi" {
source = "../../profiles/fscloud"
resource_group_id = local.resource_group_id
image_id = var.image_id
create_security_group = var.create_security_group
security_group = var.security_group
tags = var.resource_tags
subnets = module.slz_vpc.subnet_zone_list
vpc_id = module.slz_vpc.vpc_id
prefix = var.prefix
machine_type = var.machine_type
user_data = var.user_data
boot_volume_encryption_key = var.boot_volume_encryption_key
existing_kms_instance_guid = var.existing_kms_instance_guid
vsi_per_subnet = var.vsi_per_subnet
ssh_key_ids = [local.ssh_key_id]
}
9 changes: 9 additions & 0 deletions examples/fscloud/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "slz_vpc" {
value = module.slz_vpc
description = "VPC module values"
}

output "slz_vsi" {
value = module.slz_vsi
description = "VSI module values"
}
4 changes: 4 additions & 0 deletions examples/fscloud/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "ibm" {
ibmcloud_api_key = var.ibmcloud_api_key
region = var.region
}
114 changes: 114 additions & 0 deletions examples/fscloud/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
variable "ibmcloud_api_key" {
description = "APIkey that's associated with the account to provision resources to"
type = string
sensitive = true
}

variable "resource_group" {
type = string
description = "An existing resource group name to use for this example, if unset a new resource group will be created"
default = null
}

variable "region" {
description = "The region to which to deploy the VPC"
type = string
default = "us-south"
}

variable "prefix" {
description = "The prefix that you would like to append to your resources"
type = string
default = "rajat-fs-vsi"
}

variable "resource_tags" {
description = "List of tags to apply to resources created by this module."
type = list(string)
default = []
}

variable "image_id" {
description = "Image ID used for VSI. Run 'ibmcloud is images' to find available images in a region"
type = string
default = "r006-7ca7884c-c797-468e-a565-5789102aedc6"
}

variable "machine_type" {
description = "VSI machine type. Run 'ibmcloud is instance-profiles' to get a list of regional profiles"
type = string
default = "cx2-2x4"
}

variable "create_security_group" {
description = "Create security group for VSI"
type = string
default = false
}

variable "security_group" {
description = "Security group created for VSI"
type = object({
name = string
rules = list(
object({
name = string
direction = string
source = string
tcp = optional(
object({
port_max = number
port_min = number
})
)
udp = optional(
object({
port_max = number
port_min = number
})
)
icmp = optional(
object({
type = number
code = number
})
)
})
)
})
default = null
}

variable "user_data" {
description = "User data to initialize VSI deployment"
type = string
default = null
}

variable "vsi_per_subnet" {
description = "Number of VSI instances for each subnet"
type = number
default = 1
}

variable "ssh_key" {
type = string
description = "An existing ssh key name to use for this example, if unset a new ssh key will be created"
default = null
}

variable "vpc_name" {
type = string
description = "Name for VPC"
default = "vpc"
}

variable "boot_volume_encryption_key" {
description = "CRN of boot volume encryption key"
type = string
}

variable "existing_kms_instance_guid" {
description = "The GUID of the Hyper Protect Crypto Services or Key Protect instance in which the key specified in var.kms_key_crn and var.backup_encryption_key_crn is coming from. Required only if var.kms_encryption_enabled is set to true, var.skip_iam_authorization_policy is set to false, and you pass a value for var.kms_key_crn, var.backup_encryption_key_crn, or both."
type = string
}
15 changes: 15 additions & 0 deletions examples/fscloud/version.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
required_version = ">= 1.3.0"
required_providers {
# Pin to the lowest provider version of the range defined in the main module's version.tf to ensure lowest version still works
ibm = {
source = "IBM-Cloud/ibm"
version = "1.52.0"
}
# The tls provider is not actually required by the module itself, just this example, so OK to use ">=" here instead of locking into a version
tls = {
source = "hashicorp/tls"
version = ">= 4.0.4"
}
}
}
24 changes: 22 additions & 2 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
locals {
# Validation (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
# tflint-ignore: terraform_unused_declarations
validate_kms_values = !var.kms_encryption_enabled && var.boot_volume_encryption_key != null ? tobool("When passing values for var.boot_volume_encryption_key, you must set var.kms_encryption_enabled to true. Otherwise unset them to use default encryption") : true
# tflint-ignore: terraform_unused_declarations
validate_kms_vars = var.kms_encryption_enabled && var.boot_volume_encryption_key == null ? tobool("When setting var.kms_encryption_enabled to true, a value must be passed for var.boot_volume_encryption_key") : true
# tflint-ignore: terraform_unused_declarations
validate_auth_policy = var.kms_encryption_enabled && var.skip_iam_authorization_policy == false && var.existing_kms_instance_guid == null ? tobool("When var.skip_iam_authorization_policy is set to false, and var.kms_encryption_enabled to true, a value must be passed for var.existing_kms_instance_guid in order to create the auth policy.") : true
}

##############################################################################
# Virtual Server Data
##############################################################################
locals {

# Create list of VSI using subnets and VSI per subnet
# Create list of VSI using subnets and VSI per subnet
vsi_list = flatten([
# For each number in a range from 0 to VSI per subnet
Expand Down Expand Up @@ -64,6 +73,17 @@ locals {
# Create Virtual Servers
##############################################################################

resource "ibm_iam_authorization_policy" "block_storage_policy" {
count = var.skip_iam_authorization_policy ? 0 : 1
source_service_name = "server-protect"
# commented the following as policy is not working as expected with this option. Related support case - https://cloud.ibm.com/unifiedsupport/cases?number=CS3419700
# source_resource_group_id = var.resource_group_id
target_service_name = "hs-crypto"
target_resource_instance_id = var.existing_kms_instance_guid
roles = ["Reader"]
description = "Allow block storage volumes to be encrypted by Key Management instance."
}

resource "ibm_is_instance" "vsi" {
for_each = local.vsi_map
name = each.key
Expand Down Expand Up @@ -107,7 +127,7 @@ resource "ibm_is_instance" "vsi" {
}

boot_volume {
encryption = var.boot_volume_encryption_key == "" ? null : var.boot_volume_encryption_key
encryption = var.boot_volume_encryption_key
}

# Only add volumes if volumes are being created by the module
Expand Down

0 comments on commit 8f10810

Please sign in to comment.