From 35149e2e2f4e1159de8707a81f5299b71067defc Mon Sep 17 00:00:00 2001 From: guybarak Date: Wed, 12 Mar 2025 14:22:36 +0000 Subject: [PATCH 1/2] Adding modules for Azure Check Point deployments --- .gitattributes | 7 + README.md | 14 +- modules/common/outputs.tf | 4 +- modules/common/variables.tf | 5 +- .../high_availability_existing_vnet/README.md | 130 +++++ .../cloud-init.sh | 22 + .../high_availability_existing_vnet/locals.tf | 4 + .../high_availability_existing_vnet/main.tf | 521 +++++++++++++++++ .../variables.tf | 324 +++++++++++ .../versions.tf | 12 + modules/high_availability_new_vnet/README.md | 132 +++++ .../high_availability_new_vnet/cloud-init.sh | 22 + modules/high_availability_new_vnet/locals.tf | 4 + modules/high_availability_new_vnet/main.tf | 528 ++++++++++++++++++ .../high_availability_new_vnet/variables.tf | 323 +++++++++++ .../high_availability_new_vnet/versions.tf | 12 + modules/management_existing_vnet/README.md | 87 +++ .../management_existing_vnet/cloud-init.sh | 16 + modules/management_existing_vnet/locals.tf | 4 + modules/management_existing_vnet/main.tf | 304 ++++++++++ modules/management_existing_vnet/variables.tf | 228 ++++++++ modules/management_existing_vnet/versions.tf | 12 + modules/management_new_vnet/README.md | 4 +- modules/management_new_vnet/cloud-init.sh | 2 +- modules/management_new_vnet/locals.tf | 4 +- modules/management_new_vnet/main.tf | 34 +- modules/management_new_vnet/variables.tf | 3 +- modules/mds_existing_vnet/README.md | 99 ++++ modules/mds_existing_vnet/cloud-init.sh | 20 + modules/mds_existing_vnet/locals.tf | 4 + modules/mds_existing_vnet/main.tf | 307 ++++++++++ modules/mds_existing_vnet/variables.tf | 257 +++++++++ modules/mds_existing_vnet/versions.tf | 12 + modules/mds_new_vnet/README.md | 98 ++++ modules/mds_new_vnet/cloud-init.sh | 20 + modules/mds_new_vnet/locals.tf | 4 + modules/mds_new_vnet/main.tf | 312 +++++++++++ modules/mds_new_vnet/variables.tf | 256 +++++++++ modules/mds_new_vnet/versions.tf | 12 + modules/nva_into_existing_hub/README.md | 98 ++++ modules/nva_into_existing_hub/main.tf | 278 +++++++++ modules/nva_into_existing_hub/variables.tf | 198 +++++++ modules/nva_into_existing_hub/versions.tf | 31 + modules/nva_into_new_vwan/README.md | 102 ++++ modules/nva_into_new_vwan/main.tf | 259 +++++++++ modules/nva_into_new_vwan/variables.tf | 209 +++++++ modules/nva_into_new_vwan/versions.tf | 31 + .../single_gateway_existing_vnet/README.md | 102 ++++ .../cloud-init.sh | 18 + .../single_gateway_existing_vnet/locals.tf | 4 + modules/single_gateway_existing_vnet/main.tf | 235 ++++++++ .../single_gateway_existing_vnet/variables.tf | 271 +++++++++ .../single_gateway_existing_vnet/versions.tf | 12 + modules/single_gateway_new_vnet/README.md | 8 +- modules/single_gateway_new_vnet/cloud-init.sh | 2 +- modules/single_gateway_new_vnet/locals.tf | 4 +- modules/single_gateway_new_vnet/main.tf | 36 +- modules/single_gateway_new_vnet/variables.tf | 6 +- modules/vmss_existing_vnet/README.md | 128 +++++ modules/vmss_existing_vnet/cloud-init.sh | 17 + modules/vmss_existing_vnet/locals.tf | 4 + modules/vmss_existing_vnet/main.tf | 426 ++++++++++++++ modules/vmss_existing_vnet/variables.tf | 399 +++++++++++++ modules/vmss_existing_vnet/versions.tf | 14 + modules/vmss_new_vnet/README.md | 12 +- modules/vmss_new_vnet/cloud-init.sh | 2 +- modules/vmss_new_vnet/locals.tf | 4 +- modules/vmss_new_vnet/main.tf | 32 +- modules/vmss_new_vnet/variables.tf | 3 +- 69 files changed, 7019 insertions(+), 89 deletions(-) create mode 100755 .gitattributes create mode 100755 modules/high_availability_existing_vnet/README.md create mode 100755 modules/high_availability_existing_vnet/cloud-init.sh create mode 100755 modules/high_availability_existing_vnet/locals.tf create mode 100755 modules/high_availability_existing_vnet/main.tf create mode 100755 modules/high_availability_existing_vnet/variables.tf create mode 100755 modules/high_availability_existing_vnet/versions.tf create mode 100755 modules/high_availability_new_vnet/README.md create mode 100755 modules/high_availability_new_vnet/cloud-init.sh create mode 100755 modules/high_availability_new_vnet/locals.tf create mode 100755 modules/high_availability_new_vnet/main.tf create mode 100755 modules/high_availability_new_vnet/variables.tf create mode 100755 modules/high_availability_new_vnet/versions.tf create mode 100755 modules/management_existing_vnet/README.md create mode 100755 modules/management_existing_vnet/cloud-init.sh create mode 100755 modules/management_existing_vnet/locals.tf create mode 100755 modules/management_existing_vnet/main.tf create mode 100755 modules/management_existing_vnet/variables.tf create mode 100755 modules/management_existing_vnet/versions.tf create mode 100755 modules/mds_existing_vnet/README.md create mode 100755 modules/mds_existing_vnet/cloud-init.sh create mode 100755 modules/mds_existing_vnet/locals.tf create mode 100755 modules/mds_existing_vnet/main.tf create mode 100755 modules/mds_existing_vnet/variables.tf create mode 100755 modules/mds_existing_vnet/versions.tf create mode 100755 modules/mds_new_vnet/README.md create mode 100755 modules/mds_new_vnet/cloud-init.sh create mode 100755 modules/mds_new_vnet/locals.tf create mode 100755 modules/mds_new_vnet/main.tf create mode 100755 modules/mds_new_vnet/variables.tf create mode 100755 modules/mds_new_vnet/versions.tf create mode 100755 modules/nva_into_existing_hub/README.md create mode 100755 modules/nva_into_existing_hub/main.tf create mode 100755 modules/nva_into_existing_hub/variables.tf create mode 100755 modules/nva_into_existing_hub/versions.tf create mode 100755 modules/nva_into_new_vwan/README.md create mode 100755 modules/nva_into_new_vwan/main.tf create mode 100755 modules/nva_into_new_vwan/variables.tf create mode 100755 modules/nva_into_new_vwan/versions.tf create mode 100755 modules/single_gateway_existing_vnet/README.md create mode 100755 modules/single_gateway_existing_vnet/cloud-init.sh create mode 100755 modules/single_gateway_existing_vnet/locals.tf create mode 100755 modules/single_gateway_existing_vnet/main.tf create mode 100755 modules/single_gateway_existing_vnet/variables.tf create mode 100755 modules/single_gateway_existing_vnet/versions.tf create mode 100755 modules/vmss_existing_vnet/README.md create mode 100755 modules/vmss_existing_vnet/cloud-init.sh create mode 100755 modules/vmss_existing_vnet/locals.tf create mode 100755 modules/vmss_existing_vnet/main.tf create mode 100755 modules/vmss_existing_vnet/variables.tf create mode 100755 modules/vmss_existing_vnet/versions.tf diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 0000000..8dbd631 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +* text=auto eol=lf +*.tf text eol=lf +*.sh text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.json text eol=lf +*.md text eol=lf \ No newline at end of file diff --git a/README.md b/README.md index 11f9743..218d81b 100755 --- a/README.md +++ b/README.md @@ -18,11 +18,17 @@ This repository provides a structured set of Terraform modules for deploying Che **Submodules:** - -* [`management_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/management_new_vnet) - Deploys CloudGuard Management solution into a new VNet. - +* [`high_availability_existing_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/high_availability_existing_vnet) - Deploys CloudGuard High Availability solution into an existing VNet in azure. +* [`high_availability_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/high_availability_new_vnet) Deploys CloudGuard High Availability solution into a new VNet. +* [`management_existing_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/management_existing_vnet) - Deploys CloudGuard Management solution into an existing VNet. +* [`management_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/management_new_vnet) - Deploys CloudGuard Management solution into a new VNet +* [`mds_existing_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/mds_existing_vnet) - Deploys CloudGuard Management solution into a new VNet. +* [`mds_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/mds_new_vnet) - Deploys CloudGuard Management solution into a new VNet. +* [`nva_into_existing_hub`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/nva_into_existing_hub) - Deploys CloudGuard Virtual WAN NVA solution into an existing vWAN Hub. +* [`nva_into_new_vwan`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/nva_into_new_vwan) - Deploys CloudGuard Virtual WAN NVA solution into a new vWAN Hub. +* [`single_gateway_existing_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/single_gateway_existing_vnet) - Deploys CloudGuard Single Gateway solution into an existing VNet. * [`single_gateway_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/single_gateway_new_vnet) - Deploys CloudGuard Single Gateway solution into a new VNet. - +* [`vmss_existing_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/vmss_existing_vnet) - Deploys CloudGuard VMSS solution into an existing VNet. * [`vmss_new_vnet`](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest/submodules/vmss_new_vnet) - Deploys CloudGuard VMSS solution into a new VNet. Internal Submodules - diff --git a/modules/common/outputs.tf b/modules/common/outputs.tf index 462f5a6..675a9e3 100755 --- a/modules/common/outputs.tf +++ b/modules/common/outputs.tf @@ -26,8 +26,8 @@ output "vm_instance_identity" { value = var.vm_instance_identity_type } -output "template_name"{ - value = var.template_name +output "module_name"{ + value = var.module_name } output "module_version" { diff --git a/modules/common/variables.tf b/modules/common/variables.tf index 16b308e..492ba1b 100755 --- a/modules/common/variables.tf +++ b/modules/common/variables.tf @@ -113,7 +113,7 @@ variable "vm_instance_identity_type" { default = "SystemAssigned" } -variable "template_name"{ +variable "module_name"{ description = "Template name. Should be defined according to deployment type(ha, vmss)" type = string } @@ -216,13 +216,12 @@ variable "publisher" { //************** Storage image reference and plan variables ****************// variable "vm_os_offer" { - description = "The name of the image offer to be deployed.Choose from: check-point-cg-r81, check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" type = string } locals { // locals for 'vm_os_offer' allowed values vm_os_offer_allowed_values = [ - "check-point-cg-r81", "check-point-cg-r8110", "check-point-cg-r8120", "check-point-cg-r82" diff --git a/modules/high_availability_existing_vnet/README.md b/modules/high_availability_existing_vnet/README.md new file mode 100755 index 0000000..2d28c10 --- /dev/null +++ b/modules/high_availability_existing_vnet/README.md @@ -0,0 +1,130 @@ +# Check Point CloudGuard High Availability Module - Existing VNet +This Terraform module deploys Check Point CloudGuard Network Security High Availability solution into an existing VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- System assigned identity +- Availability Set - conditional creation + +For additional information, +please see the [CloudGuard Network for Azure High Availability Cluster Deployment Guide](https://sc1.checkpoint.com/documents/IaaS/WebAdminGuides/EN/CP_CloudGuard_Network_for_Azure_HA_Cluster/Default.htm) + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/high_availability_existing_vnet" + version = "1.0.4" + + tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-ha-terraform" + cluster_name = "checkpoint-ha-terraform" + location = "eastus" + vnet_name = "checkpoint-ha-vnet" + vnet_resource_group = "existing-vnet" + frontend_subnet_name = "frontend" + backend_subnet_name = "backend" + frontend_IP_addresses = [5, 6, 7] + backend_IP_addresses = [5, 6, 7] + admin_password = "xxxxxxxxxxxx" + smart_1_cloud_token_a = "xxxxxxxxxxxx" + smart_1_cloud_token_b = "xxxxxxxxxxxx" + sic_key = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "sg-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + availability_type = "Availability Zone" + enable_custom_metrics = true + enable_floating_ip = false + use_public_ip_prefix = false + create_public_ip_prefix = false + existing_public_ip_prefix_id = "" + admin_shell = "/etc/cli.sh" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + +## Conditional creation +- To deploy the solution based on Azure Availability Set and create a new Availability Set for the virtual machines: + ``` + availability_type = "Availability Set" + ``` + Otherwise, to deploy the solution based on Azure Availability Zone: + ``` + availability_type = "Availability Zone" + ``` + +- To enable CloudGuard metrics in order to send statuses and statistics collected from HA instances to the Azure Monitor service: + ``` + enable_custom_metrics = true + ``` + +- To create new public IP prefix for the public IP: + ``` + use_public_ip_prefix = true + create_public_ip_prefix = true + ``` +- To use an existing public IP prefix for the public IP: + ``` + use_public_ip_prefix = true + create_public_ip_prefix = false + existing_public_ip_prefix_id = "public IP prefix resource id" + ``` + +### Module's variables: + | Name | Description | Type | Allowed values | +|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **tenant_id** | The tenant ID of the Service Principal used to deploy the solution | string | | +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period
| +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions
| +| **cluster_name** | The name of the Check Point Cluster Object | string | Only alphanumeric characters are allowed, and the name must be 1-30 characters long
| +| **vnet_name** | Virtual Network name | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens
| +| **vnet_resource_group** | Resource Group of the existing virtual network | string | The exact name of the existing vnet's resource group
| +| **frontend_subnet_name** | Specifies the name of the external subnet | string | The exact name of the existing external subnet
| +| **backend_subnet_name** | Specifies the name of the internal subnet | string | The exact name of the existing internal subnet
| +| **frontend_IP_addresses** | A list of three whole numbers representing the private IP addresses of the members' eth0 NICs and the cluster VIP IP addresses | list(number) | | +| **backend_IP_addresses** | A list of three whole numbers representing the private IP addresses of the members' eth1 NICs and the backend LB IP addresses | list(number) | | +| **admin_password** | The password associated with the local administrator account on each cluster member | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character
| +| **smart_1_cloud_token_a** | Smart-1 Cloud token to connect automatically ***Member A*** to Check Point's Security Management as a Service. Follow these instructions to connect this member. | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal
| +| **smart_1_cloud_token_b** | Smart-1 Cloud token to connect automatically ***Member B*** to Check Point's Security Management as a Service. Follow these instructions to connect this member. | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal
| +| **sic_key** | The Secure Internal Communication one-time secret used to set up trust between the cluster object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long
| +| **vm_size** | Specifies the size of Virtual Machine | string | Various valid sizes (e.g., "Standard_DS2_v2", "Standard_D4s_v3", etc.)
| +| **disk_size** | Storage data disk size (GB) | string | A number in the range 100 - 3995 (GB)
| +| **vm_os_sku** | A SKU of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license
| +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r81.10";
"check-point-cg-r81.20";
"check-point-cg-r82";
| +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82";
| +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt"
| +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false;
| +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key";
| +| **availability_type** | Specifies whether to deploy the solution based on Azure Availability Set or based on Azure Availability Zone | string | "Availability Zone";
"Availability Set";
**Default:** "Availability Zone" | +| **enable_custom_metrics** | Indicates whether CloudGuard Metrics will be used for Cluster members monitoring | boolean | true;
false;
**Default:** true | +| **enable_floating_ip** | Indicates whether the load balancers will be deployed with floating IP | boolean | true;
false;
**Default:** false | +| **use_public_ip_prefix** | Indicates whether the public IP resources will be deployed with public IP prefix | boolean | true;
false;
**Default:** false | +| **create_public_ip_prefix** | Indicates whether the public IP prefix will be created or an existing one will be used | boolean | true;
false;
**Default:** false | +| **existing_public_ip_prefix_id** | The existing public IP prefix resource ID | string | Existing public IP prefix resource ID
| +| **admin_shell** | Enables selecting different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh;
| +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions | string | | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location | boolean | true;
false;
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs
**Default:** [] | +| **security_rules** | Security rules for the Network Security Group | list(any) | A security rule composed of: {name, priority, direction, access, protocol, source_port_ranges, destination_port_ranges, source_address_prefix, destination_address_prefix, description}
**Default:** [] | +| **admin_SSH_key** | The SSH public key for SSH connections to the instance. Used when the authentication_type is 'SSH Public Key' | string | **Default:** "" | diff --git a/modules/high_availability_existing_vnet/cloud-init.sh b/modules/high_availability_existing_vnet/cloud-init.sh new file mode 100755 index 0000000..77bc6ab --- /dev/null +++ b/modules/high_availability_existing_vnet/cloud-init.sh @@ -0,0 +1,22 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +sicKey="${sic_key}" +tenantId="${tenant_id}" +virtualNetwork="${virtual_network}" +clusterName="${cluster_name}" +externalPrivateAddresses="${external_private_addresses}" +customMetrics="${enable_custom_metrics}" +adminShell="${admin_shell}" +smart1CloudToken="${smart_1_cloud_token}" +Vips='[{"name": "cluster-vip", "privateIPAddress": "${external_private_addresses}", "publicIPAddress": "${cluster_name}"}]' +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" \ No newline at end of file diff --git a/modules/high_availability_existing_vnet/locals.tf b/modules/high_availability_existing_vnet/locals.tf new file mode 100755 index 0000000..c39021c --- /dev/null +++ b/modules/high_availability_existing_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "high_availability" + module_version = "1.0.4" +} diff --git a/modules/high_availability_existing_vnet/main.tf b/modules/high_availability_existing_vnet/main.tf new file mode 100755 index 0000000..d711440 --- /dev/null +++ b/modules/high_availability_existing_vnet/main.tf @@ -0,0 +1,521 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = var.number_of_vm_instances + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = var.is_blink + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +resource "random_id" "random_id" { + byte_length = 13 + keepers = { + rg_id = module.common.resource_group_id + } +} + +resource "azurerm_public_ip_prefix" "public_ip_prefix" { + count = var.use_public_ip_prefix && var.create_public_ip_prefix ? 1 : 0 + name = "${module.common.resource_group_name}-ipprefix" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + prefix_length = 30 +} + +data "azurerm_subnet" "frontend" { + name = var.frontend_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +data "azurerm_subnet" "backend" { + name = var.backend_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +resource "azurerm_public_ip" "public-ip" { + count = 2 + name = "${var.cluster_name}${count.index+1}_IP" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-${count.index+1}-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_public_ip" "cluster-vip" { + name = var.cluster_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-vip-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_network_interface" "nic_vip" { + depends_on = [ + azurerm_public_ip.cluster-vip, + azurerm_public_ip.public-ip] + name = "${var.cluster_name}1-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig1" + primary = true + subnet_id = data.azurerm_subnet.frontend.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(data.azurerm_subnet.frontend.address_prefixes[0], var.frontend_IP_addresses[0]) + public_ip_address_id = azurerm_public_ip.public-ip.0.id + } + ip_configuration { + name = "cluster-vip" + subnet_id = data.azurerm_subnet.frontend.id + primary = false + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(data.azurerm_subnet.frontend.address_prefixes[0], var.frontend_IP_addresses[2]) + public_ip_address_id = azurerm_public_ip.cluster-vip.id + } + lifecycle { + ignore_changes = [ + # Ignore changes to ip_configuration when Re-applying, e.g. because a cluster failover and associating the cluster- vip with the other member. + # updates these based on some ruleset managed elsewhere. + ip_configuration + ] + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic_vip_lb_association" { + depends_on = [azurerm_network_interface.nic_vip, azurerm_lb_backend_address_pool.frontend-lb-pool] + network_interface_id = azurerm_network_interface.nic_vip.id + ip_configuration_name = "ipconfig1" + backend_address_pool_id = azurerm_lb_backend_address_pool.frontend-lb-pool.id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip, + azurerm_lb.frontend-lb] + name = "${var.cluster_name}2-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig1" + primary = true + subnet_id = data.azurerm_subnet.frontend.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(data.azurerm_subnet.frontend.address_prefixes[0], var.frontend_IP_addresses[1]) + public_ip_address_id = azurerm_public_ip.public-ip.1.id + } + lifecycle { + ignore_changes = [ + # Ignore changes to ip_configuration when Re-applying, e.g. because a cluster failover and associating the cluster- vip with the other member. + # updates these based on some ruleset managed elsewhere. + ip_configuration + ] + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic_lb_association" { + depends_on = [azurerm_network_interface.nic, azurerm_lb_backend_address_pool.frontend-lb-pool] + network_interface_id = azurerm_network_interface.nic.id + ip_configuration_name = "ipconfig1" + backend_address_pool_id = azurerm_lb_backend_address_pool.frontend-lb-pool.id +} + +resource "azurerm_network_interface" "nic1" { + depends_on = [ + azurerm_lb.backend-lb] + count = 2 + name = "${var.cluster_name}${count.index+1}-eth1" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig2" + subnet_id = data.azurerm_subnet.backend.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(data.azurerm_subnet.backend.address_prefixes[0], var.backend_IP_addresses[count.index+1]) + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic1_lb_association" { + depends_on = [azurerm_network_interface.nic1, azurerm_lb_backend_address_pool.backend-lb-pool] + count = 2 + network_interface_id = azurerm_network_interface.nic1[count.index].id + ip_configuration_name = "ipconfig2" + backend_address_pool_id = azurerm_lb_backend_address_pool.backend-lb-pool.id +} + +//********************** Load Balancers **************************// +resource "azurerm_public_ip" "public-ip-lb" { + name = "frontend_lb_ip" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_lb" "frontend-lb" { + depends_on = [ + azurerm_public_ip.public-ip-lb] + name = "frontend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + + frontend_ip_configuration { + name = "LoadBalancerFrontend" + public_ip_address_id = azurerm_public_ip.public-ip-lb.id + } +} + +resource "azurerm_lb_backend_address_pool" "frontend-lb-pool" { + loadbalancer_id = azurerm_lb.frontend-lb.id + name = "frontend-lb-pool" +} + +resource "azurerm_lb" "backend-lb" { + name = "backend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + frontend_ip_configuration { + name = "backend-lb" + subnet_id = data.azurerm_subnet.backend.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(data.azurerm_subnet.backend.address_prefixes[0], var.backend_IP_addresses[0]) + } +} + +resource "azurerm_lb_backend_address_pool" "backend-lb-pool" { + name = "backend-lb-pool" + loadbalancer_id = azurerm_lb.backend-lb.id +} + +resource "azurerm_lb_probe" "azure_lb_healprob" { + count = 2 + loadbalancer_id = count.index == 0 ? azurerm_lb.frontend-lb.id : azurerm_lb.backend-lb.id + name = var.lb_probe_name + protocol = var.lb_probe_protocol + port = var.lb_probe_port + interval_in_seconds = var.lb_probe_interval + number_of_probes = var.lb_probe_unhealthy_threshold +} + +resource "azurerm_lb_rule" "backend_lb_rules" { + loadbalancer_id = azurerm_lb.backend-lb.id + name = "backend-lb" + protocol = "All" + frontend_port = 0 + backend_port = 0 + frontend_ip_configuration_name = "backend-lb" + load_distribution = "Default" + backend_address_pool_ids = [azurerm_lb_backend_address_pool.backend-lb-pool.id] + probe_id = azurerm_lb_probe.azure_lb_healprob[1].id + enable_floating_ip = var.enable_floating_ip +} + +//********************** Availability Set **************************// +locals { + availability_set_condition = var.availability_type == "Availability Set" ? true : false + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false +} +resource "azurerm_availability_set" "availability-set" { + count = local.availability_set_condition ? 1 : 0 + name = "${var.cluster_name}-AvailabilitySet" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + platform_fault_domain_count = 2 + platform_update_domain_count = 5 + managed = true +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } +} + +//********************** Virtual Machines **************************// +locals { + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} +resource "azurerm_virtual_machine" "vm-instance-availability-set" { + depends_on = [ + azurerm_network_interface.nic, + azurerm_network_interface.nic1, + azurerm_network_interface.nic_vip] + count = local.availability_set_condition ? module.common.number_of_vm_instances : 0 + name = "${var.cluster_name}${count.index+1}" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + availability_set_id = local.availability_set_condition ? azurerm_availability_set.availability-set[0].id : "" + vm_size = module.common.vm_size + network_interface_ids = count.index == 0 ? [ + azurerm_network_interface.nic_vip.id, + azurerm_network_interface.nic1.0.id] : [ + azurerm_network_interface.nic.id, + azurerm_network_interface.nic1.1.id] + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = count.index == 0 ? azurerm_network_interface.nic_vip.id : azurerm_network_interface.nic.id + identity { + type = module.common.vm_instance_identity + } + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = "${var.cluster_name}-${count.index+1}" + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + os_profile { + computer_name = "${lower(var.cluster_name)}${count.index+1}" + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + tenant_id = var.tenant_id + virtual_network = var.vnet_name + cluster_name = var.cluster_name + external_private_addresses = azurerm_network_interface.nic_vip.ip_configuration[1].private_ip_address + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + smart_1_cloud_token = count.index == 0 ? var.smart_1_cloud_token_a : var.smart_1_cloud_token_b + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } +} + +resource "azurerm_virtual_machine" "vm-instance-availability-zone" { + depends_on = [ + azurerm_network_interface.nic, + azurerm_network_interface.nic1, + azurerm_network_interface.nic_vip] + count = local.availability_set_condition ? 0 : module.common.number_of_vm_instances + name = "${var.cluster_name}${count.index+1}" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + zones = [ + count.index+1] + vm_size = module.common.vm_size + network_interface_ids = count.index == 0 ? [ + azurerm_network_interface.nic_vip.id, + azurerm_network_interface.nic1.0.id] : [ + azurerm_network_interface.nic.id, + azurerm_network_interface.nic1.1.id] + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = count.index == 0 ? azurerm_network_interface.nic_vip.id : azurerm_network_interface.nic.id + identity { + type = module.common.vm_instance_identity + } + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = "${var.cluster_name}-${count.index+1}" + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + os_profile { + computer_name = "${lower(var.cluster_name)}${count.index+1}" + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + tenant_id = var.tenant_id + virtual_network = var.vnet_name + cluster_name = var.cluster_name + external_private_addresses = azurerm_network_interface.nic_vip.ip_configuration[1].private_ip_address + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + smart_1_cloud_token = count.index == 0 ? var.smart_1_cloud_token_a : var.smart_1_cloud_token_b + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } +} +//********************** Role Assigments **************************// +data "azurerm_role_definition" "virtual_machine_contributor_role_definition" { + name = "Virtual Machine Contributor" +} +data "azurerm_role_definition" "reader_role_definition" { + name = "Reader" +} +data "azurerm_client_config" "client_config" { +} +resource "azurerm_role_assignment" "cluster_virtual_machine_contributor_assignment" { + count = 2 + lifecycle { + ignore_changes = [ + role_definition_id, principal_id + ] + } + scope = module.common.resource_group_id + role_definition_id = data.azurerm_role_definition.virtual_machine_contributor_role_definition.id + principal_id = local.availability_set_condition ? lookup(azurerm_virtual_machine.vm-instance-availability-set[count.index].identity[0], "principal_id") : lookup(azurerm_virtual_machine.vm-instance-availability-zone[count.index].identity[0], "principal_id") +} +resource "azurerm_role_assignment" "cluster_reader_assigment" { + count = 2 + lifecycle { + ignore_changes = [ + role_definition_id, principal_id + ] + } + scope = module.common.resource_group_id + role_definition_id = data.azurerm_role_definition.reader_role_definition.id + principal_id = local.availability_set_condition ? lookup(azurerm_virtual_machine.vm-instance-availability-set[count.index].identity[0], "principal_id") : lookup(azurerm_virtual_machine.vm-instance-availability-zone[count.index].identity[0], "principal_id") +} \ No newline at end of file diff --git a/modules/high_availability_existing_vnet/variables.tf b/modules/high_availability_existing_vnet/variables.tf new file mode 100755 index 0000000..045a651 --- /dev/null +++ b/modules/high_availability_existing_vnet/variables.tf @@ -0,0 +1,324 @@ +//********************** Basic Configuration Variables **************************// + +variable "tenant_id" { + description = "Tenant ID" + type = string +} + +variable "cluster_name" { + description = "Cluster name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resources will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "availability_type" { + description = "Specifies whether to deploy the solution based on Azure Availability Set or based on Azure Availability Zone." + type = string + default = "Availability Zone" +} + +locals { // locals for 'availability_type' allowed values + availability_type_allowed_values = [ + "Availability Zone", + "Availability Set" + ] + // will fail if [var.availability_type] is invalid: + validate_availability_type_value = index(local.availability_type_allowed_values, var.availability_type) +} + +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "smart_1_cloud_token_a" { + description = "Smart-1 Cloud Token, for configuring member A" + type = string +} + +variable "smart_1_cloud_token_b" { + description = "Smart-1 Cloud Token, for configuring member B" + type = string +} + +variable "sic_key" { + description = "Secure Internal Communication(SIC) key" + type = string +} +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "installation_type" { + description = "Installation type" + type = string + default = "cluster" +} + +variable "number_of_vm_instances" { + description = "Number of VM instances to deploy " + type = string + default = "2" +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "is_blink" { + description = "Define if blink image is used for deployment" + default = true +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "vnet_resource_group" { + description = "Resource group of existing vnet" + type = string +} + +variable "frontend_subnet_name" { + description = "Frontend subnet name" + type = string +} + +variable "backend_subnet_name" { + description = "Backend subnet name" + type = string +} + +variable "frontend_IP_addresses" { + description = "A list of three whole numbers representing the private ip addresses of the members eth0 NICs and the cluster vip ip addresses. The numbers can be represented as binary integers with no more than the number of digits remaining in the address after the given frontend subnet prefix. The IP addresses are defined by their position in the frontend subnet." + type = list(number) +} + +variable "backend_IP_addresses" { + description = "A list of three whole numbers representing the private ip addresses of the members eth1 NICs and the backend lb ip addresses. The numbers can be represented as binary integers with no more than the number of digits remaining in the address after the given backend subnet prefix. The IP addresses are defined by their position in the backend subnet." + type = list(number) +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "lb_probe_name" { + description = "Name to be used for lb health probe" + default = "health_prob_port" +} + +variable "lb_probe_port" { + description = "Port to be used for load balancer health probes and rules" + default = "8117" +} + +variable "lb_probe_protocol" { + description = "Protocols to be used for load balancer health probes and rules" + default = "Tcp" +} + +variable "lb_probe_unhealthy_threshold" { + description = "Number of times load balancer health probe has an unsuccessful attempt before considering the endpoint unhealthy." + default = 2 +} + +variable "lb_probe_interval" { + description = "Interval in seconds load balancer health probe rule performs a check" + default = 5 +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "enable_custom_metrics" { + description = "Indicates whether CloudGuard Metrics will be use for Cluster members monitoring." + type = bool + default = true +} + +variable "enable_floating_ip" { + description = "Indicates whether the load balancers will be deployed with floating IP." + type = bool + default = false +} + +variable "use_public_ip_prefix" { + description = "Indicates whether the public IP resources will be deployed with public IP prefix." + type = bool + default = false +} + +variable "create_public_ip_prefix" { + description = "Indicates whether the public IP prefix will created or an existing will be used." + type = bool + default = false +} + +variable "existing_public_ip_prefix_id" { + description = "The existing public IP prefix resource id." + type = string + default = "" +} + +locals{ + # Validate both s1c tokens are used or both empty + is_both_tokens_used = length(var.smart_1_cloud_token_a) > 0 == length(var.smart_1_cloud_token_b) > 0 + validation_message_both = "To connect to Smart-1 Cloud, you must provide two tokens (one per member)" + _ = regex("^$", (local.is_both_tokens_used ? "" : local.validation_message_both)) + + is_tokens_used = length(var.smart_1_cloud_token_a) > 0 + # Validate both s1c tokens are unqiue + token_parts_a = split(" ",var.smart_1_cloud_token_a) + token_parts_b = split(" ",var.smart_1_cloud_token_b) + acutal_token_a = local.token_parts_a[length(local.token_parts_a) - 1] + acutal_token_b = local.token_parts_b[length(local.token_parts_b) - 1] + is_both_tokens_the_same = local.acutal_token_a == local.acutal_token_b + validation_message_unique = "Same Smart-1 Cloud token used for both memeber, you must provide unique token for each member" + __ = local.is_tokens_used ? regex("^$", (local.is_both_tokens_the_same ? local.validation_message_unique : "")) : "" +} + +variable "admin_SSH_key" { + type = string + description = "Used when the authentication_type is 'SSH Public Key': The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [] +} + diff --git a/modules/high_availability_existing_vnet/versions.tf b/modules/high_availability_existing_vnet/versions.tf new file mode 100755 index 0000000..8827a9f --- /dev/null +++ b/modules/high_availability_existing_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} \ No newline at end of file diff --git a/modules/high_availability_new_vnet/README.md b/modules/high_availability_new_vnet/README.md new file mode 100755 index 0000000..c86384d --- /dev/null +++ b/modules/high_availability_new_vnet/README.md @@ -0,0 +1,132 @@ +# Check Point CloudGuard High Availability Module - New VNet + +This Terraform module deploys Check Point CloudGuard Network Security High Availability solution into a new VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- Virtual network +- Network security group +- System assigned identity +- Availability Set - conditional creation + +For additional information, +please see the [CloudGuard Network for Azure High Availability Cluster Deployment Guide](https://sc1.checkpoint.com/documents/IaaS/WebAdminGuides/EN/CP_CloudGuard_Network_for_Azure_HA_Cluster/Default.htm) + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. +- vnet - used for creating new virtual network and subnets. +- network_security_group - used for creating new network security groups and rules. + + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/high_availability_new_vnet" + version = "1.0.4" + + tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-ha-terraform" + cluster_name = "checkpoint-ha-terraform" + location = "eastus" + vnet_name = "checkpoint-ha-vnet" + address_space = "10.0.0.0/16" + subnet_prefixes = ["10.0.1.0/24","10.0.2.0/24"] + admin_password = "xxxxxxxxxxxx" + smart_1_cloud_token_a = "xxxxxxxxxxxx" + smart_1_cloud_token_b = "xxxxxxxxxxxx" + sic_key = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "sg-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + availability_type = "Availability Zone" + enable_custom_metrics = true + enable_floating_ip = false + use_public_ip_prefix = false + create_public_ip_prefix = false + existing_public_ip_prefix_id = "" + admin_shell = "/etc/cli.sh" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + +## Conditional creation +- To deploy the solution based on Azure Availability Set and create a new Availability Set for the virtual machines: + ``` + availability_type = "Availability Set" + ``` + Otherwise, to deploy the solution based on Azure Availability Zone: + ``` + availability_type = "Availability Zone" + ``` + +- To enable CloudGuard metrics in order to send statuses and statistics collected from HA instances to the Azure Monitor service: + ``` + enable_custom_metrics = true + ``` + +- To create new public IP prefix for the public IP: + ``` + use_public_ip_prefix = true + create_public_ip_prefix = true + ``` +- To use an existing public IP prefix for the public IP: + ``` + use_public_ip_prefix = true + create_public_ip_prefix = false + existing_public_ip_prefix_id = "public IP prefix resource id" + ``` + +### Module's variables: + | Name | Description | Type | Allowed values | +|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **tenant_id** | The tenant ID of the Service Principal used to deploy the solution | string | | +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens, and parentheses and cannot end in a period
| +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions
| +| **cluster_name** | The name of the Check Point Cluster Object | string | Only alphanumeric characters are allowed, and the name must be 1-30 characters long
| +| **vnet_name** | The name of the virtual network that will be created | string | The name must begin with a letter or number, end with a letter, number, or underscore, and may contain only letters, numbers, underscores, periods, or hyphens
| +| **address_space** | The address prefixes of the virtual network | string | Valid CIDR block
**Default:** "10.0.0.0/16" | +| **subnet_prefixes** | The address prefixes to be used for created subnets | string | The subnets need to contain within the address space for this virtual network (defined by the `address_space` variable)
**Default:** ["10.0.0.0/24", "10.0.1.0/24"] | +| **admin_password** | The password associated with the local administrator account on each cluster member | string | Password must have 3 of the following: 1 lowercase character, 1 uppercase character, 1 number, and 1 special character
| +| **smart_1_cloud_token_a** | Smart-1 Cloud token to connect automatically ***Member A*** to Check Point's Security Management as a Service. | string | A valid token copied from the Connect Gateway screen in the Smart-1 Cloud portal
| +| **smart_1_cloud_token_b** | Smart-1 Cloud token to connect automatically ***Member B*** to Check Point's Security Management as a Service. | string | A valid token copied from the Connect Gateway screen in the Smart-1 Cloud portal
| +| **sic_key** | The Secure Internal Communication one-time secret used to set up trust between the cluster object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long
| +| **vm_size** | Specifies the size of the Virtual Machine | string | Various valid sizes (e.g., "Standard_DS2_v2", "Standard_D4s_v3", etc.)
| +| **disk_size** | Storage data disk size (GB) | string | A number in the range 100 - 3995 (GB)
| +| **vm_os_sku** | A SKU of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license;
| +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82";
| +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82";
| +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt"
| +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false;
| +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key";
| +| **availability_type** | Specifies whether to deploy the solution based on Azure Availability Set or Azure Availability Zone | string | "Availability Zone";
"Availability Set";
**Default:** "Availability Zone" | +| **enable_custom_metrics** | Indicates whether CloudGuard Metrics will be used for Cluster members monitoring | boolean | true;
false;
**Default:** true | +| **enable_floating_ip** | Indicates whether the load balancers will be deployed with floating IP | boolean | true;
false;
**Default:** false | +| **use_public_ip_prefix** | Indicates whether the public IP resources will be deployed with public IP prefix | boolean | true;
false;
**Default:** false | +| **create_public_ip_prefix** | Indicates whether the public IP prefix will be created or an existing one will be used | boolean | true;
false;
**Default:** false | +| **existing_public_ip_prefix_id** | The existing public IP prefix resource ID | string | Existing public IP prefix resource ID
**Default:** "" | +| **admin_shell** | Enables selecting different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh;
**Default:** "/etc/cli.sh" | +| **serial_console_password_hash** | Optional parameter to enable serial console connection in case of SSH key as authentication type | string | | +| **maintenance_mode_password_hash**| Maintenance mode password hash, relevant only for R81.20 and higher versions | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure. If not provided, a default NSG will be created | string | Existing NSG resource ID
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location | boolean | true;
false;
**Default:** false | +| **storage_account_additional_ips**| IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs
**Default:** [] | +| **security_rules** | Security rules for the Network Security Group | list(any) | A security rule composed of: {name, priority, direction, access, protocol, source_port_ranges, destination_port_ranges, source_address_prefix, destination_address_prefix, description}
**Default:** [] | +| **admin_SSH_key** | The SSH public key for SSH connections to the instance. Used when the authentication_type is 'SSH Public Key' | string | **Default:** "" | diff --git a/modules/high_availability_new_vnet/cloud-init.sh b/modules/high_availability_new_vnet/cloud-init.sh new file mode 100755 index 0000000..0c9f2ef --- /dev/null +++ b/modules/high_availability_new_vnet/cloud-init.sh @@ -0,0 +1,22 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +sicKey="${sic_key}" +tenantId="${tenant_id}" +virtualNetwork="${virtual_network}" +clusterName="${cluster_name}" +externalPrivateAddresses="${external_private_addresses}" +customMetrics="${enable_custom_metrics}" +adminShell="${admin_shell}" +smart1CloudToken="${smart_1_cloud_token}" +Vips='[{"name": "cluster-vip", "privateIPAddress": "${external_private_addresses}", "publicIPAddress": "${cluster_name}"}]' +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" diff --git a/modules/high_availability_new_vnet/locals.tf b/modules/high_availability_new_vnet/locals.tf new file mode 100755 index 0000000..9579de5 --- /dev/null +++ b/modules/high_availability_new_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "high_availability_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/high_availability_new_vnet/main.tf b/modules/high_availability_new_vnet/main.tf new file mode 100755 index 0000000..7dd1514 --- /dev/null +++ b/modules/high_availability_new_vnet/main.tf @@ -0,0 +1,528 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = var.number_of_vm_instances + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = var.is_blink + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +module "vnet" { + source = "../vnet" + vnet_name = var.vnet_name + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + nsg_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id + address_space = var.address_space + subnet_prefixes = var.subnet_prefixes +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}_nsg" + location = module.common.resource_group_location + security_rules = var.security_rules +} + +resource "random_id" "random_id" { + byte_length = 13 + keepers = { + rg_id = module.common.resource_group_id + } +} + +resource "azurerm_public_ip_prefix" "public_ip_prefix" { + count = var.use_public_ip_prefix && var.create_public_ip_prefix ? 1 : 0 + name = "${module.common.resource_group_name}-ipprefix" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + prefix_length = 30 +} + +resource "azurerm_public_ip" "public-ip" { + count = 2 + name = "${var.cluster_name}${count.index+1}_IP" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = module.vnet.allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-${count.index+1}-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_public_ip" "cluster-vip" { + name = var.cluster_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = module.vnet.allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-vip-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_network_interface" "nic_vip" { + depends_on = [ + azurerm_public_ip.cluster-vip, + azurerm_public_ip.public-ip] + name = "${var.cluster_name}1-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig1" + primary = true + subnet_id = module.vnet.vnet_subnets[0] + private_ip_address_allocation = module.vnet.allocation_method + private_ip_address = cidrhost(module.vnet.subnet_prefixes[0], 5) + public_ip_address_id = azurerm_public_ip.public-ip.0.id + } + ip_configuration { + name = "cluster-vip" + subnet_id = module.vnet.vnet_subnets[0] + primary = false + private_ip_address_allocation = module.vnet.allocation_method + private_ip_address = cidrhost(module.vnet.subnet_prefixes[0], 7) + public_ip_address_id = azurerm_public_ip.cluster-vip.id + } + lifecycle { + ignore_changes = [ + # Ignore changes to ip_configuration when Re-applying, e.g. because a cluster failover and associating the cluster- vip with the other member. + # updates these based on some ruleset managed elsewhere. + ip_configuration + ] + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic_vip_lb_association" { + depends_on = [azurerm_network_interface.nic_vip, azurerm_lb_backend_address_pool.frontend-lb-pool] + network_interface_id = azurerm_network_interface.nic_vip.id + ip_configuration_name = "ipconfig1" + backend_address_pool_id = azurerm_lb_backend_address_pool.frontend-lb-pool.id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip, + azurerm_lb.frontend-lb] + name = "${var.cluster_name}2-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig1" + primary = true + subnet_id = module.vnet.vnet_subnets[0] + private_ip_address_allocation = module.vnet.allocation_method + private_ip_address = cidrhost(module.vnet.subnet_prefixes[0], 6) + public_ip_address_id = azurerm_public_ip.public-ip.1.id + } + lifecycle { + ignore_changes = [ + # Ignore changes to ip_configuration when Re-applying, e.g. because a cluster failover and associating the cluster- vip with the other member. + # updates these based on some ruleset managed elsewhere. + ip_configuration + ] + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic_lb_association" { + depends_on = [azurerm_network_interface.nic, azurerm_lb_backend_address_pool.frontend-lb-pool] + network_interface_id = azurerm_network_interface.nic.id + ip_configuration_name = "ipconfig1" + backend_address_pool_id = azurerm_lb_backend_address_pool.frontend-lb-pool.id +} + +resource "azurerm_network_interface" "nic1" { + depends_on = [ + azurerm_lb.backend-lb] + count = 2 + name = "${var.cluster_name}${count.index+1}-eth1" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + ip_configuration { + name = "ipconfig2" + subnet_id = module.vnet.vnet_subnets[1] + private_ip_address_allocation = module.vnet.allocation_method + private_ip_address = cidrhost(module.vnet.subnet_prefixes[1], count.index+5) + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "nic1_lb_association" { + depends_on = [azurerm_network_interface.nic1, azurerm_lb_backend_address_pool.backend-lb-pool] + count = 2 + network_interface_id = azurerm_network_interface.nic1[count.index].id + ip_configuration_name = "ipconfig2" + backend_address_pool_id = azurerm_lb_backend_address_pool.backend-lb-pool.id +} + +//********************** Load Balancers **************************// +resource "azurerm_public_ip" "public-ip-lb" { + name = "frontend_lb_ip" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = module.vnet.allocation_method + sku = var.sku + domain_name_label = "${lower(var.cluster_name)}-${random_id.random_id.hex}" + public_ip_prefix_id = var.use_public_ip_prefix ? (var.create_public_ip_prefix ? azurerm_public_ip_prefix.public_ip_prefix[0].id : var.existing_public_ip_prefix_id) : null +} + +resource "azurerm_lb" "frontend-lb" { +// depends_on = [ +// azurerm_public_ip.public-ip-lb] + name = "frontend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + + frontend_ip_configuration { + name = "LoadBalancerFrontend" + public_ip_address_id = azurerm_public_ip.public-ip-lb.id + } +} + +resource "azurerm_lb_backend_address_pool" "frontend-lb-pool" { + loadbalancer_id = azurerm_lb.frontend-lb.id + name = "frontend-lb-pool" +} + +resource "azurerm_lb" "backend-lb" { + name = "backend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + frontend_ip_configuration { + name = "backend-lb" + subnet_id = module.vnet.vnet_subnets[1] + private_ip_address_allocation = module.vnet.allocation_method + private_ip_address = cidrhost(module.vnet.subnet_prefixes[1], 4) + } +} + +resource "azurerm_lb_backend_address_pool" "backend-lb-pool" { + name = "backend-lb-pool" + loadbalancer_id = azurerm_lb.backend-lb.id +} + +resource "azurerm_lb_probe" "azure_lb_healprob" { + count = 2 + loadbalancer_id = count.index == 0 ? azurerm_lb.frontend-lb.id : azurerm_lb.backend-lb.id + name = var.lb_probe_name + protocol = var.lb_probe_protocol + port = var.lb_probe_port + interval_in_seconds = var.lb_probe_interval + number_of_probes = var.lb_probe_unhealthy_threshold +} + +resource "azurerm_lb_rule" "backend_lb_rules" { + loadbalancer_id = azurerm_lb.backend-lb.id + name = "backend-lb" + protocol = "All" + frontend_port = 0 + backend_port = 0 + frontend_ip_configuration_name = "backend-lb" + load_distribution = "Default" + backend_address_pool_ids = [azurerm_lb_backend_address_pool.backend-lb-pool.id] + probe_id = azurerm_lb_probe.azure_lb_healprob[1].id + enable_floating_ip = var.enable_floating_ip +} + +//********************** Availability Set **************************// +locals { + availability_set_condition = var.availability_type == "Availability Set" ? true : false + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false +} +resource "azurerm_availability_set" "availability-set" { + count = local.availability_set_condition ? 1 : 0 + name = "${var.cluster_name}-AvailabilitySet" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + platform_fault_domain_count = 2 + platform_update_domain_count = 5 + managed = true +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } +} + +//********************** Virtual Machines **************************// +locals { + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} +resource "azurerm_virtual_machine" "vm-instance-availability-set" { + depends_on = [ + azurerm_network_interface.nic, + azurerm_network_interface.nic1, + azurerm_network_interface.nic_vip] + count = local.availability_set_condition ? module.common.number_of_vm_instances : 0 + name = "${var.cluster_name}${count.index+1}" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + availability_set_id = local.availability_set_condition ? azurerm_availability_set.availability-set[0].id : "" + vm_size = module.common.vm_size + network_interface_ids = count.index == 0 ? [ + azurerm_network_interface.nic_vip.id, + azurerm_network_interface.nic1.0.id] : [ + azurerm_network_interface.nic.id, + azurerm_network_interface.nic1.1.id] + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = count.index == 0 ? azurerm_network_interface.nic_vip.id : azurerm_network_interface.nic.id + identity { + type = module.common.vm_instance_identity + } + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = "${var.cluster_name}-${count.index+1}" + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + os_profile { + computer_name = "${lower(var.cluster_name)}${count.index+1}" + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + tenant_id = var.tenant_id + virtual_network = module.vnet.vnet_name + cluster_name = var.cluster_name + external_private_addresses = azurerm_network_interface.nic_vip.ip_configuration[1].private_ip_address + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + smart_1_cloud_token = count.index == 0 ? var.smart_1_cloud_token_a : var.smart_1_cloud_token_b + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } +} + +resource "azurerm_virtual_machine" "vm-instance-availability-zone" { + depends_on = [ + azurerm_network_interface.nic, + azurerm_network_interface.nic1, + azurerm_network_interface.nic_vip] + count = local.availability_set_condition ? 0 : module.common.number_of_vm_instances + name = "${var.cluster_name}${count.index+1}" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + zones = [ + count.index+1] + vm_size = module.common.vm_size + network_interface_ids = count.index == 0 ? [ + azurerm_network_interface.nic_vip.id, + azurerm_network_interface.nic1.0.id] : [ + azurerm_network_interface.nic.id, + azurerm_network_interface.nic1.1.id] + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = count.index == 0 ? azurerm_network_interface.nic_vip.id : azurerm_network_interface.nic.id + identity { + type = module.common.vm_instance_identity + } + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = "${var.cluster_name}-${count.index+1}" + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + os_profile { + computer_name = "${lower(var.cluster_name)}${count.index+1}" + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + tenant_id = var.tenant_id + virtual_network = module.vnet.vnet_name + cluster_name = var.cluster_name + external_private_addresses = cidrhost(module.vnet.subnet_prefixes[0], 7) + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + smart_1_cloud_token = count.index == 0 ? var.smart_1_cloud_token_a : var.smart_1_cloud_token_b + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } +} +//********************** Role Assigments **************************// +data "azurerm_role_definition" "virtual_machine_contributor_role_definition" { + name = "Virtual Machine Contributor" +} +data "azurerm_role_definition" "reader_role_definition" { + name = "Reader" +} +data "azurerm_client_config" "client_config" { +} +resource "azurerm_role_assignment" "cluster_virtual_machine_contributor_assignment" { + count = 2 + lifecycle { + ignore_changes = [ + role_definition_id, principal_id + ] + } + scope = module.common.resource_group_id + role_definition_id = data.azurerm_role_definition.virtual_machine_contributor_role_definition.id + principal_id = local.availability_set_condition ? lookup(azurerm_virtual_machine.vm-instance-availability-set[count.index].identity[0], "principal_id") : lookup(azurerm_virtual_machine.vm-instance-availability-zone[count.index].identity[0], "principal_id") +} +resource "azurerm_role_assignment" "cluster_reader_assigment" { + count = 2 + lifecycle { + ignore_changes = [ + role_definition_id, principal_id + ] + } + scope = module.common.resource_group_id + role_definition_id = data.azurerm_role_definition.reader_role_definition.id + principal_id = local.availability_set_condition ? lookup(azurerm_virtual_machine.vm-instance-availability-set[count.index].identity[0], "principal_id") : lookup(azurerm_virtual_machine.vm-instance-availability-zone[count.index].identity[0], "principal_id") +} \ No newline at end of file diff --git a/modules/high_availability_new_vnet/variables.tf b/modules/high_availability_new_vnet/variables.tf new file mode 100755 index 0000000..55ade50 --- /dev/null +++ b/modules/high_availability_new_vnet/variables.tf @@ -0,0 +1,323 @@ +//********************** Basic Configuration Variables **************************// +variable "tenant_id" { + description = "Tenant ID" + type = string +} + +variable "cluster_name" { + description = "Cluster name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resources will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "availability_type" { + description = "Specifies whether to deploy the solution based on Azure Availability Set or based on Azure Availability Zone." + type = string + default = "Availability Zone" +} + +locals { // locals for 'availability_type' allowed values + availability_type_allowed_values = [ + "Availability Zone", + "Availability Set" + ] + // will fail if [var.availability_type] is invalid: + validate_availability_type_value = index(local.availability_type_allowed_values, var.availability_type) +} + +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Macine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "smart_1_cloud_token_a" { + description = "Smart-1 Cloud Token, for configuring member A" + type = string +} + +variable "smart_1_cloud_token_b" { + description = "Smart-1 Cloud Token, for configuring member B" + type = string +} + +variable "sic_key" { + description = "Secure Internal Communication(SIC) key" + type = string +} +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "installation_type" { + description = "Installaiton type" + type = string + default = "cluster" +} + +variable "number_of_vm_instances" { + description = "Number of VM instances to deploy " + type = string + default = "2" +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "is_blink" { + description = "Define if blink image is used for deployment" + default = true +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Natworking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "address_space" { + description = "The address space that is used by a Virtual Network." + type = string + default = "10.0.0.0/16" +} + +variable "subnet_prefixes" { + description = "Address prefix to be used for netwok subnets" + type = list(string) + default = [ + "10.0.0.0/24", + "10.0.1.0/24"] +} + +variable "lb_probe_name" { + description = "Name to be used for lb health probe" + default = "health_prob_port" +} + +variable "lb_probe_port" { + description = "Port to be used for load balancer health probes and rules" + default = "8117" +} + +variable "lb_probe_protocol" { + description = "Protocols to be used for load balancer health probes and rules" + default = "Tcp" +} + +variable "lb_probe_unhealthy_threshold" { + description = "Number of times load balancer health probe has an unsuccessful attempt before considering the endpoint unhealthy." + default = 2 +} + +variable "lb_probe_interval" { + description = "Interval in seconds load balancer health probe rule perfoms a check" + default = 5 +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "enable_custom_metrics" { + description = "Indicates whether CloudGuard Metrics will be use for Cluster members monitoring." + type = bool + default = true +} + +variable "enable_floating_ip" { + description = "Indicates whether the load balancers will be deployed with floating IP." + type = bool + default = false +} + +variable "use_public_ip_prefix" { + description = "Indicates whether the public IP resources will be deployed with public IP prefix." + type = bool + default = false +} + +variable "create_public_ip_prefix" { + description = "Indicates whether the public IP prefix will created or an existing will be used." + type = bool + default = false +} + +variable "existing_public_ip_prefix_id" { + description = "The existing public IP prefix resource id." + type = string + default = "" +} + +locals{ + # Validate both s1c tokens are used or both empty + is_both_tokens_used = length(var.smart_1_cloud_token_a) > 0 == length(var.smart_1_cloud_token_b) > 0 + validation_message_both = "To connect to Smart-1 Cloud, you must provide two tokens (one per member)" + _ = regex("^$", (local.is_both_tokens_used ? "" : local.validation_message_both)) + + is_tokens_used = length(var.smart_1_cloud_token_a) > 0 + # Validate both s1c tokens are unqiue + token_parts_a = split(" ",var.smart_1_cloud_token_a) + token_parts_b = split(" ",var.smart_1_cloud_token_b) + acutal_token_a = local.token_parts_a[length(local.token_parts_a) - 1] + acutal_token_b = local.token_parts_b[length(local.token_parts_b) - 1] + is_both_tokens_the_same = local.acutal_token_a == local.acutal_token_b + validation_message_unique = "Same Smart-1 Cloud token used for both memeber, you must provide unique token for each member" + __ = local.is_tokens_used ? regex("^$", (local.is_both_tokens_the_same ? local.validation_message_unique : "")) : "" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [ + { + name = "AllowAllInBound" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_ranges = "*" + destination_port_ranges = "*" + description = "Allow all inbound connections" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ] +} diff --git a/modules/high_availability_new_vnet/versions.tf b/modules/high_availability_new_vnet/versions.tf new file mode 100755 index 0000000..8827a9f --- /dev/null +++ b/modules/high_availability_new_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} \ No newline at end of file diff --git a/modules/management_existing_vnet/README.md b/modules/management_existing_vnet/README.md new file mode 100755 index 0000000..54cd60c --- /dev/null +++ b/modules/management_existing_vnet/README.md @@ -0,0 +1,87 @@ +# Check Point CloudGuard Management Module - Existing VNet + +This Terraform module deploys Check Point CloudGuard Network Security Management solution into an existing VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- Network security group +- Virtual Machine +- System assigned identity + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. +- network_security_group - used for creating new network security groups and rules. + + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/management_existing_vnet" + version = "1.0.4" + + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-mgmt-terraform" + mgmt_name = "checkpoint-mgmt-terraform" + location = "eastus" + vnet_name = "checkpoint-mgmt-vnet" + vnet_resource_group = "existing-vnet" + management_subnet_name = "mgmt-subnet" + subnet_1st_Address = "10.0.1.4" + management_GUI_client_network = "0.0.0.0/0" + mgmt_enable_api = "disable" + admin_password = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "mgmt-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + admin_shell = "/etc/cli.sh" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + + +### Module's variables: + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **tenant_id** | The tenant ID of the Service Principal used to deploy the solution | string | | +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period. | +| **mgmt_name** | Management name | string | | +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions. | +| **vnet_name** | Virtual Network name | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **vnet_resource_group** | Resource Group of the existing virtual network | string | The exact name of the existing vnet's resource group. | +| **management_subnet_name** | Management subnet name | string | The exact name of the existing subnet. | +| **subnet_1st_Address** | The first available address of the subnet | string | | +| **management_GUI_client_network** | Allowed GUI clients - GUI clients network CIDR | string | | +| **mgmt_enable_api** | Enable api access to the management | string | "all";
"management_only";
"gui_clients";
"disable".
**Default:** "disable" | +| **admin_password** | The password associated with the local administrator account on each cluster member | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. | +| **vm_size** | Specifies the size of Virtual Machine | string | "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_D4s_v3", "Standard_D8s_v3", "Standard_D16s_v3", "Standard_D32s_v3", "Standard_D64s_v3", "Standard_E4s_v3", "Standard_E8s_v3", "Standard_E16s_v3", "Standard_E20s_v3", "Standard_E32s_v3", "Standard_E64s_v3", "Standard_E64is_v3", "Standard_F4s_v2", "Standard_F8s_v2", "Standard_F16s_v2", "Standard_F32s_v2", "Standard_F64s_v2", "Standard_M8ms", "Standard_M16ms", "Standard_M32ms", "Standard_M64ms", "Standard_M64s", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_D4_v3", "Standard_D8_v3", "Standard_D16_v3", "Standard_D32_v3", "Standard_D64_v3", "Standard_E4_v3", "Standard_E8_v3", "Standard_E16_v3", "Standard_E20_v3", "Standard_E32_v3", "Standard_E64_v3", "Standard_E64i_v3", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_D2_v5", "Standard_D4_v5", "Standard_D8_v5", "Standard_D16_v5","Standard_D32_v5", "Standard_D2s_v5", "Standard_D4s_v5", "Standard_D8s_v5", "Standard_D16s_v5", "Standard_D2d_v5", "Standard_D4d_v5", "Standard_D8d_v5", "Standard_D16d_v5", "Standard_D32d_v5", "Standard_D2ds_v5", "Standard_D4ds_v5", "Standard_D8ds_v5", "Standard_D16ds_v5", "Standard_D32ds_v5". | +| **disk_size** | Storage data disk size size(GB) | string | A number in the range 100 - 3995 (GB). | +| **vm_os_sku** | A sku of the image to be deployed | string | "mgmt-byol" - BYOL license;
"mgmt-25" - PAYG. | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82". | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82". | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false. | +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key". | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type, to generate password hash use the command 'openssl passwd -6 PASSWORD' on Linux and paste it here | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions, to generate a password hash use the command 'grub2-mkpasswd-pbkdf2' on Linux and paste it here | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure, if not provided, will create a default NSG | string | Existing NSG resource ID.
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location, if false then accses will be allowed from all networks | boolean | true;
false.
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs.
**Default:** [] | \ No newline at end of file diff --git a/modules/management_existing_vnet/cloud-init.sh b/modules/management_existing_vnet/cloud-init.sh new file mode 100755 index 0000000..cd7c697 --- /dev/null +++ b/modules/management_existing_vnet/cloud-init.sh @@ -0,0 +1,16 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +managementGUIClientNetwork="${management_GUI_client_network}" +enableApi="${enable_api}" +adminShell="${admin_shell}" +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" diff --git a/modules/management_existing_vnet/locals.tf b/modules/management_existing_vnet/locals.tf new file mode 100755 index 0000000..873657d --- /dev/null +++ b/modules/management_existing_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "management_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/management_existing_vnet/main.tf b/modules/management_existing_vnet/main.tf new file mode 100755 index 0000000..b4aac2c --- /dev/null +++ b/modules/management_existing_vnet/main.tf @@ -0,0 +1,304 @@ + +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = 1 + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = false + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +data "azurerm_subnet" "mgmt_subnet" { + name = var.management_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +resource "azurerm_public_ip" "public-ip" { + name = var.mgmt_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + idle_timeout_in_minutes = 30 + domain_name_label = join("", [ + lower(var.mgmt_name), + "-", + random_id.randomId.hex]) +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}-nsg" + location = module.common.resource_group_location + security_rules = setunion(var.security_rules, [ + { + name = "SSH" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "22" + description = "Allow inbound SSH connection" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "GAiA-portal" + priority = "110" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "443" + description = "Allow inbound HTTPS access to the GAiA portal" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-1" + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18190" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-2" + priority = "130" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "19009" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "Logs" + priority = "140" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "257" + description = "Allow inbound logging connections from managed gateways" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "ICA-pull" + priority = "150" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18210" + description = "Allow security gateways to pull a SIC certificate" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "CRL-fetch" + priority = "160" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18264" + description = "Allow security gateways to fetch CRLs" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Policy-fetch" + priority = "170" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18191" + description = "Allow security gateways to fetch policy" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ]) +} + +resource "azurerm_network_interface_security_group_association" "security_group_association" { + depends_on = [azurerm_network_interface.nic] + network_interface_id = azurerm_network_interface.nic.id + network_security_group_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip] + name = "${var.mgmt_name}-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = false + + ip_configuration { + name = "ipconfig1" + subnet_id = data.azurerm_subnet.mgmt_subnet.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = var.subnet_1st_Address + public_ip_address_id = azurerm_public_ip.public-ip.id + } +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + account_kind = "Storage" + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } + +} + +//********************** Virtual Machines **************************// +locals { + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} + +resource "azurerm_virtual_machine" "mgmt-vm-instance" { + depends_on = [ + azurerm_network_interface.nic] + location = module.common.resource_group_location + name = var.mgmt_name + network_interface_ids = [ + azurerm_network_interface.nic.id] + resource_group_name = module.common.resource_group_name + vm_size = module.common.vm_size + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = azurerm_network_interface.nic.id + + identity { + type = module.common.vm_instance_identity + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } + + os_profile { + computer_name = lower(var.mgmt_name) + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + management_GUI_client_network = var.management_GUI_client_network + enable_api = var.mgmt_enable_api + admin_shell = var.admin_shell + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = var.mgmt_name + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } +} \ No newline at end of file diff --git a/modules/management_existing_vnet/variables.tf b/modules/management_existing_vnet/variables.tf new file mode 100755 index 0000000..fc68193 --- /dev/null +++ b/modules/management_existing_vnet/variables.tf @@ -0,0 +1,228 @@ +//********************** Basic Configuration Variables **************************// +variable "mgmt_name" { + description = "Management name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resource will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "installation_type" { + description = "Installation type" + type = string + default = "management" +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82", + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "management_subnet_name" { + description = "management subnet name" + type = string +} + +variable "subnet_1st_Address" { + description = "The first available address of the subnet" + type = string +} + +variable "vnet_resource_group" { + description = "Resource group of existing vnet" + type = string +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "management_GUI_client_network" { + description = "Allowed GUI clients - GUI clients network CIDR" + type = string +} + +variable "mgmt_enable_api" { + description = "Enable api access to the management. allowed values: all, management_only, gui_clients, disable" + type = string + default = "disable" +} + +locals { + regex_valid_management_GUI_client_network = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/(3[0-2]|2[0-9]|1[0-9]|[0-9]))$" + // Will fail if var.management_GUI_client_network is invalid + regex_management_GUI_client_network = regex(local.regex_valid_management_GUI_client_network, var.management_GUI_client_network) == var.management_GUI_client_network ? 0 : "Variable [management_GUI_client_network] must be a valid IPv4 network CIDR." + + mgmt_enable_api_allowed_values = [ + "disable", + "all", + "management_only", + "gui_clients" + ] + // will fail if [var.mgmt_enable_api] is invalid: + validate_mgmt_enable_api_value = index(local.mgmt_enable_api_allowed_values, var.mgmt_enable_api) + + regex_valid_subnet_1st_Address = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" + // Will fail if var.subnet_1st_Address is invalid + regex_subnet_1st_Address = regex(local.regex_valid_subnet_1st_Address, var.subnet_1st_Address) == var.subnet_1st_Address ? 0 : "Variable [subnet_1st_Address] must be a valid address." +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + default = "" + type = string + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [] +} diff --git a/modules/management_existing_vnet/versions.tf b/modules/management_existing_vnet/versions.tf new file mode 100755 index 0000000..8827a9f --- /dev/null +++ b/modules/management_existing_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} \ No newline at end of file diff --git a/modules/management_new_vnet/README.md b/modules/management_new_vnet/README.md index e2b621a..7cd33e5 100755 --- a/modules/management_new_vnet/README.md +++ b/modules/management_new_vnet/README.md @@ -26,7 +26,7 @@ provider "azurerm" { module "example_module" { source = "CheckPointSW/cloudguard-network-security/azure//modules/management_new_vnet" - version = "1.0.3" + version = "1.0.4" source_image_vhd_uri = "noCustomUri" resource_group_name = "checkpoint-mgmt-terraform" @@ -73,7 +73,7 @@ module "example_module" { | **vm_size** | Specifies the size of the Virtual Machine | string | A list of valid VM sizes (e.g., "Standard_DS2_v2", "Standard_DS3_v2", etc.)
| | **disk_size** | Storage data disk size (GB) | string | A number in the range 100 - 3995 (GB)
| | **vm_os_sku** | A SKU of the image to be deployed | string | "mgmt-byol" - BYOL license;
"mgmt-25" - PAYG;
| -| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r81";
"check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82";
| +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82";
| | **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82";
| | **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt"
**Default:** "" | | **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false;
| diff --git a/modules/management_new_vnet/cloud-init.sh b/modules/management_new_vnet/cloud-init.sh index 58fd101..cd7c697 100755 --- a/modules/management_new_vnet/cloud-init.sh +++ b/modules/management_new_vnet/cloud-init.sh @@ -3,7 +3,7 @@ installationType="${installation_type}" allowUploadDownload="${allow_upload_download}" osVersion="${os_version}" -templateName="${template_name}" +templateName="${module_name}" templateVersion="${module_version}" templateType="${template_type}" isBlink="${is_blink}" diff --git a/modules/management_new_vnet/locals.tf b/modules/management_new_vnet/locals.tf index 7130e3a..873657d 100755 --- a/modules/management_new_vnet/locals.tf +++ b/modules/management_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { - template_name = "mgmt_terraform_registry" - module_version = "1.0.3" + module_name = "management_terraform_registry" + module_version = "1.0.4" } diff --git a/modules/management_new_vnet/main.tf b/modules/management_new_vnet/main.tf index 40f4883..fa467f1 100755 --- a/modules/management_new_vnet/main.tf +++ b/modules/management_new_vnet/main.tf @@ -5,7 +5,7 @@ module "common" { location = var.location admin_password = var.admin_password installation_type = var.installation_type - template_name = local.template_name + module_name = local.module_name module_version = local.module_version number_of_vm_instances = 1 allow_upload_download = var.allow_upload_download @@ -258,22 +258,22 @@ resource "azurerm_virtual_machine" "mgmt-vm-instance" { computer_name = lower(var.mgmt_name) admin_username = module.common.admin_username admin_password = module.common.admin_password - custom_data = templatefile("${path.module}/cloud-init.sh", { - installation_type = module.common.installation_type - allow_upload_download = module.common.allow_upload_download - os_version = module.common.os_version - template_name = module.common.template_name - module_version = module.common.module_version - template_type = "terraform" - is_blink = module.common.is_blink - bootstrap_script64 = base64encode(var.bootstrap_script) - location = module.common.resource_group_location - management_GUI_client_network = var.management_GUI_client_network - enable_api = var.mgmt_enable_api - admin_shell = var.admin_shell - serial_console_password_hash = var.serial_console_password_hash - maintenance_mode_password_hash = var.maintenance_mode_password_hash - }) + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + management_GUI_client_network = var.management_GUI_client_network + enable_api = var.mgmt_enable_api + admin_shell = var.admin_shell + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) } os_profile_linux_config { diff --git a/modules/management_new_vnet/variables.tf b/modules/management_new_vnet/variables.tf index b180a35..0ee2e7f 100755 --- a/modules/management_new_vnet/variables.tf +++ b/modules/management_new_vnet/variables.tf @@ -91,13 +91,12 @@ variable "vm_os_sku" { } variable "vm_os_offer" { - description = "The name of the image offer to be deployed.Choose from: check-point-cg-r81, check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" type = string } locals { // locals for 'vm_os_offer' allowed values vm_os_offer_allowed_values = [ - "check-point-cg-r81", "check-point-cg-r8110", "check-point-cg-r8120", "check-point-cg-r82" diff --git a/modules/mds_existing_vnet/README.md b/modules/mds_existing_vnet/README.md new file mode 100755 index 0000000..c85c8ed --- /dev/null +++ b/modules/mds_existing_vnet/README.md @@ -0,0 +1,99 @@ +# Check Point CloudGuard MDS Module - Existing VNet + +This Terraform module deploys Check Point CloudGuard Network Security Management solution into an existing VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- Network security group +- Virtual Machine +- System assigned identity + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. +- network_security_group - used for creating new network security groups and rules. + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/mds_existing_vnet" + version = "1.0.4" + + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-mds-rg-terraform" + mds_name = "checkpoint-mds-terraform" + location = "eastus" + vnet_name = "checkpoint-mds-vnet" + vnet_resource_group = "existing-vnet" + management_subnet_name = "mgmt-subnet" + subnet_1st_Address = "10.0.1.4" + management_GUI_client_network = "0.0.0.0/0" + mds_enable_api = "disable" + admin_password = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "mgmt-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + admin_shell = "/etc/cli.sh" + sic_key = "xxxxxxxxxxxx" + installation_type = "mds-primary" + primary = "true" + secondary = "false" + logserver = "false" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + + +### Module's variables: + +# Parameters Description + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period. | +| **mds_name** | MDS name | string | | +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions. | +| **vnet_name** | The name of virtual network that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **vnet_resource_group** | Resource Group of the existing virtual network | string | The exact name of the existing vnet's resource group. | +| **management_subnet_name** | Specifies the name of the external subnet | string | The exact name of the existing external subnet. | +| **subnet_1st_Address** | First available address in management subnet | string | | +| **management_GUI_client_network** | Allowed GUI clients - GUI clients network CIDR | string | | +| **mds_enable_api** | Enable api access to the mds | string | "all";
"management_only";
"gui_clients";
"disable".
**Default:** "disable" | +| **admin_password** | The password associated with the local administrator account on the mds | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. | +| **vm_size** | Specifies the size of Virtual Machine | string | "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_D4s_v3", "Standard_D8s_v3", "Standard_D16s_v3", "Standard_D32s_v3", "Standard_D64s_v3", "Standard_E4s_v3", "Standard_E8s_v3", "Standard_E16s_v3", "Standard_E20s_v3", "Standard_E32s_v3", "Standard_E64s_v3", "Standard_E64is_v3", "Standard_F4s_v2", "Standard_F8s_v2", "Standard_F16s_v2", "Standard_F32s_v2", "Standard_F64s_v2", "Standard_M8ms", "Standard_M16ms", "Standard_M32ms", "Standard_M64ms", "Standard_M64s", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_D4_v3", "Standard_D8_v3", "Standard_D16_v3", "Standard_D32_v3", "Standard_D64_v3", "Standard_E4_v3", "Standard_E8_v3", "Standard_E16_v3", "Standard_E20_v3", "Standard_E32_v3", "Standard_E64_v3", "Standard_E64i_v3", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_D2_v5", "Standard_D4_v5", "Standard_D8_v5", "Standard_D16_v5","Standard_D32_v5", "Standard_D2s_v5", "Standard_D4s_v5", "Standard_D8s_v5", "Standard_D16s_v5", "Standard_D2d_v5", "Standard_D4d_v5", "Standard_D8d_v5", "Standard_D16d_v5", "Standard_D32d_v5", "Standard_D2ds_v5", "Standard_D4ds_v5", "Standard_D8ds_v5", "Standard_D16ds_v5", "Standard_D32ds_v5". | +| **disk_size** | Storage data disk size size(GB) | string | A number in the range 100 - 3995 (GB). | +| **vm_os_sku** | A sku of the image to be deployed | string | "mgmt-byol" - BYOL license;
"mgmt-25" - PAYG. | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82". | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82". | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false. | +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key". | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **sic_key** | Set the Secure Internal Communication one time secret used to set up trust between the primary and secondary servers. SIC key must be provided if installing a secondary Multi-Domain Server or a Multi-Domain Log Server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **installation_type** | Enables to select installation type - gateway/standalone | string | mds-primary;
mds-secondary;
mds-logserver. | +| **primary** | Indicates if the installation type is mds-primary | boolean | true;
false. | +| **secondary** | Indicates if the installation type is mds-secondary | boolean | true;
false. | +| **logserver** | Indicates if the installation type is mds-logserver | boolean | true;
false. | +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type, to generate password hash use the command 'openssl passwd -6 PASSWORD' on Linux and paste it here | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions, to generate a password hash use the command 'grub2-mkpasswd-pbkdf2' on Linux and paste it here | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure, if not provided, will create a default NSG | string | Existing NSG resource ID.
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location, if false then accses will be allowed from all networks | boolean | true;
false.
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs.
**Default:** [] | +| **security_rules** | Security rules for the Network Security | list(any) | A list of valid security rules values.
A security rule composed of:
{name, priority, direction, access, protocol, source_port_ranges, destination_port_ranges, source_address_prefix, destination_address_prefix, description}.
**Default:** [{"name":"AllowAllInBound", "priority":"100", "direction":"Inbound", "access":"Allow", "protocol":"*", "source_port_ranges":"*", "destination_port_ranges":"", "description":"Allow all inbound connections", "source_address_prefix":"*", "destination_address_prefix":""}] | +| **admin_SSH_key** | The SSH public key for SSH connections to the instance.
Used when the authentication_type is 'SSH Public Key' | string | **Default:** "" | \ No newline at end of file diff --git a/modules/mds_existing_vnet/cloud-init.sh b/modules/mds_existing_vnet/cloud-init.sh new file mode 100755 index 0000000..2f25a58 --- /dev/null +++ b/modules/mds_existing_vnet/cloud-init.sh @@ -0,0 +1,20 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +managementGUIClientNetwork="${management_GUI_client_network}" +enableApi="${enable_api}" +adminShell="${admin_shell}" +sicKey="${sic_key}" +primary="${primary}" +secondary="${secondary}" +logserver="${logserver}" +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" diff --git a/modules/mds_existing_vnet/locals.tf b/modules/mds_existing_vnet/locals.tf new file mode 100755 index 0000000..cdca346 --- /dev/null +++ b/modules/mds_existing_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "mds_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/mds_existing_vnet/main.tf b/modules/mds_existing_vnet/main.tf new file mode 100755 index 0000000..c26f8cd --- /dev/null +++ b/modules/mds_existing_vnet/main.tf @@ -0,0 +1,307 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + module_name = local.module_name + installation_type = var.installation_type + module_version = local.module_version + number_of_vm_instances = 1 + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = false + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +data "azurerm_subnet" "mds_subnet" { + name = var.management_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +resource "azurerm_public_ip" "public-ip" { + name = var.mds_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + idle_timeout_in_minutes = 30 + domain_name_label = join("", [ + lower(var.mds_name), + "-", + random_id.randomId.hex]) +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}-nsg" + location = module.common.resource_group_location + security_rules = setunion(var.security_rules, [ + { + name = "SSH" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "22" + description = "Allow inbound SSH connection" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "GAiA-portal" + priority = "110" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "443" + description = "Allow inbound HTTPS access to the GAiA portal" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-1" + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18190" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-2" + priority = "130" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "19009" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "Logs" + priority = "140" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "257" + description = "Allow inbound logging connections from managed gateways" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "ICA-pull" + priority = "150" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18210" + description = "Allow security gateways to pull a SIC certificate" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "CRL-fetch" + priority = "160" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18264" + description = "Allow security gateways to fetch CRLs" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Policy-fetch" + priority = "170" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18191" + description = "Allow security gateways to fetch policy" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ]) +} + +resource "azurerm_network_interface_security_group_association" "security_group_association" { + depends_on = [azurerm_network_interface.nic] + network_interface_id = azurerm_network_interface.nic.id + network_security_group_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip] + name = "${var.mds_name}-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = false + + ip_configuration { + name = "ipconfig1" + subnet_id = data.azurerm_subnet.mds_subnet.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = var.subnet_1st_Address + public_ip_address_id = azurerm_public_ip.public-ip.id + } +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + account_kind = "Storage" + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } + +} + +//********************** Virtual Machines **************************// +locals { + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} + +resource "azurerm_virtual_machine" "mds-vm-instance" { + depends_on = [ + azurerm_network_interface.nic] + location = module.common.resource_group_location + name = var.mds_name + network_interface_ids = [ + azurerm_network_interface.nic.id] + resource_group_name = module.common.resource_group_name + vm_size = module.common.vm_size + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = azurerm_network_interface.nic.id + + identity { + type = module.common.vm_instance_identity + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } + + os_profile { + computer_name = lower(var.mds_name) + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = var.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + management_GUI_client_network = var.management_GUI_client_network + enable_api = var.mds_enable_api + admin_shell = var.admin_shell + sic_key = var.sic_key + primary = var.primary + secondary = var.secondary + logserver = var.logserver + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = var.mds_name + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } +} \ No newline at end of file diff --git a/modules/mds_existing_vnet/variables.tf b/modules/mds_existing_vnet/variables.tf new file mode 100755 index 0000000..542e36c --- /dev/null +++ b/modules/mds_existing_vnet/variables.tf @@ -0,0 +1,257 @@ +//********************** Basic Configuration Variables **************************// +variable "mds_name" { + description = "MDS name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resource will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "installation_type" { + description = "Installaiton type" + type = string + default = "mds-primary" +} + +variable "primary" { + type = string +} + +variable "secondary" { + type = string +} + +variable "logserver" { + type = string +} + +locals { //locals for 'installation_type' + isntallation_type_allowed_values = [ + "mds-primary", + "mds-secondary", + "mds-logserver" + ] +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "management_subnet_name" { + description = "management subnet name" + type = string +} + +variable "subnet_1st_Address" { + description = "The first available address of the subnet" + type = string +} + +variable "vnet_resource_group" { + description = "Resource group of existing vnet" + type = string +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "management_GUI_client_network" { + description = "Allowed GUI clients - GUI clients network CIDR" + type = string + validation { + condition = can(regex("(^0\\.0\\.0\\.0\\/0$)|(^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/32)?$)", var.management_GUI_client_network)) && var.management_GUI_client_network != "0.0.0.0/32" + error_message = "Variable [management_GUI_client_network] must be a valid IPv4 network CIDR (only 0.0.0.0/0, X.X.X.X/32 or X.X.X.X are acceptable)." + } +} + +variable "mds_enable_api" { + description = "Enable api access to the management. allowed values: all, management_only, gui_clients, disable" + type = string + default = "disable" +} + +locals { + mds_enable_api_allowed_values = [ + "disable", + "all", + "management_only", + "gui_clients" + ] + // will fail if [var.mds_enable_api] is invalid: + validate_mds_enable_api_value = index(local.mds_enable_api_allowed_values, var.mds_enable_api) + + regex_valid_subnet_1st_Address = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" + // Will fail if var.subnet_1st_Address is invalid + regex_subnet_1st_Address = regex(local.regex_valid_subnet_1st_Address, var.subnet_1st_Address) == var.subnet_1st_Address ? 0 : "Variable [subnet_1st_Address] must be a valid address." +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + default = "" + type = string + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable sic_key { + description = "sic_key" + type = string +} + +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [] +} diff --git a/modules/mds_existing_vnet/versions.tf b/modules/mds_existing_vnet/versions.tf new file mode 100755 index 0000000..8827a9f --- /dev/null +++ b/modules/mds_existing_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} \ No newline at end of file diff --git a/modules/mds_new_vnet/README.md b/modules/mds_new_vnet/README.md new file mode 100755 index 0000000..49208b9 --- /dev/null +++ b/modules/mds_new_vnet/README.md @@ -0,0 +1,98 @@ +# Check Point CloudGuard MDS Module - New VNet + +This Terraform module deploys Check Point CloudGuard Network Security Management solution into a new VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- Virtual network +- Network security group +- Virtual Machine +- System assigned identity + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. +- vnet - used for creating new virtual network and subnets. +- network_security_group - used for creating new network security groups and rules. + + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/mds_new_vnet" + version = "1.0.4" + + + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-mds-rg-terraform" + mds_name = "checkpoint-mds-terraform" + location = "eastus" + vnet_name = "checkpoint-mds-vnet" + address_space = "10.0.0.0/16" + subnet_prefix = "10.0.0.0/24" + management_GUI_client_network = "0.0.0.0/0" + mds_enable_api = "disable" + admin_password = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "mgmt-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + admin_shell = "/etc/cli.sh" + sic_key = "xxxxxxxxxxxx" + installation_type = "mds-primary" + primary = "true" + secondary = "false" + logserver = "false" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + + +### Module's variables: + +# Parameters Description + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period. | +| **mds_name** | MDS name | string | | +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions. | +| **vnet_name** | The name of virtual network that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **address_space** | The address space that is used by a Virtual Network | string | A valid address in CIDR notation.
**Default:** "10.0.0.0/16" | +| **subnet_prefix** | Address prefix to be used for network subnet | string | A valid address in CIDR notation.
**Default:** "10.0.0.0/24" | +| **management_GUI_client_network** | Allowed GUI clients - GUI clients network CIDR | string | | +| **mds_enable_api** | Enable api access to the mds | string | "all";
"management_only";
"gui_clients";
"disable".
**Default:** "disable" | +| **admin_password** | The password associated with the local administrator account on the mds | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. | +| **vm_size** | Specifies the size of Virtual Machine | string | "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_D4s_v3", "Standard_D8s_v3", "Standard_D16s_v3", "Standard_D32s_v3", "Standard_D64s_v3", "Standard_E4s_v3", "Standard_E8s_v3", "Standard_E16s_v3", "Standard_E20s_v3", "Standard_E32s_v3", "Standard_E64s_v3", "Standard_E64is_v3", "Standard_F4s_v2", "Standard_F8s_v2", "Standard_F16s_v2", "Standard_F32s_v2", "Standard_F64s_v2", "Standard_M8ms", "Standard_M16ms", "Standard_M32ms", "Standard_M64ms", "Standard_M64s", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_D4_v3", "Standard_D8_v3", "Standard_D16_v3", "Standard_D32_v3", "Standard_D64_v3", "Standard_E4_v3", "Standard_E8_v3", "Standard_E16_v3", "Standard_E20_v3", "Standard_E32_v3", "Standard_E64_v3", "Standard_E64i_v3", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_D2_v5", "Standard_D4_v5", "Standard_D8_v5", "Standard_D16_v5","Standard_D32_v5", "Standard_D2s_v5", "Standard_D4s_v5", "Standard_D8s_v5", "Standard_D16s_v5", "Standard_D2d_v5", "Standard_D4d_v5", "Standard_D8d_v5", "Standard_D16d_v5", "Standard_D32d_v5", "Standard_D2ds_v5", "Standard_D4ds_v5", "Standard_D8ds_v5", "Standard_D16ds_v5", "Standard_D32ds_v5". | +| **disk_size** | Storage data disk size size(GB) | string | A number in the range 100 - 3995 (GB). | +| **vm_os_sku** | A sku of the image to be deployed | string | "mgmt-byol" - BYOL license;
"mgmt-25" - PAYG. | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82". | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82". | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false. | +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key". | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **sic_key** | Set the Secure Internal Communication one time secret used to set up trust between the primary and secondary servers. SIC key must be provided if installing a secondary Multi-Domain Server or a Multi-Domain Log Server| string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **installation_type** | Enables to select installation type- gateway/standalone | string | mds-primary;
mds-secondary;
mds-logserver. | +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type, to generate password hash use the command 'openssl passwd -6 PASSWORD' on Linux and paste it here | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions, to generate a password hash use the command 'grub2-mkpasswd-pbkdf2' on Linux and paste it here | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure, if not provided, will create a default NSG | string | Existing NSG resource ID.
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location, if false then accses will be allowed from all networks | boolean | true;
false.
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs.
**Default:** [] | +| **security_rules** | Security rules for the Network Security | list(any) | A list of valid security rules values.
A security rule composed of:
{name, priority, direction, access, protocol, source_port_ranges, destination_port_ranges, source_address_prefix, destination_address_prefix, description}.
**Default:** [{"name":"AllowAllInBound", "priority":"100", "direction":"Inbound", "access":"Allow", "protocol":"*", "source_port_ranges":"*", "destination_port_ranges":"", "description":"Allow all inbound connections", "source_address_prefix":"*", "destination_address_prefix":""}] | +| **admin_SSH_key** | The SSH public key for SSH connections to the instance.
Used when the authentication_type is 'SSH Public Key' | string | **Default:** "" | \ No newline at end of file diff --git a/modules/mds_new_vnet/cloud-init.sh b/modules/mds_new_vnet/cloud-init.sh new file mode 100755 index 0000000..2f25a58 --- /dev/null +++ b/modules/mds_new_vnet/cloud-init.sh @@ -0,0 +1,20 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +managementGUIClientNetwork="${management_GUI_client_network}" +enableApi="${enable_api}" +adminShell="${admin_shell}" +sicKey="${sic_key}" +primary="${primary}" +secondary="${secondary}" +logserver="${logserver}" +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" diff --git a/modules/mds_new_vnet/locals.tf b/modules/mds_new_vnet/locals.tf new file mode 100755 index 0000000..cdca346 --- /dev/null +++ b/modules/mds_new_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "mds_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/mds_new_vnet/main.tf b/modules/mds_new_vnet/main.tf new file mode 100755 index 0000000..328e806 --- /dev/null +++ b/modules/mds_new_vnet/main.tf @@ -0,0 +1,312 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = 1 + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = false + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +module "vnet" { + source = "../vnet" + + vnet_name = var.vnet_name + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + address_space = var.address_space + subnet_prefixes = [var.subnet_prefix] + subnet_names = ["${var.mds_name}-subnet"] + nsg_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}-nsg" + location = module.common.resource_group_location + security_rules = setunion(var.security_rules ,[ + { + name = "SSH" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "22" + description = "Allow inbound SSH connection" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "GAiA-portal" + priority = "110" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "443" + description = "Allow inbound HTTPS access to the GAiA portal" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-1" + priority = "120" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18190" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "SmartConsole-2" + priority = "130" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "19009" + description = "Allow inbound access using the SmartConsole GUI client" + source_address_prefix = var.management_GUI_client_network + destination_address_prefix = "*" + }, + { + name = "Logs" + priority = "140" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "257" + description = "Allow inbound logging connections from managed gateways" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "ICA-pull" + priority = "150" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18210" + description = "Allow security gateways to pull a SIC certificate" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "CRL-fetch" + priority = "160" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18264" + description = "Allow security gateways to fetch CRLs" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "Policy-fetch" + priority = "170" + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_ranges = "*" + destination_port_ranges = "18191" + description = "Allow security gateways to fetch policy" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ]) +} + +resource "azurerm_public_ip" "public-ip" { + name = var.mds_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + idle_timeout_in_minutes = 30 + domain_name_label = join("", [ + lower(var.mds_name), + "-", + random_id.randomId.hex]) +} + +resource "azurerm_network_interface_security_group_association" "security_group_association" { + depends_on = [azurerm_network_interface.nic, module.network_security_group] + network_interface_id = azurerm_network_interface.nic.id + network_security_group_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip] + name = "${var.mds_name}-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = false + + ip_configuration { + name = "ipconfig1" + subnet_id = module.vnet.vnet_subnets[0] + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = cidrhost(var.subnet_prefix, 4) + public_ip_address_id = azurerm_public_ip.public-ip.id + } +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + account_kind = "Storage" + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } + +} + +//********************** Virtual Machines **************************// +locals { + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} + +resource "azurerm_virtual_machine" "mds-vm-instance" { + depends_on = [ + azurerm_network_interface.nic] + location = module.common.resource_group_location + name = var.mds_name + network_interface_ids = [ + azurerm_network_interface.nic.id] + resource_group_name = module.common.resource_group_name + vm_size = module.common.vm_size + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = azurerm_network_interface.nic.id + + identity { + type = module.common.vm_instance_identity + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } + + os_profile { + computer_name = lower(var.mds_name) + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = var.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + management_GUI_client_network = var.management_GUI_client_network + enable_api = var.mds_enable_api + admin_shell = var.admin_shell + sic_key = var.sic_key + primary = var.primary + secondary = var.secondary + logserver = var.logserver + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = var.mds_name + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } +} diff --git a/modules/mds_new_vnet/variables.tf b/modules/mds_new_vnet/variables.tf new file mode 100755 index 0000000..29d4afe --- /dev/null +++ b/modules/mds_new_vnet/variables.tf @@ -0,0 +1,256 @@ +//********************** Basic Configuration Variables **************************// +variable "mds_name" { + description = "MDS name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resource will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "installation_type" { + description = "Installaiton type" + type = string + default = "mds-primary" +} + +variable "primary" { + type = string +} + +variable "secondary" { + type = string +} + +variable "logserver" { + type = string +} + +locals { //locals for 'installation_type' + isntallation_type_allowed_values = [ + "mds-primary", + "mds-secondary", + "mds-logserver" + ] +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "address_space" { + description = "The address space that is used by a Virtual Network." + type = string + default = "10.0.0.0/16" +} + +variable "subnet_prefix" { + description = "Address prefix to be used for network subnet" + type = string + default = "10.0.0.0/24" +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "management_GUI_client_network" { + description = "Allowed GUI clients - GUI clients network CIDR" + type = string + validation { + condition = can(regex("(^0\\.0\\.0\\.0\\/0$)|(^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/32)?$)", var.management_GUI_client_network)) && var.management_GUI_client_network != "0.0.0.0/32" + error_message = "Variable [management_GUI_client_network] must be a valid IPv4 network CIDR (only 0.0.0.0/0, X.X.X.X/32 or X.X.X.X are acceptable)." + } +} + +variable "mds_enable_api" { + description = "Enable api access to the management. allowed values: all, management_only, gui_clients, disable" + type = string + default = "disable" +} + +locals { + mds_enable_api_allowed_values = [ + "disable", + "all", + "management_only", + "gui_clients" + ] + // will fail if [var.mds_enable_api] is invalid: + validate_mds_enable_api_value = index(local.mds_enable_api_allowed_values, var.mds_enable_api) + + regex_valid_network_cidr = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/(3[0-2]|2[0-9]|1[0-9]|[0-9]))|$" + // Will fail if var.address_space is invalid + regex_address_space = regex(local.regex_valid_network_cidr, var.address_space) == var.address_space ? 0 : "Variable [address_space] must be a valid address in CIDR notation." + // Will fail if var.subnet_prefix is invalid + regex_subnet_prefix = regex(local.regex_valid_network_cidr, var.subnet_prefix) == var.subnet_prefix ? 0 : "Variable [subnet_prefix] must be a valid address in CIDR notation." +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + default = "" + type = string + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable "sic_key" { + description = "sic key" + type = string +} + +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [] +} diff --git a/modules/mds_new_vnet/versions.tf b/modules/mds_new_vnet/versions.tf new file mode 100755 index 0000000..0018913 --- /dev/null +++ b/modules/mds_new_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} diff --git a/modules/nva_into_existing_hub/README.md b/modules/nva_into_existing_hub/README.md new file mode 100755 index 0000000..4087bf4 --- /dev/null +++ b/modules/nva_into_existing_hub/README.md @@ -0,0 +1,98 @@ +# Check Point CloudGuard Virtual WAN Module - Existing Hub + +This Terraform module deploys Check Point CloudGuard Network Security Virtual WAN NVA solution into an existing vWAN Hub in Azure. +As part of the deployment the following resources are created: +- Resource groups +- Azure Managed Application: + - NVA + - Managed identity + +For additional information, +please see the [CloudGuard Network for Azure Virtual WAN Deployment Guide](https://sc1.checkpoint.com/documents/IaaS/WebAdminGuides/EN/CP_CloudGuard_Network_for_Azure_vWAN/Default.htm) + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/nva_into_existing_hub" + version = "1.0.4" + + authentication_method = "Service Principal" + client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + subscription_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + resource-group-name = "tf-managed-app-resource-group" + location = "westcentralus" + vwan-hub-name = "tf-vwan-hub" + vwan-hub-resource-group = "tf-vwan-hub-rg" + managed-app-name = "tf-vwan-managed-app-nva" + nva-rg-name = "tf-vwan-nva-rg" + nva-name = "tf-vwan-nva" + os-version = "R8120" + license-type = "Security Enforcement (NGTP)" + scale-unit = "2" + bootstrap-script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + admin-shell = "/etc/cli.sh" + sic-key = "xxxxxxxxxxxx" + admin_SSH_key = "ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxx imported-openssh-key" + bgp-asn = "64512" + custom-metrics = "yes" + routing-intent-internet-traffic = "yes" + routing-intent-private-traffic = "yes" + smart1-cloud-token-a = "" + smart1-cloud-token-b = "" + smart1-cloud-token-c = "" + smart1-cloud-token-d = "" + smart1-cloud-token-e = "" + existing-public-ip = "" + new-public-ip = "yes" +} +``` + +## Known limitations +1. 'terraform destroy' doesn't work if routing-intent is configured. To destroy the deployment, the routing-intent should be deleted manually first. + +### Module's variables: + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **authentication_method** | The authentication method used to deploy the solution | string | "Service Principal";
"Azure CLI". | +| **client_secret** | The client secret value of the Service Principal used to deploy the solution | string | | +| **client_id** | The client ID of the Service Principal used to deploy the solution | string | | +| **tenant_id** | The tenant ID of the Service Principal used to deploy the solution | string | | +| **subscription_id** | The subscription ID is used to pay for Azure cloud services | string | | +| **resource-group-name** | The name of the resource group that will contain the managed application | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.
**Default:** "tf-managed-app-resource-group" | +| **location** | The region where the resources will be deployed at | string | The full list of supported Azure regions can be found at https://learn.microsoft.com/en-us/azure/virtual-wan/virtual-wan-locations-partners#locations.
**Default:** "westcentralus" | +| **vwan-hub-name** | The name of the virtual WAN hub that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **vwan-hub-resource-group** | The virtual WAN hub resource group name | string | | +| **managed-app-name** | The name of the managed application that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** "tf-vwan-managed-app-nva" | +| **nva-name** | The name of the NVA that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** "tf-vwan-nva" | +| **nva-rg-name** | The name of the resource group that will contain the NVA | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.
**Default:** "tf-vwan-nva-rg" | +| **os-version** | The GAIA os version | string | "R8110";
"R8120";
"R82".
**Default:** "R8120" | +| **license-type** | The Check Point licence type | string | "Security Enforcement (NGTP)";
"Full Package (NGTX + S1C)";
"Full Package Premium (NGTX + S1C++)".
**Default:** "Security Enforcement (NGTP)" | +| **scale-unit** | The scale unit determines the size and number of resources deployed. The higher the scale unit, the greater the amount of traffic that can be handled | string | "2";
"4";
"10";
"20";
"30";
"60";
"80".
**Default:** "2" | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **sic-key** | The Secure Internal Communication one time secret used to set up trust between the gateway object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **admin_SSH_key** | The public ssh key used for ssh connection to the NVA GW instances | string | ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxx generated-by-azure. | +| **bgp-asn** | The BGP autonomous system number | string | 64512.
**Default:** "64512" | +| **custom-metrics** | Indicates whether CloudGuard Metrics will be use for gateway monitoring | string | yes;
no.
**Default:** "yes" | +| **routing-intent-internet-traffic** | Set routing intent policy to allow internet traffic through the new nva | string | yes;
no.
Please verify routing-intent is configured successfully post-deployment.
**Default:** "yes" | +| **routing-intent-private-traffic** | Set routing intent policy to allow private traffic through the new nva | string | yes;
no.
Please verify routing-intent is configured successfully post-deployment.
**Default:** "yes" | +| **smart1-cloud-token-a** | Smart-1 Cloud token to connect automatically ***NVA instance a*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-b** | Smart-1 Cloud token to connect automatically ***NVA instance b*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-c** | Smart-1 Cloud token to connect automatically ***NVA instance c*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-d** | Smart-1 Cloud token to connect automatically ***NVA instance d*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-e** | Smart-1 Cloud token to connect automatically ***NVA instance e*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | + + + + diff --git a/modules/nva_into_existing_hub/main.tf b/modules/nva_into_existing_hub/main.tf new file mode 100755 index 0000000..0d95a50 --- /dev/null +++ b/modules/nva_into_existing_hub/main.tf @@ -0,0 +1,278 @@ +//********************** Basic Configuration **************************// +resource "azurerm_resource_group" "managed-app-rg" { + name = var.resource-group-name + location = var.location +} + +data "azurerm_virtual_hub" "vwan-hub" { + name = var.vwan-hub-name + resource_group_name = var.vwan-hub-resource-group +} + +//********************** Image Version **************************// + +data "external" "az_access_token" { + count = var.authentication_method == "Azure CLI" ? 1 : 0 + program = ["az", "account", "get-access-token", "--resource=https://management.azure.com", "--query={accessToken: accessToken}", "--output=json"] +} + +data "http" "azure_auth" { + count = var.authentication_method == "Service Principal" ? 1 : 0 + url = "https://login.microsoftonline.com/${var.tenant_id}/oauth2/v2.0/token" + method = "POST" + request_headers = { + "Content-Type" = "application/x-www-form-urlencoded" + } + request_body = "grant_type=client_credentials&client_id=${var.client_id}&client_secret=${var.client_secret}&scope=https://management.azure.com/.default" +} + +locals { + access_token = var.authentication_method == "Service Principal" ? jsondecode(data.http.azure_auth[0].response_body).access_token : data.external.az_access_token[0].result.accessToken +} + +data "http" "image-versions" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.Network/networkVirtualApplianceSKUs/checkpoint${var.license-type == "Full Package (NGTX + S1C)" ? "-ngtx" : var.license-type == "Full Package Premium (NGTX + S1C++)" ? "-premium" : ""}?api-version=2020-05-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +locals { + image_versions = tolist([for version in jsondecode(data.http.image-versions.response_body).properties.availableVersions : version if substr(version, 0, 4) == substr(lower(length(var.os-version) > 3 ? var.os-version : "${var.os-version}00"), 1, 4)]) + routing_intent-internet-policy = { + "name": "InternetTraffic", + "destinations": [ + "Internet" + ], + "nextHop": "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}/providers/Microsoft.Network/networkVirtualAppliances/${var.nva-name}" + } + routing_intent-private-policy = { + "name": "PrivateTrafficPolicy", + "destinations": [ + "PrivateTraffic" + ], + "nextHop": "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}/providers/Microsoft.Network/networkVirtualAppliances/${var.nva-name}" + } + routing-intent-policies = var.routing-intent-internet-traffic == "yes" ? (var.routing-intent-private-traffic == "yes" ? tolist([local.routing_intent-internet-policy, local.routing_intent-private-policy]) : tolist([local.routing_intent-internet-policy])) : (var.routing-intent-private-traffic == "yes" ? tolist([local.routing_intent-private-policy]) : []) + public_ip_resource_group = "/subscriptions/${var.subscription_id}/resourceGroups/${var.new-public-ip == "yes" ? azurerm_resource_group.managed-app-rg.name : var.existing-public-ip != "" ? split("/", var.existing-public-ip)[4] : ""}" +} + +//********************** Marketplace Terms & Solution Registration **************************// +data "http" "accept-marketplace-terms-existing-agreement" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.MarketplaceOrdering/agreements/checkpoint/offers/cp-vwan-managed-app/plans/vwan-app?api-version=2021-01-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +resource "azurerm_marketplace_agreement" "accept-marketplace-terms" { + count = can(jsondecode(data.http.accept-marketplace-terms-existing-agreement.response_body).id) ? (jsondecode(data.http.accept-marketplace-terms-existing-agreement.response_body).properties.state == "Active" ? 0 : 1) : 1 + publisher = "checkpoint" + offer = "cp-vwan-managed-app" + plan = "vwan-app" +} + +data "http" "azurerm_resource_provider_registration-exist" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.Solutions?api-version=2021-01-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +resource "azurerm_resource_provider_registration" "solutions" { + count = jsondecode(data.http.azurerm_resource_provider_registration-exist.response_body).registrationState == "Registered" ? 0 : 1 + name = "Microsoft.Solutions" +} + +//********************** Managed Identity **************************// +resource "azurerm_user_assigned_identity" "managed_app_identity" { + location = azurerm_resource_group.managed-app-rg.location + name = "managed_app_identity" + resource_group_name = azurerm_resource_group.managed-app-rg.name +} + +resource "azurerm_role_assignment" "reader" { + depends_on = [azurerm_user_assigned_identity.managed_app_identity] + scope = data.azurerm_virtual_hub.vwan-hub.id + role_definition_name = "Reader" + principal_id = azurerm_user_assigned_identity.managed_app_identity.principal_id +} + +resource "random_id" "randomId" { + keepers = { + resource_group = azurerm_resource_group.managed-app-rg.name + } + byte_length = 8 +} + +resource "azurerm_role_definition" "public-ip-join-role" { + count = var.new-public-ip == "yes" || length(var.existing-public-ip) > 0 ? 1 : 0 + name = "Managed Application Public IP Join Role - ${random_id.randomId.hex}" + scope = local.public_ip_resource_group + permissions { + actions = ["Microsoft.Network/publicIPAddresses/join/action"] + not_actions = [] + } + assignable_scopes = [local.public_ip_resource_group] +} + +resource "azurerm_role_assignment" "public-ip-join-role-assignment" { + count = var.new-public-ip == "yes" || length(var.existing-public-ip) > 0 ? 1 : 0 + scope = local.public_ip_resource_group + role_definition_id = azurerm_role_definition.public-ip-join-role[0].role_definition_resource_id + principal_id = azurerm_user_assigned_identity.managed_app_identity.principal_id +} + +//********************** Managed Application Configuration **************************// +resource "azapi_resource" "managed-app" { + depends_on = [azurerm_marketplace_agreement.accept-marketplace-terms, azurerm_resource_provider_registration.solutions] + type = "Microsoft.Solutions/applications@2019-07-01" + name = var.managed-app-name + location = azurerm_resource_group.managed-app-rg.location + parent_id = azurerm_resource_group.managed-app-rg.id + body = { + kind = "MarketPlace", + plan = { + name = "vwan-app" + product = "cp-vwan-managed-app" + publisher = "checkpoint" + version = "1.0.22" + }, + identity = { + type = "UserAssigned" + userAssignedIdentities = { + (azurerm_user_assigned_identity.managed_app_identity.id) = {} + } + }, + properties = { + parameters = { + location = { + value = azurerm_resource_group.managed-app-rg.location + }, + hubId = { + value = data.azurerm_virtual_hub.vwan-hub.id + }, + osVersion = { + value = var.os-version + }, + LicenseType = { + value = var.license-type + }, + imageVersion = { + value = element(local.image_versions, length(local.image_versions) -1) + }, + scaleUnit = { + value = var.scale-unit + }, + bootstrapScript = { + value = var.bootstrap-script + }, + adminShell = { + value = var.admin-shell + }, + sicKey = { + value = var.sic-key + }, + sshPublicKey = { + value = var.admin_SSH_key + }, + BGP = { + value = var.bgp-asn + }, + NVA = { + value = var.nva-name + }, + customMetrics = { + value = var.custom-metrics + }, + hubASN = { + value = data.azurerm_virtual_hub.vwan-hub.virtual_router_asn + }, + hubPeers = { + value = data.azurerm_virtual_hub.vwan-hub.virtual_router_ips + }, + smart1CloudTokenA = { + value = var.smart1-cloud-token-a + }, + smart1CloudTokenB = { + value = var.smart1-cloud-token-b + }, + smart1CloudTokenC = { + value = var.smart1-cloud-token-c + }, + smart1CloudTokenD = { + value = var.smart1-cloud-token-d + }, + smart1CloudTokenE = { + value = var.smart1-cloud-token-e + }, + publicIPIngress = { + value = (var.new-public-ip == "yes" || length(var.existing-public-ip) > 0) ? "yes" : "no" + }, + createNewIPIngress = { + value = var.new-public-ip + }, + ipIngressExistingResourceId = { + value = var.existing-public-ip + }, + templateName = { + value = "wan_terraform_registry" + } + }, + managedResourceGroupId = "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}" + } + } +} + +//********************** Routing Intent **************************// + +data "azapi_resource_list" "existing_routing_intent" { + type = "Microsoft.Network/virtualHubs/routingIntent@2024-05-01" + parent_id = data.azurerm_virtual_hub.vwan-hub.id + response_export_values = { + "values" = "value[].{routingPolicies: properties.routingPolicies}" + } + +} + +locals { + routing_intent_exists = length([for intent in data.azapi_resource_list.existing_routing_intent.output.values : intent]) > 0 + existing_policies = try(data.azapi_resource_list.existing_routing_intent.output.values[0].routingPolicies, []) + merged_policies = concat( + local.routing-intent-policies, + [for policy in local.existing_policies : policy if !contains([for p in local.routing-intent-policies : p.destinations[0]], policy.destinations[0])] + ) +} + +resource "azapi_resource" "routing_intent" { + count = length(local.routing-intent-policies) != 0 && !local.routing_intent_exists ? 1 : 0 + depends_on = [azapi_resource.managed-app] + type = "Microsoft.Network/virtualHubs/routingIntent@2024-05-01" + name = "hubRoutingIntent" + parent_id = data.azurerm_virtual_hub.vwan-hub.id + + body = { + properties = { + routingPolicies = local.routing-intent-policies + } +} +} + +resource "azapi_update_resource" "update_routing_intent" { + count = length(local.routing-intent-policies) != 0 && local.routing_intent_exists ? 1 : 0 + depends_on = [azapi_resource.managed-app] + type = "Microsoft.Network/virtualHubs/routingIntent@2024-05-01" + resource_id = "${data.azurerm_virtual_hub.vwan-hub.id}/routingIntent/hubRoutingIntent" + + body = { + properties = { + routingPolicies = local.merged_policies + } + } +} diff --git a/modules/nva_into_existing_hub/variables.tf b/modules/nva_into_existing_hub/variables.tf new file mode 100755 index 0000000..968e2f1 --- /dev/null +++ b/modules/nva_into_existing_hub/variables.tf @@ -0,0 +1,198 @@ +variable "authentication_method" { + description = "Azure authentication method" + type = string + validation { + condition = contains(["Azure CLI", "Service Principal"], var.authentication_method) + error_message = "Valid values for authentication_method are 'Azure CLI','Service Principal'" + } +} + +variable "subscription_id" { + description = "Subscription ID" + type = string +} + +variable "tenant_id" { + description = "Tenant ID" + type = string +} + +variable "client_id" { + description = "Application ID(Client ID)" + type = string +} + +variable "client_secret" { + description = "A secret string that the application uses to prove its identity when requesting a token. Also can be referred to as application password." + type = string +} + +variable "resource-group-name" { + type = string + default = "tf-managed-app-resource-group" +} + +variable "location" { + type = string + default = "westcentralus" +} + +variable "managed-app-name" { + type = string + default = "tf-vwan-managed-app-nva" +} + +variable "vwan-hub-name" { + type = string +} + +variable "vwan-hub-resource-group" { + type = string +} + +variable "nva-rg-name" { + type = string + default = "tf-vwan-nva-rg" +} + +variable "nva-name" { + type = string + default = "tf-vwan-nva" +} + +variable "os-version" { + description = "GAIA OS version" + type = string + default = "R8120" + validation { + condition = contains(["R8110", "R8120", "R82"], var.os-version) + error_message = "Allowed values for os-version are 'R8110', 'R8120', 'R82'" + } +} + +variable "license-type" { + type = string + default = "Security Enforcement (NGTP)" + validation { + condition = contains(["Security Enforcement (NGTP)", "Full Package (NGTX + S1C)", "Full Package Premium (NGTX + S1C++)"], var.license-type) + error_message = "Allowed values for License Type are 'Security Enforcement (NGTP)', 'Full Package (NGTX + S1C)', 'Full Package Premium (NGTX + S1C++)'" + } +} + +variable "scale-unit" { + type = string + default = "2" + validation { + condition = contains(["2", "4", "10", "20", "30", "60", "80"], var.scale-unit) + error_message = "Valid values for CloudGuard version are '2', '4', '10', '20', '30', '60', '80'" + } +} + +variable "bootstrap-script" { + type = string + default = "" +} + +variable "admin-shell" { + type = string + default = "/etc/cli.sh" + validation { + condition = contains(["/etc/cli.sh", "/bin/bash", "/bin/tcsh", "/bin/csh"], var.admin-shell) + error_message = "Valid shells are '/etc/cli.sh', '/bin/bash', '/bin/tcsh', '/bin/csh'" + } +} + +variable "sic-key" { + type = string + default = "" + sensitive = true + validation { + condition = can(regex("^[a-z0-9A-Z]{8,30}$", var.sic-key)) + error_message = "Only alphanumeric characters are allowed, and the value must be 8-30 characters long." + } +} + +variable "admin_SSH_key" { + type = string + default = "" +} + +variable "bgp-asn" { + type = string + default = "64512" + validation { + condition = tonumber(var.bgp-asn) >= 64512 && tonumber(var.bgp-asn) <= 65534 && !contains([65515, 65520], tonumber(var.bgp-asn)) + error_message = "Only numbers between 64512 to 65534 are allowed excluding 65515, 65520." + } +} + +variable "custom-metrics" { + type = string + default = "yes" + validation { + condition = contains(["yes", "no"], var.custom-metrics) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "routing-intent-internet-traffic" { + default = "yes" + validation { + condition = contains(["yes", "no"], var.routing-intent-internet-traffic) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "routing-intent-private-traffic" { + default = "yes" + validation { + condition = contains(["yes", "no"], var.routing-intent-private-traffic) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "smart1-cloud-token-a" { + type = string + default = "" +} + +variable "smart1-cloud-token-b" { + type = string + default = "" +} + +variable "smart1-cloud-token-c" { + type = string + default = "" +} + +variable "smart1-cloud-token-d" { + type = string + default = "" +} + +variable "smart1-cloud-token-e" { + type = string + default = "" +} + +variable "existing-public-ip" { + type = string + default = "" +} + +variable "new-public-ip" { + type = string + default = "no" + validation { + condition = contains(["yes", "no"], var.new-public-ip) + error_message = "Valid options are string('yes' or 'no')" + } +} + +locals{ + # Validate that new-public-ip is false when existing-public-ip is used + is_both_params_used = length(var.existing-public-ip) > 0 && var.new-public-ip == "yes" + validation_message_both = "Only one parameter of existing-public-ip or new-public-ip can be used" + _ = regex("^$", (!local.is_both_params_used ? "" : local.validation_message_both)) +} \ No newline at end of file diff --git a/modules/nva_into_existing_hub/versions.tf b/modules/nva_into_existing_hub/versions.tf new file mode 100755 index 0000000..0df2f1c --- /dev/null +++ b/modules/nva_into_existing_hub/versions.tf @@ -0,0 +1,31 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + azapi = { + source = "Azure/azapi" + version = "~> 2.2.0" + } + random = { + version = "~> 3.5.1" + } + } +} + +provider "azapi" { + subscription_id = var.subscription_id + client_id = var.client_id + client_secret = var.client_secret + tenant_id = var.tenant_id +} + +provider "azurerm" { + subscription_id = var.subscription_id + client_id = var.client_id + client_secret = var.client_secret + tenant_id = var.tenant_id + features {} +} diff --git a/modules/nva_into_new_vwan/README.md b/modules/nva_into_new_vwan/README.md new file mode 100755 index 0000000..a4ac6ad --- /dev/null +++ b/modules/nva_into_new_vwan/README.md @@ -0,0 +1,102 @@ +# Check Point CloudGuard Virtual WAN Module - New Virtual WAN + +This Terraform module deploys Check Point CloudGuard Network Security Virtual WAN NVA solution into a new vWAN Hub in Azure. +As part of the deployment the following resources are created: +- Resource groups +- Virtual WAN +- Virtual WAN Hub +- Azure Managed Application: + - NVA + - Managed identity + +For additional information, +please see the [CloudGuard Network for Azure Virtual WAN Deployment Guide](https://sc1.checkpoint.com/documents/IaaS/WebAdminGuides/EN/CP_CloudGuard_Network_for_Azure_vWAN/Default.htm) + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/nva_into_new_vwan" + version = "1.0.4" + + authentication_method = "Service Principal" + client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + subscription_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + resource-group-name = "tf-managed-app-resource-group" + location = "westcentralus" + vwan-name = "tf-vwan" + vwan-hub-name = "tf-vwan-hub" + vwan-hub-address-prefix = "10.0.0.0/16" + managed-app-name = "tf-vwan-managed-app-nva" + nva-rg-name = "tf-vwan-nva-rg" + nva-name = "tf-vwan-nva" + os-version = "R8120" + license-type = "Security Enforcement (NGTP)" + scale-unit = "2" + bootstrap-script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + admin-shell = "/etc/cli.sh" + sic-key = "xxxxxxxxxxxx" + admin_SSH_key = "ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxx imported-openssh-key" + bgp-asn = "64512" + custom-metrics = "yes" + routing-intent-internet-traffic = "yes" + routing-intent-private-traffic = "yes" + smart1-cloud-token-a = "" + smart1-cloud-token-b = "" + smart1-cloud-token-c = "" + smart1-cloud-token-d = "" + smart1-cloud-token-e = "" + existing-public-ip = "" + new-public-ip = "yes" +} +``` + +## Known limitations +1. 'terraform destroy' doesn't work if routing-intent is configured. To destroy the deployment, the routing-intent should be deleted manually first. + + +### Module's variables: + + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **authentication_method** | The authentication method used to deploy the solution | string | "Service Principal";
"Azure CLI". | +| **client_secret** | The client secret value of the Service Principal used to deploy the solution | string | | +| **client_id** | The client ID of the Service Principal used to deploy the solution | string | | +| **tenant_id** | The tenant ID of the Service Principal used to deploy the solution | string | | +| **subscription_id** | The subscription ID is used to pay for Azure cloud services | string | | +| **resource-group-name** | The name of the resource group that will contain the managed application | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.
**Default:** "managed-app-resource-group" | +| **location** | The region where the resources will be deployed at | string | The full list of supported Azure regions can be found at https://learn.microsoft.com/en-us/azure/virtual-wan/virtual-wan-locations-partners#locations.
**Default:** "westcentralus" | +| **vwan-name** | The name of the virtual WAN that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** "tf-vwan" | +| **vwan-hub-name** | The name of the virtual WAN hub that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** "tf-vwan-hub" | +| **vwan-hub-address-prefix** | The address prefixes of the virtual hub | string | Valid CIDR block.
**Default:** "10.0.0.0/16" | +| **managed-app-name** | The name of the managed application that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** tf-vwan-managed-app | +| **nva-name** | The name of the NVA that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.
**Default:** tf-vwan-nva | +| **nva-rg-name** | The name of the resource group that will contain the NVA | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.
**Default:** tf-vwan-nva-rg | +| **os-version** | The GAIA os version | string | "R8110";
"R8120";
"R82".
**Default:** "R8120" | +| **license-type** | The Check Point licence type | string | "Security Enforcement (NGTP)";
"Full Package (NGTX + S1C)";
"Full Package Premium (NGTX + S1C++)".
**Default:** "Security Enforcement (NGTP)" | +| **scale-unit** | The scale unit determines the size and number of resources deployed. The higher the scale unit, the greater the amount of traffic that can be handled | string | "2";
"4";
"10";
"20";
"30";
"60";
"80".
**Default:** "2" | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **sic-key** | The Secure Internal Communication one time secret used to set up trust between the gateway object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **admin_SSH_key** | The public ssh key used for ssh connection to the NVA GW instances | string | ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxx generated-by-azure. | +| **bgp-asn** | The BGP autonomous system number | string | 64512.
**Default:** "64512" | +| **custom-metrics** | Indicates whether CloudGuard Metrics will be use for gateway monitoring | string | yes;
no.
**Default:** "yes" | +| **routing-intent-internet-traffic** | Set routing intent policy to allow internet traffic through the new nva | string | yes;
no.
Please verify routing-intent is configured successfully post-deployment.
**Default:** "yes" | +| **routing-intent-private-traffic** | Set routing intent policy to allow private traffic through the new nva | string | yes;
no.
Please verify routing-intent is configured successfully post-deployment.
**Default:** "yes" | +| **smart1-cloud-token-a** | Smart-1 Cloud token to connect automatically ***NVA instance a*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-b** | Smart-1 Cloud token to connect automatically ***NVA instance b*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-c** | Smart-1 Cloud token to connect automatically ***NVA instance c*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-d** | Smart-1 Cloud token to connect automatically ***NVA instance d*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **smart1-cloud-token-e** | Smart-1 Cloud token to connect automatically ***NVA instance e*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **existing-public-ip** | Existing public IP reosurce to attach to the newly deployed NVA | string | A resource ID of the public IP resource. | +| **new-public-ip** | Deploy a new public IP resource as part of the managed app and attach to the NVA | string | yes;
no. | diff --git a/modules/nva_into_new_vwan/main.tf b/modules/nva_into_new_vwan/main.tf new file mode 100755 index 0000000..968ae6b --- /dev/null +++ b/modules/nva_into_new_vwan/main.tf @@ -0,0 +1,259 @@ +//********************** Basic Configuration **************************// +resource "azurerm_resource_group" "managed-app-rg" { + name = var.resource-group-name + location = var.location +} + +resource "azurerm_virtual_wan" "vwan" { + name = var.vwan-name + resource_group_name = azurerm_resource_group.managed-app-rg.name + location = var.location +} + +resource "azurerm_virtual_hub" "vwan-hub" { + name = var.vwan-hub-name + resource_group_name = azurerm_resource_group.managed-app-rg.name + location = azurerm_resource_group.managed-app-rg.location + address_prefix = var.vwan-hub-address-prefix + virtual_wan_id = azurerm_virtual_wan.vwan.id +} + +//********************** Image Version **************************// + +data "external" "az_access_token" { + count = var.authentication_method == "Azure CLI" ? 1 : 0 + program = ["az", "account", "get-access-token", "--resource=https://management.azure.com", "--query={accessToken: accessToken}", "--output=json"] +} + +data "http" "azure_auth" { + count = var.authentication_method == "Service Principal" ? 1 : 0 + url = "https://login.microsoftonline.com/${var.tenant_id}/oauth2/v2.0/token" + method = "POST" + request_headers = { + "Content-Type" = "application/x-www-form-urlencoded" + } + request_body = "grant_type=client_credentials&client_id=${var.client_id}&client_secret=${var.client_secret}&scope=https://management.azure.com/.default" +} + +locals { + access_token = var.authentication_method == "Service Principal" ? jsondecode(data.http.azure_auth[0].response_body).access_token : data.external.az_access_token[0].result.accessToken +} + +data "http" "image-versions" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.Network/networkVirtualApplianceSKUs/checkpoint${var.license-type == "Full Package (NGTX + S1C)" ? "-ngtx" : var.license-type == "Full Package Premium (NGTX + S1C++)" ? "-premium" : ""}?api-version=2020-05-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +locals { + image_versions = tolist([for version in jsondecode(data.http.image-versions.response_body).properties.availableVersions : version if substr(version, 0, 4) == substr(lower(length(var.os-version) > 3 ? var.os-version : "${var.os-version}00"), 1, 4)]) + routing_intent-internet-policy = { + "name": "InternetTraffic", + "destinations": [ + "Internet" + ], + "nextHop": "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}/providers/Microsoft.Network/networkVirtualAppliances/${var.nva-name}" + } + routing_intent-private-policy = { + "name": "PrivateTrafficPolicy", + "destinations": [ + "PrivateTraffic" + ], + "nextHop": "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}/providers/Microsoft.Network/networkVirtualAppliances/${var.nva-name}" + } + routing-intent-policies = var.routing-intent-internet-traffic == "yes" ? (var.routing-intent-private-traffic == "yes" ? tolist([local.routing_intent-internet-policy, local.routing_intent-private-policy]) : tolist([local.routing_intent-internet-policy])) : (var.routing-intent-private-traffic == "yes" ? tolist([local.routing_intent-private-policy]) : []) + public_ip_resource_group = "/subscriptions/${var.subscription_id}/resourceGroups/${var.new-public-ip == "yes" ? azurerm_resource_group.managed-app-rg.name : var.existing-public-ip != "" ? split("/", var.existing-public-ip)[4] : ""}" + +} + +//********************** Marketplace Terms & Solution Registration **************************// +data "http" "accept-marketplace-terms-existing-agreement" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.MarketplaceOrdering/agreements/checkpoint/offers/cp-vwan-managed-app/plans/vwan-app?api-version=2021-01-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +resource "azurerm_marketplace_agreement" "accept-marketplace-terms" { + count = can(jsondecode(data.http.accept-marketplace-terms-existing-agreement.response_body).id) ? (jsondecode(data.http.accept-marketplace-terms-existing-agreement.response_body).properties.state == "Active" ? 0 : 1) : 1 + publisher = "checkpoint" + offer = "cp-vwan-managed-app" + plan = "vwan-app" +} + + +data "http" "azurerm_resource_provider_registration-exist" { + method = "GET" + url = "https://management.azure.com/subscriptions/${var.subscription_id}/providers/Microsoft.Solutions?api-version=2021-01-01" + request_headers = { + Accept = "application/json" + "Authorization" = "Bearer ${local.access_token}" + } +} + +resource "azurerm_resource_provider_registration" "solutions" { + count = jsondecode(data.http.azurerm_resource_provider_registration-exist.response_body).registrationState == "Registered" ? 0 : 1 + name = "Microsoft.Solutions" +} + +//********************** Managed Identity **************************// +resource "azurerm_user_assigned_identity" "managed_app_identity" { + location = azurerm_resource_group.managed-app-rg.location + name = "managed_app_identity" + resource_group_name = azurerm_resource_group.managed-app-rg.name +} + +resource "azurerm_role_assignment" "reader" { + depends_on = [azurerm_user_assigned_identity.managed_app_identity] + scope = azurerm_virtual_hub.vwan-hub.id + role_definition_name = "Reader" + principal_id = azurerm_user_assigned_identity.managed_app_identity.principal_id +} + +resource "random_id" "randomId" { + keepers = { + resource_group = azurerm_resource_group.managed-app-rg.name + } + byte_length = 8 +} + +resource "azurerm_role_definition" "public-ip-join-role" { + count = var.new-public-ip == "yes" || length(var.existing-public-ip) > 0 ? 1 : 0 + name = "Managed Application Public IP Join Role - ${random_id.randomId.hex}" + scope = local.public_ip_resource_group + permissions { + actions = ["Microsoft.Network/publicIPAddresses/join/action"] + not_actions = [] + } + assignable_scopes = [local.public_ip_resource_group] +} + +resource "azurerm_role_assignment" "public-ip-join-role-assignment" { + count = var.new-public-ip == "yes" || length(var.existing-public-ip) > 0 ? 1 : 0 + scope = local.public_ip_resource_group + role_definition_id = azurerm_role_definition.public-ip-join-role[0].role_definition_resource_id + principal_id = azurerm_user_assigned_identity.managed_app_identity.principal_id +} + +//********************** Managed Application Configuration **************************// +resource "azapi_resource" "managed-app" { + depends_on = [azurerm_marketplace_agreement.accept-marketplace-terms, azurerm_resource_provider_registration.solutions] + type = "Microsoft.Solutions/applications@2019-07-01" + name = var.managed-app-name + location = azurerm_resource_group.managed-app-rg.location + parent_id = azurerm_resource_group.managed-app-rg.id + body = { + kind = "MarketPlace", + plan = { + name = "vwan-app" + product = "cp-vwan-managed-app" + publisher = "checkpoint" + version = "1.0.22" + }, + identity = { + type = "UserAssigned" + userAssignedIdentities = { + (azurerm_user_assigned_identity.managed_app_identity.id) = {} + } + }, + properties = { + parameters = { + location = { + value = azurerm_resource_group.managed-app-rg.location + }, + hubId = { + value = azurerm_virtual_hub.vwan-hub.id + }, + osVersion = { + value = var.os-version + }, + LicenseType = { + value = var.license-type + }, + imageVersion = { + value = element(local.image_versions, length(local.image_versions) -1) + }, + scaleUnit = { + value = var.scale-unit + }, + bootstrapScript = { + value = var.bootstrap-script + }, + adminShell = { + value = var.admin-shell + }, + sicKey = { + value = var.sic-key + }, + sshPublicKey = { + value = var.admin_SSH_key + }, + BGP = { + value = var.bgp-asn + }, + NVA = { + value = var.nva-name + }, + customMetrics = { + value = var.custom-metrics + }, + hubASN = { + value = azurerm_virtual_hub.vwan-hub.virtual_router_asn + }, + hubPeers = { + value = azurerm_virtual_hub.vwan-hub.virtual_router_ips + }, + smart1CloudTokenA = { + value = var.smart1-cloud-token-a + }, + smart1CloudTokenB = { + value = var.smart1-cloud-token-b + }, + smart1CloudTokenC = { + value = var.smart1-cloud-token-c + }, + smart1CloudTokenD = { + value = var.smart1-cloud-token-d + }, + smart1CloudTokenE = { + value = var.smart1-cloud-token-e + }, + publicIPIngress = { + value = (var.new-public-ip == "yes" || length(var.existing-public-ip) > 0) ? "yes" : "no" + }, + createNewIPIngress = { + value = var.new-public-ip + }, + ipIngressExistingResourceId = { + value = var.existing-public-ip + }, + templateName = { + value = "wan_terraform_registry" + } + }, + managedResourceGroupId = "/subscriptions/${var.subscription_id}/resourcegroups/${var.nva-rg-name}" + } + } +} + + +//********************** Routing Intent **************************// + +resource "azapi_resource" "routing_intent" { + count = length(local.routing-intent-policies) != 0 ? 1 : 0 + depends_on = [azapi_resource.managed-app] + type = "Microsoft.Network/virtualHubs/routingIntent@2024-05-01" + name = "hubRoutingIntent" + parent_id = azurerm_virtual_hub.vwan-hub.id + + body = { + properties = { + routingPolicies = local.routing-intent-policies + } + } +} \ No newline at end of file diff --git a/modules/nva_into_new_vwan/variables.tf b/modules/nva_into_new_vwan/variables.tf new file mode 100755 index 0000000..b82996b --- /dev/null +++ b/modules/nva_into_new_vwan/variables.tf @@ -0,0 +1,209 @@ +variable "authentication_method" { + description = "Azure authentication method" + type = string + validation { + condition = contains(["Azure CLI", "Service Principal"], var.authentication_method) + error_message = "Valid values for authentication_method are 'Azure CLI','Service Principal'" + } +} + +variable "subscription_id" { + description = "Subscription ID" + type = string +} + +variable "tenant_id" { + description = "Tenant ID" + type = string +} + +variable "client_id" { + description = "Application ID(Client ID)" + type = string +} + +variable "client_secret" { + description = "A secret string that the application uses to prove its identity when requesting a token. Also can be referred to as application password." + type = string +} + +variable "resource-group-name" { + type = string + default = "managed-app-resource-group" +} + +variable "location" { + type = string + default = "westcentralus" +} + +variable "vwan-name" { + type = string + default = "tf-vwan" +} + +variable "vwan-hub-name" { + type = string + default = "tf-vwan-hub" +} + +variable "vwan-hub-address-prefix" { + type = string + default = "10.0.0.0/16" + validation { + condition = can(cidrhost(var.vwan-hub-address-prefix, 0)) + error_message = "Please provide a valid CIDR specification for the VWAN address space" + } +} + +variable "managed-app-name" { + type = string + default = "tf-vwan-managed-app" +} + +variable "nva-rg-name" { + type = string + default = "tf-vwan-nva-rg" +} + +variable "nva-name" { + type = string + default = "tf-vwan-nva" +} + +variable "os-version" { + description = "GAIA OS version" + type = string + default = "R8120" + validation { + condition = contains(["R8110", "R8120", "R82"], var.os-version) + error_message = "Allowed values for os-version are 'R8110', 'R8120', 'R82'" + } +} + +variable "license-type" { + type = string + default = "Security Enforcement (NGTP)" + validation { + condition = contains(["Security Enforcement (NGTP)", "Full Package (NGTX + S1C)", "Full Package Premium (NGTX + S1C++)"], var.license-type) + error_message = "Allowed values for License Type are 'Security Enforcement (NGTP)', 'Full Package (NGTX + S1C)', 'Full Package Premium (NGTX + S1C++)'" + } +} + +variable "scale-unit" { + type = string + default = "2" + validation { + condition = contains(["2", "4", "10", "20", "30", "60", "80"], var.scale-unit) + error_message = "Valid values for CloudGuard version are '2', '4', '10', '20', '30', '60', '80'" + } +} + +variable "bootstrap-script" { + type = string + default = "" +} + +variable "admin-shell" { + type = string + default = "/etc/cli.sh" + validation { + condition = contains(["/etc/cli.sh", "/bin/bash", "/bin/tcsh", "/bin/csh"], var.admin-shell) + error_message = "Valid shells are '/etc/cli.sh', '/bin/bash', '/bin/tcsh', '/bin/csh'" + } +} + +variable "sic-key" { + type = string + default = "" + sensitive = true + validation { + condition = can(regex("^[a-z0-9A-Z]{8,30}$", var.sic-key)) + error_message = "Only alphanumeric characters are allowed, and the value must be 8-30 characters long." + } +} + +variable "admin_SSH_key" { + type = string + default = "" +} + +variable "bgp-asn" { + type = string + default = "64512" + validation { + condition = tonumber(var.bgp-asn) >= 64512 && tonumber(var.bgp-asn) <= 65534 && !contains([65515, 65520], tonumber(var.bgp-asn)) + error_message = "Only numbers between 64512 to 65534 are allowed excluding 65515, 65520." + } +} + +variable "custom-metrics" { + type = string + default = "yes" + validation { + condition = contains(["yes", "no"], var.custom-metrics) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "routing-intent-internet-traffic" { + default = "yes" + validation { + condition = contains(["yes", "no"], var.routing-intent-internet-traffic) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "routing-intent-private-traffic" { + default = "yes" + validation { + condition = contains(["yes", "no"], var.routing-intent-private-traffic) + error_message = "Valid options are string('yes' or 'no')" + } +} + +variable "smart1-cloud-token-a" { + type = string + default = "" +} + +variable "smart1-cloud-token-b" { + type = string + default = "" +} + +variable "smart1-cloud-token-c" { + type = string + default = "" +} + +variable "smart1-cloud-token-d" { + type = string + default = "" +} + +variable "smart1-cloud-token-e" { + type = string + default = "" +} + +variable "existing-public-ip" { + type = string + default = "" +} + +variable "new-public-ip" { + type = string + default = "no" + validation { + condition = contains(["yes", "no"], var.new-public-ip) + error_message = "Valid options are string('yes' or 'no')" + } +} + +locals{ + # Validate that new-public-ip is false when existing-public-ip is used + is_both_params_used = length(var.existing-public-ip) > 0 && var.new-public-ip == "yes" + validation_message_both = "Only one parameter of existing-public-ip or new-public-ip can be used" + _ = regex("^$", (!local.is_both_params_used ? "" : local.validation_message_both)) +} \ No newline at end of file diff --git a/modules/nva_into_new_vwan/versions.tf b/modules/nva_into_new_vwan/versions.tf new file mode 100755 index 0000000..0df2f1c --- /dev/null +++ b/modules/nva_into_new_vwan/versions.tf @@ -0,0 +1,31 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + azapi = { + source = "Azure/azapi" + version = "~> 2.2.0" + } + random = { + version = "~> 3.5.1" + } + } +} + +provider "azapi" { + subscription_id = var.subscription_id + client_id = var.client_id + client_secret = var.client_secret + tenant_id = var.tenant_id +} + +provider "azurerm" { + subscription_id = var.subscription_id + client_id = var.client_id + client_secret = var.client_secret + tenant_id = var.tenant_id + features {} +} diff --git a/modules/single_gateway_existing_vnet/README.md b/modules/single_gateway_existing_vnet/README.md new file mode 100755 index 0000000..88b03ba --- /dev/null +++ b/modules/single_gateway_existing_vnet/README.md @@ -0,0 +1,102 @@ + +# Check Point CloudGuard Network Security Single Gateway Module - Existing VNet + +This Terraform module deploys Check Point CloudGuard Network Security Single Gateway solution into an existing VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- System assigned identity + + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. + + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/single_gateway_existing_vnet" + version = "1.0.4" + + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-single-gw-terraform" + single_gateway_name = "checkpoint-single-gw-terraform" + location = "eastus" + vnet_name = "checkpoint-single-gw-vnet" + vnet_resource_group = "existing-vnet-rg" + subnet_frontend_name = "frontend" + subnet_backend_name = "backend" + subnet_frontend_1st_Address = "10.0.1.4" + subnet_backend_1st_Address = "10.12.1.5" + management_GUI_client_network = "0.0.0.0/0" + admin_password = "xxxxxxxxxxxx" + smart_1_cloud_token = "xxxxxxxxxxxx" + sic_key = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "110" + vm_os_sku = "sg-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + enable_custom_metrics = true + admin_shell = "/etc/cli.sh" + installation_type = "gateway" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] + +} +``` + +## Conditional creation +- To enable CloudGuard metrics in order to send statuses and statistics collected from the gateway instance to the Azure Monitor service: + ``` + enable_custom_metrics = true + ``` + +### Module's variables: + + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period. | +| **single_gateway_name** | The name of the Check Point single GW Object | string | Only alphanumeric characters are allowed, and the name must be 1-30 characters long. | +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions. | +| **vnet_name** | The name of virtual network that will be created | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **vnet_resource_group** | Resource Group of the existing virtual network | string | The exact name of the existing vnet's resource group. | +| **frontend_subnet_name** | Specifies the name of the external subnet | string | The exact name of the existing external subnet. | +| **backend_subnet_name** | Specifies the name of the internal subnet | string | The exact name of the existing internal subnet. | +| **subnet_frontend_1st_Address** | First available address in frontend subnet | string | | +| **subnet_backend_1st_Address** | First available address in backend subnet | string | | +| **management_GUI_client_network** | Allowed GUI clients - GUI clients network CIDR | string | | +| **admin_password** | The password associated with the local administrator account on the gateway | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. | +| **smart_1_cloud_token** | Smart-1 Cloud token to connect automatically ***Gateway*** to Check Point's Security Management as a Service.

Follow these instructions to quickly connect this member to Smart-1 Cloud - [SK180501](https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk180501) | string | A valid token copied from the Connect Gateway screen in Smart-1 Cloud portal. | +| **sic_key** | The Secure Internal Communication one time secret used to set up trust between the gateway object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **vm_size** | Specifies the size of Virtual Machine | string | "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_D4s_v3", "Standard_D8s_v3", "Standard_D16s_v3", "Standard_D32s_v3", "Standard_D64s_v3", "Standard_E4s_v3", "Standard_E8s_v3", "Standard_E16s_v3", "Standard_E20s_v3", "Standard_E32s_v3", "Standard_E64s_v3", "Standard_E64is_v3", "Standard_F4s_v2", "Standard_F8s_v2", "Standard_F16s_v2", "Standard_F32s_v2", "Standard_F64s_v2", "Standard_M8ms", "Standard_M16ms", "Standard_M32ms", "Standard_M64ms", "Standard_M64s", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_D4_v3", "Standard_D8_v3", "Standard_D16_v3", "Standard_D32_v3", "Standard_D64_v3", "Standard_E4_v3", "Standard_E8_v3", "Standard_E16_v3", "Standard_E20_v3", "Standard_E32_v3", "Standard_E64_v3", "Standard_E64i_v3", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_D2_v5", "Standard_D4_v5", "Standard_D8_v5", "Standard_D16_v5","Standard_D32_v5", "Standard_D2s_v5", "Standard_D4s_v5", "Standard_D8s_v5", "Standard_D16s_v5", "Standard_D2d_v5", "Standard_D4d_v5", "Standard_D8d_v5", "Standard_D16d_v5", "Standard_D32d_v5", "Standard_D2ds_v5", "Standard_D4ds_v5", "Standard_D8ds_v5", "Standard_D16ds_v5", "Standard_D32ds_v5". | +| **disk_size** | Storage data disk size size(GB) | string | A number in the range 100 - 3995 (GB). | +| **vm_os_sku** | A sku of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license. | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82". | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82". | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it.
**Default:** "" | +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false. | +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key". | +| **enable_custom_metrics** | Indicates whether CloudGuard Metrics will be use for gateways monitoring | boolean | true;
false.
**Default:** true | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **installation_type** | Enables to select installation type- gateway/standalone | string | gateway;
standalone. | +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type, to generate password hash use the command 'openssl passwd -6 PASSWORD' on Linux and paste it here | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions, to generate a password hash use the command 'grub2-mkpasswd-pbkdf2' on Linux and paste it here | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure, if not provided, will create a default NSG | string | Existing NSG resource ID.
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location, if false then accses will be allowed from all networks | boolean | true;
false.
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs.
**Default:** [] | \ No newline at end of file diff --git a/modules/single_gateway_existing_vnet/cloud-init.sh b/modules/single_gateway_existing_vnet/cloud-init.sh new file mode 100755 index 0000000..ff60d82 --- /dev/null +++ b/modules/single_gateway_existing_vnet/cloud-init.sh @@ -0,0 +1,18 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +adminShell="${admin_shell}" +sicKey="${sic_key}" +managementGUIClientNetwork="${management_GUI_client_network}" +smart1CloudToken="${smart_1_cloud_token}" +customMetrics="${enable_custom_metrics}" +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" \ No newline at end of file diff --git a/modules/single_gateway_existing_vnet/locals.tf b/modules/single_gateway_existing_vnet/locals.tf new file mode 100755 index 0000000..56cb061 --- /dev/null +++ b/modules/single_gateway_existing_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "single_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/single_gateway_existing_vnet/main.tf b/modules/single_gateway_existing_vnet/main.tf new file mode 100755 index 0000000..9891a59 --- /dev/null +++ b/modules/single_gateway_existing_vnet/main.tf @@ -0,0 +1,235 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = 1 + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = var.is_blink + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// +data "azurerm_subnet" "frontend_subnet" { + name = var.subnet_frontend_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +data "azurerm_subnet" "backend_subnet" { + name = var.subnet_backend_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +resource "azurerm_public_ip" "public-ip" { + name = var.single_gateway_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + idle_timeout_in_minutes = 30 + domain_name_label = join("", [ + lower(var.single_gateway_name), + "-", + random_id.randomId.hex]) +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}-nsg" + location = module.common.resource_group_location + security_rules = var.security_rules +} + +resource "azurerm_network_interface_security_group_association" "security_group_association" { + depends_on = [azurerm_network_interface.nic] + network_interface_id = azurerm_network_interface.nic.id + network_security_group_id = var.nsg_id == "" ? module.network_security_group[0].network_security_group_id: var.nsg_id +} + +resource "azurerm_network_interface" "nic" { + depends_on = [ + azurerm_public_ip.public-ip] + name = "${var.single_gateway_name}-eth0" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + + ip_configuration { + name = "ipconfig1" + subnet_id = data.azurerm_subnet.frontend_subnet.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = var.subnet_frontend_1st_Address + public_ip_address_id = azurerm_public_ip.public-ip.id + } +} + +resource "azurerm_network_interface" "nic1" { + depends_on = [] + name = "${var.single_gateway_name}-eth1" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + enable_ip_forwarding = true + enable_accelerated_networking = true + + + ip_configuration { + name = "ipconfig2" + subnet_id = data.azurerm_subnet.backend_subnet.id + private_ip_address_allocation = var.vnet_allocation_method + private_ip_address = var.subnet_backend_1st_Address + } +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "bootdiag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + account_kind = "Storage" + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } + +} + +//********************** Virtual Machines **************************// +locals { + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} + +resource "azurerm_virtual_machine" "single-gateway-vm-instance" { + depends_on = [ + azurerm_network_interface.nic, + azurerm_network_interface.nic1] + location = module.common.resource_group_location + name = var.single_gateway_name + network_interface_ids = [ + azurerm_network_interface.nic.id, + azurerm_network_interface.nic1.id] + resource_group_name = module.common.resource_group_name + vm_size = module.common.vm_size + delete_os_disk_on_termination = module.common.delete_os_disk_on_termination + primary_network_interface_id = azurerm_network_interface.nic.id + + identity { + type = module.common.vm_instance_identity + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [ + ] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + boot_diagnostics { + enabled = module.common.boot_diagnostics + storage_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } + + os_profile { + computer_name = lower(var.single_gateway_name) + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + admin_shell = var.admin_shell + sic_key = var.sic_key + management_GUI_client_network = var.management_GUI_client_network + smart_1_cloud_token = var.smart_1_cloud_token + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) + } + + + os_profile_linux_config { + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "ssh_keys" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + path = "/home/notused/.ssh/authorized_keys" + key_data = var.admin_SSH_key + } + } + } + + storage_image_reference { + id = local.custom_image_condition ? azurerm_image.custom-image[0].id : null + publisher = local.custom_image_condition ? null : module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + + storage_os_disk { + name = var.single_gateway_name + create_option = module.common.storage_os_disk_create_option + caching = module.common.storage_os_disk_caching + managed_disk_type = module.common.storage_account_type + disk_size_gb = module.common.disk_size + } +} diff --git a/modules/single_gateway_existing_vnet/variables.tf b/modules/single_gateway_existing_vnet/variables.tf new file mode 100755 index 0000000..1c2f588 --- /dev/null +++ b/modules/single_gateway_existing_vnet/variables.tf @@ -0,0 +1,271 @@ +//********************** Basic Configuration Variables **************************// +variable "single_gateway_name" { + description = "Single gateway name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resource will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + + +//********************** Virtual Machine Instances Variables **************************// +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "smart_1_cloud_token" { + description = "Smart-1 Cloud Token" + type = string +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "installation_type" { + description = "Installation type" + type = string + default = "gateway" +} + +locals { // locals for 'installation_type' allowed values + installation_type_allowed_values = [ + "gateway", + "standalone" + ] +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995" + type = string +} + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} + +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "vm_os_offer" { + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "enable_custom_metrics" { + description = "Indicates whether CloudGuard Metrics will be use for Cluster members monitoring." + type = bool + default = true +} + +variable "is_blink" { + description = "Define if blink image is used for deployment" + default = true +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "subnet_frontend_name" { + description = "management subnet name" + type = string +} + +variable "subnet_backend_name" { + description = "management subnet name" + type = string +} + +variable "subnet_frontend_1st_Address" { + description = "The first available address of the frontend subnet" + type = string +} + +variable "subnet_backend_1st_Address" { + description = "The first available address of the backend subnet" + type = string +} + +variable "vnet_resource_group" { + description = "Resource group of existing vnet" + type = string +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "management_GUI_client_network" { + description = "Allowed GUI clients - GUI clients network CIDR" + type = string +} + +locals { + regex_valid_single_GUI_client_network = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/(3[0-2]|2[0-9]|1[0-9]|[0-9]))$" + // Will fail if var.management_GUI_client_network is invalid + regex_single_GUI_client_network = regex(local.regex_valid_single_GUI_client_network, var.management_GUI_client_network) == var.management_GUI_client_network ? 0 : "Variable [management_GUI_client_network] must be a valid IPv4 network CIDR." + + + regex_valid_subnet_1st_Address = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" + // Will fail if var.subnet_1st_Address is invalid + regex_subnet_frontend_1st_Address = regex(local.regex_valid_subnet_1st_Address, var.subnet_frontend_1st_Address) == var.subnet_frontend_1st_Address ? 0 : "Variable [subnet_1st_Address] must be a valid address." + + regex_subnet_backend_1st_Address = regex(local.regex_valid_subnet_1st_Address, var.subnet_backend_1st_Address) == var.subnet_backend_1st_Address ? 0 : "Variable [subnet_1st_Address] must be a valid address." +} + +variable "bootstrap_script" { + description = "An optional script to run on the initial boot" + default = "" + type = string + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +variable "sic_key" { + type = string +} + +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [ + { + name = "AllowAllInBound" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_ranges = "*" + destination_port_ranges = "" + description = "Allow all inbound connections" + source_address_prefix = "*" + destination_address_prefix = "" + } + ] +} diff --git a/modules/single_gateway_existing_vnet/versions.tf b/modules/single_gateway_existing_vnet/versions.tf new file mode 100755 index 0000000..8827a9f --- /dev/null +++ b/modules/single_gateway_existing_vnet/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} \ No newline at end of file diff --git a/modules/single_gateway_new_vnet/README.md b/modules/single_gateway_new_vnet/README.md index a05c437..8a9ad92 100755 --- a/modules/single_gateway_new_vnet/README.md +++ b/modules/single_gateway_new_vnet/README.md @@ -25,7 +25,7 @@ provider "azurerm" { module "example_module" { source = "CheckPointSW/cloudguard-network-security/azure//modules/single_gateway_new_vnet" - version = "1.0.3" + version = "1.0.4" source_image_vhd_uri = "noCustomUri" resource_group_name = "checkpoint-single-gw-terraform" @@ -59,7 +59,7 @@ module "example_module" { ``` ## Conditional creation -- To enable CloudGuard metrics in order to send statuses and statistics collected from the gateway instance to the Azure Monitor service: +- To enable CloudGuard metrics in order to send statuses and statistics collected from the gateway instance to the Azure Monitor service: ``` enable_custom_metrics = true ``` @@ -83,8 +83,8 @@ module "example_module" { | **vm_size** | Specifies the size of Virtual Machine | string | Various valid sizes (e.g., "Standard_DS2_v2", "Standard_D4s_v3", etc.) | | **disk_size** | Storage data disk size (GB) | string | A number in the range 100 - 3995 (GB) | | **vm_os_sku** | A SKU of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license | -| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r81";
"check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82"; | -| **os_version** | GAIA OS version | string | "R81";
"R8110";
"R8120";
"R82"; | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82"; | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82"; | | **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt"
**Default:** "" | | **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false; | | **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key"; | diff --git a/modules/single_gateway_new_vnet/cloud-init.sh b/modules/single_gateway_new_vnet/cloud-init.sh index a2d209c..ff60d82 100755 --- a/modules/single_gateway_new_vnet/cloud-init.sh +++ b/modules/single_gateway_new_vnet/cloud-init.sh @@ -3,7 +3,7 @@ installationType="${installation_type}" allowUploadDownload="${allow_upload_download}" osVersion="${os_version}" -templateName="${template_name}" +templateName="${module_name}" templateVersion="${module_version}" templateType="${template_type}" isBlink="${is_blink}" diff --git a/modules/single_gateway_new_vnet/locals.tf b/modules/single_gateway_new_vnet/locals.tf index 9892b55..56cb061 100755 --- a/modules/single_gateway_new_vnet/locals.tf +++ b/modules/single_gateway_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { - template_name = "single_terraform_registry" - module_version = "1.0.3" + module_name = "single_terraform_registry" + module_version = "1.0.4" } diff --git a/modules/single_gateway_new_vnet/main.tf b/modules/single_gateway_new_vnet/main.tf index 748f740..cdb1506 100755 --- a/modules/single_gateway_new_vnet/main.tf +++ b/modules/single_gateway_new_vnet/main.tf @@ -5,7 +5,7 @@ module "common" { location = var.location admin_password = var.admin_password installation_type = var.installation_type - template_name = local.template_name + module_name = local.module_name module_version = local.module_version number_of_vm_instances = 1 allow_upload_download = var.allow_upload_download @@ -184,23 +184,23 @@ resource "azurerm_virtual_machine" "single-gateway-vm-instance" { admin_username = module.common.admin_username admin_password = module.common.admin_password custom_data = templatefile("${path.module}/cloud-init.sh", { - installation_type = module.common.installation_type - allow_upload_download = module.common.allow_upload_download - os_version = module.common.os_version - template_name = module.common.template_name - module_version = module.common.module_version - template_type = "terraform" - is_blink = module.common.is_blink - bootstrap_script64 = base64encode(var.bootstrap_script) - location = module.common.resource_group_location - admin_shell = var.admin_shell - sic_key = var.sic_key - management_GUI_client_network = var.management_GUI_client_network - smart_1_cloud_token = var.smart_1_cloud_token - enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" - serial_console_password_hash = var.serial_console_password_hash - maintenance_mode_password_hash = var.maintenance_mode_password_hash - }) + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + admin_shell = var.admin_shell + sic_key = var.sic_key + management_GUI_client_network = var.management_GUI_client_network + smart_1_cloud_token = var.smart_1_cloud_token + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + }) } os_profile_linux_config { diff --git a/modules/single_gateway_new_vnet/variables.tf b/modules/single_gateway_new_vnet/variables.tf index 7049fae..00c725d 100755 --- a/modules/single_gateway_new_vnet/variables.tf +++ b/modules/single_gateway_new_vnet/variables.tf @@ -60,7 +60,7 @@ locals { // locals for 'authentication_type' allowed values } variable "installation_type" { - description = "installation type" + description = "Installation type" type = string default = "gateway" } @@ -103,13 +103,12 @@ variable "vm_os_sku" { } variable "vm_os_offer" { - description = "The name of the image offer to be deployed.Choose from: check-point-cg-r81, check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + description = "The name of the image offer to be deployed.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" type = string } locals { // locals for 'vm_os_offer' allowed values vm_os_offer_allowed_values = [ - "check-point-cg-r81", "check-point-cg-r8110", "check-point-cg-r8120", "check-point-cg-r82" @@ -265,7 +264,6 @@ variable "sku" { default = "Standard" } - variable "admin_SSH_key" { type = string description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." diff --git a/modules/vmss_existing_vnet/README.md b/modules/vmss_existing_vnet/README.md new file mode 100755 index 0000000..ec3a871 --- /dev/null +++ b/modules/vmss_existing_vnet/README.md @@ -0,0 +1,128 @@ +# Check Point CloudGuard VMSS Module - Existing VNet + +This Terraform module deploys Check Point CloudGuard Network Security VMSS solution into an existing VNet in azure. +As part of the deployment the following resources are created: +- Resource group +- Role assignment - conditional creation + + +For additional information, +please see the [CloudGuard Network for Azure Virtual Machine Scale Sets (VMSS) Deployment Guide](https://sc1.checkpoint.com/documents/IaaS/WebAdminGuides/EN/CP_VMSS_for_Azure/Default.htm) + +This solution uses the following modules: +- common - used for creating a resource group and defining common variables. + +## Usage +Follow best practices for using CGNS modules on [the root page](https://registry.terraform.io/modules/CheckPointSW/cloudguard-network-security/azure/latest). + +**Example:** +``` +provider "azurerm" { + features {} +} + +module "example_module" { + + source = "CheckPointSW/cloudguard-network-security/azure//modules/vmss_existing_vnet" + version = "1.0.4" + + subscription_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + source_image_vhd_uri = "noCustomUri" + resource_group_name = "checkpoint-vmss-terraform" + location = "eastus" + vmss_name = "checkpoint-vmss-terraform" + vnet_name = "checkpoint-vmss-vnet" + vnet_resource_group = "existing-vnet" + frontend_subnet_name = "frontend" + backend_subnet_name = "backend" + backend_lb_IP_address = 4 + admin_password = "xxxxxxxxxxxx" + sic_key = "xxxxxxxxxxxx" + vm_size = "Standard_D3_v2" + disk_size = "100" + vm_os_sku = "sg-byol" + vm_os_offer = "check-point-cg-r8110" + os_version = "R8110" + bootstrap_script = "touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" + allow_upload_download = true + authentication_type = "Password" + availability_zones_num = "1" + minimum_number_of_vm_instances = 2 + maximum_number_of_vm_instances = 10 + management_name = "mgmt" + management_IP = "13.92.42.181" + management_interface = "eth1-private" + configuration_template_name = "vmss_template" + notification_email = "" + frontend_load_distribution = "Default" + backend_load_distribution = "Default" + enable_custom_metrics = true + enable_floating_ip = false + deployment_mode = "Standard" + admin_shell = "/etc/cli.sh" + serial_console_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + maintenance_mode_password_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + nsg_id = "" + add_storage_account_ip_rules = false + storage_account_additional_ips = [] +} +``` + +## Deploy Without Public IP + +1. By default, the VMSS is deployed with public IP +2. To deploy without public IP, remove the "public_ip_address_configuration" block in main.tf + +## Conditional creation +- To create role assignment and enable CloudGuard metrics in order to send statuses and statistics collected from VMSS instances to the Azure Monitor service: + ``` + enable_custom_metrics = true + ``` + +### Module's variables: + +# Parameters Description + +| Name | Description | Type | Allowed values | +|------|-------------|------|----------------| +| **subscription_id** | The subscription ID is used to pay for Azure cloud services | string | | +| **source_image_vhd_uri** | The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images | string | **Default:** "noCustomUri" | +| **resource_group_name** | The name of the resource group that will contain the contents of the deployment | string | Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.
Note: Resource group name must not contain reserved words based on: sk40179. | +| **location** | The region where the resources will be deployed at | string | The full list of Azure regions can be found at https://azure.microsoft.com/regions. | +| **vmss_name** | The name of the Check Point VMSS Object | string | Only alphanumeric characters are allowed, and the name must be 1-30 characters long.
Note: vmss_name name must not contain reserved words based on: sk40179. | +| **vnet_name** | Virtual Network name | string | The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens. | +| **vnet_resource_group** | Resource Group of the existing virtual network | string | The exact name of the existing vnet's resource group. | +| **frontend_subnet_name** | Specifies the name of the external subnet | string | The exact name of the existing external subnet. | +| **backend_subnet_name** | Specifies the name of the internal subnet | string | The exact name of the existing internal subnet. | +| **backend_lb_IP_address** | Is a whole number that can be represented as a binary integer with no more than the number of digits remaining in the address after the given prefix | string | Starting from 5-th IP address in a subnet. For example: subnet - 10.0.1.0/24, backend_lb_IP_address = 4 , the LB IP is 10.0.1.4. | +| **admin_password** | The password associated with the local administrator account on each cluster member | string | Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. | +| **sic_key** | The Secure Internal Communication one time secret used to set up trust between the cluster object and the management server | string | Only alphanumeric characters are allowed, and the value must be 12-30 characters long. | +| **vm_size** | Specifies the size of Virtual Machine | string | "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_D4s_v3", "Standard_D8s_v3", "Standard_D16s_v3", "Standard_D32s_v3", "Standard_D64s_v3", "Standard_E4s_v3", "Standard_E8s_v3", "Standard_E16s_v3", "Standard_E20s_v3", "Standard_E32s_v3", "Standard_E64s_v3", "Standard_E64is_v3", "Standard_F4s_v2", "Standard_F8s_v2", "Standard_F16s_v2", "Standard_F32s_v2", "Standard_F64s_v2", "Standard_M8ms", "Standard_M16ms", "Standard_M32ms", "Standard_M64ms", "Standard_M64s", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_D4_v3", "Standard_D8_v3", "Standard_D16_v3", "Standard_D32_v3", "Standard_D64_v3", "Standard_E4_v3", "Standard_E8_v3", "Standard_E16_v3", "Standard_E20_v3", "Standard_E32_v3", "Standard_E64_v3", "Standard_E64i_v3", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_D2_v5", "Standard_D4_v5", "Standard_D8_v5", "Standard_D16_v5","Standard_D32_v5", "Standard_D2s_v5", "Standard_D4s_v5", "Standard_D8s_v5", "Standard_D16s_v5", "Standard_D2d_v5", "Standard_D4d_v5", "Standard_D8d_v5", "Standard_D16d_v5", "Standard_D32d_v5", "Standard_D2ds_v5", "Standard_D4ds_v5", "Standard_D8ds_v5", "Standard_D16ds_v5", "Standard_D32ds_v5". | +| **disk_size** | Storage data disk size size(GB) must be 100 for versions R81.20 and below | string | A number in the range 100 - 3995 (GB).
**Default:** 100 | +| **vm_os_sku** | A sku of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license. | +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82". | +| **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82". | +| **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt".
The script will create bootstrap.txt file in the /home/admin/ and add 'hello word' string into it. | +| **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false. | +| **authentication_type** | Specifies whether a password authentication or SSH Public Key authentication should be used | string | "Password";
"SSH Public Key". | +| **availability_zones_num** | A list of a single item of the Availability Zone which the Virtual Machine should be allocated in | string | "centralus", "eastus2", "francecentral", "northeurope", "southeastasia", "westeurope", "westus2", "eastus", "uksouth". | +| **minimum_number_of_vm_instances** | The minimum number of VMSS instances for this resource | number | Valid values are in the range 0 - 10. | +| **maximum_number_of_vm_instances** | The maximum number of VMSS instances for this resource | number | Valid values are in the range 0 - 10. | +| **management_name** | The name of the management server as it appears in the configuration file | string | Field cannot be empty. Only alphanumeric characters or '_'/'-' are allowed, and the name must be 1-30 characters long. | +| **management_IP** | The IP address used to manage the VMSS instances | string | A valid IP address. | +| **management_interface** | Management option for the Gateways in the VMSS | string | "eth0-public" - Manages the GWs using their external NIC's public IP address;
"eth0-private" - Manages the GWs using their external NIC's private IP address;
"eth1-private" - Manages the GWs using their internal NIC's private IP address.
**Default:** "eth1-private" | +| **configuration_template_name** | The configuration template name as it appears in the configuration file | string | Field cannot be empty. Only alphanumeric characters or '_'/'-' are allowed, and the name must be 1-30 characters long. | +| **frontend_load_distribution** | The load balancing distribution method for the External Load Balancer | string | "Default" - None(5-tuple);
"SourceIP" - ClientIP(2-tuple);
"SourceIPProtocol" - ClientIP and protocol(3-tuple). | +| **backend_load_distribution** | The load balancing distribution method for the Internal Load Balancer | string | "Default" - None(5-tuple);
"SourceIP" - ClientIP(2-tuple);
"SourceIPProtocol" - ClientIP and protocol(3-tuple). | +| **notification_email** | An email address to notify about scaling operations | string | Leave empty double quotes or enter a valid email address. | +| **enable_custom_metrics** | Indicates whether Custom Metrics will be used for VMSS Scaling policy and VM monitoring | boolean | true;
false.
**Default:** true | +| **enable_floating_ip** | Indicates whether the load balancers will be deployed with floating IP | boolean | true;
false.
**Default:** false | +| **deployment_mode** | Indicates which load balancer need to be deployed. External + Internal(Standard), only External, only Internal | string | Standard;
External;
Internal.
**Default:** "Standard" | +| **admin_shell** | Enables to select different admin shells | string | /etc/cli.sh;
/bin/bash;
/bin/csh;
/bin/tcsh.
**Default:** "/etc/cli.sh" | +| **serial_console_password_hash** | Optional parameter, used to enable serial console connection in case of SSH key as authentication type, to generate password hash use the command 'openssl passwd -6 PASSWORD' on Linux and paste it here | string | | +| **maintenance_mode_password_hash** | Maintenance mode password hash, relevant only for R81.20 and higher versions, to generate a password hash use the command 'grub2-mkpasswd-pbkdf2' on Linux and paste it here | string | | +| **nsg_id** | Optional ID for a Network Security Group that already exists in Azure, if not provided, will create a default NSG | string | Existing NSG resource ID.
**Default:** "" | +| **add_storage_account_ip_rules** | Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location, if false then accses will be allowed from all networks | boolean | true;
false.
**Default:** false | +| **storage_account_additional_ips** | IPs/CIDRs that are allowed access to the Storage Account | list(string) | A list of valid IPs and CIDRs.
**Default:** [] | +| **security_rules** | Security rules for the Network Security | list(any) | A list of valid security rules values.
A security rule composed of:
{name, priority, direction, access, protocol, source_port_ranges, destination_port_ranges, source_address_prefix, destination_address_prefix, description}.
**Default:** [{"name":"AllowAllInBound", "priority":"100", "direction":"Inbound", "access":"Allow", "protocol":"*", "source_port_ranges":"*", "destination_port_ranges":"", "description":"Allow all inbound connections", "source_address_prefix":"*", "destination_address_prefix":""}] | +| **admin_SSH_key** | The SSH public key for SSH connections to the instance.
Used when the authentication_type is 'SSH Public Key' | string | **Default:** "" | \ No newline at end of file diff --git a/modules/vmss_existing_vnet/cloud-init.sh b/modules/vmss_existing_vnet/cloud-init.sh new file mode 100755 index 0000000..0775580 --- /dev/null +++ b/modules/vmss_existing_vnet/cloud-init.sh @@ -0,0 +1,17 @@ +#!/usr/bin/python3 /etc/cloud_config.py + +installationType="${installation_type}" +allowUploadDownload="${allow_upload_download}" +osVersion="${os_version}" +templateName="${module_name}" +templateVersion="${module_version}" +templateType="${template_type}" +isBlink="${is_blink}" +bootstrapScript64="${bootstrap_script64}" +location="${location}" +sicKey="${sic_key}" +vnet="${vnet}" +customMetrics="${enable_custom_metrics}" +adminShell="${admin_shell}" +passwordHash="${serial_console_password_hash}" +MaintenanceModePassword="${maintenance_mode_password_hash}" diff --git a/modules/vmss_existing_vnet/locals.tf b/modules/vmss_existing_vnet/locals.tf new file mode 100755 index 0000000..530c0a2 --- /dev/null +++ b/modules/vmss_existing_vnet/locals.tf @@ -0,0 +1,4 @@ +locals { + module_name = "vmss_terraform_registry" + module_version = "1.0.4" +} diff --git a/modules/vmss_existing_vnet/main.tf b/modules/vmss_existing_vnet/main.tf new file mode 100755 index 0000000..548b8bc --- /dev/null +++ b/modules/vmss_existing_vnet/main.tf @@ -0,0 +1,426 @@ +//********************** Basic Configuration **************************// +module "common" { + source = "../common" + resource_group_name = var.resource_group_name + location = var.location + admin_password = var.authentication_type == "SSH Public Key" ? random_id.random_id.hex : var.admin_password + installation_type = var.installation_type + module_name = local.module_name + module_version = local.module_version + number_of_vm_instances = var.number_of_vm_instances + allow_upload_download = var.allow_upload_download + vm_size = var.vm_size + disk_size = var.disk_size + is_blink = var.is_blink + os_version = var.os_version + vm_os_sku = var.vm_os_sku + vm_os_offer = var.vm_os_offer + authentication_type = var.authentication_type + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + storage_account_additional_ips = var.storage_account_additional_ips +} + +//********************** Networking **************************// + +data "azurerm_subnet" "frontend" { + name = var.frontend_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +data "azurerm_subnet" "backend" { + name = var.backend_subnet_name + virtual_network_name = var.vnet_name + resource_group_name = var.vnet_resource_group +} + +module "network_security_group" { + source = "../network_security_group" + count = var.nsg_id == "" ? 1 : 0 + resource_group_name = module.common.resource_group_name + security_group_name = "${module.common.resource_group_name}_nsg" + location = module.common.resource_group_location + security_rules = var.security_rules +} + +//********************** Load Balancers **************************// +resource "random_id" "random_id" { + byte_length = 13 + keepers = { + rg_id = module.common.resource_group_id + } +} + +resource "azurerm_public_ip" "public-ip-lb" { + count = var.deployment_mode != "Internal" ? 1 : 0 + name = "${var.vmss_name}-app-1" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + allocation_method = var.vnet_allocation_method + sku = var.sku + domain_name_label = "${lower(var.vmss_name)}-${random_id.random_id.hex}" +} + +resource "azurerm_lb" "frontend-lb" { + count = var.deployment_mode != "Internal" ? 1 : 0 + depends_on = [azurerm_public_ip.public-ip-lb] + name = "frontend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + + frontend_ip_configuration { + name = "${var.vmss_name}-app-1" + public_ip_address_id = azurerm_public_ip.public-ip-lb[0].id + } +} + +resource "azurerm_lb_backend_address_pool" "frontend-lb-pool" { + count = var.deployment_mode != "Internal" ? 1 : 0 + loadbalancer_id = azurerm_lb.frontend-lb[0].id + name = "${var.vmss_name}-app-1" +} + +resource "azurerm_lb" "backend-lb" { + count = var.deployment_mode != "External" ? 1 : 0 + name = "backend-lb" + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = var.sku + frontend_ip_configuration { + name = "backend-lb" + subnet_id = data.azurerm_subnet.backend.id + private_ip_address_allocation = "Static" + private_ip_address = cidrhost(data.azurerm_subnet.backend.address_prefixes[0],var.backend_lb_IP_address) + } +} + +resource "azurerm_lb_backend_address_pool" "backend-lb-pool" { + count = var.deployment_mode != "External" ? 1 : 0 + name = "backend-lb-pool" + loadbalancer_id = azurerm_lb.backend-lb[0].id +} + +resource "azurerm_lb_probe" "azure_lb_healprob" { + count = var.deployment_mode == "Standard" ? 2 : 1 + depends_on = [azurerm_lb.frontend-lb, azurerm_lb.backend-lb] + loadbalancer_id = var.deployment_mode == "Standard" ? (count.index == 0 ? azurerm_lb.frontend-lb[0].id : azurerm_lb.backend-lb[0].id) : (var.deployment_mode == "External" ? azurerm_lb.frontend-lb[0].id : azurerm_lb.backend-lb[0].id) + name = var.deployment_mode == "Standard" ? (count.index == 0 ? "${var.vmss_name}-app-1" : "backend-lb") : (var.deployment_mode == "External" ? "${var.vmss_name}-app-1" : "backend-lb") + protocol = var.lb_probe_protocol + port = var.lb_probe_port + interval_in_seconds = var.lb_probe_interval + number_of_probes = var.lb_probe_unhealthy_threshold +} + +// Standard deployment +resource "azurerm_lb_rule" "lbnatrule-standard" { + count = var.deployment_mode == "Standard" ? 2 : 0 + depends_on = [azurerm_lb.frontend-lb[0],azurerm_lb_probe.azure_lb_healprob,azurerm_lb.backend-lb[0]] + loadbalancer_id = count.index == 0 ? azurerm_lb.frontend-lb[0].id : azurerm_lb.backend-lb[0].id + name = count.index == 0 ? "${var.vmss_name}-app-1" : "backend-lb" + protocol = count.index == 0 ? "Tcp" : "All" + frontend_port = count.index == 0 ? var.frontend_port : "0" + backend_port = count.index == 0 ? var.backend_port : "0" + backend_address_pool_ids = count.index == 0 ? [azurerm_lb_backend_address_pool.frontend-lb-pool[0].id] : [azurerm_lb_backend_address_pool.backend-lb-pool[0].id] + frontend_ip_configuration_name = count.index == 0 ? azurerm_lb.frontend-lb[0].frontend_ip_configuration[0].name : azurerm_lb.backend-lb[0].frontend_ip_configuration[0].name + probe_id = azurerm_lb_probe.azure_lb_healprob[count.index].id + load_distribution = count.index == 0 ? var.frontend_load_distribution : var.backend_load_distribution + enable_floating_ip = var.enable_floating_ip +} + +// External deployment +resource "azurerm_lb_rule" "lbnatrule-external" { + count = var.deployment_mode == "External" ? 1 : 0 + depends_on = [azurerm_lb.frontend-lb[0],azurerm_lb_probe.azure_lb_healprob] + loadbalancer_id = azurerm_lb.frontend-lb[0].id + name = "${var.vmss_name}-app-1" + protocol = "Tcp" + frontend_port = var.frontend_port + backend_port = var.backend_port + backend_address_pool_ids = [azurerm_lb_backend_address_pool.frontend-lb-pool[0].id] + frontend_ip_configuration_name = azurerm_lb.frontend-lb[0].frontend_ip_configuration[0].name + probe_id = azurerm_lb_probe.azure_lb_healprob[0].id + load_distribution = var.frontend_load_distribution + enable_floating_ip = var.enable_floating_ip +} + +// Internal deployment +resource "azurerm_lb_rule" "lbnatrule-internal" { + count = var.deployment_mode == "Internal" ? 1 : 0 + depends_on = [azurerm_lb_probe.azure_lb_healprob,azurerm_lb.backend-lb[0]] + loadbalancer_id = azurerm_lb.backend-lb[0].id + name = "backend-lb" + protocol = "All" + frontend_port = "0" + backend_port = "0" + backend_address_pool_ids = [azurerm_lb_backend_address_pool.backend-lb-pool[0].id] + frontend_ip_configuration_name = azurerm_lb.backend-lb[0].frontend_ip_configuration[0].name + probe_id = azurerm_lb_probe.azure_lb_healprob[0].id + load_distribution = var.backend_load_distribution + enable_floating_ip = var.enable_floating_ip +} + +//********************** Storage accounts **************************// +// Generate random text for a unique storage account name +resource "random_id" "randomId" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = module.common.resource_group_name + } + byte_length = 8 +} +resource "azurerm_storage_account" "vm-boot-diagnostics-storage" { + name = "diag${random_id.randomId.hex}" + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + account_tier = module.common.storage_account_tier + account_replication_type = module.common.account_replication_type + min_tls_version = "TLS1_2" + network_rules { + default_action = var.add_storage_account_ip_rules ? "Deny" : "Allow" + ip_rules = module.common.storage_account_ip_rules + } + blob_properties { + delete_retention_policy { + days = "15" + } + } +} + + +//********************** Virtual Machines **************************// +locals { + SSH_authentication_type_condition = var.authentication_type == "SSH Public Key" ? true : false + availability_zones_num_condition = var.availability_zones_num == "0" ? null : var.availability_zones_num == "1" ? ["1"] : var.availability_zones_num == "2" ? ["1", "2"] : ["1", "2", "3"] + custom_image_condition = var.source_image_vhd_uri == "noCustomUri" ? false : true + management_interface_name = split("-", var.management_interface)[0] + management_ip_address_type = split("-", var.management_interface)[1] +} + +resource "azurerm_image" "custom-image" { + count = local.custom_image_condition ? 1 : 0 + name = "custom-image" + location = var.location + resource_group_name = module.common.resource_group_name + + os_disk { + os_type = "Linux" + os_state = "Generalized" + blob_uri = var.source_image_vhd_uri + } +} + +resource "azurerm_linux_virtual_machine_scale_set" "vmss" { + name = var.vmss_name + location = module.common.resource_group_location + resource_group_name = module.common.resource_group_name + sku = module.common.vm_size + zones = local.availability_zones_num_condition + instances = var.number_of_vm_instances + overprovision = false + + dynamic "identity" { + for_each = var.enable_custom_metrics ? [1] : [] + content { + type = "SystemAssigned" + } + } + + dynamic "source_image_reference" { + for_each = local.custom_image_condition ? [] : [1] + content { + publisher = module.common.publisher + offer = module.common.vm_os_offer + sku = module.common.vm_os_sku + version = module.common.vm_os_version + } + } + source_image_id = local.custom_image_condition? azurerm_image.custom-image[0].id : null + + os_disk { + disk_size_gb = module.common.disk_size + caching = module.common.storage_os_disk_caching + storage_account_type = module.common.storage_account_type + } + + dynamic "plan" { + for_each = local.custom_image_condition ? [] : [1] + content { + name = module.common.vm_os_sku + publisher = module.common.publisher + product = module.common.vm_os_offer + } + } + + computer_name_prefix = lower(var.vmss_name) + admin_username = module.common.admin_username + admin_password = module.common.admin_password + custom_data = base64encode(templatefile("${path.module}/cloud-init.sh", { + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + vnet = data.azurerm_subnet.frontend.address_prefixes[0] + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash + })) + + + + disable_password_authentication = local.SSH_authentication_type_condition + + dynamic "admin_ssh_key" { + for_each = local.SSH_authentication_type_condition ? [ + 1] : [] + content { + public_key = var.admin_SSH_key + username = "notused" + } + } + + + boot_diagnostics { + storage_account_uri = module.common.boot_diagnostics ? join(",", azurerm_storage_account.vm-boot-diagnostics-storage.*.primary_blob_endpoint) : "" + } + + upgrade_mode = "Manual" + + network_interface { + name = "eth0" + primary = true + enable_ip_forwarding = true + enable_accelerated_networking = true + network_security_group_id = module.network_security_group[0].network_security_group_id + ip_configuration { + name = "ipconfig1" + subnet_id = data.azurerm_subnet.frontend.id + load_balancer_backend_address_pool_ids = var.deployment_mode != "Internal" ? [azurerm_lb_backend_address_pool.frontend-lb-pool[0].id]: null + primary = true + public_ip_address { + name = "${var.vmss_name}-public-ip" + idle_timeout_in_minutes = 15 + domain_name_label = "${lower(var.vmss_name)}-dns-name" + } + } + } + + network_interface { + name = "eth1" + primary = false + enable_ip_forwarding = true + enable_accelerated_networking = true + ip_configuration { + name = "ipconfig2" + subnet_id = data.azurerm_subnet.backend.id + load_balancer_backend_address_pool_ids = var.deployment_mode != "External" ? [azurerm_lb_backend_address_pool.backend-lb-pool[0].id] : null + primary = true + } + } + + tags = var.management_interface == "eth0"?{ + x-chkp-management = var.management_name, + x-chkp-template = var.configuration_template_name, + x-chkp-ip-address = local.management_ip_address_type, + x-chkp-management-interface = local.management_interface_name, + x-chkp-management-address = var.management_IP, + x-chkp-topology = "eth0:external,eth1:internal", + x-chkp-anti-spoofing = "eth0:false,eth1:false", + x-chkp-srcImageUri = var.source_image_vhd_uri + }:{ + x-chkp-management = var.management_name, + x-chkp-template = var.configuration_template_name, + x-chkp-ip-address = local.management_ip_address_type, + x-chkp-management-interface = local.management_interface_name, + x-chkp-topology = "eth0:external,eth1:internal", + x-chkp-anti-spoofing = "eth0:false,eth1:false", + x-chkp-srcImageUri = var.source_image_vhd_uri + } +} + +resource "azurerm_monitor_autoscale_setting" "vmss_settings" { + depends_on = [azurerm_linux_virtual_machine_scale_set.vmss] + name = var.vmss_name + resource_group_name = module.common.resource_group_name + location = module.common.resource_group_location + target_resource_id = azurerm_linux_virtual_machine_scale_set.vmss.id + + profile { + name = "Profile1" + + capacity { + default = module.common.number_of_vm_instances + minimum = var.minimum_number_of_vm_instances + maximum = var.maximum_number_of_vm_instances + } + + rule { + metric_trigger { + metric_name = "Percentage CPU" + metric_resource_id = azurerm_linux_virtual_machine_scale_set.vmss.id + time_grain = "PT1M" + statistic = "Average" + time_window = "PT5M" + time_aggregation = "Average" + operator = "GreaterThan" + threshold = 80 + } + + scale_action { + direction = "Increase" + type = "ChangeCount" + value = "1" + cooldown = "PT5M" + } + } + + rule { + metric_trigger { + metric_name = "Percentage CPU" + metric_resource_id = azurerm_linux_virtual_machine_scale_set.vmss.id + time_grain = "PT1M" + statistic = "Average" + time_window = "PT5M" + time_aggregation = "Average" + operator = "LessThan" + threshold = 60 + } + + scale_action { + direction = "Decrease" + type = "ChangeCount" + value = "1" + cooldown = "PT5M" + } + } + } + + notification { + email { + send_to_subscription_administrator = false + send_to_subscription_co_administrator = false + custom_emails = var.notification_email == "" ? [] : [var.notification_email] + } + } +} + +resource "azurerm_role_assignment" "custom_metrics_role_assignment"{ + depends_on = [azurerm_linux_virtual_machine_scale_set.vmss] + count = var.enable_custom_metrics ? 1 : 0 + role_definition_id = join("", ["/subscriptions/", var.subscription_id, "/providers/Microsoft.Authorization/roleDefinitions/", "3913510d-42f4-4e42-8a64-420c390055eb"]) + principal_id = lookup(azurerm_linux_virtual_machine_scale_set.vmss.identity[0], "principal_id") + scope = module.common.resource_group_id + lifecycle { + ignore_changes = [ + role_definition_id, principal_id + ] + } +} diff --git a/modules/vmss_existing_vnet/variables.tf b/modules/vmss_existing_vnet/variables.tf new file mode 100755 index 0000000..7192af1 --- /dev/null +++ b/modules/vmss_existing_vnet/variables.tf @@ -0,0 +1,399 @@ +//********************** Basic Configuration Variables **************************// +variable "subscription_id" { + description = "Subscription ID" + type = string +} + +variable "vmss_name"{ + description = "vmss name" + type = string +} + +variable "resource_group_name" { + description = "Azure Resource Group name to build into" + type = string +} + +variable "location" { + description = "The location/region where resources will be created. The full list of Azure regions can be found at https://azure.microsoft.com/regions" + type = string +} + +//********************** Virtual Machine Instances Variables **************************// +variable "source_image_vhd_uri" { + type = string + description = "The URI of the blob containing the development image. Please use noCustomUri if you want to use marketplace images." + default = "noCustomUri" +} + +variable "admin_username" { + description = "Administrator username of deployed VM. Due to Azure limitations 'notused' name can be used" + default = "notused" +} + +variable "admin_password" { + description = "Administrator password of deployed Virtual Machine. The password must meet the complexity requirements of Azure" + type = string +} + +variable "serial_console_password_hash" { + description = "Optional parameter, used to enable serial console connection in case of SSH key as authentication type" + type = string +} + +variable "maintenance_mode_password_hash" { + description = "Maintenance mode password hash, relevant only for R81.20 and higher versions" + type = string +} + +variable "availability_zones_num" { + description = "The number of availability zones to use for Scale Set. Note that the load balancers and their IP addresses will be redundant in any case" + #Availability Zones are only supported in several regions at this time + #"centralus", "eastus2", "francecentral", "northeurope", "southeastasia", "westeurope", "westus2", "eastus", "uksouth" + #type = list(string) +} + +locals { // locals for 'availability_zones_num' allowed values + availability_zones_num_allowed_values = [ + "0", + "1", + "2", + "3" + ] + // will fail if [var.availability_zones_num] is invalid: + validate_availability_zones_num_value = index(local.availability_zones_num_allowed_values, var.availability_zones_num) +} + +variable "sic_key" { + description = "Secure Internal Communication(SIC) key" + type = string +} +resource "null_resource" "sic_key_invalid" { + count = length(var.sic_key) >= 12 ? 0 : "SIC key must be at least 12 characters long" +} + +variable "installation_type"{ + description = "Installation type" + type = string + default = "vmss" +} + +variable "number_of_vm_instances"{ + description = "Default number of VM instances to deploy" + type = string + default = "2" +} + +variable "minimum_number_of_vm_instances" { + description = "Minimum number of VM instances to deploy" + type = string +} + +variable "maximum_number_of_vm_instances" { + description = "Maximum number of VM instances to deploy" + type = string +} + +variable "vm_size" { + description = "Specifies size of Virtual Machine" + type = string +} + + +variable "os_version" { + description = "GAIA OS version" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + os_version_allowed_values = [ + "R8110", + "R8120", + "R82" + ] + // will fail if [var.os_version] is invalid: + validate_os_version_value = index(local.os_version_allowed_values, var.os_version) +} +variable "disk_size" { + description = "Storage data disk size size(GB). Select a number between 100 and 3995, if you are using R81.20 or below, the disk size must be 100" + type = string + default = 100 +} +resource "null_resource" "disk_size_validation" { + // Will fail if var.disk_size is not 100 and the version is R81.20 or below + count = tonumber(var.disk_size) != 100 && contains(["R81", "R8110", "R8120"], var.os_version) ? "variable disk_size can not be changed for R81.20 and below" : 0 +} +variable "vm_os_sku" { + description = "The sku of the image to be deployed." + type = string +} + +variable "authentication_type" { + description = "Specifies whether a password authentication or SSH Public Key authentication should be used" + type = string +} +locals { // locals for 'authentication_type' allowed values + authentication_type_allowed_values = [ + "Password", + "SSH Public Key" + ] + // will fail if [var.authentication_type] is invalid: + validate_authentication_type_value = index(local.authentication_type_allowed_values, var.authentication_type) +} + +variable "allow_upload_download" { + description = "Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point" + type = bool +} + +variable "is_blink" { + description = "Define if blink image is used for deployment" + default = true +} + +variable "management_name" { + description = "The name of the management server as it appears in the configuration file" + type = string +} + +variable "management_IP" { + description = "The IP address used to manage the VMSS instances" + type = string +} + +variable "management_interface" { + description = "Manage the Gateways in the Scale Set via the instance's external (eth0) or internal (eth1) NIC's private IP address" + type = string + default = "eth1-private" +} +locals { // locals for 'management_interface' allowed values + management_interface_allowed_values = [ + "eth0-public", + "eth0-private", + "eth1-private" + ] + // will fail if [var.management_interface] is invalid: + validate_management_interface_value = index(local.management_interface_allowed_values, var.management_interface) +} + +variable "configuration_template_name" { + description = "The configuration template name as it appears in the configuration file" + type = string +} + +variable "admin_shell" { + description = "The admin shell to configure on machine or the first time" + type = string + default = "/etc/cli.sh" +} + +locals { + admin_shell_allowed_values = [ + "/etc/cli.sh", + "/bin/bash", + "/bin/csh", + "/bin/tcsh" + ] + // Will fail if [var.admin_shell] is invalid + validate_admin_shell_value = index(local.admin_shell_allowed_values, var.admin_shell) +} + +//********************** Networking Variables **************************// +variable "vnet_name" { + description = "Virtual Network name" + type = string +} + +variable "frontend_subnet_name" { + description = "Frontend subnet name" + type = string +} + +variable "backend_subnet_name" { + description = "Backend subnet name" + type = string +} + +variable "vnet_resource_group" { + description = "Resource group of existing vnet" + type = string +} + +variable "vnet_allocation_method" { + description = "IP address allocation method" + type = string + default = "Static" +} + +variable "add_storage_account_ip_rules" { + type = bool + default = false + description = "Add Storage Account IP rules that allow access to the Serial Console only for IPs based on their geographic location" +} + +variable "storage_account_additional_ips" { + type = list(string) + description = "IPs/CIDRs that are allowed access to the Storage Account" + default = [] +} + +//********************* Load Balancers Variables **********************// + +variable "deployment_mode" { + description = "The type of the deployment, can be 'Standard' for both load balancers or 'External' for external load balancer or 'Internal for internal load balancer" + type = string + default = "Standard" +} + +locals { // locals for 'deployment_mode' allowed values + deployment_mode_allowd_values = [ + "Standard", + "External", + "Internal" + ] + // will fail if [var.deployment_mode] is invalid: + validate_deployment_mode_value = index(local.deployment_mode_allowd_values, var.deployment_mode) +} + +variable "backend_lb_IP_address" { + description = "The IP address is defined by its position in the subnet" + type = number +} + +variable "lb_probe_port" { + description = "Port to be used for load balancer health probes and rules" + default = "8117" +} + +variable "lb_probe_protocol" { + description = "Protocols to be used for load balancer health probes and rules" + default = "Tcp" +} + +variable "lb_probe_unhealthy_threshold" { + description = "Number of times load balancer health probe has an unsuccessful attempt before considering the endpoint unhealthy." + default = 2 +} + +variable "lb_probe_interval" { + description = "Interval in seconds load balancer health probe rule performs a check" + default = 5 +} + +variable "frontend_port" { + description = "Port that will be exposed to the external Load Balancer" + type = string + default = "80" +} + +variable "backend_port" { + description = "Port that will be exposed to the external Load Balance" + type = string + default = "8081" +} + +variable "frontend_load_distribution" { + description = "Specifies the load balancing distribution type to be used by the frontend load balancer" + type = string +} + +locals { // locals for 'frontend_load_distribution' allowed values + frontend_load_distribution_allowed_values = [ + "Default", + "SourceIP", + "SourceIPProtocol" + ] + // will fail if [var.frontend_load_distribution] is invalid: + validate_frontend_load_distribution_value = index(local.frontend_load_distribution_allowed_values, var.frontend_load_distribution) +} + +variable "backend_load_distribution" { + description = "Specifies the load balancing distribution type to be used by the backend load balancer" + type = string +} + +locals { // locals for 'frontend_load_distribution' allowed values + backend_load_distribution_allowed_values = [ + "Default", + "SourceIP", + "SourceIPProtocol" + ] + // will fail if [var.backend_load_distribution] is invalid: + validate_backend_load_distribution_value = index(local.backend_load_distribution_allowed_values, var.backend_load_distribution) +} + +//********************** Scale Set variables *******************// + +variable "vm_os_offer" { + description = "The name of the offer of the image that you want to deploy.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + type = string +} + +locals { // locals for 'vm_os_offer' allowed values + vm_os_offer_allowed_values = [ + "check-point-cg-r8110", + "check-point-cg-r8120", + "check-point-cg-r82" + ] + // will fail if [var.vm_os_offer] is invalid: + validate_os_offer_value = index(local.vm_os_offer_allowed_values, var.vm_os_offer) +} + +variable "bootstrap_script"{ + description = "An optional script to run on the initial boot" + #example: + #"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt" +} + +variable "notification_email" { + description = "Specifies a list of custom email addresses to which the email notifications will be sent" + type = string +} + +variable "sku" { + description = "SKU" + type = string + default = "Standard" +} + +variable "enable_custom_metrics" { + description = "Enable CloudGuard metrics in order to send statuses and statistics collected from VMSS instances to the Azure Monitor service." + type = bool + default = true +} + +variable "enable_floating_ip" { + description = "Indicates whether the load balancers will be deployed with floating IP." + type = bool + default = false +} + +variable "nsg_id" { + description = "NSG ID - Optional - if empty use default NSG" + default = "" +} + +variable "admin_SSH_key" { + type = string + description = "(Optional) TheUsed when the authentication_type is 'SSH Public Key'. The SSH public key for SSH authentication to the template instances." + default = "" +} + +variable "security_rules" { + description = "Security rules for the Network Security Group using this format [name, priority, direction, access, protocol, source_source_port_rangesport_range, destination_port_ranges, source_address_prefix, destination_address_prefix, description]" + type = list(any) + default = [ + { + name = "AllowAllInBound" + priority = "100" + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_ranges = "*" + destination_port_ranges = "*" + description = "Allow all inbound connections" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ] +} diff --git a/modules/vmss_existing_vnet/versions.tf b/modules/vmss_existing_vnet/versions.tf new file mode 100755 index 0000000..5bf8d9d --- /dev/null +++ b/modules/vmss_existing_vnet/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 0.14.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.90.0" + } + random = { + version = "~> 3.5.1" + } + } +} + + diff --git a/modules/vmss_new_vnet/README.md b/modules/vmss_new_vnet/README.md index d203010..35a8320 100755 --- a/modules/vmss_new_vnet/README.md +++ b/modules/vmss_new_vnet/README.md @@ -29,7 +29,7 @@ provider "azurerm" { module "example_module" { source = "CheckPointSW/cloudguard-network-security/azure//modules/vmss_new_vnet" - version = "1.0.3" + version = "1.0.4" subscription_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" source_image_vhd_uri = "noCustomUri" @@ -73,10 +73,10 @@ module "example_module" { ``` ## Conditional creation -To create role assignment and enable CloudGuard metrics in order to send statuses and statistics collected from VMSS instances to the Azure Monitor service: -``` -enable_custom_metrics = true -``` +- To create role assignment and enable CloudGuard metrics in order to send statuses and statistics collected from VMSS instances to the Azure Monitor service: + ``` + enable_custom_metrics = true + ``` ## Deploy Without Public IP @@ -99,7 +99,7 @@ enable_custom_metrics = true | **vm_size** | Specifies the size of Virtual Machine | string | A list of valid VM sizes, e.g., "Standard_DS2_v2", "Standard_D4s_v3", "Standard_D64s_v3", etc.
| | **disk_size** | Storage data disk size (GB) must be 100 for versions R81.20 and below | string | A number in the range 100 - 3995 (GB)
**Default:** 100 | | **vm_os_sku** | A SKU of the image to be deployed | string | "sg-byol" - BYOL license;
"sg-ngtp" - NGTP PAYG license;
"sg-ngtx" - NGTX PAYG license;
| -| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r81";
"check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82";
| +| **vm_os_offer** | The name of the image offer to be deployed | string | "check-point-cg-r8110";
"check-point-cg-r8120";
"check-point-cg-r82";
| | **os_version** | GAIA OS version | string | "R8110";
"R8120";
"R82";
| | **bootstrap_script** | An optional script to run on the initial boot | string | Bootstrap script example:
"touch /home/admin/bootstrap.txt; echo 'hello_world' > /home/admin/bootstrap.txt"
| | **allow_upload_download** | Automatically download Blade Contracts and other important data. Improve product experience by sending data to Check Point | boolean | true;
false;
| diff --git a/modules/vmss_new_vnet/cloud-init.sh b/modules/vmss_new_vnet/cloud-init.sh index f595e2b..0775580 100755 --- a/modules/vmss_new_vnet/cloud-init.sh +++ b/modules/vmss_new_vnet/cloud-init.sh @@ -3,7 +3,7 @@ installationType="${installation_type}" allowUploadDownload="${allow_upload_download}" osVersion="${os_version}" -templateName="${template_name}" +templateName="${module_name}" templateVersion="${module_version}" templateType="${template_type}" isBlink="${is_blink}" diff --git a/modules/vmss_new_vnet/locals.tf b/modules/vmss_new_vnet/locals.tf index c309b21..530c0a2 100755 --- a/modules/vmss_new_vnet/locals.tf +++ b/modules/vmss_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { - template_name = "vmss_terraform_registry" - module_version = "1.0.3" + module_name = "vmss_terraform_registry" + module_version = "1.0.4" } diff --git a/modules/vmss_new_vnet/main.tf b/modules/vmss_new_vnet/main.tf index 881a33b..559c27a 100755 --- a/modules/vmss_new_vnet/main.tf +++ b/modules/vmss_new_vnet/main.tf @@ -5,7 +5,7 @@ module "common" { location = var.location admin_password = var.authentication_type == "SSH Public Key" ? random_id.random_id.hex : var.admin_password installation_type = var.installation_type - template_name = local.template_name + module_name = local.module_name module_version = local.module_version number_of_vm_instances = var.number_of_vm_instances allow_upload_download = var.allow_upload_download @@ -253,21 +253,21 @@ resource "azurerm_linux_virtual_machine_scale_set" "vmss" { admin_username = module.common.admin_username admin_password = module.common.admin_password custom_data = base64encode(templatefile("${path.module}/cloud-init.sh", { - installation_type = module.common.installation_type - allow_upload_download = module.common.allow_upload_download - os_version = module.common.os_version - template_name = module.common.template_name - module_version = module.common.module_version - template_type = "terraform" - is_blink = module.common.is_blink - bootstrap_script64 = base64encode(var.bootstrap_script) - location = module.common.resource_group_location - sic_key = var.sic_key - vnet = module.vnet.subnet_prefixes[0] - enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" - admin_shell = var.admin_shell - serial_console_password_hash = var.serial_console_password_hash - maintenance_mode_password_hash = var.maintenance_mode_password_hash + installation_type = module.common.installation_type + allow_upload_download = module.common.allow_upload_download + os_version = module.common.os_version + module_name = module.common.module_name + module_version = module.common.module_version + template_type = "terraform" + is_blink = module.common.is_blink + bootstrap_script64 = base64encode(var.bootstrap_script) + location = module.common.resource_group_location + sic_key = var.sic_key + vnet = module.vnet.subnet_prefixes[0] + enable_custom_metrics = var.enable_custom_metrics ? "yes" : "no" + admin_shell = var.admin_shell + serial_console_password_hash = var.serial_console_password_hash + maintenance_mode_password_hash = var.maintenance_mode_password_hash })) diff --git a/modules/vmss_new_vnet/variables.tf b/modules/vmss_new_vnet/variables.tf index fe4962c..1ecda9d 100755 --- a/modules/vmss_new_vnet/variables.tf +++ b/modules/vmss_new_vnet/variables.tf @@ -314,13 +314,12 @@ locals { // locals for 'frontend_load_distribution' allowed values //********************** Scale Set variables *******************// variable "vm_os_offer" { - description = "The name of the offer of the image that you want to deploy.Choose from: check-point-cg-r81, check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" + description = "The name of the offer of the image that you want to deploy.Choose from: check-point-cg-r8110, check-point-cg-r8120, check-point-cg-r82" type = string } locals { // locals for 'vm_os_offer' allowed values vm_os_offer_allowed_values = [ - "check-point-cg-r81", "check-point-cg-r8110", "check-point-cg-r8120", "check-point-cg-r82" From 4d4a004107eb7926ca95848b99ae97503239b721 Mon Sep 17 00:00:00 2001 From: ofirni Date: Wed, 25 Jun 2025 13:49:54 +0000 Subject: [PATCH 2/2] Resolve issue with new VNet route configuration causing incorrect routing --- modules/high_availability_existing_vnet/locals.tf | 2 +- modules/high_availability_new_vnet/locals.tf | 2 +- modules/management_existing_vnet/locals.tf | 2 +- modules/management_new_vnet/locals.tf | 2 +- modules/mds_existing_vnet/locals.tf | 2 +- modules/mds_new_vnet/locals.tf | 2 +- modules/single_gateway_existing_vnet/locals.tf | 2 +- modules/single_gateway_new_vnet/locals.tf | 2 +- modules/vmss_existing_vnet/locals.tf | 2 +- modules/vmss_new_vnet/locals.tf | 2 +- modules/vnet/main.tf | 4 ++-- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/high_availability_existing_vnet/locals.tf b/modules/high_availability_existing_vnet/locals.tf index c39021c..2b41872 100755 --- a/modules/high_availability_existing_vnet/locals.tf +++ b/modules/high_availability_existing_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "high_availability" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/high_availability_new_vnet/locals.tf b/modules/high_availability_new_vnet/locals.tf index 9579de5..7e60623 100755 --- a/modules/high_availability_new_vnet/locals.tf +++ b/modules/high_availability_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "high_availability_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/management_existing_vnet/locals.tf b/modules/management_existing_vnet/locals.tf index 873657d..d0c0838 100755 --- a/modules/management_existing_vnet/locals.tf +++ b/modules/management_existing_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "management_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/management_new_vnet/locals.tf b/modules/management_new_vnet/locals.tf index 873657d..d0c0838 100755 --- a/modules/management_new_vnet/locals.tf +++ b/modules/management_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "management_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/mds_existing_vnet/locals.tf b/modules/mds_existing_vnet/locals.tf index cdca346..20053eb 100755 --- a/modules/mds_existing_vnet/locals.tf +++ b/modules/mds_existing_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "mds_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/mds_new_vnet/locals.tf b/modules/mds_new_vnet/locals.tf index cdca346..20053eb 100755 --- a/modules/mds_new_vnet/locals.tf +++ b/modules/mds_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "mds_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/single_gateway_existing_vnet/locals.tf b/modules/single_gateway_existing_vnet/locals.tf index 56cb061..f9af94a 100755 --- a/modules/single_gateway_existing_vnet/locals.tf +++ b/modules/single_gateway_existing_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "single_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/single_gateway_new_vnet/locals.tf b/modules/single_gateway_new_vnet/locals.tf index 56cb061..f9af94a 100755 --- a/modules/single_gateway_new_vnet/locals.tf +++ b/modules/single_gateway_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "single_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/vmss_existing_vnet/locals.tf b/modules/vmss_existing_vnet/locals.tf index 530c0a2..f391758 100755 --- a/modules/vmss_existing_vnet/locals.tf +++ b/modules/vmss_existing_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "vmss_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/vmss_new_vnet/locals.tf b/modules/vmss_new_vnet/locals.tf index 530c0a2..f391758 100755 --- a/modules/vmss_new_vnet/locals.tf +++ b/modules/vmss_new_vnet/locals.tf @@ -1,4 +1,4 @@ locals { module_name = "vmss_terraform_registry" - module_version = "1.0.4" + module_version = "1.0.5" } diff --git a/modules/vnet/main.tf b/modules/vnet/main.tf index 17127b0..f4665fe 100755 --- a/modules/vnet/main.tf +++ b/modules/vnet/main.tf @@ -53,7 +53,7 @@ resource "azurerm_route_table" "frontend" { name = "To-Internal" address_prefix = var.address_space next_hop_type = local.next_hop_type_allowed_values[3] - next_hop_in_ip_address = substr(replace(azurerm_subnet.subnet[0].address_prefixes[0], "0/", "4/"), 0, local.address_prefix_length - 3) + next_hop_in_ip_address = join(".", [for i, v in split(".", element(split("/", azurerm_subnet.subnet[0].address_prefixes[0]), 0)) : i == 3 ? tostring(tonumber(v) + 4) : v]) } } @@ -72,7 +72,7 @@ resource "azurerm_route_table" "backend" { name = "To-Internet" address_prefix = "0.0.0.0/0" next_hop_type = local.next_hop_type_allowed_values[3] - next_hop_in_ip_address = substr(replace(azurerm_subnet.subnet[1].address_prefixes[0], "0/", "4/"), 0, local.address_prefix_length - 3) + next_hop_in_ip_address = join(".", [for i, v in split(".", element(split("/", azurerm_subnet.subnet[1].address_prefixes[0]), 0)) : i == 3 ? tostring(tonumber(v) + 4) : v]) } }