Skip to content

Commit bf186a0

Browse files
authored
feat: CBR service profile submodule to support multiple target services (#59)
1 parent 0950e06 commit bf186a0

File tree

16 files changed

+524
-5
lines changed

16 files changed

+524
-5
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ You need the following permissions to run this module.
5454
<!-- BEGIN EXAMPLES HOOK -->
5555
## Examples
5656

57+
- [ CBR Multi Service Profile](examples/multi-service-profile)
5758
- [ Multi-zone example](examples/multizone-rule)
5859
- [ Zone example](examples/zone)
5960
<!-- END EXAMPLES HOOK -->
@@ -87,7 +88,7 @@ You need the following permissions to run this module.
8788
| <a name="input_excluded_addresses"></a> [excluded\_addresses](#input\_excluded\_addresses) | (Optional, List) The list of excluded addresses in the zone | <pre>list(object({<br> type = optional(string)<br> value = optional(string)<br> }))</pre> | `[]` | no |
8889
| <a name="input_name"></a> [name](#input\_name) | (Optional, String) The name of the zone | `string` | `null` | no |
8990
| <a name="input_operations"></a> [operations](#input\_operations) | (Optional, List) The operations this rule applies to | <pre>list(object({<br> api_types = list(object({<br> api_type_id = string<br> }))<br> }))</pre> | `[]` | no |
90-
| <a name="input_resources"></a> [resources](#input\_resources) | (Optional, List) The resources this rule apply to | <pre>list(object({<br> attributes = list(object({<br> name = string<br> value = string<br> operator = optional(string)<br> }))<br> tags = optional(list(object({<br> name = string<br> value = string<br> operator = optional(string)<br> })))<br> }))</pre> | `[]` | no |
91+
| <a name="input_resources"></a> [resources](#input\_resources) | (Optional, List) The resources this rule apply to | <pre>list(object({<br> attributes = list(object({<br> name = string<br> value = string<br> operator = optional(string)<br> }))<br> tags = optional(list(object({ #These access tags should match to the target service access tags for the CBR rules to work<br> name = string<br> value = string<br> operator = optional(string)<br> })))<br> }))</pre> | `[]` | no |
9192
| <a name="input_rule_contexts"></a> [rule\_contexts](#input\_rule\_contexts) | (List) The contexts the rule applies to | <pre>list(object({<br> attributes = list(object({<br> name = string<br> value = string<br> }))<br> }))</pre> | <pre>[<br> {<br> "attributes": [<br> {<br> "name": "va",<br> "value": "va"<br> }<br> ]<br> }<br>]</pre> | no |
9293
| <a name="input_rule_description"></a> [rule\_description](#input\_rule\_description) | (Optional, String) The description of the rule | `string` | `null` | no |
9394
| <a name="input_zone_description"></a> [zone\_description](#input\_zone\_description) | (Optional, String) The description of the zone | `string` | `null` | no |

cbr-rule-module/main.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ resource "ibm_cbr_rule" "cbr_rule" {
3636
operator = attribute.value["operator"]
3737
}
3838
}
39+
# Access tags for the target resources. These tags specified in the rule should match to the tags attached to the target service access tags.
40+
# These tags should be valid in the account. Refer https://cloud.ibm.com/docs/account?topic=account-access&interface=ui for more details
3941
dynamic "tags" {
4042
for_each = resource.value["tags"] == null ? [] : resource.value["tags"]
4143
iterator = tag

cbr-service-profile/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# CBR Rule Profile
2+
3+
Accepts a list of VPC crns / service references to create CBR zones and a list of target services, to create the rule matching these profiles. It supports to target the service using name, account id, tags, resource group.

cbr-service-profile/main.tf

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# ##############################################################################
2+
# # Get Cloud Account ID
3+
# ##############################################################################
4+
data "ibm_iam_account_settings" "iam_account_settings" {
5+
}
6+
7+
##############################################################################
8+
#
9+
# CBR Rule for a list of target services
10+
##############################################################################
11+
locals {
12+
# tflint-ignore: terraform_unused_declarations
13+
validate_zone_inputs = ((length(var.zone_vpc_crn_list) == 0) && (length(var.zone_service_ref_list) == 0)) ? tobool("Error: Provide a valid zone vpc and/or service references") : true
14+
15+
# Restrict and allow the api types as per the target service
16+
icd_api_types = ["crn:v1:bluemix:public:context-based-restrictions::::api-type:data-plane"]
17+
operations_apitype_val = {
18+
databases-for-enterprisedb = local.icd_api_types,
19+
containers-kubernetes = ["crn:v1:bluemix:public:containers-kubernetes::::api-type:cluster", "crn:v1:bluemix:public:containers-kubernetes::::api-type:management"],
20+
databases-for-cassandra = local.icd_api_types,
21+
databases-for-elasticsearch = local.icd_api_types,
22+
databases-for-etcd = local.icd_api_types,
23+
databases-for-mongodb = local.icd_api_types,
24+
databases-for-postgresql = local.icd_api_types,
25+
databases-for-redis = local.icd_api_types,
26+
messages-for-rabbitmq = local.icd_api_types
27+
}
28+
29+
vpc_zone_list = (length(var.zone_vpc_crn_list) > 0) ? [{
30+
name = "${var.prefix}-cbr-vpc-zone"
31+
account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
32+
zone_description = "cbr-vpc-zone-terraform"
33+
addresses = [
34+
for zone_vpc_crn in var.zone_vpc_crn_list :
35+
{ "type" = "vpc", value = zone_vpc_crn }
36+
]
37+
}] : []
38+
39+
service_ref_zone_list = (length(var.zone_service_ref_list) > 0) ? [{
40+
name = "${var.prefix}-cbr-serviceref-zone"
41+
account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
42+
zone_description = "cbr-serviceref-zone-terraform"
43+
# when the target service is containers-kubernetes or any icd services, context cannot have a serviceref
44+
addresses = [
45+
for serviceref in var.zone_service_ref_list : {
46+
type = "serviceRef"
47+
ref = {
48+
account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
49+
service_name = serviceref
50+
}
51+
}
52+
]
53+
}] : []
54+
zone_list = concat(tolist(local.vpc_zone_list), tolist(local.service_ref_zone_list))
55+
}
56+
57+
module "cbr_zone" {
58+
count = length(local.zone_list)
59+
source = "../cbr-zone-module"
60+
name = local.zone_list[count.index].name
61+
zone_description = local.zone_list[count.index].zone_description
62+
account_id = local.zone_list[count.index].account_id
63+
addresses = local.zone_list[count.index].addresses
64+
}
65+
66+
locals {
67+
rule_contexts = [{
68+
attributes = [
69+
{
70+
"name" : "endpointType",
71+
"value" : "private"
72+
},
73+
{
74+
name = "networkZoneId"
75+
value = join(",", ([for zone in module.cbr_zone : zone.zone_id]))
76+
}]
77+
}]
78+
}
79+
80+
module "cbr_rule" {
81+
count = length(var.target_service_details)
82+
source = "../cbr-rule-module"
83+
rule_description = "${var.prefix}-${var.target_service_details[count.index].target_service_name}-serviceprofile-rule"
84+
enforcement_mode = var.target_service_details[count.index].enforcement_mode
85+
rule_contexts = local.rule_contexts
86+
operations = (length(lookup(local.operations_apitype_val, var.target_service_details[count.index].target_service_name, [])) > 0) ? [{
87+
api_types = [
88+
# lookup the map for the target service name, if not present make api_type_id as empty
89+
for apitype in lookup(local.operations_apitype_val, var.target_service_details[count.index].target_service_name, []) : {
90+
api_type_id = apitype
91+
}]
92+
}] : []
93+
94+
resources = [{
95+
tags = var.target_service_details[count.index].tags != null ? [for tag in var.target_service_details[count.index].tags : {
96+
name = split(":", tag)[0]
97+
value = split(":", tag)[1]
98+
}] : []
99+
attributes = var.target_service_details[count.index].target_rg != null ? [
100+
{
101+
name = "accountId",
102+
operator = "stringEquals",
103+
value = data.ibm_iam_account_settings.iam_account_settings.account_id
104+
},
105+
{
106+
name = "resourceGroupId",
107+
operator = "stringEquals",
108+
value = var.target_service_details[count.index].target_rg
109+
},
110+
{
111+
name = "serviceName",
112+
operator = "stringEquals",
113+
value = var.target_service_details[count.index].target_service_name
114+
}] : [
115+
{
116+
name = "accountId",
117+
operator = "stringEquals",
118+
value = data.ibm_iam_account_settings.iam_account_settings.account_id
119+
},
120+
{
121+
name = "serviceName",
122+
operator = "stringEquals",
123+
value = var.target_service_details[count.index].target_service_name
124+
}]
125+
}]
126+
}

cbr-service-profile/outputs.tf

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
##############################################################################
2+
# Outputs
3+
##############################################################################
4+
5+
output "zone_ids" {
6+
value = module.cbr_zone[*].zone_id
7+
description = "CBR zone resource instance id(s)"
8+
}
9+
10+
output "zone_crns" {
11+
value = module.cbr_zone[*].zone_crn
12+
description = "CBR zone crn(s)"
13+
}
14+
15+
output "zone_hrefs" {
16+
value = module.cbr_zone[*].zone_href
17+
description = "CBR zone href(s)"
18+
}
19+
20+
output "rule_ids" {
21+
value = join(",", module.cbr_rule[*].rule_id)
22+
description = "CBR rule id(s)"
23+
}
24+
25+
output "rule_crns" {
26+
value = join(",", module.cbr_rule[*].rule_crn)
27+
description = "CBR rule crn(s)"
28+
}
29+
30+
output "rule_hrefs" {
31+
value = join(",", module.cbr_rule[*].rule_href)
32+
description = "CBR rule href(s)"
33+
}

cbr-service-profile/variables.tf

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
##############################################################################
2+
# Rule Related Input Variables
3+
##############################################################################
4+
5+
variable "prefix" {
6+
type = string
7+
description = "Prefix to append to all resources created by this example"
8+
default = "serviceprofile"
9+
}
10+
11+
variable "zone_vpc_crn_list" {
12+
type = list(string)
13+
default = []
14+
description = "(List) VPC CRN for the zones"
15+
}
16+
17+
variable "zone_service_ref_list" {
18+
type = list(string)
19+
validation {
20+
condition = alltrue([
21+
for service_ref in var.zone_service_ref_list :
22+
contains(["cloud-object-storage", "codeengine", "containers-kubernetes",
23+
"databases-for-cassandra", "databases-for-elasticsearch", "databases-for-enterprisedb",
24+
"databases-for-etcd", "databases-for-mongodb",
25+
"databases-for-mysql", "databases-for-postgresql",
26+
"databases-for-redis", "directlink",
27+
"iam-groups", "is", "messagehub",
28+
"messages-for-rabbitmq", "schematics", "secrets-manager", "server-protect", "user-management"],
29+
service_ref)
30+
])
31+
error_message = "Provide a valid service reference for zone creation"
32+
}
33+
default = []
34+
description = "(List) Service reference for the zone creation"
35+
}
36+
37+
variable "target_service_details" {
38+
type = list(object({
39+
target_service_name = string
40+
target_rg = optional(string)
41+
enforcement_mode = string
42+
tags = optional(list(string))
43+
}))
44+
description = "(String) Details of the target service for which the rule has to be created"
45+
#Validation to restrict the target service name to be the list of supported targets only.
46+
validation {
47+
condition = alltrue([
48+
for service_detail in var.target_service_details :
49+
contains(["iam-groups", "iam-access-management", "iam-identity",
50+
"user-management", "cloud-object-storage", "codeengine",
51+
"container-registry", "databases-for-cassandra",
52+
"databases-for-enterprisedb", "databases-for-elasticsearch",
53+
"databases-for-etcd", "databases-for-mongodb",
54+
"databases-for-mysql", "databases-for-postgresql", "databases-for-redis",
55+
"directlink", "dns-svcs", "messagehub", "kms", "containers-kubernetes",
56+
"messages-for-rabbitmq", "secrets-manager", "transit", "is",
57+
"schematics"], service_detail.target_service_name)
58+
])
59+
error_message = "Provide a valid target service name that is supported by context-based restrictions"
60+
}
61+
}

cbr-service-profile/version.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.3.0"
3+
required_providers {
4+
# Pin to the lowest provider version of the range defined in the main module's version.tf to ensure lowest version still works
5+
ibm = {
6+
source = "IBM-Cloud/ibm"
7+
version = ">= 1.49.0"
8+
}
9+
}
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# CBR Multi Service Profile
2+
3+
An end-to-end example that uses the module's default variable values. This example uses the IBM Cloud Provider to automate the following infrastructure::
4+
5+
- Create a VPC and create a CBR zone to allowlist the VPC.
6+
- Create a service reference based CBR zone.
7+
- Create a set of CBR rules.
8+
- Based on the list of target service details provided, create rules for each of them.
9+
- Target service instances access is granted based on the following parameters.
10+
- Based on the account.
11+
- Based on the access tags.
12+
- Based on the resource group.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
##############################################################################
2+
# Resource Group
3+
##############################################################################
4+
5+
module "resource_group" {
6+
source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-resource-group.git?ref=v1.0.5"
7+
# if an existing resource group is not set (null) create a new one using prefix
8+
resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null
9+
existing_resource_group_name = var.resource_group
10+
}
11+
12+
# ##############################################################################
13+
# # Get Cloud Account ID
14+
# ##############################################################################
15+
data "ibm_iam_account_settings" "iam_account_settings" {
16+
}
17+
18+
##############################################################################
19+
# VPC
20+
##############################################################################
21+
resource "ibm_is_vpc" "example_vpc" {
22+
name = "${var.prefix}-vpc"
23+
resource_group = module.resource_group.resource_group_id
24+
tags = var.resource_tags
25+
}
26+
27+
resource "ibm_is_public_gateway" "testacc_gateway" {
28+
name = "${var.prefix}-pgateway"
29+
vpc = ibm_is_vpc.example_vpc.id
30+
zone = "${var.region}-1"
31+
resource_group = module.resource_group.resource_group_id
32+
}
33+
34+
resource "ibm_is_subnet" "testacc_subnet" {
35+
name = "${var.prefix}-subnet"
36+
vpc = ibm_is_vpc.example_vpc.id
37+
zone = "${var.region}-1"
38+
public_gateway = ibm_is_public_gateway.testacc_gateway.id
39+
total_ipv4_address_count = 256
40+
resource_group = module.resource_group.resource_group_id
41+
}
42+
43+
##############################################################################
44+
# CBR zone & rule creation
45+
##############################################################################
46+
47+
locals {
48+
zone_vpc_crn_list = [ibm_is_vpc.example_vpc.crn]
49+
enforcement_mode = "report"
50+
# Merge zone ids to pass as contexts to the rule
51+
target_services_details = [
52+
{
53+
target_service_name = "cloud-object-storage",
54+
# Note these are access tags and all iam access tags must be present on the COS instance for the rule to match
55+
tags = var.existing_access_tags,
56+
enforcement_mode = local.enforcement_mode,
57+
},
58+
{
59+
target_service_name = "kms",
60+
target_rg = module.resource_group.resource_group_id
61+
enforcement_mode = local.enforcement_mode,
62+
63+
},
64+
{
65+
target_service_name = "messagehub",
66+
target_rg = module.resource_group.resource_group_id
67+
enforcement_mode = local.enforcement_mode
68+
}
69+
]
70+
}
71+
72+
module "cbr_rule_multi_service_profile" {
73+
source = "../../cbr-service-profile"
74+
zone_service_ref_list = var.zone_service_ref_list
75+
zone_vpc_crn_list = local.zone_vpc_crn_list
76+
target_service_details = local.target_services_details
77+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
##############################################################################
2+
# Outputs
3+
##############################################################################
4+
5+
output "zone_ids" {
6+
value = module.cbr_rule_multi_service_profile[*].zone_ids
7+
description = "CBR zone resource instance id(s)"
8+
}
9+
10+
output "zone_crns" {
11+
value = module.cbr_rule_multi_service_profile[*].zone_crns
12+
description = "CBR zones crn(s)"
13+
}
14+
15+
output "zone_hrefs" {
16+
value = module.cbr_rule_multi_service_profile[*].zone_hrefs
17+
description = "CBR zones href(s)"
18+
}
19+
20+
output "rule_ids" {
21+
value = module.cbr_rule_multi_service_profile[*].rule_ids
22+
description = "CBR rule id(s)"
23+
}
24+
25+
output "rule_crns" {
26+
value = module.cbr_rule_multi_service_profile[*].rule_crns
27+
description = "CBR rule resource instance crn(s)"
28+
}
29+
30+
output "rule_hrefs" {
31+
value = module.cbr_rule_multi_service_profile[*].rule_hrefs
32+
description = "CBR rule resource instance href(s)"
33+
}
34+
35+
output "vpc_crn" {
36+
value = ibm_is_vpc.example_vpc.crn
37+
description = "VPC CRN"
38+
}
39+
40+
output "account_id" {
41+
value = data.ibm_iam_account_settings.iam_account_settings.account_id
42+
description = "Account ID (used in tests)"
43+
}

0 commit comments

Comments
 (0)