diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml index 9a791ad9..7cb4fa35 100644 --- a/.catalog-onboard-pipeline.yaml +++ b/.catalog-onboard-pipeline.yaml @@ -6,9 +6,17 @@ offerings: catalog_id: 7df1e4ca-d54c-4fd0-82ce-3d13247308cd offering_id: 7ee5876d-6e30-49d1-be25-259a442085e8 variations: - - name: standard + - name: fully-configurable mark_ready: true install_type: fullstack scc: instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 region: us-south + scope_resource_group_var_name: existing_resource_group_name + - name: security-enforced + mark_ready: true + install_type: fullstack + scc: + instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 + region: us-south + scope_resource_group_var_name: existing_resource_group_name diff --git a/.secrets.baseline b/.secrets.baseline index a933ea3d..88ee2d53 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2025-03-02T09:01:42Z", + "generated_at": "2025-06-24T13:00:25Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -87,7 +87,7 @@ "verified_result": null } ], - "solutions/standard/DA-types.md": [ + "solutions/fully-configurable/DA-types.md": [ { "hashed_secret": "44cdfc3615970ada14420caaaa5c5745fca06002", "is_secret": false, @@ -104,6 +104,16 @@ "type": "Secret Keyword", "verified_result": null } + ], + "tests/pr_test.go": [ + { + "hashed_secret": "8c7c51db5075ebd0369c51e9f14737d9b4c1c21d", + "is_secret": false, + "is_verified": false, + "line_number": 353, + "type": "Base64 High Entropy String", + "verified_result": null + } ] }, "version": "0.13.1+ibm.62.dss", diff --git a/README.md b/README.md index bb2b53cc..7bf50d57 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ You need the following permissions to run this module. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.9.0 | -| [ibm](#requirement\_ibm) | >= 1.70.0, <2.0.0 | +| [ibm](#requirement\_ibm) | >= 1.79.2, <2.0.0 | | [null](#requirement\_null) | >= 3.2.1, < 4.0.0 | -| [time](#requirement\_time) | >= 0.9.1 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | ### Modules @@ -76,16 +76,16 @@ You need the following permissions to run this module. | Name | Type | |------|------| -| [ibm_database.elasticsearch](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/database) | resource | -| [ibm_iam_authorization_policy.backup_kms_policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | -| [ibm_iam_authorization_policy.policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | -| [ibm_resource_key.service_credentials](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_key) | resource | -| [ibm_resource_tag.elasticsearch_tag](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_tag) | resource | +| [ibm_database.elasticsearch](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database) | resource | +| [ibm_iam_authorization_policy.backup_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_resource_key.service_credentials](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_key) | resource | +| [ibm_resource_tag.elasticsearch_tag](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_tag) | resource | | [null_resource.put_vectordb_model](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | | [null_resource.start_vectordb_model](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | | [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [time_sleep.wait_for_backup_kms_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | -| [ibm_database_connection.database_connection](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/database_connection) | data source | +| [ibm_database_connection.database_connection](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/database_connection) | data source | ### Inputs @@ -97,15 +97,15 @@ You need the following permissions to run this module. | [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 both provisioning is complete and the new deployment that uses that data starts. Specify a backup CRN is in the format `crn:v1:<...>:backup:`. If not specified, the database is provisioned empty. | `string` | `null` | no | | [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no | | [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of context-based restrictions rules to create. |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [cpu\_count](#input\_cpu\_count) | The dedicated CPU per member that is allocated. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling). | `number` | `0` | no | +| [disk\_mb](#input\_disk\_mb) | The disk that is allocated per member. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling). | `number` | `5120` | no | | [elasticsearch\_version](#input\_elasticsearch\_version) | The version of Databases for Elasticsearch to deploy. Possible values: `8.7`, `8.10`, `8.12`, `8.15` which requires an Enterprise Platinum pricing plan. If no value is specified, the current preferred version for IBM Cloud Databases is used. | `string` | `null` | no | | [elser\_model\_type](#input\_elser\_model\_type) | Trained ELSER model to be used for Elastic's Natural Language Processing. Possible values: `.elser_model_1`, `.elser_model_2` and `.elser_model_2_linux-x86_64`. Applies only if also 'plan' is set to 'platinum'. [Learn more](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html) | `string` | `".elser_model_2_linux-x86_64"` | no | | [enable\_elser\_model](#input\_enable\_elser\_model) | Set it to true to install and start the Elastic's Natural Language Processing model. Applies only if also 'plan' is set to 'platinum'. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-elser-embeddings-elasticsearch) | `bool` | `false` | no | | [kms\_key\_crn](#input\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no | -| [member\_cpu\_count](#input\_member\_cpu\_count) | The dedicated CPU per member that is allocated. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling). | `number` | `0` | no | -| [member\_disk\_mb](#input\_member\_disk\_mb) | The disk that is allocated per member. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling). | `number` | `5120` | no | | [member\_host\_flavor](#input\_member\_host\_flavor) | The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor). | `string` | `null` | no | -| [member\_memory\_mb](#input\_member\_memory\_mb) | The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling) | `number` | `4096` | no | | [members](#input\_members) | The number of members that are allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling). | `number` | `3` | no | +| [memory\_mb](#input\_memory\_mb) | The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling) | `number` | `4096` | no | | [name](#input\_name) | The name of the Databases for Elasticsearch instance. | `string` | n/a | yes | | [plan](#input\_plan) | The pricing plan for the Databases for Elasticsearch instance. Must be `enterprise` or `platinum` if the `elasticsearch_version` variable is set to `8.10` or later. | `string` | `"enterprise"` | no | | [region](#input\_region) | The region where you want to deploy your instance. | `string` | `"us-south"` | no | diff --git a/common-dev-assets b/common-dev-assets index d0c2b2a1..b76eee7e 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit d0c2b2a1d3cdf41f6a844bc17816199fe3f8b20f +Subproject commit b76eee7ec33d5b81b30828e37a02d2df595e0909 diff --git a/cra-config.yaml b/cra-config.yaml index 8a1d6b57..b87cc8be 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,12 +1,12 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "solutions/standard" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "solutions/fully-configurable" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" - 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" + TF_VAR_existing_resource_group_name: "geretain-test-elasticsearch" + TF_VAR_kms_encryption_enabled: true TF_VAR_provider_visibility: "public" - TF_VAR_resource_group_name: "test-es-cra" - TF_VAR_use_existing_resource_group: false + TF_VAR_prefix: "test" diff --git a/examples/backup-restore/version.tf b/examples/backup-restore/version.tf index 6f39952e..b211acf0 100644 --- a/examples/backup-restore/version.tf +++ b/examples/backup-restore/version.tf @@ -5,7 +5,7 @@ terraform { # module's version.tf (basic example), and 1 example that will always use the latest provider version (complete example). ibm = { source = "IBM-Cloud/ibm" - version = ">=1.70.0, <2.0.0" + version = ">=1.79.2, <2.0.0" } } } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index 18b25c7e..3f0e4007 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -50,6 +50,7 @@ variable "service_endpoints" { error_message = "Valid values for service_endpoints are 'public', 'public-and-private', and 'private'" } } + variable "member_host_flavor" { type = string description = "The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 509f9700..5677e7b1 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -4,7 +4,7 @@ terraform { # 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.70.0" + version = "1.79.2" } # The elasticsearch provider is not actually required by the module itself, just this example, so OK to use ">=" here instead of locking into a version elasticsearch = { diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 60b6b53d..22d70de8 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -80,7 +80,7 @@ module "icd_elasticsearch" { tags = var.resource_tags auto_scaling = var.auto_scaling member_host_flavor = "multitenant" - member_memory_mb = 4096 + memory_mb = 4096 # Example of how to use different KMS keys for data and backups use_ibm_owned_encryption_key = false diff --git a/examples/complete/version.tf b/examples/complete/version.tf index c07b9389..3f0c1bab 100644 --- a/examples/complete/version.tf +++ b/examples/complete/version.tf @@ -4,7 +4,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = ">=1.70.0, <2.0.0" + version = ">=1.79.2, <2.0.0" } } } diff --git a/examples/fscloud/version.tf b/examples/fscloud/version.tf index cdc76d38..03d8bdf3 100644 --- a/examples/fscloud/version.tf +++ b/examples/fscloud/version.tf @@ -4,7 +4,7 @@ terraform { # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.70.0" + version = ">= 1.79.2" } } } diff --git a/ibm_catalog.json b/ibm_catalog.json index b6bc40dd..d108f771 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -9,6 +9,7 @@ "target_terraform", "terraform", "data_management", + "database", "solution" ], "keywords": [ @@ -22,61 +23,79 @@ "nosql" ], "short_description": "Creates and configures an instance of IBM Cloud Databases for Elasticsearch.", - "long_description": "This architecture supports creating and configuring an instance of Databases for Elasticsearch with KMS encryption.", + "long_description": "This architecture supports creating and configuring an instance of [Databases for Elasticsearch](https://www.ibm.com/products/databases-for-elasticsearch), with optional KMS encryption.\n\nℹ️ This Terraform-based automation is part of a broader suite of IBM-maintained Infrastructure as Code (IaC) assets, each following the naming pattern \"Cloud automation for *servicename*\" and focusing on single IBM Cloud service. These single-service deployable architectures can be used on their own to streamline and automate service deployments through an [IaC approach](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-understanding-projects), or assembled together into a broader [automated IaC stack](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-config-stack) to automate the deployment of an end-to-end solution architecture.", "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/README.md", "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/main/images/elasticsearch_icon.svg", "provider_name": "IBM", "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in the repository [https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/issues](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/issues). Please note this product is not supported via the IBM Cloud Support Center.", "features": [ { - "title": "Creates an instance of Databases for Elasticsearch", - "description": "Creates and configures an IBM Cloud Databases for Elasticsearch instance." - }, - { - "title": "Supports KMS encryption", - "description": "Provides KMS encryption for the data that you store in the database." + "title": "KMS encryption", + "description": "Provides [KMS encryption](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-key-protect&interface=ui) for the data that you store in the database, enhancing data security." }, { - "title": "Supports autoscaling", - "description": "Provides the autoscaling to allow the database to increase resources in response to usage." + "title": "Autoscaling", + "description": "Provides the [autoscaling](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-autoscaling&interface=ui) to allow the database to increase resources in response to usage." }, { - "title": "Attaches access tags", + "title": "Access tags", "description": "Attaches access tags to the Elasticsearch instance." }, { - "title": "Supports backup restoration", - "description": "Provides database restoration using a backup created by a deployment with the same service ID." + "title": "Backup restoration", + "description": "Provides [database restoration](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-dashboard-backups&interface=ui) using a backup created by a deployment with the same service ID." } ], "flavors": [ { - "label": "Standard", - "name": "standard", + "label": "Fully configurable", + "name": "fully-configurable", + "index": 1, "install_type": "fullstack", - "working_directory": "solutions/standard", + "working_directory": "solutions/fully-configurable", "compliance": { "authority": "scc-v3", "profiles": [ { "profile_name": "IBM Cloud Framework for Financial Services", - "profile_version": "1.6.0" + "profile_version": "1.7.0" } ] }, "iam_permissions": [ + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Viewer" + ], + "service_name": "Resource group only", + "notes": "Viewer access is required in the resource group you want to provision in." + }, { "role_crns": [ "crn:v1:bluemix:public:iam::::role:Editor" ], "service_name": "databases-for-elasticsearch" + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "kms", + "notes": "[Optional] Editor access is required to create keys. It is only required when using Key Protect for encryption." + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "hs-crypto", + "notes": "[Optional] Editor access is required to create keys in HPCS. It is only required when using HPCS for encryption." } ], "architecture": { "features": [ { - "title": " Creates an instance of Databases for Elasticsearch", - "description": "This architecture creates an instance of IBM Cloud Databases for Elasticsearch with KMS encryption. It accepts or creates a resource group, and provides autoscaling rules." + "title": " ", + "description": "Configured to use IBM secure by default standards, but can be edited to fit your use case." } ], "diagrams": [ @@ -96,6 +115,7 @@ }, { "key": "provider_visibility", + "hidden": true, "options": [ { "displayname": "private", @@ -112,16 +132,19 @@ ] }, { - "key": "use_existing_resource_group", - "required": true - }, - { - "key": "resource_group_name", - "required": true + "key": "existing_resource_group_name", + "display_name": "resource_group", + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } }, { - "key": "prefix", - "required": true + "key": "prefix" }, { "key": "region", @@ -177,34 +200,10 @@ } ] }, - { - "key": "name" - }, - { - "key": "existing_elasticsearch_instance_crn" - }, - { - "key": "plan", - "options": [ - { - "displayname": "enterprise", - "value": "enterprise" - }, - { - "displayname": "platinum", - "value": "platinum" - } - ] - }, { "key": "elasticsearch_version", - "required": false, - "default_value": "__NULL__", + "required": true, "options": [ - { - "displayname": "preferred", - "value": "__NULL__" - }, { "displayname": "8.15", "value": "8.15" @@ -220,13 +219,42 @@ ] }, { - "key": "tags" + "key": "name" }, { - "key": "access_tags" + "key": "plan", + "options": [ + { + "displayname": "enterprise", + "value": "enterprise" + }, + { + "displayname": "platinum", + "value": "platinum" + } + ] }, { - "key": "auto_scaling" + "key": "resource_tags", + "type": "array", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "access_tags", + "type": "array", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } }, { "key": "members" @@ -244,19 +272,46 @@ "key": "member_host_flavor" }, { - "key": "admin_pass" + "key": "auto_scaling" }, { - "key": "users" + "key": "service_endpoints", + "options": [ + { + "displayname": "private", + "value": "private" + }, + { + "displayname": "public", + "value": "public" + }, + { + "displayname": "public-and-private", + "value": "public-and-private" + } + ] }, { "key": "service_credential_names" }, + { + "key": "service_credential_secrets", + "type": "array", + "custom_config": { + "type": "textarea", + "grouping": "deployment", + "original_grouping": "deployment" + } + }, + { + "key": "admin_pass" + }, { "key": "existing_secrets_manager_instance_crn" }, { "key": "existing_secrets_manager_endpoint_type", + "hidden": true, "options": [ { "displayname": "public", @@ -269,25 +324,41 @@ ] }, { - "key": "service_credential_secrets" + "key": "skip_elasticsearch_to_secrets_manager_auth_policy" }, { - "key": "use_existing_admin_pass_secrets_manager_secret_group" + "key": "admin_pass_secrets_manager_secret_group" }, { "key": "admin_pass_secrets_manager_secret_name" }, { - "key": "admin_pass_secrets_manager_secret_group" + "key": "use_existing_admin_pass_secrets_manager_secret_group" }, { - "key": "skip_elasticsearch_to_secrets_manager_auth_policy" + "key": "users", + "type": "array", + "custom_config": { + "type": "textarea", + "grouping": "deployment", + "original_grouping": "deployment" + } }, { "key": "ibmcloud_kms_api_key" }, + { + "key": "kms_encryption_enabled" + }, + { + "key": "existing_kms_instance_crn" + }, + { + "key": "existing_kms_key_crn" + }, { "key": "kms_endpoint_type", + "hidden": true, "options": [ { "displayname": "public", @@ -300,14 +371,13 @@ ] }, { - "key": "use_ibm_owned_encryption_key" + "key": "key_ring_name" }, { - "key": "existing_kms_instance_crn", - "required": true + "key": "key_name" }, { - "key": "existing_kms_key_crn" + "key": "backup_crn" }, { "key": "existing_backup_kms_key_crn" @@ -316,16 +386,10 @@ "key": "use_default_backup_encryption_key" }, { - "key": "elasticsearch_key_ring_name" - }, - { - "key": "elasticsearch_key_name" + "key": "skip_elasticsearch_kms_auth_policy" }, { - "key": "skip_es_kms_auth_policy" - }, - { - "key": "backup_crn" + "key": "existing_elasticsearch_instance_crn" }, { "key": "enable_elser_model" @@ -389,6 +453,328 @@ "key": "cbr_rules" } ] + }, + { + "label": "Security-enforced", + "name": "security-enforced", + "index": 2, + "install_type": "fullstack", + "working_directory": "solutions/security-enforced", + "compliance": { + "authority": "scc-v3", + "profiles": [ + { + "profile_name": "IBM Cloud Framework for Financial Services", + "profile_version": "1.7.0" + } + ] + }, + "iam_permissions": [ + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Viewer" + ], + "service_name": "Resource group only", + "notes": "Viewer access is required in the resource group you want to provision in." + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "databases-for-redis" + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "kms", + "notes": "[Optional] Editor access is required to create keys. It is required only if KMS encryption is enabled." + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "hs-crypto", + "notes": "[Optional] Editor access is required to create keys in HPCS. It is only required when using HPCS for encryption." + } + ], + "architecture": { + "features": [ + { + "title": " ", + "description": "Configured to use IBM secure by default standards that can't be changed." + } + ], + "diagrams": [ + { + "diagram": { + "caption": "Databases for Elasticsearch instance on IBM Cloud", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/main/reference-architecture/deployable-architecture-elasticsearch.svg", + "type": "image/svg+xml" + }, + "description": "This architecture supports creating and configuring an instance of Databases for Elasticsearch instance with KMS encryption." + } + ] + }, + "configuration": [ + { + "key": "ibmcloud_api_key" + }, + { + "key": "existing_resource_group_name", + "display_name": "resource_group", + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } + }, + { + "key": "prefix" + }, + { + "key": "region", + "required": true, + "options": [ + { + "displayname": "Chennai (che01)", + "value": "che01" + }, + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "London (eu-gb)", + "value": "eu-gb" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Osaka (jp-osa)", + "value": "jp-osa" + }, + { + "displayname": "Paris (par01)", + "value": "par01" + }, + { + "displayname": "Sao Paulo (br-sao)", + "value": "br-sao" + }, + { + "displayname": "Sydney (au-syd)", + "value": "au-syd" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + }, + { + "displayname": "Tokyo (jp-tok)", + "value": "jp-tok" + }, + { + "displayname": "Washington (us-east)", + "value": "us-east" + } + ] + }, +{ + "key": "plan", + "options": [ + { + "displayname": "enterprise", + "value": "enterprise" + }, + { + "displayname": "platinum", + "value": "platinum" + } + ] + }, + { + "key": "elasticsearch_version", + "required": true, + "options": [ + { + "displayname": "8.15", + "value": "8.15" + }, + { + "displayname": "8.12", + "value": "8.12" + }, + { + "displayname": "8.10", + "value": "8.10" + } + ] + }, + { + "key": "name" + }, + { + "key": "resource_tags", + "type": "array", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "access_tags", + "type": "array", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "members" + }, + { + "key": "member_memory_mb" + }, + { + "key": "member_cpu_count" + }, + { + "key": "member_disk_mb" + }, + { + "key": "member_host_flavor" + }, + { + "key": "auto_scaling" + }, + { + "key": "service_credential_names" + }, + { + "key": "service_credential_secrets", + "type": "array", + "custom_config": { + "type": "textarea", + "grouping": "deployment", + "original_grouping": "deployment" + } + }, + { + "key": "admin_pass" + }, + { + "key": "existing_secrets_manager_instance_crn" + }, + { + "key": "skip_elasticsearch_to_secrets_manager_auth_policy" + }, + { + "key": "admin_pass_secrets_manager_secret_group" + }, + { + "key": "admin_pass_secrets_manager_secret_name" + }, + { + "key": "use_existing_admin_pass_secrets_manager_secret_group" + }, + { + "key": "users", + "type": "array", + "custom_config": { + "type": "textarea", + "grouping": "deployment", + "original_grouping": "deployment" + } + }, + { + "key": "ibmcloud_kms_api_key" + }, + { + "key": "existing_kms_instance_crn", + "required": true + }, + { + "key": "existing_kms_key_crn" + }, + { + "key": "key_ring_name" + }, + { + "key": "key_name" + }, + { + "key": "backup_crn" + }, + { + "key": "existing_backup_kms_key_crn" + }, + { + "key": "skip_elasticsearch_kms_auth_policy" + }, + { + "key": "existing_elasticsearch_instance_crn" + }, + { + "key": "enable_elser_model" + }, + { + "key": "elser_model_type", + "options": [ + { + "displayname": ".elser_model_1", + "value": ".elser_model_1" + }, + { + "displayname": ".elser_model_2", + "value": ".elser_model_2" + }, + { + "displayname": ".elser_model_2_linux-x86_64", + "value": ".elser_model_2_linux-x86_64" + } + ] + }, + { + "key": "enable_kibana_dashboard" + }, + { + "key": "kibana_code_engine_new_project_name" + }, + { + "key": "kibana_code_engine_new_app_name" + }, + { + "key": "existing_code_engine_project_id" + }, + { + "key": "kibana_registry_namespace_image" + }, + { + "key": "kibana_image_digest" + }, + { + "key": "kibana_image_port" + }, + { + "key": "cbr_rules" + } + ] } ] } diff --git a/main.tf b/main.tf index 6a870a48..a22ebec4 100644 --- a/main.tf +++ b/main.tf @@ -1,15 +1,10 @@ -######################################################################################################################## -# Input variable validation -# (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400) -# -# TODO: Replace with terraform cross variable validation: https://github.ibm.com/GoldenEye/issues/issues/10836 -######################################################################################################################## - ######################################################################################################################## # Locals ######################################################################################################################## locals { + # If no value passed for 'backup_encryption_key_crn' use the value of 'kms_key_crn' and perform validation of 'kms_key_crn' to check if region is supported by backup encryption key. + # If 'use_ibm_owned_encryption_key' is true or 'use_default_backup_encryption_key' is true, default to null. # If no value is passed for 'backup_encryption_key_crn', then default to use 'kms_key_crn'. backup_encryption_key_crn = var.use_ibm_owned_encryption_key || var.use_default_backup_encryption_key ? null : (var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.kms_key_crn) @@ -68,12 +63,13 @@ locals { create_backup_kms_auth_policy = !var.use_ibm_owned_encryption_key && !var.skip_iam_authorization_policy && !var.use_same_kms_key_for_backups ? 1 : 0 } -resource "ibm_iam_authorization_policy" "policy" { +# Create IAM Authorization Policies to allow Elasticsearch to access KMS for the encryption key +resource "ibm_iam_authorization_policy" "kms_policy" { count = local.create_kms_auth_policy source_service_name = "databases-for-elasticsearch" source_resource_group_id = var.resource_group_id roles = ["Reader"] - description = "Allow all Elastic Search instances in the resource group ${var.resource_group_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_key_instance_guid}" + description = "Allow all Elasticsearch instances in the resource group ${var.resource_group_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_key_instance_guid}" resource_attributes { name = "serviceName" operator = "stringEquals" @@ -108,8 +104,9 @@ resource "ibm_iam_authorization_policy" "policy" { # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 resource "time_sleep" "wait_for_authorization_policy" { - count = local.create_kms_auth_policy - depends_on = [ibm_iam_authorization_policy.policy] + count = local.create_kms_auth_policy + depends_on = [ibm_iam_authorization_policy.kms_policy] + create_duration = "30s" } @@ -118,7 +115,7 @@ resource "ibm_iam_authorization_policy" "backup_kms_policy" { source_service_name = "databases-for-elasticsearch" source_resource_group_id = var.resource_group_id roles = ["Reader"] - description = "Allow all Elastic Search instances in the Resource Group ${var.resource_group_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_key_instance_guid}" + description = "Allow all Elasticsearch instances in the Resource Group ${var.resource_group_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_key_instance_guid}" resource_attributes { name = "serviceName" operator = "stringEquals" @@ -193,12 +190,12 @@ resource "ibm_database" "elasticsearch" { dynamic "group" { for_each = local.host_flavor_set && var.member_host_flavor != "multitenant" && var.backup_crn == null ? [1] : [] content { - group_id = "member" # Only member type is allowed for elasticsearch + group_id = "member" # Only member type is allowed for IBM Cloud Databases host_flavor { id = var.member_host_flavor } disk { - allocation_mb = var.member_disk_mb + allocation_mb = var.disk_mb } members { allocation_count = var.members @@ -210,18 +207,18 @@ resource "ibm_database" "elasticsearch" { dynamic "group" { for_each = local.host_flavor_set && var.member_host_flavor == "multitenant" && var.backup_crn == null ? [1] : [] content { - group_id = "member" # Only member type is allowed for elasticsearch + group_id = "member" # Only member type is allowed for IBM Cloud Databases host_flavor { id = var.member_host_flavor } disk { - allocation_mb = var.member_disk_mb + allocation_mb = var.disk_mb } memory { - allocation_mb = var.member_memory_mb + allocation_mb = var.memory_mb } cpu { - allocation_count = var.member_cpu_count + allocation_count = var.cpu_count } members { allocation_count = var.members @@ -231,17 +228,17 @@ resource "ibm_database" "elasticsearch" { ## This block is for if host_flavor IS NOT set dynamic "group" { - for_each = local.host_flavor_set == false && var.backup_crn == null ? [1] : [] + for_each = !local.host_flavor_set && var.backup_crn == null ? [1] : [] content { - group_id = "member" # Only member type is allowed for elasticsearch + group_id = "member" # Only member type is allowed for IBM Cloud Databases memory { - allocation_mb = var.member_memory_mb + allocation_mb = var.memory_mb } disk { - allocation_mb = var.member_disk_mb + allocation_mb = var.disk_mb } cpu { - allocation_count = var.member_cpu_count + allocation_count = var.cpu_count } members { allocation_count = var.members @@ -300,7 +297,6 @@ resource "ibm_resource_tag" "elasticsearch_tag" { tag_type = "access" } - ######################################################################################################################## # Context Based Restrictions ######################################################################################################################## diff --git a/modules/fscloud/main.tf b/modules/fscloud/main.tf index 9a52d8e6..c3d9c9a7 100644 --- a/modules/fscloud/main.tf +++ b/modules/fscloud/main.tf @@ -17,11 +17,11 @@ module "elasticsearch" { tags = var.tags plan = var.plan members = var.members - member_memory_mb = var.member_memory_mb + memory_mb = var.member_memory_mb admin_pass = var.admin_pass users = var.users - member_disk_mb = var.member_disk_mb - member_cpu_count = var.member_cpu_count + disk_mb = var.member_disk_mb + cpu_count = var.member_cpu_count member_host_flavor = var.member_host_flavor auto_scaling = var.auto_scaling service_credential_names = var.service_credential_names diff --git a/reference-architecture/deployable-architecture-elasticsearch.svg b/reference-architecture/deployable-architecture-elasticsearch.svg index 5ca6ee89..367df641 100644 --- a/reference-architecture/deployable-architecture-elasticsearch.svg +++ b/reference-architecture/deployable-architecture-elasticsearch.svg @@ -1,4 +1,4 @@ - + -
IBM Cloud
IBM Cloud
KMS Encryption
KMS Encryption
Region
Region
Resource Group
Resource Group
IBM Cloud Elastic Search Instance
IBM Cloud El...
Kibana Code Engine App
IBM Cloud Code Engine Project
IBM Cloud Code Engine Project
Text is not SVG - cannot display
\ No newline at end of file +IBM CloudRegionResource GroupDatabase for Elasticsearch
ES
ES
IBM Cloud Code Engine Project
IBM Cloud Code Engine Project
Kibana Code Engine App
[Optional] KMS
[Optional] KMS
Key Ring
Key Ring
elasticsearch-key
Text is not SVG - cannot display
\ No newline at end of file diff --git a/solutions/standard/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md similarity index 100% rename from solutions/standard/DA-cbr_rules.md rename to solutions/fully-configurable/DA-cbr_rules.md diff --git a/solutions/standard/DA-types.md b/solutions/fully-configurable/DA-types.md similarity index 100% rename from solutions/standard/DA-types.md rename to solutions/fully-configurable/DA-types.md diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md new file mode 100644 index 00000000..f099860c --- /dev/null +++ b/solutions/fully-configurable/README.md @@ -0,0 +1,3 @@ +# Cloud automation for Elasticsearch (Fully Configurable) + +:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template new file mode 100644 index 00000000..fbb545af --- /dev/null +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -0,0 +1,9 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "region": "us-south", + "resource_tags": $TAGS, + "name": $PREFIX, + "existing_resource_group_name": "geretain-test-permanent", + "kms_encryption_enabled": true, + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN +} diff --git a/solutions/standard/main.tf b/solutions/fully-configurable/main.tf similarity index 75% rename from solutions/standard/main.tf rename to solutions/fully-configurable/main.tf index fd4240df..4ce977f6 100644 --- a/solutions/standard/main.tf +++ b/solutions/fully-configurable/main.tf @@ -1,37 +1,36 @@ ####################################################################################################################### # Resource Group ####################################################################################################################### +locals { + prefix = var.prefix != null ? trimspace(var.prefix) != "" ? "${var.prefix}-" : "" : "" +} module "resource_group" { source = "terraform-ibm-modules/resource-group/ibm" version = "1.2.0" - resource_group_name = var.use_existing_resource_group == false ? ((var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.resource_group_name}" : var.resource_group_name) : null - existing_resource_group_name = var.use_existing_resource_group == true ? var.resource_group_name : null + existing_resource_group_name = var.existing_resource_group_name } -####################################################################################################################### -# KMS related variable validation -# (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400) -# -# TODO: Replace with terraform cross variable validation: https://github.ibm.com/GoldenEye/issues/issues/10836 -####################################################################################################################### - ####################################################################################################################### # KMS encryption key ####################################################################################################################### locals { - create_new_kms_key = var.existing_elasticsearch_instance_crn == null && !var.use_ibm_owned_encryption_key && var.existing_kms_key_crn == null ? 1 : 0 # no need to create any KMS resources if using existing Elasticsearch, passing an existing key, or using IBM owned keys - elasticsearch_key_name = (var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.elasticsearch_key_name}" : var.elasticsearch_key_name - elasticsearch_key_ring_name = (var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.elasticsearch_key_ring_name}" : var.elasticsearch_key_ring_name + use_ibm_owned_encryption_key = !var.kms_encryption_enabled + create_new_kms_key = ( + var.kms_encryption_enabled && + var.existing_elasticsearch_instance_crn == null && + var.existing_kms_key_crn == null + ) + elasticsearch_key_name = "${local.prefix}${var.key_name}" + elasticsearch_key_ring_name = "${local.prefix}${var.key_ring_name}" } - module "kms" { providers = { ibm = ibm.kms } - count = local.create_new_kms_key + count = local.create_new_kms_key ? 1 : 0 source = "terraform-ibm-modules/kms-all-inclusive/ibm" version = "5.1.7" create_key_protect_instance = false @@ -49,7 +48,7 @@ module "kms" { standard_key = false rotation_interval_month = 3 dual_auth_delete_enabled = false - force_delete = true + force_delete = true # Force delete must be set to true, or the terraform destroy will fail since the service does not de-register itself from the key until the reclamation period has expired. } ] } @@ -93,24 +92,23 @@ data "ibm_iam_account_settings" "iam_account_settings" { locals { account_id = data.ibm_iam_account_settings.iam_account_settings.account_id - create_cross_account_kms_auth_policy = var.existing_elasticsearch_instance_crn == null && !var.skip_es_kms_auth_policy && var.ibmcloud_kms_api_key != null && !var.use_ibm_owned_encryption_key - create_cross_account_backup_kms_auth_policy = var.existing_elasticsearch_instance_crn == null && !var.skip_es_kms_auth_policy && var.ibmcloud_kms_api_key != null && !var.use_ibm_owned_encryption_key && var.existing_backup_kms_key_crn != null + create_cross_account_kms_auth_policy = var.kms_encryption_enabled && !var.skip_elasticsearch_kms_auth_policy && var.ibmcloud_kms_api_key != null + create_cross_account_backup_kms_auth_policy = var.kms_encryption_enabled && !var.skip_elasticsearch_kms_auth_policy && var.ibmcloud_kms_api_key != null && var.existing_backup_kms_key_crn != null # If KMS encryption enabled (and existing ES instance is not being passed), parse details from the existing key if being passed, otherwise get it from the key that the DA creates - kms_account_id = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id - kms_service = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name - kms_instance_guid = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : module.kms_instance_crn_parser[0].service_instance - kms_key_crn = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.elasticsearch_key_ring_name, local.elasticsearch_key_name)].crn - kms_key_id = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : module.kms[0].keys[format("%s.%s", local.elasticsearch_key_ring_name, local.elasticsearch_key_name)].key_id - kms_region = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].region : module.kms_instance_crn_parser[0].region + kms_account_id = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id + kms_service = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name + kms_instance_guid = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : module.kms_instance_crn_parser[0].service_instance + kms_key_crn = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.elasticsearch_key_ring_name, local.elasticsearch_key_name)].crn + kms_key_id = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : module.kms[0].keys[format("%s.%s", local.elasticsearch_key_ring_name, local.elasticsearch_key_name)].key_id + kms_region = !var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].region : module.kms_instance_crn_parser[0].region # If creating KMS cross account policy for backups, parse backup key details from passed in key CRN backup_kms_account_id = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].account_id : local.kms_account_id backup_kms_service = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].service_name : local.kms_service backup_kms_instance_guid = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].service_instance : local.kms_instance_guid backup_kms_key_id = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].resource : local.kms_key_id - - backup_kms_key_crn = var.existing_elasticsearch_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_backup_kms_key_crn + backup_kms_key_crn = var.existing_elasticsearch_instance_crn != null || !var.kms_encryption_enabled ? null : var.existing_backup_kms_key_crn # Always use same key for backups unless user explicially passed a value for 'existing_backup_kms_key_crn' use_same_kms_key_for_backups = var.existing_backup_kms_key_crn == null ? true : false } @@ -123,7 +121,7 @@ resource "ibm_iam_authorization_policy" "kms_policy" { source_service_name = "databases-for-elasticsearch" source_resource_group_id = module.resource_group.resource_group_id roles = ["Reader"] - description = "Allow all Elastic Search instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_instance_guid}" + description = "Allow all Elasticsearch instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_instance_guid}" resource_attributes { name = "serviceName" operator = "stringEquals" @@ -171,7 +169,7 @@ resource "ibm_iam_authorization_policy" "backup_kms_policy" { source_service_name = "databases-for-elasticsearch" source_resource_group_id = module.resource_group.resource_group_id roles = ["Reader"] - description = "Allow all Elastic Search instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_instance_guid}" + description = "Allow all Elasticsearch instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_instance_guid}" resource_attributes { name = "serviceName" operator = "stringEquals" @@ -228,7 +226,9 @@ locals { # if - replace first char with J # elseif _ replace first char with K # else use asis - admin_pass = var.admin_pass == null ? (startswith(random_password.admin_password[0].result, "-") ? "J${substr(random_password.admin_password[0].result, 1, -1)}" : startswith(random_password.admin_password[0].result, "_") ? "K${substr(random_password.admin_password[0].result, 1, -1)}" : random_password.admin_password[0].result) : var.admin_pass + generated_admin_password = (length(random_password.admin_password) > 0 ? (startswith(random_password.admin_password[0].result, "-") ? "J${substr(random_password.admin_password[0].result, 1, -1)}" : startswith(random_password.admin_password[0].result, "_") ? "K${substr(random_password.admin_password[0].result, 1, -1)}" : random_password.admin_password[0].result) : null) + # admin password to use + admin_pass = var.admin_pass == null ? local.generated_admin_password : var.admin_pass } ####################################################################################################################### @@ -276,31 +276,32 @@ data "ibm_database_connection" "existing_connection" { # Create new instance module "elasticsearch" { count = var.existing_elasticsearch_instance_crn != null ? 0 : 1 - source = "../../modules/fscloud" + source = "../.." depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy] resource_group_id = module.resource_group.resource_group_id - name = (var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.name}" : var.name + name = "${local.prefix}${var.name}" region = var.region plan = var.plan - skip_iam_authorization_policy = var.skip_es_kms_auth_policy elasticsearch_version = var.elasticsearch_version - use_ibm_owned_encryption_key = var.use_ibm_owned_encryption_key + skip_iam_authorization_policy = var.kms_encryption_enabled ? var.skip_elasticsearch_kms_auth_policy : true + use_ibm_owned_encryption_key = local.use_ibm_owned_encryption_key kms_key_crn = local.kms_key_crn backup_encryption_key_crn = local.backup_kms_key_crn use_same_kms_key_for_backups = local.use_same_kms_key_for_backups use_default_backup_encryption_key = var.use_default_backup_encryption_key - backup_crn = var.backup_crn access_tags = var.access_tags - tags = var.tags + tags = var.resource_tags admin_pass = local.admin_pass users = var.users members = var.members member_host_flavor = var.member_host_flavor - member_memory_mb = var.member_memory_mb - member_disk_mb = var.member_disk_mb - member_cpu_count = var.member_cpu_count + memory_mb = var.member_memory_mb + disk_mb = var.member_disk_mb + cpu_count = var.member_cpu_count auto_scaling = var.auto_scaling service_credential_names = var.service_credential_names + backup_crn = var.backup_crn + service_endpoints = var.service_endpoints enable_elser_model = var.enable_elser_model elser_model_type = var.elser_model_type cbr_rules = var.cbr_rules @@ -322,7 +323,7 @@ locals { ####################################################################################################################### locals { - create_sm_auth_policy = var.skip_elasticsearch_to_secrets_manager_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1 + create_secrets_manager_auth_policy = var.skip_elasticsearch_to_secrets_manager_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1 } # Parse the Secrets Manager CRN @@ -333,10 +334,9 @@ module "sm_instance_crn_parser" { crn = var.existing_secrets_manager_instance_crn } -# create a service authorization between Secrets Manager and the target service (Elastic Search) +# create a service authorization between Secrets Manager and the target service (Elasticsearch) resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { - count = local.create_sm_auth_policy - depends_on = [module.elasticsearch] + count = local.create_secrets_manager_auth_policy source_service_name = "secrets-manager" source_resource_instance_id = local.existing_secrets_manager_instance_guid target_service_name = "databases-for-elasticsearch" @@ -346,14 +346,13 @@ resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { } # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 -resource "time_sleep" "wait_for_es_authorization_policy" { - count = local.create_sm_auth_policy +resource "time_sleep" "wait_for_elasticsearch_authorization_policy" { + count = local.create_secrets_manager_auth_policy depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager] create_duration = "30s" } locals { - # Build the structure of the service credential type secret service_credential_secrets = [ for service_credentials in var.service_credential_secrets : { secret_group_name = service_credentials.secret_group_name @@ -378,10 +377,10 @@ locals { # Build the structure of the arbitrary credential type secret for admin password admin_pass_secret = [{ - secret_group_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_group != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_group}" : var.admin_pass_secrets_manager_secret_group + secret_group_name = "${local.prefix}${var.admin_pass_secrets_manager_secret_group}" existing_secret_group = var.use_existing_admin_pass_secrets_manager_secret_group secrets = [{ - secret_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_name != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_name}" : var.admin_pass_secrets_manager_secret_name + secret_name = "${local.prefix}${var.admin_pass_secrets_manager_secret_name}" secret_type = "arbitrary" secret_payload_password = local.admin_pass } @@ -395,10 +394,9 @@ locals { existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? module.sm_instance_crn_parser[0].region : null } -# Create secret(s) module "secrets_manager_service_credentials" { - count = var.existing_secrets_manager_instance_crn == null ? 0 : 1 - depends_on = [time_sleep.wait_for_es_authorization_policy] + count = length(local.service_credential_secrets) > 0 ? 1 : 0 + depends_on = [time_sleep.wait_for_elasticsearch_authorization_policy] source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets" version = "2.3.1" existing_sm_instance_guid = local.existing_secrets_manager_instance_guid @@ -413,8 +411,8 @@ module "secrets_manager_service_credentials" { locals { code_engine_project_id = var.existing_code_engine_project_id != null ? var.existing_code_engine_project_id : null - code_engine_project_name = local.code_engine_project_id != null ? null : (var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.kibana_code_engine_new_project_name}" : var.kibana_code_engine_new_project_name - code_engine_app_name = (var.prefix != null && var.prefix != "") ? "${var.prefix}-${var.kibana_code_engine_new_app_name}" : var.kibana_code_engine_new_app_name + code_engine_project_name = local.code_engine_project_id != null ? null : "${local.prefix}${var.kibana_code_engine_new_project_name}" + code_engine_app_name = "${local.prefix}${var.kibana_code_engine_new_app_name}" kibana_version = var.enable_kibana_dashboard ? jsondecode(data.http.es_metadata[0].response_body).version.number : null } diff --git a/solutions/standard/outputs.tf b/solutions/fully-configurable/outputs.tf similarity index 75% rename from solutions/standard/outputs.tf rename to solutions/fully-configurable/outputs.tf index bc00a5ae..1f52d179 100644 --- a/solutions/standard/outputs.tf +++ b/solutions/fully-configurable/outputs.tf @@ -7,16 +7,16 @@ output "id" { value = local.elasticsearch_id } -output "guid" { - description = "Elasticsearch instance guid" - value = local.elasticsearch_guid -} - output "version" { description = "Elasticsearch instance version" value = local.elasticsearch_version } +output "guid" { + description = "Elasticsearch instance guid" + value = local.elasticsearch_guid +} + output "crn" { description = "Elasticsearch instance crn" value = local.elasticsearch_crn @@ -59,3 +59,19 @@ output "kibana_app_endpoint" { description = "Code Engine Kibana endpoint URL" value = var.enable_kibana_dashboard ? module.code_engine_kibana[0].app[local.code_engine_app_name].endpoint : null } + +output "cbr_rule_ids" { + description = "CBR rule ids created to restrict Elasticsearch" + value = var.existing_elasticsearch_instance_crn != null ? null : module.elasticsearch[0].cbr_rule_ids +} + +output "adminuser" { + description = "Database admin user name" + value = var.existing_elasticsearch_instance_crn != null ? null : module.elasticsearch[0].adminuser +} + +output "certificate_base64" { + description = "Database connection certificate" + value = var.existing_elasticsearch_instance_crn != null ? null : module.elasticsearch[0].certificate_base64 + sensitive = true +} diff --git a/solutions/fully-configurable/provider.tf b/solutions/fully-configurable/provider.tf new file mode 100644 index 00000000..e66dac2c --- /dev/null +++ b/solutions/fully-configurable/provider.tf @@ -0,0 +1,14 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region + visibility = var.provider_visibility + private_endpoint_type = (var.provider_visibility == "private" && var.region == "ca-mon") ? "vpe" : null +} + +provider "ibm" { + alias = "kms" + ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key + region = local.kms_region + visibility = var.provider_visibility + private_endpoint_type = (var.provider_visibility == "private" && var.region == "ca-mon") ? "vpe" : null +} diff --git a/solutions/standard/variables.tf b/solutions/fully-configurable/variables.tf similarity index 69% rename from solutions/standard/variables.tf rename to solutions/fully-configurable/variables.tf index 8657adfe..f8963168 100644 --- a/solutions/standard/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -1,5 +1,5 @@ ############################################################################## -# DA extra +# Input Variables ############################################################################## variable "ibmcloud_api_key" { @@ -8,36 +8,38 @@ variable "ibmcloud_api_key" { sensitive = true } -variable "provider_visibility" { - description = "Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints)." +variable "existing_resource_group_name" { type = string - default = "private" - - validation { - condition = contains(["public", "private", "public-and-private"], var.provider_visibility) - error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." - } + description = "The name of an existing resource group to provision resource in." + default = "Default" + nullable = false } variable "prefix" { type = string - description = "Prefix to add to all resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string." - default = "dev" -} + nullable = true + description = "The prefix to be added to all resources created by this solution. To skip using a prefix, set this value to null or an empty string. The prefix must begin with a lowercase letter and may contain only lowercase letters, digits, and hyphens '-'. It should not exceed 16 characters, must not end with a hyphen('-'), and can not contain consecutive hyphens ('--'). Example: prod-0205-cos. [Learn more](https://terraform-ibm-modules.github.io/documentation/#/prefix.md)." -############################################################################## -# Input Variables -############################################################################## - -variable "resource_group_name" { - type = string - description = "The name of a new or an existing resource group to provision the Databases for Elasicsearch in. If a prefix input variable is specified, the prefix is added to the name in the `-` format." -} + validation { + # - null and empty string is allowed + # - Must not contain consecutive hyphens (--): length(regexall("--", var.prefix)) == 0 + # - Starts with a lowercase letter: [a-z] + # - Contains only lowercase letters (a–z), digits (0–9), and hyphens (-) + # - Must not end with a hyphen (-): [a-z0-9] + condition = (var.prefix == null || var.prefix == "" ? true : + alltrue([ + can(regex("^[a-z][-a-z0-9]*[a-z0-9]$", var.prefix)), + length(regexall("--", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter and may contain only lowercase letters, digits, and hyphens '-'. It must not end with a hyphen('-'), and cannot contain consecutive hyphens ('--')." + } -variable "use_existing_resource_group" { - type = bool - description = "Whether to use an existing resource group." - default = false + validation { + # must not exceed 16 characters in length + condition = length(var.prefix) <= 16 + error_message = "Prefix must not exceed 16 characters." + } } variable "name" { @@ -46,29 +48,9 @@ variable "name" { default = "elasticsearch" } -variable "elasticsearch_version" { - type = string - description = "The version of the Databases for Elasticsearch instance. If no value is specified, the current preferred version of Databases for Elasticsearch is used." - default = null -} - -variable "backup_crn" { - type = string - 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." - default = null - - validation { - condition = anytrue([ - var.backup_crn == null, - can(regex("^crn:.*:backup:", var.backup_crn)) - ]) - error_message = "backup_crn must be null OR starts with 'crn:' and contains ':backup:'" - } -} - variable "region" { + description = "The region where you want to deploy your instance." type = string - description = "The region where you want to deploy your instance, or the region in which your existing instance is in." default = "us-south" validation { @@ -77,28 +59,37 @@ variable "region" { } } -variable "plan" { +variable "existing_elasticsearch_instance_crn" { type = string - description = "The name of the service plan for your Databases for Elasticsearch instance. Possible values: `enterprise`, `platinum`." - default = "platinum" + default = null + description = "The CRN of an existing Databases for Elasticsearch instance. If no value is specified, a new instance is created." } -variable "existing_elasticsearch_instance_crn" { +variable "elasticsearch_version" { + description = "The version of the Databases for Elasticsearch instance. If no value is specified, the current preferred version of Databases for Elasticsearch is used." type = string default = null - description = "The CRN of an existing Databases for Elasticsearch instance. If no value is specified, a new instance is created." +} + +variable "plan" { + type = string + description = "The name of the service plan for your Databases for Elasticsearch instance. Possible values: `enterprise`, `platinum`." + default = "platinum" + nullable = false } variable "enable_elser_model" { type = bool description = "Set it to true to install and start the Elastic's Natural Language Processing model. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-elser-embeddings-elasticsearch)" default = false + nullable = false } variable "elser_model_type" { type = string description = "Trained ELSER model to be used for Elastic's Natural Language Processing. Possible values: `.elser_model_1`, `.elser_model_2` and `.elser_model_2_linux-x86_64`. Applies only if also 'plan' is set to 'platinum' and 'enable_elser_model' is enabled. [Learn more](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html)" default = ".elser_model_2_linux-x86_64" + nullable = false validation { condition = contains([".elser_model_1", ".elser_model_2", ".elser_model_2_linux-x86_64"], var.elser_model_type) error_message = "The specified elser_model_type is not a valid selection!" @@ -109,6 +100,16 @@ variable "elser_model_type" { # ICD hosting model properties ############################################################################## +variable "service_endpoints" { + type = string + description = "The type of endpoint of the database instance. Possible values: `public`, `private`, `public-and-private`." + default = "private" + + validation { + condition = can(regex("public|public-and-private|private", var.service_endpoints)) + error_message = "Valid values for service_endpoints are 'public', 'public-and-private', and 'private'" + } +} variable "members" { type = number @@ -116,6 +117,12 @@ variable "members" { default = 3 } +variable "member_memory_mb" { + type = number + description = "The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)" + default = 4096 +} + variable "member_cpu_count" { type = number description = "The dedicated CPU per member that is allocated. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." @@ -140,15 +147,15 @@ variable "member_host_flavor" { } } -variable "member_memory_mb" { - type = number - description = "The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)" - default = 4096 +variable "service_credential_names" { + description = "Map of name, role for service credentials that you want to create for the database. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#svc-credential-name)" + type = map(string) + default = {} } variable "admin_pass" { type = string - description = "The password for the database administrator. If the admin password is null, then it is created automatically. You must set 'existing_secrets_manager_instance_crn' to store admin pass into secrets manager. You can specify more users in a user block." + description = "The password for the database administrator. If no admin password is provided (i.e., it is null), one will be generated automatically. Additional users can be added using a user block." default = null sensitive = true } @@ -157,23 +164,17 @@ variable "users" { type = list(object({ name = string password = string # pragma: allowlist secret - type = optional(string) + type = string # "type" is required to generate the connection string for the outputs. role = optional(string) })) - description = "The list of users that have access to the database. Multiple blocks are allowed. The user password must be 10-32 characters. In most cases, you can use IAM service credentials (by specifying `service_credential_names`) to control access to the database instance. This block creates native database users. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/standard/DA-types.md)." default = [] sensitive = true + description = "A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service_credential_names) is sufficient to control access to the Elasticsearch instance. This blocks creates native Elasticsearch database users. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#users)" } -variable "service_credential_names" { - type = map(string) - description = "The map of name and role for service credentials that you want to create for the database. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/standard/DA-types.md)." - default = {} -} - -variable "tags" { - type = list(any) - description = "The list of tags to be added to the Databases for Elasticsearch instance." +variable "resource_tags" { + type = list(string) + description = "The list of resource tags to be added to the Databases for Elasticsearch instance." default = [] } @@ -183,98 +184,46 @@ variable "access_tags" { default = [] } -############################################################## -# Auto Scaling -############################################################## - -variable "auto_scaling" { - type = object({ - disk = object({ - capacity_enabled = optional(bool, false) - free_space_less_than_percent = optional(number, 10) - io_above_percent = optional(number, 90) - io_enabled = optional(bool, false) - io_over_period = optional(string, "15m") - rate_increase_percent = optional(number, 10) - rate_limit_mb_per_member = optional(number, 3670016) - rate_period_seconds = optional(number, 900) - rate_units = optional(string, "mb") - }) - memory = object({ - io_above_percent = optional(number, 90) - io_enabled = optional(bool, false) - io_over_period = optional(string, "15m") - rate_increase_percent = optional(number, 10) - rate_limit_mb_per_member = optional(number, 114688) - rate_period_seconds = optional(number, 900) - rate_units = optional(string, "mb") - }) - }) - description = "The rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/standard/DA-types.md)." - default = null -} - ############################################################## # Encryption ############################################################## -variable "use_ibm_owned_encryption_key" { +variable "kms_encryption_enabled" { type = bool - description = "IBM Cloud Databases will secure your deployment's data at rest automatically with an encryption key that IBM hold. Alternatively, you may select your own Key Management System instance and encryption key (Key Protect or Hyper Protect Crypto Services) by setting this to false. If setting to false, a value must be passed for `existing_kms_instance_crn` to create a new key, or `existing_kms_key_crn` and/or `existing_backup_kms_key_crn` to use an existing key." + description = "Set to true to enable KMS encryption using customer-managed keys. When enabled, you must provide a value for at least one of the following: existing_kms_instance_crn, existing_kms_key_crn, or existing_backup_kms_key_crn. If set to false, IBM-owned encryption is used (i.e., encryption keys managed and held by IBM)." default = false - # this validation ensures IBM-owned key is not used when KMS details are provided validation { - condition = ( + condition = (!var.kms_encryption_enabled || var.existing_elasticsearch_instance_crn != null || - !(var.use_ibm_owned_encryption_key && ( - var.existing_kms_instance_crn != null || - var.existing_kms_key_crn != null || - var.existing_backup_kms_key_crn != null - )) + var.existing_kms_instance_crn != null || + var.existing_kms_key_crn != null || + var.existing_backup_kms_key_crn != null ) - error_message = "When setting values for 'existing_kms_instance_crn', 'existing_kms_key_crn' or 'existing_backup_kms_key_crn', the 'use_ibm_owned_encryption_key' input must be set to false." + error_message = "When 'kms_encryption_enabled' is true, you must provide either 'existing_backup_kms_key_crn', 'existing_kms_instance_crn' (to create a new key) or 'existing_kms_key_crn' (to use an existing key)." } - # this validation ensures key info is provided when IBM-owned key is disabled and no Elasticsearch instance is given validation { - condition = !( - var.existing_elasticsearch_instance_crn == null && - var.use_ibm_owned_encryption_key == false && - var.existing_kms_instance_crn == null && - var.existing_kms_key_crn == null - ) - error_message = "When 'use_ibm_owned_encryption_key' is false, you must provide either 'existing_kms_instance_crn' (to create a new key) or 'existing_kms_key_crn' (to use an existing key)." + condition = (var.existing_kms_instance_crn == null && var.existing_kms_key_crn == null && var.existing_backup_kms_key_crn == null) || var.kms_encryption_enabled + error_message = "When either 'existing_kms_instance_crn', 'existing_kms_key_crn' or 'existing_backup_kms_key_crn' is set then 'kms_encryption_enabled' must be set to true." } } variable "existing_kms_instance_crn" { type = string - description = "The CRN of a Key Protect or Hyper Protect Crypto Services instance. Required to create a new encryption key and key ring which will be used to encrypt both deployment data and backups. Applies only if `use_ibm_owned_encryption_key` is false. To use an existing key, pass values for `existing_kms_key_crn` and/or `existing_backup_kms_key_crn`. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." + description = "The CRN of a Key Protect or Hyper Protect Crypto Services instance. Required to create a new encryption key and key ring which will be used to encrypt both deployment data and backups. To use an existing key, pass values for `existing_kms_key_crn` and/or `existing_backup_kms_key_crn`. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." default = null } variable "existing_kms_key_crn" { type = string - description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the optional `existing_backup_kms_key_crn` input. If no value is passed a new key will be created in the instance specified in the `existing_kms_instance_crn` input. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." - default = null -} - -variable "existing_backup_kms_key_crn" { - type = string - description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false. If no value is passed, the value of `existing_kms_key_crn` is used. If no value is passed for `existing_kms_key_crn`, a new key will be created in the instance specified in the `existing_kms_instance_crn` input. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." + description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. By default this key is used for both deployment data and backups, but this behaviour can be altered using the optional `existing_backup_kms_key_crn` input. If no value is passed a new key will be created in the instance specified in the `existing_kms_instance_crn` input. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." default = null } -variable "use_default_backup_encryption_key" { - type = bool - description = "When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `existing_kms_key_crn`, in `existing_backup_kms_key_crn`, or with a new key that will be created in the instance specified in the `existing_kms_instance_crn` input. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data." - default = false -} - variable "kms_endpoint_type" { type = string - description = "The type of endpoint to use for communicating with the Key Protect or Hyper Protect Crypto Services instance. Possible values: `public`, `private`." + description = "The type of endpoint to use for communicating with the Key Protect or Hyper Protect Crypto Services instance. Possible values: `public`, `private`. Applies only if `existing_kms_key_crn` is not specified." default = "private" validation { condition = can(regex("public|private", var.kms_endpoint_type)) @@ -282,34 +231,102 @@ variable "kms_endpoint_type" { } } -variable "skip_es_kms_auth_policy" { +variable "skip_elasticsearch_kms_auth_policy" { type = bool - description = "Set to true to skip the creation of IAM authorization policies that permits all Databases for Elasticsearch instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true." + description = "Set to true to skip the creation of IAM authorization policies that permits all Databases for Elasticsearch instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `kms_encryption_enabled` is false." default = false } -variable "elasticsearch_key_ring_name" { +variable "ibmcloud_kms_api_key" { + type = string + description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Elastic Search instance. Leave this input empty if the same account owns both instances." + sensitive = true + default = null +} + +variable "key_ring_name" { type = string default = "elasticsearch-key-ring" - description = "The name for the key ring created for the ElasticSearch key. Applies only if not specifying an existing key or using IBM owned keys. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + description = "The name for the key ring created for the ElasticSearch key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." } -variable "elasticsearch_key_name" { +variable "key_name" { type = string default = "elasticsearch-key" - description = "The name for the key created for the ElasticSearch key. Applies only if not specifying an existing key or using IBM owned keys. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + description = "The name for the key created for the ElasticSearch key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." } -variable "ibmcloud_kms_api_key" { +variable "existing_backup_kms_key_crn" { type = string - description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Elastic Search instance. Leave this input empty if the same account owns both instances." - sensitive = true + description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `kms_encryption_enabled` is true. If no value is passed, the value of `existing_kms_key_crn` is used. If no value is passed for `existing_kms_key_crn`, a new key will be created in the instance specified in the `existing_kms_instance_crn` input. Alternatively set `kms_encryption_enabled` to false to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." default = null } -############################################################################## -## Secrets Manager Service Credentials -############################################################################## +variable "use_default_backup_encryption_key" { + type = bool + description = "When `kms_encryption_enabled` is set to true, backups will be encrypted with either the key specified in `existing_kms_key_crn`, in `existing_backup_kms_key_crn`, or with a new key that will be created in the instance specified in the `existing_kms_instance_crn` input. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `kms_encryption_enabled` to false to use the default encryption for both backups and deployment data." + default = false +} + +variable "backup_crn" { + type = string + 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." + default = null + + validation { + condition = anytrue([ + var.backup_crn == null, + can(regex("^crn:.*:backup:", var.backup_crn)) + ]) + error_message = "backup_crn must be null OR starts with 'crn:' and contains ':backup:'" + } +} + +variable "provider_visibility" { + description = "Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints)." + type = string + default = "private" + + validation { + condition = contains(["public", "private", "public-and-private"], var.provider_visibility) + error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." + } +} + +############################################################## +# Auto Scaling +############################################################## + +variable "auto_scaling" { + type = object({ + disk = object({ + capacity_enabled = optional(bool, false) + free_space_less_than_percent = optional(number, 10) + io_above_percent = optional(number, 90) + io_enabled = optional(bool, false) + io_over_period = optional(string, "15m") + rate_increase_percent = optional(number, 10) + rate_limit_mb_per_member = optional(number, 3670016) + rate_period_seconds = optional(number, 900) + rate_units = optional(string, "mb") + }) + memory = object({ + io_above_percent = optional(number, 90) + io_enabled = optional(bool, false) + io_over_period = optional(string, "15m") + rate_increase_percent = optional(number, 10) + rate_limit_mb_per_member = optional(number, 114688) + rate_period_seconds = optional(number, 900) + rate_units = optional(string, "mb") + }) + }) + description = "Optional rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#autoscaling)" + default = null +} + +############################################################################# +# Secrets Manager Service Credentials +############################################################################# variable "existing_secrets_manager_instance_crn" { type = string @@ -345,7 +362,7 @@ variable "service_credential_secrets" { })) })) default = [] - 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)." + description = "Service credential secrets configuration for Databases for Elasticsearch. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#service-credential-secrets)." validation { # Service roles CRNs can be found at https://cloud.ibm.com/iam/roles, select the IBM Cloud Database and select the role @@ -370,7 +387,7 @@ variable "service_credential_secrets" { variable "skip_elasticsearch_to_secrets_manager_auth_policy" { type = bool default = false - description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Databases for Elasticsearch. Set to `true` to use an existing policy." + description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Databases for Elasticsearch. If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the Elasticsearch instance created by the Deployable Architecture. Set to `true` to use an existing policy. The value of this is ignored if any value for 'existing_secrets_manager_instance_crn' is not passed." } variable "admin_pass_secrets_manager_secret_group" { @@ -459,7 +476,7 @@ variable "kibana_image_port" { } variable "kibana_visibility" { - description = "Specify the visibility of Kibana application in order to define which endpoint is available for receiving the requests. Valid values are 'local_public', 'local_private' and 'local' and it is only applicable if `enable_kibana_dashboard` is true. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/standard/DA-types.md#options-for-kibana_visibility)." + description = "Specify the visibility of Kibana application in order to define which endpoint is available for receiving the requests. Valid values are 'local_public', 'local_private' and 'local' and it is only applicable if `enable_kibana_dashboard` is true. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#options-for-kibana_visibility)." type = string default = "local_private" validation { @@ -488,6 +505,6 @@ variable "cbr_rules" { })) }))) })) - description = "(Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/standard/DA-cbr_rules.md)" + description = "(Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/fully-configurable/DA-cbr_rules.md)" default = [] } diff --git a/solutions/standard/version.tf b/solutions/fully-configurable/version.tf similarity index 100% rename from solutions/standard/version.tf rename to solutions/fully-configurable/version.tf diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md new file mode 100644 index 00000000..da8cc16f --- /dev/null +++ b/solutions/security-enforced/README.md @@ -0,0 +1,3 @@ +# Cloud automation for Elasticsearch (Security-enforced) + +:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). diff --git a/solutions/standard/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template similarity index 61% rename from solutions/standard/catalogValidationValues.json.template rename to solutions/security-enforced/catalogValidationValues.json.template index e69e502f..693f534a 100644 --- a/solutions/standard/catalogValidationValues.json.template +++ b/solutions/security-enforced/catalogValidationValues.json.template @@ -1,8 +1,8 @@ { "ibmcloud_api_key": $VALIDATION_APIKEY, "region": "us-south", - "tags": $TAGS, + "resource_tags": $TAGS, "name": $PREFIX, - "resource_group_name": $PREFIX, + "existing_resource_group_name": "geretain-test-permanent", "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN } diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf new file mode 100644 index 00000000..12f28ba8 --- /dev/null +++ b/solutions/security-enforced/main.tf @@ -0,0 +1,58 @@ +module "elasticsearch" { + source = "../fully-configurable" + ibmcloud_api_key = var.ibmcloud_api_key + existing_resource_group_name = var.existing_resource_group_name + prefix = var.prefix + name = var.name + provider_visibility = "private" + region = var.region + existing_elasticsearch_instance_crn = var.existing_elasticsearch_instance_crn + elasticsearch_version = var.elasticsearch_version + backup_crn = var.backup_crn + plan = var.plan + enable_elser_model = var.enable_elser_model + elser_model_type = var.elser_model_type + # ICD hosting model properties + members = var.members + member_memory_mb = var.member_memory_mb + member_cpu_count = var.member_cpu_count + member_disk_mb = var.member_disk_mb + member_host_flavor = var.member_host_flavor + service_credential_names = var.service_credential_names + admin_pass = var.admin_pass + users = var.users + resource_tags = var.resource_tags + access_tags = var.access_tags + # Encryption + kms_encryption_enabled = true + existing_kms_instance_crn = var.existing_kms_instance_crn + existing_kms_key_crn = var.existing_kms_key_crn + kms_endpoint_type = "private" + skip_elasticsearch_kms_auth_policy = var.skip_elasticsearch_kms_auth_policy + ibmcloud_kms_api_key = var.ibmcloud_kms_api_key + key_ring_name = var.key_ring_name + key_name = var.key_name + existing_backup_kms_key_crn = var.existing_backup_kms_key_crn + use_default_backup_encryption_key = false + # Auto Scaling + auto_scaling = var.auto_scaling + # Secrets Manager Service Credentials + existing_secrets_manager_instance_crn = var.existing_secrets_manager_instance_crn + existing_secrets_manager_endpoint_type = "private" + service_credential_secrets = var.service_credential_secrets + skip_elasticsearch_to_secrets_manager_auth_policy = var.skip_elasticsearch_to_secrets_manager_auth_policy + admin_pass_secrets_manager_secret_group = var.admin_pass_secrets_manager_secret_group + use_existing_admin_pass_secrets_manager_secret_group = var.use_existing_admin_pass_secrets_manager_secret_group + admin_pass_secrets_manager_secret_name = var.admin_pass_secrets_manager_secret_name + service_endpoints = "private" + # Kibana Configuration + kibana_code_engine_new_project_name = var.kibana_code_engine_new_project_name + kibana_code_engine_new_app_name = var.kibana_code_engine_new_app_name + existing_code_engine_project_id = var.existing_code_engine_project_id + enable_kibana_dashboard = var.enable_kibana_dashboard + kibana_registry_namespace_image = var.kibana_registry_namespace_image + kibana_image_digest = var.kibana_image_digest + kibana_image_port = var.kibana_image_port + kibana_visibility = "local_private" + cbr_rules = var.cbr_rules +} diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf new file mode 100644 index 00000000..34b0f96f --- /dev/null +++ b/solutions/security-enforced/outputs.tf @@ -0,0 +1,61 @@ +############################################################################## +# Outputs +############################################################################## + +output "id" { + description = "Elasticsearch instance id" + value = module.elasticsearch.id +} + +output "version" { + description = "Elasticsearch instance version" + value = module.elasticsearch.version +} + +output "guid" { + description = "Elasticsearch instance guid" + value = module.elasticsearch.guid +} + +output "crn" { + description = "Elasticsearch instance crn" + value = module.elasticsearch.crn +} + +output "service_credentials_json" { + description = "Service credentials json map" + value = module.elasticsearch.service_credentials_json + sensitive = true +} + +output "service_credentials_object" { + description = "Service credentials object" + value = module.elasticsearch.service_credentials_object + sensitive = true +} + +output "hostname" { + description = "Database connection hostname" + value = module.elasticsearch.hostname +} + +output "port" { + description = "Database connection port" + value = module.elasticsearch.port +} + +output "cbr_rule_ids" { + description = "CBR rule ids created to restrict Elasticsearch" + value = module.elasticsearch.cbr_rule_ids +} + +output "adminuser" { + description = "Database admin user name" + value = module.elasticsearch.adminuser +} + +output "certificate_base64" { + description = "Database connection certificate" + value = module.elasticsearch.certificate_base64 + sensitive = true +} diff --git a/solutions/security-enforced/provider.tf b/solutions/security-enforced/provider.tf new file mode 100644 index 00000000..4c6add22 --- /dev/null +++ b/solutions/security-enforced/provider.tf @@ -0,0 +1 @@ +# Explicit provider config not required here as provider config in fully-configurable is used diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf new file mode 100644 index 00000000..456d7d0b --- /dev/null +++ b/solutions/security-enforced/variables.tf @@ -0,0 +1,435 @@ +############################################################################## +# Input Variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API key to deploy resources." + sensitive = true +} + +variable "existing_resource_group_name" { + type = string + description = "The name of an existing resource group to provision resource in." + default = "Default" + nullable = false +} + +variable "prefix" { + type = string + nullable = true + description = "The prefix to be added to all resources created by this solution. To skip using a prefix, set this value to null or an empty string. The prefix must begin with a lowercase letter and may contain only lowercase letters, digits, and hyphens '-'. It should not exceed 16 characters, must not end with a hyphen('-'), and can not contain consecutive hyphens ('--'). Example: prod-0205-cos. [Learn more](https://terraform-ibm-modules.github.io/documentation/#/prefix.md)." + + validation { + # - null and empty string is allowed + # - Must not contain consecutive hyphens (--): length(regexall("--", var.prefix)) == 0 + # - Starts with a lowercase letter: [a-z] + # - Contains only lowercase letters (a–z), digits (0–9), and hyphens (-) + # - Must not end with a hyphen (-): [a-z0-9] + condition = (var.prefix == null || var.prefix == "" ? true : + alltrue([ + can(regex("^[a-z][-a-z0-9]*[a-z0-9]$", var.prefix)), + length(regexall("--", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter and may contain only lowercase letters, digits, and hyphens '-'. It must not end with a hyphen('-'), and cannot contain consecutive hyphens ('--')." + } + + validation { + # must not exceed 16 characters in length + condition = length(var.prefix) <= 16 + error_message = "Prefix must not exceed 16 characters." + } +} + +variable "name" { + type = string + description = "The name of the Databases for Elasticsearch instance. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "elasticsearch" +} + +variable "region" { + description = "The region where you want to deploy your instance." + type = string + default = "us-south" +} + +variable "existing_elasticsearch_instance_crn" { + type = string + default = null + description = "The CRN of an existing Databases for Elasticsearch instance. If no value is specified, a new instance is created." +} + +variable "elasticsearch_version" { + description = "The version of the Databases for Elasticsearch instance. If no value is specified, the current preferred version of Databases for Elasticsearch is used." + type = string + default = null +} + +variable "plan" { + type = string + description = "The name of the service plan for your Databases for Elasticsearch instance. Possible values: `enterprise`, `platinum`." + default = "platinum" + nullable = false +} + +variable "enable_elser_model" { + type = bool + description = "Set it to true to install and start the Elastic's Natural Language Processing model. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-elser-embeddings-elasticsearch)" + default = false + nullable = false +} + +variable "elser_model_type" { + type = string + description = "Trained ELSER model to be used for Elastic's Natural Language Processing. Possible values: `.elser_model_1`, `.elser_model_2` and `.elser_model_2_linux-x86_64`. Applies only if also 'plan' is set to 'platinum' and 'enable_elser_model' is enabled. [Learn more](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html)" + default = ".elser_model_2_linux-x86_64" + nullable = false + validation { + condition = contains([".elser_model_1", ".elser_model_2", ".elser_model_2_linux-x86_64"], var.elser_model_type) + error_message = "The specified elser_model_type is not a valid selection!" + } +} + +############################################################################## +# ICD hosting model properties +############################################################################## + +variable "members" { + type = number + description = "The number of members that are allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." + default = 3 +} + +variable "member_memory_mb" { + type = number + description = "The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)" + default = 4096 +} + +variable "member_cpu_count" { + type = number + description = "The dedicated CPU per member that is allocated. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." + default = 3 +} + +variable "member_disk_mb" { + type = number + description = "The disk that is allocated per member. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." + default = 5120 +} + +# Use new hosting model for all DA +variable "member_host_flavor" { + type = string + description = "The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." + default = "b3c.4x16.encrypted" + # Prevent null or "", require multitenant or a machine type + validation { + condition = (length(var.member_host_flavor) > 0) + error_message = "Member host flavor must be specified. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." + } +} + +variable "service_credential_names" { + description = "Map of name, role for service credentials that you want to create for the database. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#svc-credential-name)" + type = map(string) + default = {} +} + +variable "admin_pass" { + type = string + description = "The password for the database administrator. If no admin password is provided (i.e., it is null), one will be generated automatically. Additional users can be added using a user block." + default = null + sensitive = true +} + +variable "users" { + type = list(object({ + name = string + password = string # pragma: allowlist secret + type = string # "type" is required to generate the connection string for the outputs. + role = optional(string) + })) + default = [] + sensitive = true + description = "A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service_credential_names) is sufficient to control access to the Elasticsearch instance. This blocks creates native Elasticsearch database users. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#users)" +} + +variable "resource_tags" { + type = list(string) + description = "The list of resource tags to be added to the Databases for Elasticsearch instance." + default = [] +} + +variable "access_tags" { + type = list(string) + description = "A list of access tags to apply to the Databases for Elasticsearch instance created by the solution. [Learn more](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial)." + default = [] +} + +############################################################## +# Encryption +############################################################## + +variable "existing_kms_instance_crn" { + type = string + description = "The CRN of a Key Protect or Hyper Protect Crypto Services instance. Required to create a new encryption key and key ring which will be used to encrypt both deployment data and backups. To use an existing key, pass values for `existing_kms_key_crn` and/or `existing_backup_kms_key_crn`. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." + default = null +} + +variable "existing_kms_key_crn" { + type = string + description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. By default this key is used for both deployment data and backups, but this behaviour can be altered using the optional `existing_backup_kms_key_crn` input. If no value is passed a new key will be created in the instance specified in the `existing_kms_instance_crn` input. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)." + default = null + + + validation { + condition = ( + (var.existing_kms_key_crn != null && var.existing_kms_instance_crn == null) || + (var.existing_kms_key_crn == null && var.existing_kms_instance_crn != null) + ) + error_message = "Either existing_kms_key_crn or existing_kms_instance_crn must be set, but not both." + } +} + +variable "skip_elasticsearch_kms_auth_policy" { + type = bool + description = "Whether to create an IAM authorization policy that permits all Databases for Elasticsearch 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." + default = false +} + +variable "ibmcloud_kms_api_key" { + type = string + description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the ElasticSearch instance. Leave this input empty if the same account owns both instances." + sensitive = true + default = null +} + +variable "key_ring_name" { + type = string + default = "elasticsearch-key-ring" + description = "The name for the key ring created for the Databases for ElasticSearch key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "key_name" { + type = string + default = "elasticsearch-key" + description = "The name for the key created for the Databases for ElasticSearch key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "existing_backup_kms_key_crn" { + type = string + description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. If no value is passed, the value of `existing_kms_key_crn` is used. If no value is passed for `existing_kms_key_crn`, a new key will be created in the instance specified in the `existing_kms_instance_crn` input." + default = null +} + +variable "backup_crn" { + type = string + 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." + default = null + + validation { + condition = anytrue([ + var.backup_crn == null, + can(regex("^crn:.*:backup:", var.backup_crn)) + ]) + error_message = "backup_crn must be null OR starts with 'crn:' and contains ':backup:'" + } +} + +############################################################## +# Auto Scaling +############################################################## + +variable "auto_scaling" { + type = object({ + disk = object({ + capacity_enabled = optional(bool, false) + free_space_less_than_percent = optional(number, 10) + io_above_percent = optional(number, 90) + io_enabled = optional(bool, false) + io_over_period = optional(string, "15m") + rate_increase_percent = optional(number, 10) + rate_limit_mb_per_member = optional(number, 3670016) + rate_period_seconds = optional(number, 900) + rate_units = optional(string, "mb") + }) + memory = object({ + io_above_percent = optional(number, 90) + io_enabled = optional(bool, false) + io_over_period = optional(string, "15m") + rate_increase_percent = optional(number, 10) + rate_limit_mb_per_member = optional(number, 114688) + rate_period_seconds = optional(number, 900) + rate_units = optional(string, "mb") + }) + }) + description = "Optional rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/fully-configurable/DA-types.md#autoscaling)" + default = null +} + +############################################################################# +# Secrets Manager Service Credentials +############################################################################# + +variable "existing_secrets_manager_instance_crn" { + type = string + default = null + description = "The CRN of existing secrets manager to use to create service credential secrets for Databases for Elasticsearch instance." +} + +variable "service_credential_secrets" { + type = list(object({ + secret_group_name = string + secret_group_description = optional(string) + existing_secret_group = optional(bool) + service_credentials = list(object({ + secret_name = string + service_credentials_source_service_role_crn = string + secret_labels = optional(list(string)) + secret_auto_rotation = optional(bool) + secret_auto_rotation_unit = optional(string) + secret_auto_rotation_interval = optional(number) + service_credentials_ttl = optional(string) + service_credential_secret_description = optional(string) + + })) + })) + default = [] + description = "Service credential secrets configuration for Databases for Elasticsearch. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/blob/main/solutions/fully-configurable/DA-types.md#service-credential-secrets)." + + validation { + # Service roles CRNs can be found at https://cloud.ibm.com/iam/roles, select the IBM Cloud Database and select the role + condition = alltrue([ + for group in var.service_credential_secrets : alltrue([ + # crn:v?:bluemix; two non-empty segments; three possibly empty segments; :serviceRole or role: non-empty segment + for credential in group.service_credentials : can(regex("^crn:v[0-9]:bluemix(:..*){2}(:.*){3}:(serviceRole|role):..*$", credential.service_credentials_source_service_role_crn)) + ]) + ]) + error_message = "service_credentials_source_service_role_crn must be a serviceRole CRN. See https://cloud.ibm.com/iam/roles" + } + + validation { + condition = ( + length(var.service_credential_secrets) == 0 || + var.existing_secrets_manager_instance_crn != null + ) + error_message = "`existing_secrets_manager_instance_crn` is required when adding service credentials to a secrets manager secret." + } +} + +variable "skip_elasticsearch_to_secrets_manager_auth_policy" { + type = bool + default = false + description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Databases for Elasticsearch. If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the Elasticsearch instance created by the Deployable Architecture. Set to `true` to use an existing policy. The value of this is ignored if any value for 'existing_secrets_manager_instance_crn' is not passed." +} + +variable "admin_pass_secrets_manager_secret_group" { + type = string + description = "The name of a new or existing secrets manager secret group for admin password. To use existing secret group, `use_existing_admin_pass_secrets_manager_secret_group` must be set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "elasticsearch-secrets" + + validation { + condition = ( + var.existing_secrets_manager_instance_crn == null || + var.admin_pass_secrets_manager_secret_group != null + ) + error_message = "`admin_pass_secrets_manager_secret_group` is required when `existing_secrets_manager_instance_crn` is set." + } +} + +variable "use_existing_admin_pass_secrets_manager_secret_group" { + type = bool + description = "Whether to use an existing secrets manager secret group for admin password." + default = false +} + +variable "admin_pass_secrets_manager_secret_name" { + type = string + description = "The name of a new elasticsearch administrator secret. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "elasticsearch-admin-password" + + validation { + condition = ( + var.existing_secrets_manager_instance_crn == null || + var.admin_pass_secrets_manager_secret_name != null + ) + error_message = "`admin_pass_secrets_manager_secret_name` is required when `existing_secrets_manager_instance_crn` is set." + } +} + +############################################################## +# Kibana Configuration +############################################################## + +variable "kibana_code_engine_new_project_name" { + type = string + description = "The Code Engine project name. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "ce-kibana-project" +} + +variable "kibana_code_engine_new_app_name" { + type = string + description = "The Code Engine application name. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "ce-kibana-app" +} + +variable "existing_code_engine_project_id" { + type = string + description = "Existing code engine project ID to deploy Kibana. If no value is passed, a new code engine project will be created." + default = null +} + +variable "enable_kibana_dashboard" { + type = bool + description = "Set to true to deploy Kibana in Code Engine. NOTE: By default, the Kibana image will be pulled from the official Elastic registry (docker.elastic.co) and is not certified by IBM, however this can be overridden using the `kibana_registry_namespace_image` and `kibana_image_digest` inputs." + default = false +} + +variable "kibana_registry_namespace_image" { + type = string + description = "The Kibana image reference in the format of `[registry-url]/[namespace]/[image]`. This value is used only when `enable_kibana_dashboard` is set to true." + default = "docker.elastic.co/kibana/kibana" +} + +variable "kibana_image_digest" { + type = string + description = "When `enable_kibana_dashboard` is set to true, Kibana is deployed using an image tag compatible with the Elasticsearch version. Alternatively, an image digest in the format `sha256:xxxxx...` can also be specified but it must correspond to a version compatible with the Elasticsearch instance." + default = null + validation { + condition = var.kibana_image_digest == null || can(regex("^sha256:", var.kibana_image_digest)) + error_message = "If provided, the value of kibana_image_digest must start with 'sha256:'." + } + + +} +variable "kibana_image_port" { + description = "Specify the port number used to connect to the Kibana service exposed by the container image. Default port is 5601 and it is only applicable if `enable_kibana_dashboard` is true" + type = number + default = 5601 +} + +############################################################## +# Context-based restriction (CBR) +############################################################## + +variable "cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "(Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-elasticsearch/tree/main/solutions/fully-configurable/DA-cbr_rules.md)" + default = [] +} diff --git a/solutions/security-enforced/version.tf b/solutions/security-enforced/version.tf new file mode 100644 index 00000000..70b38b5b --- /dev/null +++ b/solutions/security-enforced/version.tf @@ -0,0 +1,6 @@ +terraform { + required_version = ">= 1.9.0" + # Lock DA into an exact provider version - renovate automation will keep it updated + required_providers { + } +} diff --git a/solutions/standard/README.md b/solutions/standard/README.md deleted file mode 100644 index 8fd577c9..00000000 --- a/solutions/standard/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# IBM Cloud Databases for Elasticsearch - -This architecture creates an instance of IBM Cloud Databases for Elasticsearch and supports provisioning of the following resources: - -- A resource group, if one is not passed in. -- A KMS root key, if one is not passed in. -- An IBM Cloud Databases for Elasticsearch instance with KMS encryption. -- Autoscaling rules for the database instance, if provided. -- Install and start the Elastic's Natural Language Processing model, if enabled. -- Kibana dashboard for Elasticsearch, if enabled. - -**Note on accessing Kibana:** If Kibana is enabled, you can access the Kibana application over a IBM private network using the method outlined [here](https://cloud.ibm.com/docs/codeengine?topic=codeengine-vpe). - -**Note on setting kibana_visibility:** When the Kibana application visibility is changed from private to public using kibana_visibility variable, it will become accessible from the public Internet. However, access via the IBM Cloud private network will no longer be available. This change takes effect immediately, potentially impacting active users or integrations. It is important to consider the associated security implications before proceeding. - -![fscloud-elastic-search](../../reference-architecture/deployable-architecture-elasticsearch.svg) - -:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). diff --git a/solutions/standard/moved.tf b/solutions/standard/moved.tf deleted file mode 100644 index ddd70738..00000000 --- a/solutions/standard/moved.tf +++ /dev/null @@ -1,4 +0,0 @@ -moved { - from = module.elasticsearch - to = module.elasticsearch[0] -} diff --git a/solutions/standard/provider.tf b/solutions/standard/provider.tf deleted file mode 100644 index 515e60c2..00000000 --- a/solutions/standard/provider.tf +++ /dev/null @@ -1,12 +0,0 @@ -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region - visibility = var.provider_visibility -} - -provider "ibm" { - alias = "kms" - ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key - region = local.kms_region - visibility = var.provider_visibility -} diff --git a/tests/pr_test.go b/tests/pr_test.go index 9925204a..3dc4f0e9 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -25,7 +25,8 @@ import ( const completeExampleTerraformDir = "examples/complete" const fscloudExampleTerraformDir = "examples/fscloud" -const standardSolutionTerraformDir = "solutions/standard" +const fullyConfigurableSolutionTerraformDir = "solutions/fully-configurable" +const securityEnforcedSolutionTerraformDir = "solutions/security-enforced" const latestVersion = "8.15" // Use existing resource group @@ -58,27 +59,25 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestRunStandardSolutionSchematics(t *testing.T) { +func TestRunFullyConfigurableSolutionSchematics(t *testing.T) { t.Parallel() options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, TarIncludePatterns: []string{ "*.tf", - fmt.Sprintf("%s/*.tf", standardSolutionTerraformDir), - fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir), - fmt.Sprintf("%s/*.tf", "modules/fscloud"), + fmt.Sprintf("%s/*.tf", fullyConfigurableSolutionTerraformDir), fmt.Sprintf("%s/*.sh", "scripts"), }, - TemplateFolder: standardSolutionTerraformDir, + TemplateFolder: fullyConfigurableSolutionTerraformDir, BestRegionYAMLPath: regionSelectionPath, - Prefix: "els-sr-da", + Prefix: "els-fc-da", ResourceGroup: resourceGroup, DeleteWorkspaceOnFail: false, WaitJobCompleteMinutes: 60, }) - serviceCredentialSecrets := []map[string]any{ + serviceCredentialSecrets := []map[string]interface{}{ { "secret_group_name": fmt.Sprintf("%s-secret-group", options.Prefix), "service_credentials": []map[string]string{ @@ -97,16 +96,16 @@ func TestRunStandardSolutionSchematics(t *testing.T) { options.TerraformVars = []testschematic.TestSchematicTerraformVar{ {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, - {Name: "existing_backup_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, {Name: "kms_endpoint_type", Value: "private", DataType: "string"}, - {Name: "resource_group_name", Value: options.Prefix, DataType: "string"}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, {Name: "plan", Value: "platinum", DataType: "string"}, {Name: "enable_elser_model", Value: true, DataType: "bool"}, {Name: "service_credential_names", Value: "{\"admin_test\": \"Administrator\", \"editor_test\": \"Editor\"}", DataType: "map(string)"}, {Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"}, {Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"}, - {Name: "admin_pass", Value: GetRandomAdminPassword(t), DataType: "string"}, + {Name: "service_endpoints", Value: "private", DataType: "string"}, {Name: "admin_pass_secrets_manager_secret_group", Value: options.Prefix, DataType: "string"}, {Name: "admin_pass_secrets_manager_secret_name", Value: options.Prefix, DataType: "string"}, {Name: "enable_kibana_dashboard", Value: true, DataType: "bool"}, @@ -118,24 +117,23 @@ func TestRunStandardSolutionSchematics(t *testing.T) { assert.Nil(t, err, "This should not have errored") } -func TestRunStandardUpgradeSolution(t *testing.T) { +func TestRunSecurityEnforcedUpgradeSolution(t *testing.T) { t.Parallel() options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ Testing: t, - TerraformDir: standardSolutionTerraformDir, + TerraformDir: securityEnforcedSolutionTerraformDir, BestRegionYAMLPath: regionSelectionPath, Prefix: "els-st-da-upg", ResourceGroup: resourceGroup, CheckApplyResultForUpgrade: true, }) - options.TerraformVars = map[string]any{ - "access_tags": permanentResources["accessTags"], - "existing_kms_instance_crn": permanentResources["hpcs_south_crn"], - "kms_endpoint_type": "public", - "resource_group_name": options.Prefix, - "provider_visibility": "public", + options.TerraformVars = map[string]interface{}{ + "prefix": options.Prefix, + "access_tags": permanentResources["accessTags"], + "existing_kms_instance_crn": permanentResources["hpcs_south_crn"], + "existing_resource_group_name": resourceGroup, // Currently, we can not have upgrade test for elser model, because test provision private endpoint for ES (fscloud profile), and script can not connect to private ES API without schematics // "plan": "platinum", // "enable_elser_model": true, @@ -149,6 +147,61 @@ func TestRunStandardUpgradeSolution(t *testing.T) { } } +func TestRunSecurityEnforcedSolutionSchematics(t *testing.T) { + t.Parallel() + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + TarIncludePatterns: []string{ + "*.tf", + fmt.Sprintf("%s/*.tf", securityEnforcedSolutionTerraformDir), + fmt.Sprintf("%s/*.tf", fullyConfigurableSolutionTerraformDir), + fmt.Sprintf("%s/*.sh", "scripts"), + }, + TemplateFolder: securityEnforcedSolutionTerraformDir, + BestRegionYAMLPath: regionSelectionPath, + Prefix: "els-se-da", + ResourceGroup: resourceGroup, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + + serviceCredentialSecrets := []map[string]interface{}{ + { + "secret_group_name": fmt.Sprintf("%s-secret-group", options.Prefix), + "service_credentials": []map[string]string{ + { + "secret_name": fmt.Sprintf("%s-cred-reader", options.Prefix), + "service_credentials_source_service_role_crn": "crn:v1:bluemix:public:iam::::role:Viewer", + }, + { + "secret_name": fmt.Sprintf("%s-cred-writer", options.Prefix), + "service_credentials_source_service_role_crn": "crn:v1:bluemix:public:iam::::role:Editor", + }, + }, + }, + } + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, + {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "plan", Value: "platinum", DataType: "string"}, + {Name: "enable_elser_model", Value: true, DataType: "bool"}, + {Name: "service_credential_names", Value: "{\"admin_test\": \"Administrator\", \"editor_test\": \"Editor\"}", DataType: "map(string)"}, + {Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"}, + {Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"}, + {Name: "admin_pass_secrets_manager_secret_group", Value: options.Prefix, DataType: "string"}, + {Name: "admin_pass_secrets_manager_secret_name", Value: options.Prefix, DataType: "string"}, + {Name: "enable_kibana_dashboard", Value: true, DataType: "bool"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + } + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") +} + func TestRunExistingInstance(t *testing.T) { t.Parallel() prefix := fmt.Sprintf("elastic-t-%s", strings.ToLower(random.UniqueId())) @@ -191,12 +244,12 @@ func TestRunExistingInstance(t *testing.T) { Testing: t, TarIncludePatterns: []string{ "*.tf", - fmt.Sprintf("%s/*.tf", standardSolutionTerraformDir), + fmt.Sprintf("%s/*.tf", fullyConfigurableSolutionTerraformDir), fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir), fmt.Sprintf("%s/*.tf", "modules/fscloud"), fmt.Sprintf("%s/*.sh", "scripts"), }, - TemplateFolder: standardSolutionTerraformDir, + TemplateFolder: fullyConfigurableSolutionTerraformDir, BestRegionYAMLPath: regionSelectionPath, Prefix: "els-sr-da", ResourceGroup: resourceGroup, @@ -205,11 +258,11 @@ func TestRunExistingInstance(t *testing.T) { }) options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "prefix", Value: options.Prefix, DataType: "string"}, {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, {Name: "existing_elasticsearch_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "elasticsearch_crn"), DataType: "string"}, - {Name: "resource_group_name", Value: fmt.Sprintf("%s-resource-group", prefix), DataType: "string"}, + {Name: "existing_resource_group_name", Value: fmt.Sprintf("%s-resource-group", prefix), DataType: "string"}, {Name: "region", Value: region, DataType: "string"}, - {Name: "use_existing_resource_group", Value: true, DataType: "bool"}, {Name: "provider_visibility", Value: "public", DataType: "string"}, } err := options.RunSchematicTest() @@ -229,22 +282,23 @@ func TestRunExistingInstance(t *testing.T) { } // Test the DA when using IBM owned encryption keys -func TestRunStandardSolutionIBMKeys(t *testing.T) { +func TestFullyConfigurableSolutionIBMKeys(t *testing.T) { t.Parallel() options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ Testing: t, - TerraformDir: standardSolutionTerraformDir, + TerraformDir: fullyConfigurableSolutionTerraformDir, Region: "us-south", - Prefix: "es-icd-key", + Prefix: "esicdkey", ResourceGroup: resourceGroup, }) options.TerraformVars = map[string]any{ "elasticsearch_version": "8.12", "provider_visibility": "public", - "resource_group_name": options.Prefix, - "use_ibm_owned_encryption_key": true, + "existing_resource_group_name": resourceGroup, + "kms_encryption_enabled": false, + "prefix": options.Prefix, } output, err := options.RunTestConsistency() @@ -255,8 +309,8 @@ func TestRunStandardSolutionIBMKeys(t *testing.T) { func TestPlanValidation(t *testing.T) { options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ Testing: t, - TerraformDir: standardSolutionTerraformDir, - Prefix: "validate-plan", + TerraformDir: fullyConfigurableSolutionTerraformDir, + Prefix: "val-plan", ResourceGroup: resourceGroup, Region: "us-south", // skip VPC region picker }) @@ -264,37 +318,39 @@ func TestPlanValidation(t *testing.T) { options.TerraformOptions.NoColor = true options.TerraformOptions.Logger = logger.Discard options.TerraformOptions.Vars = map[string]interface{}{ - "prefix": options.Prefix, - "region": "us-south", - "elasticsearch_version": "8.10", - "provider_visibility": "public", - "resource_group_name": options.Prefix, + "prefix": options.Prefix, + "existing_resource_group_name": resourceGroup, + "region": "us-south", + "elasticsearch_version": "8.10", + "provider_visibility": "public", } // Test the DA when using Elser model - var standardSolutionWithElserModelVars = map[string]interface{}{ + var fullyConfigurableSolutionWithElserModelVars = map[string]interface{}{ + "kms_encryption_enabled": true, "existing_kms_instance_crn": permanentResources["hpcs_south_crn"], "enable_elser_model": true, "plan": "platinum", } // Test the DA when using Kibana dashboard and existing KMS instance - var standardSolutionWithKibanaDashboardVars = map[string]interface{}{ + var fullyConfigurableSolutionWithKibanaDashboardVars = map[string]interface{}{ "enable_kibana_dashboard": true, + "kms_encryption_enabled": true, "existing_kms_instance_crn": permanentResources["hpcs_south_crn"], "plan": "enterprise", } // Test the DA when using IBM owned encryption key - var standardSolutionWithUseIbmOwnedEncKey = map[string]interface{}{ - "use_ibm_owned_encryption_key": true, + var fullyConfigurableSolutionWithUseIbmOwnedEncKey = map[string]interface{}{ + "kms_encryption_enabled": false, } // Create a map of the variables tfVarsMap := map[string]map[string]interface{}{ - "standardSolutionWithElserModelVars": standardSolutionWithElserModelVars, - "standardSolutionWithKibanaDashboardVars": standardSolutionWithKibanaDashboardVars, - "standardSolutionWithUseIbmOwnedEncKey": standardSolutionWithUseIbmOwnedEncKey, + "fullyConfigurableSolutionWithElserModelVars": fullyConfigurableSolutionWithElserModelVars, + "fullyConfigurableSolutionWithKibanaDashboardVars": fullyConfigurableSolutionWithKibanaDashboardVars, + "fullyConfigurableSolutionWithUseIbmOwnedEncKey": fullyConfigurableSolutionWithUseIbmOwnedEncKey, } _, initErr := terraform.InitE(t, options.TerraformOptions) diff --git a/variables.tf b/variables.tf index 5762f1ec..4b72a8b8 100644 --- a/variables.tf +++ b/variables.tf @@ -60,14 +60,14 @@ variable "members" { # Validation is done in the Terraform plan phase by the IBM provider, so no need to add extra validation here. } -variable "member_cpu_count" { +variable "cpu_count" { type = number description = "The dedicated CPU per member that is allocated. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." default = 0 # Validation is done in the Terraform plan phase by the IBM provider, so no need to add extra validation here. } -variable "member_disk_mb" { +variable "disk_mb" { type = number description = "The disk that is allocated per member. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)." default = 5120 @@ -81,7 +81,7 @@ variable "member_host_flavor" { # Validation is done in the Terraform plan phase by the IBM provider, so no need to add extra validation here. } -variable "member_memory_mb" { +variable "memory_mb" { type = number description = "The memory per member that is allocated. [Learn more](https://cloud.ibm.com/docs/databases-for-elasticsearch?topic=databases-for-elasticsearch-resources-scaling)" default = 4096 diff --git a/version.tf b/version.tf index 0f6877bf..db383db5 100644 --- a/version.tf +++ b/version.tf @@ -1,10 +1,10 @@ terraform { required_version = ">= 1.9.0" - # Use "greater than or equal to" range in modules required_providers { ibm = { - source = "ibm-cloud/ibm" - version = ">= 1.70.0, <2.0.0" + source = "IBM-Cloud/ibm" + # Use "greater than or equal to" range in modules + version = ">= 1.79.2, <2.0.0" } null = { source = "hashicorp/null" @@ -12,7 +12,7 @@ terraform { } time = { source = "hashicorp/time" - version = ">= 0.9.1" + version = ">= 0.9.1, < 1.0.0" } } }