Skip to content

Commit 6b094fa

Browse files
feat: added support for hyper protect + support to create the IAM auth policy with KMS + added new fscloud profile module (#120)
BREAKING CHANGE: - `key_protect_key_crn` renamed to `kms_key_crn` since it now support Hyper Protect
1 parent a0e8ff6 commit 6b094fa

File tree

16 files changed

+231
-133
lines changed

16 files changed

+231
-133
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ jobs:
1818
with:
1919
craTarget: "examples/fscloud"
2020
craGoalIgnoreFile: "cra-tf-validate-ignore-goals.json"
21-
craEnvironmentVariables: "TF_VAR_existing_at_instance_crn=crn:v1:bluemix:public:logdnaat:eu-de:a/abac0df06b644a9cabc6e44f55b3880e:b1ef3365-dfbf-4d8f-8ac8-75f4f84d6f4a::"
21+
craEnvironmentVariables: "TF_VAR_existing_at_instance_crn=crn:v1:bluemix:public:logdnaat:eu-de:a/abac0df06b644a9cabc6e44f55b3880e:b1ef3365-dfbf-4d8f-8ac8-75f4f84d6f4a::,TF_VAR_existing_kms_instance_guid=${{ vars.HPCS_SOUTH_GUID }},TF_VAR_kms_key_crn=${{ vars.HPCS_SOUTH_KEY_CRN }}"

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "go.sum|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2023-04-05T23:15:43Z",
6+
"generated_at": "2023-04-06T13:46:57Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -82,7 +82,7 @@
8282
"hashed_secret": "8acbd0ff478f744859b92e1251622e4124bceef0",
8383
"is_secret": false,
8484
"is_verified": false,
85-
"line_number": 22,
85+
"line_number": 24,
8686
"type": "Secret Keyword",
8787
"verified_result": null
8888
}

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
> WARNING: **This module does not support major version upgrade or updates to encryption and backup encryption keys**: To upgrade version create a new postgresql instance with the updated version and follow the [Upgrading PostgreSQL docs](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-upgrading&interface=cli)
1717
18+
> NOTE: The database encryption for backups supports only Key Protect keys, not the Hyper Protect Crypto Key at the moment. More info: https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs&interface=cli
19+
1820
```hcl
1921
module "postgresql_db" {
2022
# replace main with version
@@ -76,6 +78,7 @@ You need the following permissions to run this module.
7678
| Name | Type |
7779
|------|------|
7880
| [ibm_database.postgresql_db](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database) | resource |
81+
| [ibm_iam_authorization_policy.kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
7982
| [ibm_resource_key.service_credentials](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_key) | resource |
8083

8184
## Inputs
@@ -85,10 +88,11 @@ You need the following permissions to run this module.
8588
| <a name="input_allowlist"></a> [allowlist](#input\_allowlist) | Set of IP address and description to allowlist in database | <pre>list(object({<br> address = optional(string)<br> description = optional(string)<br> }))</pre> | `[]` | no |
8689
| <a name="input_auto_scaling"></a> [auto\_scaling](#input\_auto\_scaling) | (Optional) Configure rules to allow your database to automatically increase its resources. Single block of autoscaling is allowed at once. | <pre>object({<br> cpu = object({<br> rate_increase_percent = optional(number, 10)<br> rate_limit_count_per_member = optional(number, 20)<br> rate_period_seconds = optional(number, 900)<br> rate_units = optional(string, "count")<br> })<br> disk = object({<br> capacity_enabled = optional(bool, false)<br> free_space_less_than_percent = optional(number, 10)<br> io_above_percent = optional(number, 90)<br> io_enabled = optional(bool, false)<br> io_over_period = optional(string, "15m")<br> rate_increase_percent = optional(number, 10)<br> rate_limit_mb_per_member = optional(number, 3670016)<br> rate_period_seconds = optional(number, 900)<br> rate_units = optional(string, "mb")<br> })<br> memory = object({<br> io_above_percent = optional(number, 90)<br> io_enabled = optional(bool, false)<br> io_over_period = optional(string, "15m")<br> rate_increase_percent = optional(number, 10)<br> rate_limit_mb_per_member = optional(number, 114688)<br> rate_period_seconds = optional(number, 900)<br> rate_units = optional(string, "mb")<br> })<br> })</pre> | `null` | no |
8790
| <a name="input_backup_crn"></a> [backup\_crn](#input\_backup\_crn) | 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. | `string` | `null` | no |
88-
| <a name="input_backup_encryption_key_crn"></a> [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | (Optional) The CRN of a key protect key, that you want to use for encrypting disk that holds deployment backups. If null, will use 'key\_protect\_key\_crn' as encryption key. If 'key\_protect\_key\_crn' is also null database is encrypted by using randomly generated keys. | `string` | `null` | no |
91+
| <a name="input_backup_encryption_key_crn"></a> [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | (Optional) The CRN of a Key Protect Key to use for encrypting backups. If left null, the value passed for the 'kms\_key\_crn' variable will be used. Take note that Hyper Protect Crypto Services for IBM Cloud® Databases backups is not currently supported. | `string` | `null` | no |
8992
| <a name="input_cbr_rules"></a> [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of CBR rules to create | <pre>list(object({<br> description = string<br> account_id = string<br> rule_contexts = list(object({<br> attributes = optional(list(object({<br> name = string<br> value = string<br> }))) }))<br> enforcement_mode = string<br> }))</pre> | `[]` | no |
9093
| <a name="input_configuration"></a> [configuration](#input\_configuration) | (Optional, Json String) Database Configuration in JSON format. | <pre>object({<br> max_connections = optional(number)<br> max_prepared_transactions = optional(number)<br> deadlock_timeout = optional(number)<br> effective_io_concurrency = optional(number)<br> max_replication_slots = optional(number)<br> max_wal_senders = optional(number)<br> shared_buffers = optional(number)<br> synchronous_commit = optional(string)<br> wal_level = optional(string)<br> archive_timeout = optional(number)<br> log_min_duration_statement = optional(number)<br> })</pre> | `null` | no |
91-
| <a name="input_key_protect_key_crn"></a> [key\_protect\_key\_crn](#input\_key\_protect\_key\_crn) | (Optional) The root key CRN of a Key Management Service like Key Protect or Hyper Protect Crypto Service (HPCS) that you want to use for disk encryption. If `null`, database is encrypted by using randomly generated keys. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok for current list of supported regions for BYOK | `string` | `null` | no |
94+
| <a name="input_existing_kms_instance_guid"></a> [existing\_kms\_instance\_guid](#input\_existing\_kms\_instance\_guid) | The GUID of the Hyper Protect or Key Protect instance in which the key specified in var.kms\_key\_crn is coming from. Only required if skip\_iam\_authorization\_policy is false | `string` | `null` | no |
95+
| <a name="input_kms_key_crn"></a> [kms\_key\_crn](#input\_kms\_key\_crn) | (Optional) The root key CRN of a Key Management Service like Key Protect or Hyper Protect Crypto Service (HPCS) that you want to use for disk encryption. If `null`, database is encrypted by using randomly generated keys. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok for current list of supported regions for BYOK | `string` | `null` | no |
9296
| <a name="input_member_cpu_count"></a> [member\_cpu\_count](#input\_member\_cpu\_count) | CPU allocation required for postgresql database | `string` | `"3"` | no |
9397
| <a name="input_member_disk_mb"></a> [member\_disk\_mb](#input\_member\_disk\_mb) | Disk allocation required for postgresql database | `string` | `"5120"` | no |
9498
| <a name="input_member_memory_mb"></a> [member\_memory\_mb](#input\_member\_memory\_mb) | Memory allocation required for postgresql database | `string` | `"1024"` | no |
@@ -98,12 +102,13 @@ You need the following permissions to run this module.
98102
| <a name="input_pitr_id"></a> [pitr\_id](#input\_pitr\_id) | (Optional) The ID of the postgresql instance that you want to recover back to. Here ID of the postgresql instance is expected to be up and in running state. | `string` | `null` | no |
99103
| <a name="input_pitr_time"></a> [pitr\_time](#input\_pitr\_time) | (Optional) The timestamp in UTC format (%Y-%m-%dT%H:%M:%SZ) that you want to restore to. To retrieve the timestamp, run the command (ibmcloud cdb postgresql earliest-pitr-timestamp <deployment name or CRN>) | `string` | `null` | no |
100104
| <a name="input_plan_validation"></a> [plan\_validation](#input\_plan\_validation) | Enable or disable validating the database parameters for postgres during the plan phase | `bool` | `true` | no |
101-
| <a name="input_region"></a> [region](#input\_region) | The region postgresql is to be created on. The region must support BYOK if key\_protect\_key\_crn is used | `string` | `"us-south"` | no |
105+
| <a name="input_region"></a> [region](#input\_region) | The region postgresql is to be created on. The region must support BYOK region if Key Protect Key is used or KYOK region if Hyper Protect Crypto Service (HPCS) is used. | `string` | `"us-south"` | no |
102106
| <a name="input_remote_leader_crn"></a> [remote\_leader\_crn](#input\_remote\_leader\_crn) | The CRN of the leader database to make the replica(read-only) deployment. | `string` | `null` | no |
103107
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the postgresql will be created | `string` | n/a | yes |
104108
| <a name="input_resource_tags"></a> [resource\_tags](#input\_resource\_tags) | Optional list of tags to be added to created resources | `list(string)` | `[]` | no |
105109
| <a name="input_service_credential_names"></a> [service\_credential\_names](#input\_service\_credential\_names) | Map of name, role for service credentials that you want to create for the database | `map(string)` | `{}` | no |
106110
| <a name="input_service_endpoints"></a> [service\_endpoints](#input\_service\_endpoints) | Sets the endpoint of the Postgresql instance, valid values are 'public', 'private', or 'public-and-private' | `string` | `"private"` | no |
111+
| <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 PostgreSQL database instances in the given Resource group to read the encryption key from the Hyper Protect or Key Protect instance in `existing_kms_instance_guid`. | `bool` | `true` | no |
107112

108113
## Outputs
109114

examples/complete/main.tf

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ module "postgresql_db" {
8282
region = var.region
8383
service_endpoints = "private"
8484
pg_version = var.pg_version
85-
key_protect_key_crn = module.key_protect_all_inclusive.keys["icd-pg.${var.prefix}-pg"].crn
85+
kms_key_crn = module.key_protect_all_inclusive.keys["icd-pg.${var.prefix}-pg"].crn
8686
resource_tags = var.resource_tags
8787
service_credential_names = var.service_credential_names
8888
cbr_rules = [
@@ -134,6 +134,12 @@ resource "ibm_is_virtual_endpoint_gateway" "pgvpe" {
134134
resource_group = module.resource_group.resource_group_id
135135
security_groups = [ibm_is_security_group.sg1.id]
136136
depends_on = [
137-
time_sleep.wait_120_seconds
137+
time_sleep.wait_120_seconds,
138+
time_sleep.wait_30_seconds
138139
]
139140
}
141+
142+
resource "time_sleep" "wait_30_seconds" {
143+
depends_on = [ibm_is_security_group.sg1]
144+
destroy_duration = "30s"
145+
}

examples/fscloud/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
## *Note:* This example is only deploying Postgresql in a compliant manner the other infrastructure is not necessarily compliant.
44

5+
### Requirements
6+
This example expects you have Hyper Protect Crypto Service instances in the region you wish to deploy your Postgresql database instance.
7+
8+
### Deploys
59
An example using the fscloud profile to deploy a compliant Postgresql instance. This example uses the IBM Cloud terraform provider to:
610

711
- Create a new resource group if one is not passed in.
8-
- Create a new ICD Postgresql database instance and credentials.
9-
- Create Key Protect instance with root key.
10-
- Backend encryption using generated Key Protect key.
12+
- Create an IAM Authorization between PostgreSQL Database Resource group and HPSC permanent Instance.
13+
- Create a new ICD Postgresql database instance and credentials that is encrypted using the Hyper Protect Crypto Service resources that are passed in.
1114
- Create a Sample VPC.
1215
- Create Context Based Restriction(CBR) to only allow Postgresql to be accessible from the VPC.

examples/fscloud/main.tf

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module "resource_group" {
1313
# Key Protect All Inclusive
1414
##############################################################################
1515

16+
# Need Key Protect instance for backup_encryption_key_crn as backup encryption key is not supported by Hyper Protect instaces yet.
1617
module "key_protect_all_inclusive" {
1718
source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-key-protect-all-inclusive.git?ref=v4.0.0"
1819
resource_group_id = module.resource_group.resource_group_id
@@ -76,14 +77,15 @@ module "cbr_zone" {
7677
##############################################################################
7778

7879
module "postgresql_db" {
79-
source = "../../profiles/fscloud"
80-
resource_group_id = module.resource_group.resource_group_id
81-
name = "${var.prefix}-postgres"
82-
region = var.region
83-
pg_version = var.pg_version
84-
key_protect_key_crn = module.key_protect_all_inclusive.keys["icd-pg.${var.prefix}-pg"].crn
85-
resource_tags = var.resource_tags
86-
allowlist = var.allowlist
80+
source = "../../profiles/fscloud"
81+
resource_group_id = module.resource_group.resource_group_id
82+
name = "${var.prefix}-postgres"
83+
region = var.region
84+
pg_version = var.pg_version
85+
kms_key_crn = var.kms_key_crn
86+
existing_kms_instance_guid = var.existing_kms_instance_guid
87+
resource_tags = var.resource_tags
88+
backup_encryption_key_crn = module.key_protect_all_inclusive.keys["icd-pg.${var.prefix}-pg"].crn
8789
cbr_rules = [
8890
{
8991
description = "${var.prefix}-postgres access only from vpc"

examples/fscloud/variables.tf

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ variable "region" {
1313
variable "prefix" {
1414
type = string
1515
description = "Prefix to append to all resources created by this example"
16-
default = "sm-test"
16+
default = "fs-cloud"
1717
}
1818

1919
variable "resource_group" {
@@ -34,11 +34,12 @@ variable "pg_version" {
3434
default = null
3535
}
3636

37-
variable "allowlist" {
38-
type = list(object({
39-
address = optional(string)
40-
description = optional(string)
41-
}))
42-
default = []
43-
description = "Set of IP address and description to allowlist in database"
37+
variable "existing_kms_instance_guid" {
38+
description = "The GUID of the Hyper Protect Crypto service in which the key specified in var.kms_key_crn is coming from"
39+
type = string
40+
}
41+
42+
variable "kms_key_crn" {
43+
type = string
44+
description = "The root key CRN of a Hyper Protect Crypto Service (HPCS) that you want to use for disk encryption. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs&interface=ui for more information on integrating HPCS with PostgreSQL database."
4445
}

examples/pitr/variables.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ variable "region" {
1313
variable "prefix" {
1414
type = string
1515
description = "Prefix to append to all resources created by this example"
16-
default = "pg"
16+
default = "pg-pitr"
1717
}
1818

1919
variable "resource_group" {

main.tf

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,34 @@
55
##############################################################################
66

77
locals {
8-
kp_backup_crn = var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.key_protect_key_crn
8+
# The backup encryption key crn doesn't support Hyper Protect Crypto Service (HPCS) at the moment. If 'backup_encryption_key_crn' is null, will use 'kms_key_crn' as encryption key if its Key Protect key otherwise it will use using randomly generated keys.
9+
# https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs&interface=cli
10+
kp_backup_crn = var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : (can(regex(".*kms.*", var.kms_key_crn)) ? var.kms_key_crn : null)
11+
912
auto_scaling_enabled = var.auto_scaling == null ? [] : [1]
13+
kms_service = var.kms_key_crn != null ? (
14+
can(regex(".*kms.*", var.kms_key_crn)) ? "kms" : (
15+
can(regex(".*hs-crypto.*", var.kms_key_crn)) ? "hs-crypto" : null
16+
)
17+
) : null
18+
19+
# tflint-ignore: terraform_unused_declarations
20+
validate_hpcs_guid_input = var.skip_iam_authorization_policy == false && var.existing_kms_instance_guid == null ? tobool("A value must be passed for var.existing_kms_instance_guid when creating an instance, var.skip_iam_authorization_policy is false.") : true
21+
}
22+
23+
# Create IAM Authorization Policies to allow postgresql to access kms for the encryption key
24+
resource "ibm_iam_authorization_policy" "kms_policy" {
25+
count = var.skip_iam_authorization_policy ? 0 : 1
26+
source_service_name = "databases-for-postgresql"
27+
source_resource_group_id = var.resource_group_id
28+
target_service_name = local.kms_service
29+
target_resource_instance_id = var.existing_kms_instance_guid
30+
roles = ["Reader"]
1031
}
1132

1233
# Create postgresql database
1334
resource "ibm_database" "postgresql_db" {
35+
depends_on = [ibm_iam_authorization_policy.kms_policy]
1436
resource_group_id = var.resource_group_id
1537
name = var.name
1638
service = "databases-for-postgresql"
@@ -24,7 +46,7 @@ resource "ibm_database" "postgresql_db" {
2446
service_endpoints = var.service_endpoints
2547
configuration = var.configuration != null ? jsonencode(var.configuration) : null
2648

27-
key_protect_key = var.key_protect_key_crn
49+
key_protect_key = var.kms_key_crn
2850
backup_encryption_key_crn = local.kp_backup_crn
2951

3052
point_in_time_recovery_deployment_id = var.pitr_id

0 commit comments

Comments
 (0)