Skip to content

Commit 367259a

Browse files
jor2Jordan-Williams2
andauthored
feat: DA solution - added support for backups and backup encryption (#336) <br> - new DA input backup_crn to support creation from a backup <br> - new DA inputs existing_backup_kms_key_crn and existing_backup_kms_instance_crn to allow using a different encryption key for backups
* feat: add support to use a different KMS key for backup encryption * fix: add policy * fix: id instead of crn --------- Co-authored-by: Jordan-Williams2 <[email protected]>
1 parent f3a7129 commit 367259a

File tree

7 files changed

+164
-7
lines changed

7 files changed

+164
-7
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,14 @@ You need the following permissions to run this module.
7575
| Name | Type |
7676
|------|------|
7777
| [ibm_database.elasticsearch](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/database) | resource |
78+
| [ibm_iam_authorization_policy.backup_kms_policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
7879
| [ibm_iam_authorization_policy.policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
7980
| [ibm_resource_key.service_credentials](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_key) | resource |
8081
| [ibm_resource_tag.elasticsearch_tag](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_tag) | resource |
8182
| [null_resource.put_vectordb_model](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
8283
| [null_resource.start_vectordb_model](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
8384
| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
85+
| [time_sleep.wait_for_backup_kms_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
8486
| [ibm_database_connection.database_connection](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/database_connection) | data source |
8587

8688
### Inputs

cra-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CRA_TARGETS:
66
PROFILE_ID: "bfacb71d-4b84-41ac-9825-e8a3a3eb7405" # SCC profile ID (currently set to IBM Cloud Framework for Financial Services 1.6.0 profile).
77
CRA_ENVIRONMENT_VARIABLES:
88
TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::"
9-
TF_VAR_kms_key_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9:key:76170fae-4e0c-48c3-8ebe-326059ebb533"
9+
TF_VAR_existing_kms_key_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9:key:76170fae-4e0c-48c3-8ebe-326059ebb533"
1010
TF_VAR_provider_visibility: "public"
1111
TF_VAR_resource_group_name: "test-es-cra"
1212
TF_VAR_use_existing_resource_group: false

ibm_catalog.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
{
4343
"title": "Attaches access tags",
4444
"description": "Attaches access tags to the Elasticsearch instance."
45+
},
46+
{
47+
"title": "Supports backup restoration",
48+
"description": "Provides database restoration using a backup created by a deployment with the same service ID."
4549
}
4650
],
4751
"flavors": [
@@ -278,6 +282,15 @@
278282
{
279283
"key": "auto_scaling"
280284
},
285+
{
286+
"key": "backup_crn"
287+
},
288+
{
289+
"key": "existing_backup_kms_key_crn"
290+
},
291+
{
292+
"key": "existing_backup_kms_instance_crn"
293+
},
281294
{
282295
"key": "enable_elser_model"
283296
},

main.tf

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ locals {
1717

1818
# For more info, see https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok and https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups"
1919

20-
backup_encryption_key_crn = var.use_default_backup_encryption_key == true ? null : (var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.kms_key_crn)
20+
backup_encryption_key_crn = var.use_default_backup_encryption_key == true ? null : (var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.kms_key_crn)
21+
parsed_backup_encryption_key_crn = local.backup_encryption_key_crn != null ? split(":", local.backup_encryption_key_crn) : []
22+
backup_kms_key_id = length(local.parsed_backup_encryption_key_crn) > 0 ? local.parsed_backup_encryption_key_crn[9] : null
23+
24+
create_backup_kms_policy = local.create_kp_auth_policy == 1 && local.backup_encryption_key_crn != null && var.backup_encryption_key_crn != null
2125

2226
# Determine if auto scaling is enabled
2327
auto_scaling_enabled = var.auto_scaling == null ? [] : [1]
@@ -81,9 +85,52 @@ resource "time_sleep" "wait_for_authorization_policy" {
8185
create_duration = "30s"
8286
}
8387

88+
resource "ibm_iam_authorization_policy" "backup_kms_policy" {
89+
count = local.create_backup_kms_policy ? 1 : 0
90+
source_service_name = "databases-for-elasticsearch"
91+
source_resource_group_id = var.resource_group_id
92+
roles = ["Reader"]
93+
description = "Allow all Elastic Search instances in the Resource Group ${var.resource_group_id} to read the ${local.kms_service} key ${local.backup_kms_key_id} from the instance GUID ${var.existing_kms_instance_guid}"
94+
resource_attributes {
95+
name = "serviceName"
96+
operator = "stringEquals"
97+
value = local.kms_service
98+
}
99+
resource_attributes {
100+
name = "accountId"
101+
operator = "stringEquals"
102+
value = local.kms_account_id
103+
}
104+
resource_attributes {
105+
name = "serviceInstance"
106+
operator = "stringEquals"
107+
value = var.existing_kms_instance_guid
108+
}
109+
resource_attributes {
110+
name = "resourceType"
111+
operator = "stringEquals"
112+
value = "key"
113+
}
114+
resource_attributes {
115+
name = "resource"
116+
operator = "stringEquals"
117+
value = local.backup_kms_key_id
118+
}
119+
# Scope of policy now includes the key, so ensure to create new policy before
120+
# destroying old one to prevent any disruption to every day services.
121+
lifecycle {
122+
create_before_destroy = true
123+
}
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+
}
84131

85132
resource "ibm_database" "elasticsearch" {
86-
depends_on = [time_sleep.wait_for_authorization_policy]
133+
depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy]
87134
name = var.name
88135
plan = var.plan
89136
location = var.region

solutions/standard/main.tf

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,85 @@ module "kms" {
122122
]
123123
}
124124

125+
126+
#######################################################################################################################
127+
# KMS backup encryption key for Elasticsearch
128+
#######################################################################################################################
129+
130+
locals {
131+
existing_backup_kms_instance_guid = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].service_instance : null
132+
existing_backup_kms_instance_region = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].region : null
133+
134+
backup_key_name = var.prefix != null ? "${var.prefix}-backup-encryption-${var.elasticsearch_key_name}" : "backup-encryption-${var.elasticsearch_key_name}"
135+
backup_key_ring_name = var.prefix != null ? "${var.prefix}-backup-encryption-${var.elasticsearch_key_ring_name}" : "backup-encryption-${var.elasticsearch_key_ring_name}"
136+
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
137+
backup_kms_service_name = var.existing_backup_kms_instance_crn != null ? module.backup_kms_instance_crn_parser[0].service_name : null
138+
}
139+
140+
# If existing KMS intance CRN passed, parse details from it
141+
module "backup_kms_instance_crn_parser" {
142+
count = var.existing_backup_kms_instance_crn != null ? 1 : 0
143+
source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
144+
version = "1.1.0"
145+
crn = var.existing_backup_kms_instance_crn
146+
}
147+
148+
resource "ibm_iam_authorization_policy" "backup_kms_policy" {
149+
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
150+
provider = ibm.kms
151+
source_service_account = local.create_cross_account_auth_policy ? data.ibm_iam_account_settings.iam_account_settings[0].account_id : null
152+
source_service_name = "databases-for-elasticsearch"
153+
source_resource_group_id = module.resource_group.resource_group_id
154+
target_service_name = local.backup_kms_service_name
155+
target_resource_instance_id = local.existing_backup_kms_instance_guid
156+
roles = ["Reader"]
157+
description = "Allow all Elasticsearch 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}"
158+
}
159+
160+
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
161+
resource "time_sleep" "wait_for_backup_kms_authorization_policy" {
162+
depends_on = [ibm_iam_authorization_policy.backup_kms_policy]
163+
create_duration = "30s"
164+
}
165+
166+
module "backup_kms" {
167+
providers = {
168+
ibm = ibm.kms
169+
}
170+
count = var.use_ibm_owned_encryption_key ? 0 : var.existing_backup_kms_key_crn != null ? 0 : var.existing_backup_kms_instance_crn != null ? 1 : 0
171+
source = "terraform-ibm-modules/kms-all-inclusive/ibm"
172+
version = "4.16.8"
173+
create_key_protect_instance = false
174+
region = local.existing_backup_kms_instance_region
175+
existing_kms_instance_crn = var.existing_backup_kms_instance_crn
176+
key_ring_endpoint_type = var.kms_endpoint_type
177+
key_endpoint_type = var.kms_endpoint_type
178+
keys = [
179+
{
180+
key_ring_name = local.backup_key_ring_name
181+
existing_key_ring = false
182+
force_delete_key_ring = true
183+
keys = [
184+
{
185+
key_name = local.backup_key_name
186+
standard_key = false
187+
rotation_interval_month = 3
188+
dual_auth_delete_enabled = false
189+
force_delete = true
190+
}
191+
]
192+
}
193+
]
194+
}
195+
125196
#######################################################################################################################
126197
# Elasticsearch
127198
#######################################################################################################################
128199

129200
module "elasticsearch" {
130201
count = local.use_existing_db_instance ? 0 : 1
131202
source = "../../modules/fscloud"
132-
depends_on = [time_sleep.wait_for_authorization_policy]
203+
depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy]
133204
resource_group_id = module.resource_group.resource_group_id
134205
name = var.prefix != null ? "${var.prefix}-${var.name}" : var.name
135206
region = var.region
@@ -139,6 +210,8 @@ module "elasticsearch" {
139210
existing_kms_instance_guid = local.existing_kms_instance_guid
140211
use_ibm_owned_encryption_key = var.use_ibm_owned_encryption_key
141212
kms_key_crn = local.kms_key_crn
213+
backup_encryption_key_crn = local.backup_kms_key_crn
214+
backup_crn = var.backup_crn
142215
access_tags = var.access_tags
143216
tags = var.tags
144217
admin_pass = local.admin_pass

solutions/standard/variables.tf

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ variable "elasticsearch_version" {
5959
default = null
6060
}
6161

62+
variable "backup_crn" {
63+
type = string
64+
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."
65+
default = null
66+
}
67+
6268
variable "region" {
6369
type = string
6470
description = "The region where you want to deploy your instance."
@@ -208,7 +214,7 @@ variable "auto_scaling" {
208214

209215
variable "existing_kms_key_crn" {
210216
type = string
211-
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 specified in the `existing_kms_instance_crn` input."
217+
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 specified 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."
212218
default = null
213219
}
214220

@@ -230,7 +236,7 @@ variable "kms_endpoint_type" {
230236

231237
variable "existing_kms_instance_crn" {
232238
type = string
233-
description = "The CRN of a Hyper Protect Crypto Services or Key Protect instance. Required to create a new root key if no value is passed with the `existing_kms_key_crn` input. Also required to create an authorization policy if `skip_iam_authorization_policy` is false."
239+
description = "The CRN of a Hyper Protect Crypto Services or Key Protect instance. Required to create a new root key if no value is passed with the `existing_kms_key_crn` input. Also required to create an authorization policy if `skip_iam_authorization_policy` is false. 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."
234240
default = null
235241
}
236242

@@ -294,7 +300,7 @@ variable "service_credential_secrets" {
294300
}))
295301
}))
296302
default = []
297-
description = "Service credential secrets configuration for Databases for Elasticsearch. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-elasticsearch/tree/main/solutions/instance/DA-types.md#service-credential-secrets)."
303+
description = "Service credential secrets configuration for Databases for Elasticsearch. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/standard/DA-types.md#service-credential-secrets)."
298304

299305
validation {
300306
condition = alltrue([
@@ -354,3 +360,18 @@ variable "elasticsearch_full_version" {
354360
type = string
355361
default = null
356362
}
363+
364+
##############################################################
365+
# Backup Encryption
366+
##############################################################
367+
variable "existing_backup_kms_key_crn" {
368+
type = string
369+
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."
370+
default = null
371+
}
372+
373+
variable "existing_backup_kms_instance_crn" {
374+
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)"
375+
type = string
376+
default = null
377+
}

tests/pr_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func TestRunStandardSolutionSchematics(t *testing.T) {
121121
{Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
122122
{Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"},
123123
{Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
124+
{Name: "existing_backup_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"},
124125
{Name: "kms_endpoint_type", Value: "public", DataType: "string"},
125126
{Name: "resource_group_name", Value: options.Prefix, DataType: "string"},
126127
{Name: "plan", Value: "platinum", DataType: "string"},

0 commit comments

Comments
 (0)