Skip to content
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a7f13f0
add: service credential to secrets manager in DA
Aayush-Abhyarthi Aug 9, 2024
b64eb7d
fix: common dev assets
Aayush-Abhyarthi Aug 11, 2024
d92e921
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Aug 11, 2024
e76d755
add: DA-types file
Aayush-Abhyarthi Aug 12, 2024
332cad0
add: DA-types file
Aayush-Abhyarthi Aug 12, 2024
66e8eff
Merge branch 'store-service-credentials' of https://github.com/terraf…
Aayush-Abhyarthi Aug 12, 2024
10745fa
fix: error
Aayush-Abhyarthi Aug 13, 2024
d613123
fix: error
Aayush-Abhyarthi Aug 14, 2024
ef861ad
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Aug 14, 2024
0705b42
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Aug 21, 2024
0225e76
fix: minor fix
Aayush-Abhyarthi Aug 21, 2024
0ca7a3a
fix: minor changes
Aayush-Abhyarthi Aug 22, 2024
55ea4cd
add: description parameter
Aayush-Abhyarthi Aug 26, 2024
f276c7c
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Aug 26, 2024
9a11b71
add validation
Aayush-Abhyarthi Aug 26, 2024
b7a75a4
Merge branch 'main' into store-service-credentials
Aashiq-J Aug 27, 2024
58b0c3a
fix: cra failure
Aayush-Abhyarthi Aug 27, 2024
d7408b1
fix: cra fail
Aayush-Abhyarthi Aug 27, 2024
a7ec26d
add condition
Aayush-Abhyarthi Aug 28, 2024
0395b9b
Merge branch 'main' into store-service-credentials
Soaib024 Aug 29, 2024
0d79077
refactor
Aayush-Abhyarthi Aug 29, 2024
d6774d7
fix: resolve comment
Aayush-Abhyarthi Aug 29, 2024
c30ae24
fix: pre commit
Aayush-Abhyarthi Aug 29, 2024
0a7585e
fix: cra failure
Aayush-Abhyarthi Aug 29, 2024
caed0a3
add: existing database
Aayush-Abhyarthi Sep 1, 2024
14e62e9
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 1, 2024
1fedaf1
fix: resolve error
Aayush-Abhyarthi Sep 1, 2024
e9d6a8d
Merge remote-tracking branch 'origin/store-service-credentials' into …
Aayush-Abhyarthi Sep 1, 2024
4def7a2
add link to documentation
Aayush-Abhyarthi Sep 2, 2024
ca37cf8
reference scs in scn
Aayush-Abhyarthi Sep 2, 2024
9d3530c
Merge branch 'main' into store-service-credentials
Ak-sky Sep 10, 2024
09fd02d
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 13, 2024
2851bf4
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 16, 2024
6df5b46
resolve conf
Aayush-Abhyarthi Sep 22, 2024
8ffcc10
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 22, 2024
f419c6f
resolve some comments
Aayush-Abhyarthi Sep 23, 2024
e9b0435
Merge remote-tracking branch 'origin/store-service-credentials' into …
Aayush-Abhyarthi Sep 23, 2024
91de09b
resolve comments
Aayush-Abhyarthi Sep 27, 2024
d20f632
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 27, 2024
226578e
resolve conflict error
Aayush-Abhyarthi Sep 27, 2024
88c09a9
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Sep 30, 2024
9484671
Merge branch 'main' into store-service-credentials
Aayush-Abhyarthi Oct 14, 2024
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
101 changes: 101 additions & 0 deletions solutions/standard/DA-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Configuring complex inputs in Event Notification

Several optional input variables in the IBM Cloud [Event Notification deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure you deployable architecture.

- [Service credentials](#svc-credential-name) (`service_credential_names`)
- [Service credential secrets](#service-credential-secrets) (`service_credential_secrets`)

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

You can specify a set of IAM credentials to connect to the instance with the `service_credential_names` input variable. Include a credential name and IAM service role for each key-value pair. Each role provides a specific level of access to the instance. For more information, see [Adding and viewing credentials](https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui).

- Variable name: `service_credential_names`.
- Type: A map. The key is the name of the service credential. The value is the role that is assigned to that credential.
- Default value: An empty map (`{}`).

### Options for service_credential_names

- Key (required): The name of the service credential.
- Value (required): The IAM service role that is assigned to the credential. For more information, see [IBM Cloud IAM roles](https://cloud.ibm.com/docs/account?topic=account-userroles).

### Example service credential

```hcl
{
"en_manager" : "Manager",
"en_reader" : "Reader",
"en_writer" : "Writer",
"en_email_sender" : "Email Sender"
}
```

## Service credential secrets <a name="service-credential-secrets"></a>

When you add an IBM Event Notification 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 Event Notification service. Acceptable values are `Writer`, `Reader`, `Manager`, `None`, `Event Source Manager`, `Channel Editor`, `Event Notification Publisher`, `Status Reporter`, `Device Manager`, `Email Sender`, `Custom Email Status Reporter` , and `Pool ID Manager`
- `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
{
"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
{
"secret_name": "cred-3"
"service_credentials_source_service_role": "Editor"
},
{
"secret_name": "cred-4"
"service_credentials_source_service_role": "None"
}
] # pragma: allowlist secret
}
]
```
82 changes: 73 additions & 9 deletions solutions/standard/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ locals {
cos_instance_guid = var.existing_cos_instance_crn != null ? element(split(":", var.existing_cos_instance_crn), length(split(":", var.existing_cos_instance_crn)) - 3) : null
cos_kms_key_crn = var.existing_cos_bucket_name != null ? null : var.existing_kms_root_key_crn != null ? var.existing_kms_root_key_crn : module.kms[0].keys[format("%s.%s", local.cos_key_ring_name, local.cos_key_name)].crn

existing_en_instance_guid = var.existing_en_instance_crn != null ? element(split(":", var.existing_en_instance_crn), length(split(":", var.existing_en_instance_crn)) - 3) : null
use_existing_en_instance = var.existing_en_instance_crn != null

eventnotification_guid = local.use_existing_en_instance ? data.ibm_resource_instance.existing_en_instance[0].guid : module.event_notifications[0].guid

kms_service_name = var.existing_kms_instance_crn != null ? (
can(regex(".*kms.*", var.existing_kms_instance_crn)) ? "kms" : (
can(regex(".*hs-crypto.*", var.existing_kms_instance_crn)) ? "hs-crypto" : null
Expand Down Expand Up @@ -161,18 +166,10 @@ locals {
# KMS Related
existing_kms_instance_crn = var.existing_kms_instance_crn != null ? var.existing_kms_instance_crn : null
cos_endpoint = var.existing_cos_bucket_name == null ? "https://${module.cos[0].s3_endpoint_public}" : var.existing_cos_endpoint
# Event Notification Related
parsed_existing_en_instance_crn = var.existing_en_instance_crn != null ? split(":", var.existing_en_instance_crn) : []
existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null
}

data "ibm_resource_instance" "existing_en" {
count = var.existing_en_instance_crn == null ? 0 : 1
identifier = var.existing_en_instance_crn
}

module "event_notifications" {
count = var.existing_en_instance_crn != null ? 0 : 1
count = local.use_existing_en_instance ? 0 : 1
source = "../.."
resource_group_id = module.resource_group.resource_group_id
region = var.region
Expand All @@ -194,3 +191,70 @@ module "event_notifications" {
skip_en_cos_auth_policy = var.skip_en_cos_auth_policy
cos_endpoint = local.cos_endpoint
}

# create a service authorization between Secrets Manager and the target service (Event Notification)
resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" {
count = var.skip_en_sm_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1
depends_on = [module.event_notifications]
source_service_name = "secrets-manager"
source_resource_instance_id = local.existing_secrets_manager_instance_guid
target_service_name = "event-notifications"
target_resource_instance_id = local.eventnotification_guid
roles = ["Key Manager"]
description = "Allow Secrets Manager with instance id ${local.existing_secrets_manager_instance_guid} to manage key for the event-notification instance"
}

# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
resource "time_sleep" "wait_for_en_authorization_policy" {
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 = local.use_existing_en_instance ? data.ibm_resource_instance.existing_en_instance[0].id : module.event_notifications[0].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_en_authorization_policy]
source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets"
version = "1.17.4"
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
}

# this extra block is needed when passing in an existing EN instance - the resource data block
# requires an id to retrieve the data
data "ibm_resource_instance" "existing_en_instance" {
count = local.use_existing_en_instance ? 1 : 0
identifier = local.existing_en_instance_guid
}
20 changes: 15 additions & 5 deletions solutions/standard/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,37 @@

output "event_notification_instance_name" {
description = "Event Notification name"
value = var.existing_en_instance_crn == null ? module.event_notifications[0].event_notification_instance_name : data.ibm_resource_instance.existing_en[0].name
value = local.use_existing_en_instance ? data.ibm_resource_instance.existing_en_instance[0].name : module.event_notifications[0].event_notification_instance_name
}

output "crn" {
description = "Event Notification crn"
value = var.existing_en_instance_crn == null ? module.event_notifications[0].crn : var.existing_en_instance_crn
value = local.use_existing_en_instance ? var.existing_en_instance_crn : module.event_notifications[0].crn
}

output "guid" {
description = "Event Notification guid"
value = var.existing_en_instance_crn == null ? module.event_notifications[0].guid : local.existing_en_guid
value = local.eventnotification_guid
}

output "service_credentials_json" {
description = "Service credentials json map"
value = var.existing_en_instance_crn == null ? module.event_notifications[0].service_credentials_json : null
value = local.use_existing_en_instance ? null : module.event_notifications[0].service_credentials_json
sensitive = true
}

output "service_credentials_object" {
description = "Service credentials object"
value = var.existing_en_instance_crn == null ? module.event_notifications[0].service_credentials_object : null
value = local.use_existing_en_instance ? null : module.event_notifications[0].service_credentials_object
sensitive = true
}

output "service_credential_secrets" {
description = "Service credential secrets"
value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0].secrets : 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
}
61 changes: 60 additions & 1 deletion solutions/standard/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ variable "prefix" {

variable "service_credential_names" {
type = map(string)
description = "The mapping of names and roles for service credentials that you want to create for the Event Notifications instance."
description = "The mapping of names and roles for service credentials that you want to create for the Event Notifications instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/standard/DA-types.md#service-credential-secrets"
default = {}

validation {
Expand Down Expand Up @@ -280,3 +280,62 @@ variable "existing_cos_endpoint" {
description = "The endpoint URL for your bucket region. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-endpoints). Only required if using an existing bucket with the `existing_cos_bucket_name` variable."
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 Event Notification 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 Event Notification. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/standard/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", "Event Source Manager", "Channel Editor", "Event Notification Publisher", "Status Reporter", "Device Manager", "Email Sender", "Custom Email Status Reporter", "Pool ID Manager"], credential.service_credentials_source_service_role
)
])
])
error_message = "service_credentials_source_service_role role must be one of 'Writer', 'Reader', 'Manager', 'None', 'Event Source Manager', 'Channel Editor', 'Event Notification Publisher', 'Status Reporter', 'Device Manager', 'Email Sender', 'Custom Email Status Reporter' and 'Pool ID Manager'."

}
}

variable "skip_en_sm_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 Event Notification. Set to `true` to use an existing policy."
}
4 changes: 4 additions & 0 deletions solutions/standard/version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ terraform {
source = "IBM-Cloud/ibm"
version = "1.69.2"
}
time = {
source = "hashicorp/time"
version = "0.12.0"
}
}
}
19 changes: 19 additions & 0 deletions tests/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package test

import (
"fmt"
"log"
"math/rand"
"os"
Expand Down Expand Up @@ -109,13 +110,31 @@ func TestDAInSchematics(t *testing.T) {
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": "Reader",
},
{
"secret_name": fmt.Sprintf("%s-cred-writer", options.Prefix),
"service_credentials_source_service_role": "Writer",
},
},
},
}

options.TerraformVars = []testschematic.TestSchematicTerraformVar{
{Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
{Name: "region", Value: region, DataType: "string"},
{Name: "resource_group_name", Value: options.Prefix, DataType: "string"},
{Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
{Name: "kms_endpoint_url", Value: permanentResources["hpcs_south_private_endpoint"], DataType: "string"},
{Name: "cross_region_location", Value: "us", DataType: "string"},
{Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"},
{Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"},
}

err := options.RunSchematicTest()
Expand Down