Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to store service credentials in sm #411

Merged
merged 20 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|^.secrets.baseline$",
"lines": null
},
"generated_at": "2024-07-23T12:23:38Z",
"generated_at": "2024-08-27T19:58:40Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -102,15 +102,15 @@
"hashed_secret": "44cdfc3615970ada14420caaaa5c5745fca06002",
"is_secret": false,
"is_verified": false,
"line_number": 59,
"line_number": 60,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "bd0d0d73a240c29656fb8ae0dfa5f863077788dc",
"is_secret": false,
"is_verified": false,
"line_number": 64,
"line_number": 65,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
71 changes: 71 additions & 0 deletions solutions/standard/DA-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Several optional input variables in the IBM Cloud [Databases for Redis deployabl
- [Users](#users) (`users`)
- [Autoscaling](#autoscaling) (`auto_scaling`)
- [Configuration](#configuaration) (`configuration`)
- [Service credential secrets](#service-credential-secrets) (`service_credential_secrets`)

## Service credentials <a name="svc-credential-name"></a>

Expand Down Expand Up @@ -173,3 +174,73 @@ The following example shows values for the `configuration` input.
"stop-writes-on-bgsave-error": "yes"
}
```
## Service credential secrets <a name="service-credential-secrets"></a>

When you add an IBM Database for Redis service from the IBM Cloud catalog to an IBM Cloud Projects service, you can configure service credentials. In the edit mode for the projects configuration, select the Configure panel and then click the optional tab.

In the configuration, specify the secret group name, whether it already exists or will be created and include all the necessary service credential secrets that need to be created within that secret group.

To enter a custom value, use the edit action to open the "Edit Array" panel. Add the service credential secrets configurations to the array here.

[Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/sm_service_credentials_secret) about service credential secrets.

- Variable name: `service_credential_secrets`.
- Type: A list of objects that represent a service credential secret groups and secrets
- Default value: An empty list (`[]`)

### Options for service_credential_secrets

- `secret_group_name` (required): A unique human-readable name that identifies this service credential secret group.
- `secret_group_description` (optional, default = `null`): A human-readable description for this secret group.
- `existing_secret_group`: (optional, default = `false`): Set to true, if secret group name provided in the variable `secret_group_name` already exists.
- `service_credentials`: (optional, default = `[]`): A list of object that represents a service credential secret.

### Options for service_credentials

- `secret_name`: (required): A unique human-readable name of the secret to create.
- `service_credentials_source_service_role`: (required): The role to give the service credential in the Databases for Redis service. Acceptable values are `Writer`, `Reader`, `Manager`, and `None`
- `secret_labels`: (optional, default = `[]`): Labels of the secret to create. Up to 30 labels can be created. Labels can be 2 - 30 characters, including spaces. Special characters that are not permitted include the angled brackets (<>), comma (,), colon (:), ampersand (&), and vertical pipe character (|).
- `secret_auto_rotation`: (optional, default = `true`): Whether to configure automatic rotation of service credential.
- `secret_auto_rotation_unit`: (optional, default = `day`): Specifies the unit of time for rotation of a secret. Acceptable values are `day` or `month`.
- `secret_auto_rotation_interval`: (optional, default = `89`): Specifies the rotation interval for the rotation unit.
- `service_credentials_ttl`: (optional, default = `7776000`): The time-to-live (TTL) to assign to generated service credentials (in seconds).
- `service_credential_secret_description`: (optional, default = `null`): Description of the secret to create.

The following example includes all the configuration options for four service credentials and two secret groups.
```hcl
[
{
"secret_group_name": "sg-1"
"existing_secret_group": true
"service_credentials": [ # pragma: allowlist secret
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
{
"secret_name": "cred-1"
"service_credentials_source_service_role": "Writer"
"secret_labels": ["test-writer-1", "test-writer-2"]
"secret_auto_rotation": true
"secret_auto_rotation_unit": "day"
"secret_auto_rotation_interval": 89
"service_credentials_ttl": 7776000
"service_credential_secret_description": "sample description"
},
{
"secret_name": "cred-2"
"service_credentials_source_service_role": "Reader"
}
]
},
{
"secret_group_name": "sg-2"
"service_credentials": [ # pragma: allowlist secret
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
{
"secret_name": "cred-3"
"service_credentials_source_service_role": "Editor"
},
{
"secret_name": "cred-4"
"service_credentials_source_service_role": "None"
}
] # pragma: allowlist secret
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
}
]
```
60 changes: 60 additions & 0 deletions solutions/standard/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,63 @@ module "redis" {
configuration = var.configuration
service_credential_names = var.service_credential_names
}

# create a service authorization between Secrets Manager and the target service (Databases for Redis)
resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" {
count = var.skip_rd_sm_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
depends_on = [module.redis]
source_service_name = "secrets-manager"
source_resource_instance_id = local.existing_secrets_manager_instance_guid
target_service_name = "databases-for-redis"
target_resource_instance_id = module.redis.guid
roles = ["Key Manager"]
description = "Allow Secrets Manager with instance id ${local.existing_secrets_manager_instance_guid} to manage key for the databases-for-redis instance"
}

# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
resource "time_sleep" "wait_for_rd_authorization_policy" {
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager]
create_duration = "30s"
}

locals {
service_credential_secrets = [
for service_credentials in var.service_credential_secrets : {
secret_group_name = service_credentials.secret_group_name
secret_group_description = service_credentials.secret_group_description
existing_secret_group = service_credentials.existing_secret_group
secrets = [
for secret in service_credentials.service_credentials : {
secret_name = secret.secret_name
secret_labels = secret.secret_labels
secret_auto_rotation = secret.secret_auto_rotation
secret_auto_rotation_unit = secret.secret_auto_rotation_unit
secret_auto_rotation_interval = secret.secret_auto_rotation_interval
service_credentials_ttl = secret.service_credentials_ttl
service_credential_secret_description = secret.service_credential_secret_description
service_credentials_source_service_role = secret.service_credentials_source_service_role
service_credentials_source_service_crn = module.redis.crn
secret_type = "service_credentials" #checkov:skip=CKV_SECRET_6
}
]
}
]

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
}

module "secrets_manager_service_credentials" {
count = length(local.service_credential_secrets) > 0 ? 1 : 0
depends_on = [time_sleep.wait_for_rd_authorization_policy]
source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets"
version = "1.17.8"
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
}
59 changes: 59 additions & 0 deletions solutions/standard/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,62 @@ variable "auto_scaling" {
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-redis/blob/main/solutions/standard/DA-types.md#autoscaling)"
default = null
}

##############################################################################
## Secrets Manager Service Credentials
##############################################################################

variable "skip_rd_sm_auth_policy" {
Aayush-Abhyarthi marked this conversation as resolved.
Show resolved Hide resolved
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 Redis. Set to `true` to use an existing policy."
}

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 Redis instance."
}

variable "existing_secrets_manager_endpoint_type" {
type = string
description = "The endpoint type to use if `existing_secrets_manager_instance_crn` is specified. Possible values: public, private."
default = "private"
validation {
condition = contains(["public", "private"], var.existing_secrets_manager_endpoint_type)
error_message = "Only \"public\" and \"private\" are allowed values for 'existing_secrets_endpoint_type'."
}
}

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 = 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 Redis. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-icd-redis/tree/main/solutions/instance/DA-types.md#service-credential-secrets)."

validation {
condition = alltrue([
for group in var.service_credential_secrets : alltrue([
for credential in group.service_credentials : contains(
["Writer", "Reader", "Manager", "None"], credential.service_credentials_source_service_role
)
])
])
error_message = "service_credentials_source_service_role role must be one of 'Writer', 'Reader', 'Manager', and 'None'."

}
}
30 changes: 25 additions & 5 deletions tests/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package test
import (
"crypto/rand"
"encoding/base64"
"fmt"
"log"
"os"
"testing"
Expand Down Expand Up @@ -91,12 +92,31 @@ func TestRunStandardSolution(t *testing.T) {
ResourceGroup: resourceGroup,
})

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": "Reader",
},
{
"secret_name": fmt.Sprintf("%s-cred-writer", options.Prefix),
"service_credentials_source_service_role": "Writer",
},
},
},
}

options.TerraformVars = map[string]interface{}{
"access_tags": permanentResources["accessTags"],
"redis_version": "7.2", // Always lock this test into the latest supported Redis version
"existing_kms_instance_crn": permanentResources["hpcs_south_crn"],
"kms_endpoint_type": "public",
"resource_group_name": options.Prefix,
"access_tags": permanentResources["accessTags"],
"redis_version": "7.2", // Always lock this test into the latest supported Redis version
"existing_kms_instance_crn": permanentResources["hpcs_south_crn"],
"existing_secrets_manager_instance_crn": permanentResources["secretsManagerCRN"],
"existing_secrets_manager_endpoint_type": "public",
"kms_endpoint_type": "public",
"resource_group_name": options.Prefix,
"service_credential_secrets": serviceCredentialSecrets,
}

output, err := options.RunTestConsistency()
Expand Down