Skip to content

Commit

Permalink
feat: add secure-by-default cbr submodule (#267)
Browse files Browse the repository at this point in the history
Co-authored-by: Akash Kumar <[email protected]>
Co-authored-by: Akash Kumar <[email protected]>
Co-authored-by: Aashiq-J <[email protected]>
  • Loading branch information
4 people authored Jul 31, 2023
1 parent 4ec347e commit 5ac15fc
Show file tree
Hide file tree
Showing 17 changed files with 866 additions and 126 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

This module can be used to provision and configure [Context Based Restrictions](https://cloud.ibm.com/docs/account?topic=account-context-restrictions-create&interface=ui).

See in particular the [fscloud profile](./profiles/fscloud/) module that enables creating an opiniated account-level coarse-grained set of CBR rules and zones aligned with the "secure by default" principles.

## Usage

```hcl
Expand Down Expand Up @@ -55,32 +57,33 @@ You need the following permissions to run this module.
<!-- BEGIN EXAMPLES HOOK -->
## Examples

- [ Pre-wired CBR configuration for FS Cloud example](examples/fscloud)
- [ CBR Multi Service Profile](examples/multi-service-profile)
- [ Multi-zone example](examples/multizone-rule)
- [ Zone example](examples/zone)
<!-- END EXAMPLES HOOK -->
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements
### Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.49.0 |

## Modules
### Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_cbr_rule"></a> [cbr\_rule](#module\_cbr\_rule) | ./cbr-rule-module | n/a |
| <a name="module_cbr_zone"></a> [cbr\_zone](#module\_cbr\_zone) | ./cbr-zone-module | n/a |

## Resources
### Resources

| Name | Type |
|------|------|
| [ibm_iam_account_settings.iam_account_settings](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/iam_account_settings) | data source |

## Inputs
### Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
Expand All @@ -94,7 +97,7 @@ You need the following permissions to run this module.
| <a name="input_rule_description"></a> [rule\_description](#input\_rule\_description) | (Optional, String) The description of the rule | `string` | `null` | no |
| <a name="input_zone_description"></a> [zone\_description](#input\_zone\_description) | (Optional, String) The description of the zone | `string` | `null` | no |

## Outputs
### Outputs

| Name | Description |
|------|-------------|
Expand Down
2 changes: 1 addition & 1 deletion cbr-service-profile/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ locals {
vpc_zone_list = (length(var.zone_vpc_crn_list) > 0) ? [{
name = "${var.prefix}-cbr-vpc-zone"
account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
zone_description = "cbr-vpc-zone-terraform"
zone_description = "${var.prefix}-cbr-vpc-zone-terraform"
addresses = [
for zone_vpc_crn in var.zone_vpc_crn_list :
{ "type" = "vpc", value = zone_vpc_crn }
Expand Down
121 changes: 2 additions & 119 deletions cbr-zone-module/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ variable "excluded_addresses" {
default = []
validation {
condition = alltrue([
for address in var.excluded_addresses : contains(["ipAddress", "ipRange", "subnet", "vpc", "serviceRef"], address.type)
for address in var.excluded_addresses : contains(["ipAddress", "ipRange", "subnet"], address.type)
])
error_message = "Valid values for address types are 'ipAddress', 'ipRange', 'subnet', 'vpc', and 'serviceRef'"
error_message = "Valid values for address types are 'ipAddress', 'ipRange' and 'subnet'"
}
validation {
condition = alltrue([
Expand All @@ -215,121 +215,4 @@ variable "excluded_addresses" {
])
error_message = "Value should be a valid as per the type"
}

validation {
condition = alltrue(
flatten(
[for address in var.excluded_addresses :
(address.ref != null ?
(
alltrue(
[for ref in address.ref : alltrue([
length(address.ref.account_id) >= 1,
length(address.ref.account_id) <= 128,
can(regex("^[a-zA-Z0-9-]+$", address.ref.account_id))
])]
)
) : true
)
]
)
)
error_message = "Value should be a valid account id"
}

validation {
condition = alltrue(
flatten(
[for address in var.excluded_addresses :
(address.ref != null ?
(
alltrue(
[for ref in address.ref : anytrue([
address.ref.location == null,
alltrue([
can(length(address.ref.location) >= 1),
can(length(address.ref.location) <= 128),
can(regex("^[0-9a-z-]+$", address.ref.location))
])
])]
)
) : true
)
]
)
)
error_message = "Value should be a valid location"
}

validation {
condition = alltrue(
flatten(
[for address in var.excluded_addresses :
(address.ref != null ?
(
alltrue(
[for ref in address.ref : anytrue([
address.ref.service_instance == null,
alltrue([
can(length(address.ref.service_instance) >= 1),
can(length(address.ref.service_instance) <= 128),
can(regex("^[0-9a-z-/]+$", address.ref.service_instance))
])
])]
)
) : true
)
]
)
)
error_message = "Value should be a valid service instance"
}

validation {
condition = alltrue(
flatten(
[for address in var.excluded_addresses :
(address.ref != null ?
(
alltrue(
[for ref in address.ref : anytrue([
address.ref.service_name == null,
alltrue([
can(length(address.ref.service_name) >= 1),
can(length(address.ref.service_name) <= 128),
can(regex("^[0-9a-z-/]+$", address.ref.service_name))
])
])]
)
) : true
)
]
)
)
error_message = "Value should be a valid service name"
}

validation {
condition = alltrue(
flatten(
[for address in var.excluded_addresses :
(address.ref != null ?
(
alltrue(
[for ref in address.ref : anytrue([
address.ref.service_type == null,
alltrue([
can(length(address.ref.service_type) >= 1),
can(length(address.ref.service_type) <= 128),
can(regex("^[0-9a-z_]+$", address.ref.service_type))
])
])]
)
) : true
)
]
)
)
error_message = "Value should be a valid service type"
}
}
15 changes: 15 additions & 0 deletions examples/fscloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Pre-wired CBR configuration for FS Cloud example

This example demonstrates how to use the [fscloud profile](../../profiles/fscloud/) module to lay out a complete "secure by default" coarse-grained CBR topology in a given account.

This examples is designed to show case some of the key customization options for the module. In addition to the pre-wired CBR rules documented at [fscloud profile](../../profiles/fscloud/), this examples show how to customize the module to:
1. Open up network traffic flow from ICD mongodb, ICD Postgresql to the Key Protect private endpoints
2. Open up network traffic flow from Schematics to Key Protect public endpoints
3. Open up network traffic flow from a block of IPs to the Schematics public endpoint
4. Open up network traffic flow from the VPC created in this example to ICD postgresql private endpoints

Context: this examples covers a "pseudo" real-world scenario where:
1. ICD Mongodb, and Postgresql instances are encrypted using keys storage in Key Protect.
2. Schematics is used to execute terraform that create Key Protect keys and key ring over its public endpoint
3. Operators used machines with a set list of public IPs to interact with Schematics
4. Applications are running the VPC and need access to PostgreSQL via the private endpoint - eg: a VPE.
116 changes: 116 additions & 0 deletions examples/fscloud/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
##############################################################################
# Resource Group
##############################################################################

module "resource_group" {
source = "terraform-ibm-modules/resource-group/ibm"
version = "1.0.5"
# if an existing resource group is not set (null) create a new one using prefix
resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null
existing_resource_group_name = var.resource_group
}

# ##############################################################################
# # Get Cloud Account ID
# ##############################################################################
data "ibm_iam_account_settings" "iam_account_settings" {
}

##############################################################################
# VPC
##############################################################################
resource "ibm_is_vpc" "example_vpc" {
name = "${var.prefix}-vpc"
resource_group = module.resource_group.resource_group_id
tags = var.resource_tags
}

resource "ibm_is_public_gateway" "testacc_gateway" {
name = "${var.prefix}-pgateway"
vpc = ibm_is_vpc.example_vpc.id
zone = "${var.region}-1"
resource_group = module.resource_group.resource_group_id
}

resource "ibm_is_subnet" "testacc_subnet" {
name = "${var.prefix}-subnet"
vpc = ibm_is_vpc.example_vpc.id
zone = "${var.region}-1"
public_gateway = ibm_is_public_gateway.testacc_gateway.id
total_ipv4_address_count = 256
resource_group = module.resource_group.resource_group_id
}

##############################################################################
# CBR zone & rule creation
##############################################################################

module "cbr_account_level" {
source = "../../profiles/fscloud"
prefix = var.prefix
zone_vpc_crn_list = [ibm_is_vpc.example_vpc.crn]
allow_cos_to_kms = var.allow_cos_to_kms
allow_block_storage_to_kms = var.allow_block_storage_to_kms
allow_roks_to_kms = var.allow_roks_to_kms
allow_vpcs_to_container_registry = var.allow_vpcs_to_container_registry
allow_vpcs_to_cos = var.allow_vpcs_to_cos

## Enable enforcement for key protect as an example
## The other services not referenced here, are either report, or disabled (when not support report)
target_service_details = {
"kms" = {
"enforcement_mode" = "enabled"
}
}

# Demonstrates how additional context to the rules created by this module can be added.
# This example open up:
# 1. Flows from icd mongodb, postgresql to kms on private endpoint
# 2. Flow from schematics on public kms endpoint
# 3. Add a block of ips to schematics public endpoint
# 4. Flow from vpc(s) specified in input zone_vpc_crn_list to postgresql private endpoint
custom_rule_contexts_by_service = {
"kms" = [{
endpointType = "private"
service_ref_names = ["databases-for-mongodb", "databases-for-postgresql"]
},
{
endpointType = "public"
service_ref_names = ["schematics"]
}
],
"schematics" = [{
endpointType = "public"
zone_ids = [module.cbr_zone_operator_ips.zone_id]
}],
"databases-for-postgresql" = [{
endpointType = "private"
## Give access to the zone containing the VPC passed in zone_vpc_crn_list input
add_managed_vpc_zone = true
}]
}
}

## Example of zone using ip addresses, and reference in one of the zone created by the cbr_account_level above.
## A zone used to group operator machine ips.
module "cbr_zone_operator_ips" {
source = "../../cbr-zone-module"
name = "List of operator environment public IPs"
account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
zone_description = "Zone grouping list of known public ips for operator machines"
addresses = [{
type = "subnet"
value = "0.0.0.0/0" # All ip for this public example - this would be narrowed down typically to an enterprise ip block
}]
}

## Examples of data lookup on objects (zone, rule) created by the fscoud profile module
## Get rule targetting "event-notification"
data "ibm_cbr_rule" "event_notification_rule" {
rule_id = module.cbr_account_level.map_target_service_rule_ids["event-notifications"].rule_id
}

## Get zone having "event-notification" as single source
data "ibm_cbr_zone" "event_notifications_zone" {
zone_id = module.cbr_account_level.map_service_ref_name_zoneid["event-notifications"].zone_id
}
33 changes: 33 additions & 0 deletions examples/fscloud/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
##############################################################################
# Outputs
##############################################################################

output "account_id" {
value = data.ibm_iam_account_settings.iam_account_settings.account_id
description = "Account ID (used in tests)"
}

output "map_service_ref_name_zoneid" {
value = module.cbr_account_level.map_service_ref_name_zoneid
description = "Map of service reference and zone ids"
}

output "map_vpc_zoneid" {
value = module.cbr_account_level.map_vpc_zoneid
description = "Map of VPC and zone ids"
}

output "map_target_service_rule_ids" {
value = module.cbr_account_level.map_target_service_rule_ids
description = "Map of target service and rule ids"
}

output "example_event_notification_zone" {
value = data.ibm_cbr_rule.event_notification_rule
description = "Example of rule created by the module. Demonstrates data lookup."
}

output "example_event_notification_rule" {
value = data.ibm_cbr_zone.event_notifications_zone
description = "Example of zone created by the module. Demonstrates data lookup."
}
4 changes: 4 additions & 0 deletions examples/fscloud/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "ibm" {
ibmcloud_api_key = var.ibmcloud_api_key
region = var.region
}
Loading

0 comments on commit 5ac15fc

Please sign in to comment.