Skip to content

Commit 68cd6c7

Browse files
authored
feat: added support to the DA to use a different KMS instance / key for backup encryption using new optional inputs existing_backup_kms_key_crn and existing_backup_kms_instance_crn<br>* added support to to the DA to provision and instance from a backup CRN using new input backup_crn (#511)
1 parent ffc908c commit 68cd6c7

File tree

4 files changed

+120
-14
lines changed

4 files changed

+120
-14
lines changed

ibm_catalog.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
{
4040
"title": "Supports autoscaling",
4141
"description": "Provides the autoscaling to allow the database to increase resources in response to usage."
42+
},
43+
{
44+
"title": "Supports backup restoration",
45+
"description": "Provides database restoration using a backup created by a deployment with the same service ID."
4246
}
4347
],
4448
"flavors": [
@@ -259,6 +263,9 @@
259263
},
260264
{
261265
"key": "auto_scaling"
266+
},
267+
{
268+
"key": "backup_crn"
262269
}
263270
]
264271
}

solutions/standard/main.tf

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
#######################################################################################################################
44

55
locals {
6-
existing_kms_instance_crn_split = var.existing_kms_instance_crn != null ? split(":", var.existing_kms_instance_crn) : null
7-
existing_kms_instance_guid = var.existing_kms_instance_crn != null ? element(local.existing_kms_instance_crn_split, length(local.existing_kms_instance_crn_split) - 3) : null
8-
existing_kms_instance_region = var.existing_kms_instance_crn != null ? element(local.existing_kms_instance_crn_split, length(local.existing_kms_instance_crn_split) - 5) : null
6+
existing_kms_instance_guid = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_instance : null
7+
existing_kms_instance_region = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].region : null
98

109
key_name = var.prefix != null ? "${var.prefix}-${var.key_name}" : var.key_name
1110
key_ring_name = var.prefix != null ? "${var.prefix}-${var.key_ring_name}" : var.key_ring_name
@@ -14,9 +13,7 @@ locals {
1413

1514
create_cross_account_auth_policy = !var.skip_iam_authorization_policy && var.ibmcloud_kms_api_key != null
1615

17-
kms_service_name = local.kms_key_crn != null ? (
18-
can(regex(".*kms.*", local.kms_key_crn)) ? "kms" : can(regex(".*hs-crypto.*", local.kms_key_crn)) ? "hs-crypto" : null
19-
) : null
16+
kms_service_name = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_name : null
2017
}
2118

2219
#######################################################################################################################
@@ -37,6 +34,14 @@ data "ibm_iam_account_settings" "iam_account_settings" {
3734
count = local.create_cross_account_auth_policy ? 1 : 0
3835
}
3936

37+
# If existing KMS intance CRN passed, parse details from it
38+
module "kms_instance_crn_parser" {
39+
count = var.existing_kms_instance_crn != null ? 1 : 0
40+
source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
41+
version = "1.1.0"
42+
crn = var.existing_kms_instance_crn
43+
}
44+
4045
resource "ibm_iam_authorization_policy" "kms_policy" {
4146
count = local.create_cross_account_auth_policy ? 1 : 0
4247
provider = ibm.kms
@@ -84,17 +89,87 @@ module "kms" {
8489
]
8590
}
8691

92+
#######################################################################################################################
93+
# KMS backup encryption key for Postgresql
94+
#######################################################################################################################
95+
96+
locals {
97+
existing_backup_kms_instance_guid = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].service_instance : null
98+
existing_backup_kms_instance_region = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].region : null
99+
100+
backup_key_name = var.prefix != null ? "${var.prefix}-backup-encryption-${var.key_name}" : "backup-encryption-${var.key_name}"
101+
backup_key_ring_name = var.prefix != null ? "${var.prefix}-backup-encryption-${var.key_ring_name}" : "backup-encryption-${var.key_ring_name}"
102+
backup_kms_key_crn = var.existing_backup_kms_key_crn != null ? var.existing_backup_kms_key_crn : var.existing_backup_kms_instance_crn != null ? module.backup_kms[0].keys[format("%s.%s", local.backup_key_ring_name, local.backup_key_name)].crn : null
103+
backup_kms_service_name = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].service_name : null
104+
}
105+
106+
# If existing KMS intance CRN passed, parse details from it
107+
module "backup_kms_instance_crn_parser" {
108+
count = var.existing_backup_kms_instance_crn != null ? 1 : 0
109+
source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
110+
version = "1.1.0"
111+
crn = var.existing_backup_kms_instance_crn
112+
}
113+
114+
resource "ibm_iam_authorization_policy" "backup_kms_policy" {
115+
count = local.existing_backup_kms_instance_guid == local.existing_kms_instance_guid ? 0 : var.existing_backup_kms_key_crn != null ? 0 : var.existing_backup_kms_instance_crn != null ? !var.skip_iam_authorization_policy ? 1 : 0 : 0
116+
provider = ibm.kms
117+
source_service_account = local.create_cross_account_auth_policy ? data.ibm_iam_account_settings.iam_account_settings[0].account_id : null
118+
source_service_name = "databases-for-postgresql"
119+
source_resource_group_id = module.resource_group.resource_group_id
120+
target_service_name = local.backup_kms_service_name
121+
target_resource_instance_id = local.existing_backup_kms_instance_guid
122+
roles = ["Reader"]
123+
description = "Allow all Postgresql instances in the resource group ${module.resource_group.resource_group_id} to read from the ${local.backup_kms_service_name} instance GUID ${local.existing_backup_kms_instance_guid}"
124+
}
125+
126+
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
127+
resource "time_sleep" "wait_for_backup_kms_authorization_policy" {
128+
depends_on = [ibm_iam_authorization_policy.backup_kms_policy]
129+
create_duration = "30s"
130+
}
131+
132+
module "backup_kms" {
133+
providers = {
134+
ibm = ibm.kms
135+
}
136+
count = var.existing_backup_kms_key_crn != null ? 0 : var.existing_backup_kms_instance_crn != null ? 1 : 0
137+
source = "terraform-ibm-modules/kms-all-inclusive/ibm"
138+
version = "4.15.13"
139+
create_key_protect_instance = false
140+
region = local.existing_backup_kms_instance_region
141+
existing_kms_instance_crn = var.existing_backup_kms_instance_crn
142+
key_ring_endpoint_type = var.kms_endpoint_type
143+
key_endpoint_type = var.kms_endpoint_type
144+
keys = [
145+
{
146+
key_ring_name = local.backup_key_ring_name
147+
existing_key_ring = false
148+
force_delete_key_ring = true
149+
keys = [
150+
{
151+
key_name = local.backup_key_name
152+
standard_key = false
153+
rotation_interval_month = 3
154+
dual_auth_delete_enabled = false
155+
force_delete = true
156+
}
157+
]
158+
}
159+
]
160+
}
161+
87162
#######################################################################################################################
88163
# Postgresql
89164
#######################################################################################################################
90165

91166
module "postgresql_db" {
92167
source = "../../modules/fscloud"
93-
depends_on = [time_sleep.wait_for_authorization_policy]
168+
depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy]
94169
resource_group_id = module.resource_group.resource_group_id
95170
name = var.prefix != null ? "${var.prefix}-${var.name}" : var.name
96171
region = var.region
97-
skip_iam_authorization_policy = var.skip_iam_authorization_policy
172+
skip_iam_authorization_policy = local.create_cross_account_auth_policy ? true : var.skip_iam_authorization_policy
98173
pg_version = var.pg_version
99174
existing_kms_instance_guid = local.existing_kms_instance_guid
100175
kms_key_crn = local.kms_key_crn
@@ -110,4 +185,6 @@ module "postgresql_db" {
110185
auto_scaling = var.auto_scaling
111186
configuration = var.configuration
112187
service_credential_names = var.service_credential_names
188+
backup_encryption_key_crn = local.backup_kms_key_crn
189+
backup_crn = var.backup_crn
113190
}

solutions/standard/variables.tf

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ variable "pg_version" {
5050
default = null
5151
}
5252

53+
variable "backup_crn" {
54+
type = string
55+
description = "The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty."
56+
default = null
57+
}
58+
5359
##############################################################################
5460
# ICD hosting model properties
5561
##############################################################################
@@ -221,12 +227,12 @@ variable "kms_endpoint_type" {
221227

222228
variable "existing_kms_key_crn" {
223229
type = string
224-
description = "The CRN of a Hyper Protect Crypto Services or Key Protect root key to use for disk encryption. If not specified, a root key is created in the KMS instance."
230+
description = "The CRN of an Hyper Protect Crypto Services or Key Protect encryption key that you want to use to use for both disk and backup encryption. If no value is passed, a new key ring and key will be created in the instance provided in the `existing_kms_instance_crn` input. Backup encryption is only supported is some regions ([learn more](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok)), so if you need to use a key from a different region for backup encryption, use the `existing_backup_kms_key_crn` input."
225231
default = null
226232
}
227233

228234
variable "existing_kms_instance_crn" {
229-
description = "The CRN of a Hyper Protect Crypto Services or Key Protect instance in the same account as the PostgreSQL instance. This value is used to create an authorization policy if `skip_iam_authorization_policy` is false. If not specified, a root key is created."
235+
description = "The CRN of an Hyper Protect Crypto Services or Key Protect instance that you want to use for both disk and backup encryption. Backup encryption is only supported is some regions ([learn more](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok)), so if you need to use a different instance for backup encryption from a supported region, use the `existing_backup_kms_instance_crn` input."
230236
type = string
231237
default = null
232238
}
@@ -236,3 +242,18 @@ variable "skip_iam_authorization_policy" {
236242
description = "Whether to create an IAM authorization policy that permits all PostgreSQL instances in the resource group to read the encryption key from the Hyper Protect Crypto Services instance specified in the `existing_kms_instance_crn` variable."
237243
default = false
238244
}
245+
246+
##############################################################
247+
# Backup Encryption
248+
##############################################################
249+
variable "existing_backup_kms_key_crn" {
250+
type = string
251+
description = "The CRN of an Hyper Protect Crypto Services or Key Protect encryption key that you want to use to encrypt database backups. If no value is passed, the value of `existing_kms_key_crn` is used. If no value is passed for that, a new key will be created in the provided KMS instance and used for both disk encryption, and backup encryption."
252+
default = null
253+
}
254+
255+
variable "existing_backup_kms_instance_crn" {
256+
description = "The CRN of an Hyper Protect Crypto Services or Key Protect instance that you want to use to encrypt database backups. If no value is passed, the value of the `existing_kms_instance_crn` input will be used, however backup encryption is only supported in certain regions so you need to ensure the KMS for backup is coming from one of the supported regions. [Learn more](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok)"
257+
type = string
258+
default = null
259+
}

tests/pr_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ func TestRunStandardSolution(t *testing.T) {
109109
})
110110

111111
options.TerraformVars = map[string]interface{}{
112-
"pg_version": "16", // Always lock this test into the latest supported PostgreSQL version
113-
"existing_kms_instance_crn": permanentResources["hpcs_south_crn"],
114-
"kms_endpoint_type": "public",
115-
"resource_group_name": options.Prefix,
112+
"pg_version": "16", // Always lock this test into the latest supported PostgreSQL version
113+
"existing_kms_instance_crn": permanentResources["hpcs_south_crn"],
114+
"kms_endpoint_type": "public",
115+
"existing_backup_kms_key_crn": permanentResources["hpcs_south_root_key_crn"],
116+
"resource_group_name": options.Prefix,
116117
}
117118

118119
output, err := options.RunTestConsistency()

0 commit comments

Comments
 (0)