Skip to content

Commit

Permalink
feat: added support to always create an admin password in the DA solu…
Browse files Browse the repository at this point in the history
…tion. If no value is entered with the `admin_pass` input, a random password is generated and can be got from the `admin_pass` sensitive output. The value can be added to a secrets manager secret using the inputs `existing_secrets_manager_instance_crn`, `admin_pass_sm_secret_group`, `use_existing_admin_pass_sm_secret_group` and `admin_pass_sm_secret_name`. (#295)
  • Loading branch information
akocbek authored Sep 24, 2024
1 parent 3a7716c commit 71e66a2
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 31 deletions.
9 changes: 9 additions & 0 deletions ibm_catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@
{
"key": "admin_pass"
},
{
"key": "admin_pass_sm_secret_group"
},
{
"key": "use_existing_admin_pass_sm_secret_group"
},
{
"key": "admin_pass_sm_secret_name"
},
{
"key": "skip_iam_authorization_policy"
},
Expand Down
30 changes: 27 additions & 3 deletions solutions/standard/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ module "elasticsearch" {
kms_key_crn = local.kms_key_crn
access_tags = var.access_tags
tags = var.tags
admin_pass = var.admin_pass
admin_pass = local.admin_pass
users = var.users
members = var.members
member_host_flavor = var.member_host_flavor
Expand All @@ -122,6 +122,13 @@ module "elasticsearch" {
elser_model_type = var.elser_model_type
}

resource "random_password" "admin_password" {
count = var.admin_pass == null ? 1 : 0
length = 32
special = true
override_special = "-_"
}

# create a service authorization between Secrets Manager and the target service (Elastic Search)
resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" {
count = var.skip_es_sm_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1
Expand Down Expand Up @@ -163,23 +170,40 @@ locals {
}
]

admin_pass = var.admin_pass == null ? random_password.admin_password[0].result : var.admin_pass
admin_pass_secret = [{
secret_group_name = var.prefix != null ? "${var.prefix}-${var.admin_pass_sm_secret_group}" : var.admin_pass_sm_secret_group
existing_secret_group = var.use_existing_admin_pass_sm_secret_group
secrets = [{
secret_name = var.prefix != null ? "${var.prefix}-${var.admin_pass_sm_secret_name}" : var.admin_pass_sm_secret_name
secret_type = "arbitrary"
secret_payload_password = local.admin_pass
}
]
}]
secrets = concat(local.service_credential_secrets, local.admin_pass_secret)

existing_secrets_manager_instance_crn_split = var.existing_secrets_manager_instance_crn != null ? split(":", var.existing_secrets_manager_instance_crn) : null
existing_secrets_manager_instance_guid = var.existing_secrets_manager_instance_crn != null ? element(local.existing_secrets_manager_instance_crn_split, length(local.existing_secrets_manager_instance_crn_split) - 3) : null
existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? element(local.existing_secrets_manager_instance_crn_split, length(local.existing_secrets_manager_instance_crn_split) - 5) : null

# tflint-ignore: terraform_unused_declarations
validate_sm_crn = length(local.service_credential_secrets) > 0 && var.existing_secrets_manager_instance_crn == null ? tobool("`existing_secrets_manager_instance_crn` is required when adding service credentials to a secrets manager secret.") : false
# tflint-ignore: terraform_unused_declarations
validate_sm_sg = var.existing_secrets_manager_instance_crn != null && var.admin_pass_sm_secret_group == null ? tobool("`admin_pass_sm_secret_group` is required when `existing_secrets_manager_instance_crn` is set.") : false
# tflint-ignore: terraform_unused_declarations
validate_sm_sn = var.existing_secrets_manager_instance_crn != null && var.admin_pass_sm_secret_name == null ? tobool("`admin_pass_sm_secret_name` is required when `existing_secrets_manager_instance_crn` is set.") : false
}

module "secrets_manager_service_credentials" {
count = length(local.service_credential_secrets) > 0 ? 1 : 0
count = var.existing_secrets_manager_instance_crn == null ? 0 : 1
depends_on = [time_sleep.wait_for_es_authorization_policy]
source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets"
version = "1.18.6"
existing_sm_instance_guid = local.existing_secrets_manager_instance_guid
existing_sm_instance_region = local.existing_secrets_manager_instance_region
endpoint_type = var.existing_secrets_manager_endpoint_type
secrets = local.service_credential_secrets
secrets = local.secrets
}

# this extra block is needed when passing in an existing ES instance - the database data block
Expand Down
13 changes: 7 additions & 6 deletions solutions/standard/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ output "port" {
value = local.use_existing_db_instance ? data.ibm_database_connection.existing_connection[0].https[0].hosts[0].port : module.elasticsearch[0].port
}

output "service_credential_secrets" {
description = "Service credential secrets"
value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0].secrets : null
output "secrets_manager_secrets" {
description = "Elasticsearch related secrets stored inside secrets manager"
value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0] : null
}

output "service_credential_secret_groups" {
description = "Service credential secret groups"
value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0].secret_groups : null
output "admin_pass" {
description = "Elasticsearch administrator password"
value = local.admin_pass
sensitive = true
}
54 changes: 32 additions & 22 deletions solutions/standard/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ variable "existing_db_instance_crn" {
description = "The CRN of an existing Databases for Elasticsearch instance. If no value is specified, a new instance is created."
}

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
}

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`. [Learn more](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html)"
default = ".elser_model_2_linux-x86_64"
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
##############################################################################
Expand Down Expand Up @@ -109,7 +125,7 @@ variable "member_memory_mb" {

variable "admin_pass" {
type = string
description = "The password for the database administrator. If the admin password is null, the admin user ID cannot be accessed. You can specify more users in a user block."
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."
default = null
sensitive = true
}
Expand Down Expand Up @@ -223,20 +239,6 @@ variable "elasticsearch_key_name" {
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 `<prefix>-<name>` format."
}

##############################################################
# Context-based restriction (CBR)
##############################################################

##############################################################
# Backup
##############################################################

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
}

##############################################################################
## Secrets Manager Service Credentials
##############################################################################
Expand Down Expand Up @@ -296,12 +298,20 @@ variable "skip_es_sm_auth_policy" {
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."
}

variable "elser_model_type" {
variable "admin_pass_sm_secret_group" {
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`. [Learn more](https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-elser.html)"
default = ".elser_model_2_linux-x86_64"
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!"
}
description = "The name of a new or existing secrets manager secret group for admin password. To use existing secret group, `use_existing_admin_pass_sm_secret_group` must be set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `<prefix>-<name>` format."
default = null
}

variable "use_existing_admin_pass_sm_secret_group" {
type = bool
description = "Whether to use an existing secrets manager secret group for admin password."
default = false
}

variable "admin_pass_sm_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 `<prefix>-<name>` format."
default = null
}
4 changes: 4 additions & 0 deletions solutions/standard/version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ terraform {
source = "hashicorp/time"
version = "0.12.1"
}
random = {
source = "hashicorp/random"
version = "3.6.2"
}
}
}
2 changes: 2 additions & 0 deletions tests/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ func TestRunStandardSolutionSchematics(t *testing.T) {
{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_sm_secret_group", Value: options.Prefix, DataType: "string"},
{Name: "admin_pass_sm_secret_name", Value: options.Prefix, DataType: "string"},
}
err := options.RunSchematicTest()
assert.Nil(t, err, "This should not have errored")
Expand Down

0 comments on commit 71e66a2

Please sign in to comment.