diff --git a/testdata/xray/jas-config/.jfrog/jfrog-apps-config.yml b/testdata/xray/jas-config/.jfrog/jfrog-apps-config.yml new file mode 100644 index 000000000..b92f76728 --- /dev/null +++ b/testdata/xray/jas-config/.jfrog/jfrog-apps-config.yml @@ -0,0 +1,11 @@ +version: "1.0" + +modules: + - source_root: "." + scanners: + secrets: + exclude_patterns: + - "**/*secret_generic*/**" + iac: + exclude_patterns: + - "**/*gcp*/**" \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/azure/vpc/module.tf b/testdata/xray/jas-config/iac/azure/vpc/module.tf new file mode 100644 index 000000000..9bdbab532 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc/module.tf @@ -0,0 +1,116 @@ + +#Azure Generic vNet Module +resource "azurerm_resource_group" "network" { + count = var.module_enabled ? 1 : 0 + name = var.short_region != " " ? var.short_region : "${var.deploy_name}-${var.region}" + location = var.region + + tags = { + environment = var.environment + } +} + +resource "azurerm_virtual_network" "vnet" { + count = var.module_enabled ? 1 : 0 + name = "${var.deploy_name}-${var.region}" + location = var.region + address_space = [var.vpc_cidr] + resource_group_name = azurerm_resource_group.network[0].name + + tags = { + environment = var.environment + costcenter = "${var.deploy_name}-${var.region}" + } +} + +resource "azurerm_subnet" "subnet" { + count = var.module_enabled ? length(var.subnet_names) : 0 + name = var.subnet_names[count.index] + virtual_network_name = azurerm_virtual_network.vnet[0].name + resource_group_name = azurerm_resource_group.network[0].name + address_prefixes = [var.subnet_prefixes[count.index]] +# service_endpoints = [ +# "Microsoft.KeyVault" +# ] + + dynamic "delegation"{ + for_each =var.subnet_names[count.index] == "flexible-dbs" ? ["exec"] : [] + content { + name = "dlg-Microsoft.DBforPostgreSQL-flexibleServers" + service_delegation { + name = "Microsoft.DBforPostgreSQL/flexibleServers" + actions = [ + "Microsoft.Network/virtualNetworks/subnets/join/action" + ] + } + } + } + + enforce_private_link_endpoint_network_policies = var.subnet_names[count.index] == "data" + enforce_private_link_service_network_policies = var.subnet_names[count.index] == "private" && var.enforce_pl_svc_net_private + lifecycle { + ignore_changes = [ + service_endpoints, + delegation[0].name + ] + } +} + + +resource "azurerm_private_dns_zone" "postgres_private_dns" { + count = var.module_enabled ? 1 : 0 + name = "privatelink.postgres.database.azure.com" + resource_group_name = azurerm_resource_group.network[0].name +} + +resource "random_string" "postgres_private_dns_net_link_name" { + count = var.module_enabled ? 1 : 0 + length = 8 + special = false + number = false + upper = false +} + +resource "azurerm_private_dns_zone_virtual_network_link" "postgres_private_dns_net_link" { + count = var.module_enabled ? 1 : 0 + name = random_string.postgres_private_dns_net_link_name[0].result + resource_group_name = azurerm_resource_group.network[0].name + private_dns_zone_name = azurerm_private_dns_zone.postgres_private_dns[0].name + virtual_network_id = azurerm_virtual_network.vnet[0].id +} + +//resource "azurerm_network_security_group" "nsg" { +// count = "${var.module_enabled ? length(var.subnet_names) : 0}" +// name = "${var.subnet_names[count.index]}-sg" +// location = "${var.region}" +// resource_group_name = "${var.deploy_name}-${var.region}" +//} +// +//resource "azurerm_subnet_network_security_group_association" "nsg" { +// count = "${var.module_enabled ? length(var.subnet_names) : 0}" +// subnet_id = "${element(azurerm_subnet.subnet.*.id, count.index)}" +// network_security_group_id = "${element(azurerm_network_security_group.nsg.*.id, count.index)}" +//} +//resource "azurerm_subnet_route_table_association" "nat" { +// count = "${var.module_enabled ? length(var.nat_subnets) : 0}" +// subnet_id = "${element(azurerm_subnet.subnet.*.id, count.index + 1)}" +// route_table_id = "${azurerm_route_table.nattable.id}" +//} +# UDR +//resource "azurerm_route_table" "nattable" { +// count = "${var.module_enabled}" +// name = "${var.deploy_name}-${var.region}" +// location = "${var.region}" +// resource_group_name = "${azurerm_resource_group.network.name}" +// +// route { +// name = "all-traffic-via-nat" +// address_prefix = "0.0.0.0/0" +// next_hop_type = "VirtualAppliance" +// next_hop_in_ip_address = "${var.natgw_private_ip}" +// } +// +// tags = { +// environment = "${var.environment}" +// } +//} diff --git a/testdata/xray/jas-config/iac/azure/vpc/outputs.tf b/testdata/xray/jas-config/iac/azure/vpc/outputs.tf new file mode 100644 index 000000000..62a693aa7 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc/outputs.tf @@ -0,0 +1,79 @@ +################################################################################## +# OUTPUT +################################################################################## + +output "resource_group_id" { + value = azurerm_resource_group.network[0].id +} + +output "resource_group_name" { + value = azurerm_resource_group.network[0].name +} + +output "vnet_id" { + value = element(concat(azurerm_virtual_network.vnet.*.id, [""]), 0) +} + +output "vnet_location" { + value = element(concat(azurerm_virtual_network.vnet.*.location, [""]), 0) +} + +output "vnet_name" { + value = element(concat(azurerm_virtual_network.vnet.*.name, [""]), 0) +} + +output "private_dns_id" { + value = element( + concat(azurerm_private_dns_zone.postgres_private_dns.*.id, [""]), + 0, + ) +} + +output "private_dns_name" { + value = element( + concat(azurerm_private_dns_zone.postgres_private_dns.*.name, [""]), + 0, + ) +} + +//output "vnet_subnets" { +// value = "${azurerm_subnet.subnet.*.id}" +//} + +### subnets ids ### +output "public_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 0) +} + +output "private_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 1) +} +output "flexible_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 4) +} +output "data_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 2) +} + +output "mgmt_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 3) +} + +### subnets names ### +output "public_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 0) +} + +output "private_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 1) +} + +output "data_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 2) +} + +output "mgmt_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 3) +} + + diff --git a/testdata/xray/jas-config/iac/azure/vpc/variables.tf b/testdata/xray/jas-config/iac/azure/vpc/variables.tf new file mode 100644 index 000000000..e04fd5f78 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc/variables.tf @@ -0,0 +1,39 @@ +variable "module_enabled" { + default = true +} + +variable "region" { +} + +variable "deploy_name" { +} + +variable "vpc_cidr" { +} + +variable "short_region" { + default = " " +} + +variable "subnet_prefixes" { + type = list(string) +} + +variable "ssh_source_ranges" { + type = list(string) +} + +variable "environment" { +} + +variable "subnet_names" { + type = list(string) +} + +variable "enforce_pl_svc_net_private" { + default = false +} +//variable "natgw_private_ip" {} +//variable "nat_subnets" { +// type = "list" +//} diff --git a/testdata/xray/jas-config/iac/azure/vpc/versions.tf b/testdata/xray/jas-config/iac/azure/vpc/versions.tf new file mode 100644 index 000000000..ac97c6ac8 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/testdata/xray/jas-config/iac/azure/vpc_pp/module.tf b/testdata/xray/jas-config/iac/azure/vpc_pp/module.tf new file mode 100644 index 000000000..5caae96c7 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc_pp/module.tf @@ -0,0 +1,34 @@ + +#Azure Generic vNet Module +resource "azurerm_resource_group" "network" { + count = var.module_enabled ? 1 : 0 + name = var.short_region != " " ? var.short_region : "${var.deploy_name}-${var.region}" + location = var.region + + tags = { + environment = var.environment + } +} + +resource "azurerm_virtual_network" "vnet" { + count = var.module_enabled ? 1 : 0 + name = "${var.deploy_name}-${var.region}" + location = var.region + address_space = [var.vpc_cidr] + resource_group_name = azurerm_resource_group.network[0].name + + tags = { + environment = var.environment + costcenter = "${var.deploy_name}-${var.region}" + } +} + +resource "azurerm_subnet" "subnet" { + count = var.module_enabled ? length(var.subnet_names) : 0 + name = var.subnet_names[count.index] + virtual_network_name = azurerm_virtual_network.vnet[0].name + resource_group_name = azurerm_resource_group.network[0].name + address_prefixes = [var.subnet_prefixes[count.index]] + enforce_private_link_endpoint_network_policies = var.subnet_names[count.index] == "private" && var.enforce_private_subnet + +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/azure/vpc_pp/outputs.tf b/testdata/xray/jas-config/iac/azure/vpc_pp/outputs.tf new file mode 100644 index 000000000..7e1472580 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc_pp/outputs.tf @@ -0,0 +1,62 @@ +################################################################################## +# OUTPUT +################################################################################## + +output "resource_group_id" { + value = azurerm_resource_group.network[0].id +} + +output "resource_group_name" { + value = azurerm_resource_group.network[0].name +} + +output "vnet_id" { + value = element(concat(azurerm_virtual_network.vnet.*.id, [""]), 0) +} + +output "vnet_location" { + value = element(concat(azurerm_virtual_network.vnet.*.location, [""]), 0) +} + +output "vnet_name" { + value = element(concat(azurerm_virtual_network.vnet.*.name, [""]), 0) +} + +//output "vnet_subnets" { +// value = "${azurerm_subnet.subnet.*.id}" +//} + +### subnets ids ### +output "public_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 0) +} + +output "private_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 1) +} + +output "data_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 2) +} + +output "mgmt_subnet" { + value = element(concat(azurerm_subnet.subnet.*.id, [""]), 3) +} + +### subnets names ### +output "public_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 0) +} + +output "private_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 1) +} + +output "data_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 2) +} + +output "mgmt_subnet_name" { + value = element(concat(azurerm_subnet.subnet.*.name, [""]), 3) +} + diff --git a/testdata/xray/jas-config/iac/azure/vpc_pp/variables.tf b/testdata/xray/jas-config/iac/azure/vpc_pp/variables.tf new file mode 100644 index 000000000..784782aa7 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc_pp/variables.tf @@ -0,0 +1,40 @@ +variable "module_enabled" { + default = true +} + +variable "region" { +} + +variable "deploy_name" { +} + +variable "vpc_cidr" { +} + +variable "short_region" { + default = " " +} + +variable "subnet_prefixes" { + type = list(string) +} + +variable "ssh_source_ranges" { + type = list(string) +} + +variable "environment" { +} + +variable "subnet_names" { + type = list(string) +} + +variable "enforce_private_subnet" { + default = true +} + +//variable "natgw_private_ip" {} +//variable "nat_subnets" { +// type = "list" +//} diff --git a/testdata/xray/jas-config/iac/azure/vpc_pp/versions.tf b/testdata/xray/jas-config/iac/azure/vpc_pp/versions.tf new file mode 100644 index 000000000..ac97c6ac8 --- /dev/null +++ b/testdata/xray/jas-config/iac/azure/vpc_pp/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/testdata/xray/jas-config/iac/gcp/k8s-oss/files/chk_k8s_nat b/testdata/xray/jas-config/iac/gcp/k8s-oss/files/chk_k8s_nat new file mode 100644 index 000000000..f4f318bbf --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-oss/files/chk_k8s_nat @@ -0,0 +1,17 @@ +#!/bin/bash + +# This script checks the functionality of the NAT gateway VM. + +tf_output=$(terraform output) +k8s_name=$(echo "$tf_output" | grep k8s_cluster_name | cut -d = -f 2) +k8s_project=$(echo "$tf_output" | grep k8s_project | cut -d = -f 2) +k8s_zone=$(echo "$tf_output" | grep k8s_zone | cut -d = -f 2) +k8s_ext_ip=$(echo "$tf_output" | grep external_ip | cut -d = -f 2) + +echo Testing k8s cluster connectivity to NAT.. +gcloud container clusters get-credentials $k8s_name --zone $k8s_zone --project $k8s_project > /dev/null + +chk_ext_ip=$(kubectl run test -it --restart=Never --image=centos:7 -- curl -s http://ipinfo.io/ip) +kubectl delete po test > /dev/null + +echo $k8s_ext_ip $chk_ext_ip diff --git a/testdata/xray/jas-config/iac/gcp/k8s-oss/module.tf b/testdata/xray/jas-config/iac/gcp/k8s-oss/module.tf new file mode 100644 index 000000000..53746b756 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-oss/module.tf @@ -0,0 +1,158 @@ +# Create new K8S cluster with autoscaling + +data "google_container_engine_versions" "region" { + location = var.region +} + +resource "random_string" "admin-password" { + count = var.module_enabled ? 1 : 0 + length = 16 + +// lifecycle { +// ignore_changes = [ +// initial_node_count, master_authorized_networks_config +// ] +// } +} + +# New K8s Cluster, if creation failed you'll need to cleanup manually before running again. +resource "google_container_cluster" "primary" { + count = var.module_enabled ? 1 : 0 + provider = google-beta + name = "${var.deploy_name}-${var.region}" + location = var.k8s_zonal == "" ? var.region : var.region_zone + min_master_version = var.k8s_master_version == "" ? data.google_container_engine_versions.region.latest_master_version : var.k8s_master_version + network = var.network + subnetwork = var.subnetwork + logging_service = var.logging_service + monitoring_service = var.monitoring_service + enable_legacy_abac = var.enable_legacy_abac + remove_default_node_pool = "true" + initial_node_count = 1 + enable_shielded_nodes = var.gke_auth.shielded_nodes + enable_intranode_visibility = var.gke_auth.enable_intranode_visibility + + master_auth { + username = var.gke_auth.basic_auth ? "basic-admin" : "" + password = var.gke_auth.basic_auth ? random_string.admin-password[0].result : "" + + client_certificate_config { + issue_client_certificate = var.client_certificate + } + } + + private_cluster_config { + enable_private_endpoint = false + enable_private_nodes = true + master_ipv4_cidr_block = var.subnet_cidr["k8s-private"] + } + + ip_allocation_policy { + cluster_secondary_range_name = "pods-private-range" + services_secondary_range_name = "services-private-range" + } + + # Authoroized networks allowed to access the Master + + master_authorized_networks_config { + cidr_blocks { + cidr_block = "82.81.195.5/32" + display_name = "jfrog-office" + } + cidr_blocks { + cidr_block = "52.8.67.255/32" + display_name = "GlobalVpn" + } + cidr_blocks { + cidr_block = "12.252.18.78/32" + display_name = "US Office HA Public" + } + cidr_blocks { + cidr_block = "52.9.243.19/32" + display_name = "US IT AWS-NATGW" + } + cidr_blocks { + cidr_block = "52.215.237.185/32" + display_name = "EU IT AWS-NATGW" + } + cidr_blocks { + cidr_block = "52.16.203.109/32" + display_name = "GlobalVpn" + } + cidr_blocks { + cidr_block = "146.148.8.199/32" + display_name = "GCP jfrog-dev NAT" + } + cidr_blocks { + cidr_block = "192.168.20.0/24" //should be 192.168.21.0/24 + display_name = "all_local" + } + cidr_blocks { + cidr_block = "${var.natgw_ip[0]}/32" + display_name = "natgw" + } + cidr_blocks { + cidr_block = "${var.natgw_ip[1]}/32" + display_name = "natgw" + } + } + lifecycle { + ignore_changes = [ + initial_node_count, master_authorized_networks_config, master_auth + ] + } +} + +# K8s cluster node pool creation +resource "google_container_node_pool" "worker" { + count = var.module_enabled ? 1 : 0 + name = var.override_ng_name == "" ? "${var.deploy_name}-${var.region}-ng-1" : var.override_ng_name + location = var.k8s_zonal == "" ? var.region : var.region_zone + cluster = google_container_cluster.primary[0].name + node_count = 1 + version = var.k8s_node_version == "" ? data.google_container_engine_versions.region.latest_node_version : var.k8s_node_version + + autoscaling { + min_node_count = var.min_node_count + max_node_count = var.max_node_count + } + + management { + auto_repair = lookup(var.node_config, "node_auto_repair") + auto_upgrade = lookup(var.node_config, "node_auto_upgrade" ) + } + + node_config { + machine_type = var.worker_machine_type + image_type = var.image_type + disk_size_gb = var.ng_disk_size_gb + disk_type = "pd-ssd" + + shielded_instance_config { + enable_secure_boot = lookup(var.node_config, "enable_secure_boot" ) + } +// workload_metadata_config { +// node_metadata = "GKE_METADATA_SERVER" +// } +// oauth_scopes = [ +// "https://www.googleapis.com/auth/compute", +// "https://www.googleapis.com/auth/devstorage.read_only", +// "https://www.googleapis.com/auth/logging.write", +// "https://www.googleapis.com/auth/monitoring", +// ] + +// labels = { +// cluster = var.label +// } +// metadata = { +// ssh-keys = "ubuntu:${var.ssh_key} ubuntu" +// disable-legacy-endpoints = "true" +// } + tags = var.instance_tags + } + lifecycle { + ignore_changes = [ + autoscaling.0.max_node_count, node_count + ] + } +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/gcp/k8s-oss/outputs.tf b/testdata/xray/jas-config/iac/gcp/k8s-oss/outputs.tf new file mode 100644 index 000000000..7d3cea754 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-oss/outputs.tf @@ -0,0 +1,54 @@ +# The following outputs allow authentication and connectivity to the GKE Cluster. +output "client_certificate" { + value = google_container_cluster.primary.*.master_auth.0.client_certificate +} + +output "client_key" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.client_key, + [""], + ), + 0, + ) +} + +output "cluster_ca_certificate" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.cluster_ca_certificate, + [""], + ), + 0, + ) +} + +output "cluster_name" { + value = element(concat(google_container_cluster.primary.*.name, [""]), 0) +} + +output "cluster_ip" { + value = element(concat(google_container_cluster.primary.*.endpoint, [""]), 0) +} + +output "cluster_username" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.username, + [""], + ), + 0, + ) +} + +output "cluster_password" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.password, + [""], + ), + 0, + ) + sensitive = true +} + diff --git a/testdata/xray/jas-config/iac/gcp/k8s-oss/variables.tf b/testdata/xray/jas-config/iac/gcp/k8s-oss/variables.tf new file mode 100644 index 000000000..1124605c7 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-oss/variables.tf @@ -0,0 +1,102 @@ +variable "module_enabled" { + default = true +} + +variable "project_name" { +} + +variable "region" { +} + +variable "region_zone" { +} + +variable "deploy_name" { +} + +variable "network" { +} + +variable "subnetwork" { +} + +variable "instance_tags" { + type = list(string) +} + +variable "subnet_cidr" { + type = map(string) +} + +variable "min_node_count" { +} + +variable "max_node_count" { +} + +variable "logging_service" { +} + +variable "monitoring_service" { +} + +variable "enable_legacy_abac" { +} + +variable "worker_machine_type" { +} + +variable "ft_machine_type" { +} + +variable "image_type" { +} + +variable "ng_disk_size_gb" { +} +variable "ft_disk_size_gb" { +} + +variable "label" { +} + +variable "natgw_ip" { +} + +variable "gcp_azs" { + type = map(string) + default = { + us-east1 = "us-east1-c,us-east1-d" + us-west1 = "us-west1-c,us-west1-a" + us-central1 = "us-central1-c,us-central1-f" + europe-west2 = "europe-west2-a,europe-west2-c" + europe-west1 = "europe-west1-c,europe-west1-d" + } +} + +variable "ssh_key" { +} + +variable "k8s_master_version" { +} + +variable "k8s_node_version" { +} + +variable "client_certificate" { +} + +variable "k8s_zonal" { +} + +variable "override_ft_name" { +} + +variable "override_ng_name" { +} + +variable "gke_auth" { +} + +variable "node_config" { +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/gcp/k8s-oss/versions.tf b/testdata/xray/jas-config/iac/gcp/k8s-oss/versions.tf new file mode 100644 index 000000000..ac97c6ac8 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-oss/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/files/chk_k8s_nat b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/files/chk_k8s_nat new file mode 100644 index 000000000..f4f318bbf --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/files/chk_k8s_nat @@ -0,0 +1,17 @@ +#!/bin/bash + +# This script checks the functionality of the NAT gateway VM. + +tf_output=$(terraform output) +k8s_name=$(echo "$tf_output" | grep k8s_cluster_name | cut -d = -f 2) +k8s_project=$(echo "$tf_output" | grep k8s_project | cut -d = -f 2) +k8s_zone=$(echo "$tf_output" | grep k8s_zone | cut -d = -f 2) +k8s_ext_ip=$(echo "$tf_output" | grep external_ip | cut -d = -f 2) + +echo Testing k8s cluster connectivity to NAT.. +gcloud container clusters get-credentials $k8s_name --zone $k8s_zone --project $k8s_project > /dev/null + +chk_ext_ip=$(kubectl run test -it --restart=Never --image=centos:7 -- curl -s http://ipinfo.io/ip) +kubectl delete po test > /dev/null + +echo $k8s_ext_ip $chk_ext_ip diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/module.tf b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/module.tf new file mode 100644 index 000000000..f2d68663c --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/module.tf @@ -0,0 +1,207 @@ +# Create new K8S cluster with autoscaling + +data "google_container_engine_versions" "region" { + location = var.region +} + +resource "random_string" "admin-password" { + count = var.module_enabled ? 1 : 0 + length = 16 + +// lifecycle { +// ignore_changes = [ +// initial_node_count, master_authorized_networks_config +// ] +// } +} + +# New K8s Cluster, if creation failed you'll need to cleanup manually before running again. +resource "google_container_cluster" "primary" { + count = var.module_enabled ? 1 : 0 + provider = google-beta + name = "${var.deploy_name}-${var.region}" + location = var.k8s_zonal == "" ? var.region : var.region_zone + min_master_version = var.k8s_master_version == "" ? data.google_container_engine_versions.region.latest_master_version :lookup(var.gke_map.override,"k8s_master_version") + network = var.network + subnetwork = var.subnetwork + logging_service = var.logging_service + monitoring_service = var.monitoring_service + enable_legacy_abac = var.enable_legacy_abac + remove_default_node_pool = "true" + initial_node_count = 1 + enable_shielded_nodes = var.gke_auth.shielded_nodes + enable_intranode_visibility = var.enable_intranode_visibility + + master_auth { + username = var.gke_auth.basic_auth ? "basic-admin" : "" + password = var.gke_auth.basic_auth ? random_string.admin-password[0].result : "" + + client_certificate_config { + issue_client_certificate = var.client_certificate + } + } + + private_cluster_config { + enable_private_endpoint = false + enable_private_nodes = true + master_ipv4_cidr_block = var.subnet_cidr["k8s-private"] + } + + ip_allocation_policy { + cluster_secondary_range_name = "pods-private-range" + services_secondary_range_name = "services-private-range" + } + maintenance_policy { + recurring_window { + recurrence = var.maintenance_window.recurrence + start_time = var.maintenance_window.start_time + end_time = var.maintenance_window.end_time + } + } + + # Authoroized networks allowed to access the Master + + # master_authorized_networks_config { + + # cidr_blocks { + # cidr_block = "${var.natgw_ip[0]}/32" + # display_name = "natgw" + # } + # cidr_blocks { + # cidr_block = "${var.natgw_ip[1]}/32" + # display_name = "natgw" + # } + # } + master_authorized_networks_config { + dynamic "cidr_blocks" { + for_each = var.gke_map.override["public_access_cidrs"] + iterator = authorized_network + content { + cidr_block = authorized_network.value.cidr_block + display_name = authorized_network.value.display_name + } + } + } + + dynamic "resource_usage_export_config" { + for_each = toset(var.resource_usage_export_config_parameters != null ? ["exec"] : []) + content { + enable_network_egress_metering = lookup(var.resource_usage_export_config_parameters, "enable_network_egress_metering") + enable_resource_consumption_metering = lookup(var.resource_usage_export_config_parameters, "enable_resource_consumption_metering") + bigquery_destination { + dataset_id = lookup(var.resource_usage_export_config_parameters, "bigquery_destination.dataset_id") + } + } + } + + lifecycle { + ignore_changes = [ + initial_node_count, master_auth + ] + } +} + +# K8s cluster node pool creation +resource "google_container_node_pool" "worker" { + count = contains(keys(var.gke_map),"ng") ? 1 : 0 + name = lookup(var.gke_map.ng, "name", "${var.deploy_name}-${var.region}-ng-1" ) + location = var.k8s_zonal == "" ? var.region : var.region_zone + cluster = google_container_cluster.primary[0].name + node_count = 1 + version = lookup(var.gke_map.override, "k8s_node_version", data.google_container_engine_versions.region.latest_node_version) + +dynamic "autoscaling" { + for_each = toset(var.autoscaling_parameters != null ? ["exec"] : []) + content { + min_node_count = lookup(var.autoscaling_parameters, "min_node_count") + max_node_count = lookup(var.autoscaling_parameters, "max_node_count") + } + } + management { + auto_repair = lookup(var.node_config, "node_auto_repair") + auto_upgrade = lookup(var.node_config, "node_auto_upgrade" ) + } + node_config { + machine_type = lookup(var.gke_map.ng, "instance_type", "n2-highmem-2") + image_type = lookup(var.gke_map.ng, "image_type","COS") + disk_size_gb = lookup(var.gke_map.ng, "disk_size", "2000") + disk_type = "pd-ssd" + oauth_scopes = var.oauth_scopes + + shielded_instance_config { + enable_secure_boot = lookup(var.node_config, "enable_secure_boot" ) + } +// workload_metadata_config { +// node_metadata = "GKE_METADATA_SERVER" +// } + + +// labels = { +// cluster = var.label +// } + metadata = { + ssh-keys = "${var.ssh_key}" + disable-legacy-endpoints = "true" + } + tags = var.instance_tags + } + lifecycle { + ignore_changes = [ + autoscaling.0.max_node_count, node_count + ] + } +} +###node group for devops### +resource "google_container_node_pool" "devops_nodegroup" { + count = contains(keys(var.gke_map),"devops") ? 1 : 0 + name = lookup(var.gke_map.devops, "name", "${var.deploy_name}-${var.region}-ng-1" ) + location = var.k8s_zonal == "" ? var.region : var.region_zone + cluster = google_container_cluster.primary[0].name + node_count = 1 + version = lookup(var.gke_map.override, "k8s_node_version", data.google_container_engine_versions.region.latest_node_version) + management { + auto_repair = lookup(var.node_config, "node_auto_repair") + auto_upgrade = lookup(var.node_config, "node_auto_upgrade" ) + } + +dynamic "autoscaling" { + for_each = toset(var.gke_map.devops["autoscaling_parameters"] != {} ? ["exec"] : []) + content { + min_node_count = lookup(var.gke_map.devops["autoscaling_parameters"], "min_node_count") + max_node_count = lookup(var.gke_map.devops["autoscaling_parameters"], "max_node_count") + } + } + + node_config { + machine_type = lookup(var.gke_map.devops, "instance_type", "n2-standard-2") + labels = { + "k8s.jfrog.com/pool_type" = "devops" + } + image_type = var.image_type + disk_size_gb = lookup(var.gke_map.devops, "disk_size", "2000") + disk_type = "pd-ssd" + oauth_scopes= var.oauth_scopes + taint { + effect = "NO_SCHEDULE" + key = "pool_type" + value = "devops" + } + shielded_instance_config { + enable_secure_boot = lookup(var.node_config, "enable_secure_boot" ) + } +// workload_metadata_config { +// node_metadata = "GKE_METADATA_SERVER" +// } + + metadata = { + ssh-keys = "ubuntu:${var.ssh_key} ubuntu" + disable-legacy-endpoints = "true" + } + tags = var.instance_tags + } + lifecycle { + ignore_changes = [ + autoscaling.0.max_node_count, node_count + ] + } +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/outputs.tf b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/outputs.tf new file mode 100644 index 000000000..7d3cea754 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/outputs.tf @@ -0,0 +1,54 @@ +# The following outputs allow authentication and connectivity to the GKE Cluster. +output "client_certificate" { + value = google_container_cluster.primary.*.master_auth.0.client_certificate +} + +output "client_key" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.client_key, + [""], + ), + 0, + ) +} + +output "cluster_ca_certificate" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.cluster_ca_certificate, + [""], + ), + 0, + ) +} + +output "cluster_name" { + value = element(concat(google_container_cluster.primary.*.name, [""]), 0) +} + +output "cluster_ip" { + value = element(concat(google_container_cluster.primary.*.endpoint, [""]), 0) +} + +output "cluster_username" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.username, + [""], + ), + 0, + ) +} + +output "cluster_password" { + value = element( + concat( + google_container_cluster.primary.*.master_auth.0.password, + [""], + ), + 0, + ) + sensitive = true +} + diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/rbac.tf b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/rbac.tf new file mode 100644 index 000000000..2b2c06dc2 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/rbac.tf @@ -0,0 +1,61 @@ +provider "kubernetes" { + host = try(var.gke_map.override["k8s_sdm"], "https://${google_container_cluster.primary.*.endpoint}") +} + +resource "kubernetes_cluster_role_binding" "sdm-roles" { +for_each = toset(var.rbac_admin_roles) + metadata { + name = "${each.value}" + } + role_ref { + api_group = "rbac.authorization.k8s.io" + kind = "ClusterRole" + name = "cluster-admin" + } + subject { + kind = "Group" + name = "${each.value}" + api_group = "rbac.authorization.k8s.io" + } +} + + +resource "kubernetes_cluster_role" "sdm-ro-roles" { + for_each = toset(var.rbac_readonly_roles) + metadata { + name = "${each.value}" + } + + rule { + api_groups = [""] + resources = ["*"] + verbs = ["get", "list", "watch"] + } + rule { + api_groups = ["extensions"] + resources = ["*"] + verbs = ["get", "list", "watch"] + } + rule { + api_groups = ["apps"] + resources = ["*"] + verbs = ["get", "list", "watch"] + } +} + +resource "kubernetes_cluster_role_binding" "sdm-ro-roles" { + for_each = toset(var.rbac_readonly_roles) + metadata { + name = "${each.value}" + } + role_ref { + api_group = "rbac.authorization.k8s.io" + kind = "ClusterRole" + name = "${each.value}" + } + subject { + kind = "Group" + name = "${each.value}" + api_group = "rbac.authorization.k8s.io" + } +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/variables.tf b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/variables.tf new file mode 100644 index 000000000..f025f6049 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/variables.tf @@ -0,0 +1,137 @@ +variable "module_enabled" { + default = true +} + +variable "project_name" { +} + +variable "region" { +} + +variable "region_zone" { +} + +variable "deploy_name" { +} + +variable "network" { +} +variable "subnetwork" { +} + +variable "instance_tags" { + type = list(string) +} + +variable "subnet_cidr" { + type = map(string) +} + +variable "min_node_count" { +} + +variable "max_node_count" { +} + +variable "logging_service" { +} + +variable "monitoring_service" { +} + +variable "enable_legacy_abac" { +} + +variable "worker_machine_type" { +} + +variable "ft_machine_type" { +} + +variable "image_type" { +} + +variable "ng_disk_size_gb" { +} +variable "ft_disk_size_gb" { +} + +variable "label" { +} + +variable "natgw_ip" { +} + +variable "gcp_azs" { + type = map(string) + default = { + us-east1 = "us-east1-c,us-east1-d" + us-west1 = "us-west1-c,us-west1-a" + us-central1 = "us-central1-c,us-central1-f" + europe-west2 = "europe-west2-a,europe-west2-c" + europe-west1 = "europe-west1-c,europe-west1-d" + } +} + +variable "ssh_key" { +} + +variable "k8s_master_version" { +} + +variable "k8s_node_version" { +} + +variable "client_certificate" { +} + +variable "k8s_zonal" { +} + +variable "override_ft_name" { +} + +variable "override_ng_name" { +} + +variable "autoscaling_parameters"{ +} + +variable "gke_map"{ + +} +variable "network_policy" { + default = false +} +variable "maintenance_window" { + default = { + recurrence = "FREQ=WEEKLY;BYDAY=SU" + start_time = "2021-11-21T01:00:00Z" + end_time = "2021-11-21T18:00:00Z" + } +} + +variable "gke_auth" { +} + +variable "oauth_scopes" { + default = [ + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring", + ] +} + +variable "node_config"{ +} +variable "enable_intranode_visibility" {} +variable "rbac_admin_roles"{ +default = [] +} + +variable "rbac_readonly_roles"{ +default = [] +} + +variable "resource_usage_export_config_parameters" { + default = null +} \ No newline at end of file diff --git a/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/versions.tf b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/versions.tf new file mode 100644 index 000000000..ac97c6ac8 --- /dev/null +++ b/testdata/xray/jas-config/iac/gcp/k8s-pipelines-bp/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/testdata/xray/jas-config/main.py b/testdata/xray/jas-config/main.py new file mode 100644 index 000000000..064571e46 --- /dev/null +++ b/testdata/xray/jas-config/main.py @@ -0,0 +1,5 @@ +import yaml + +with open('example.yaml') as f: + data = yaml.full_load(f) + print(data) \ No newline at end of file diff --git a/testdata/xray/jas-config/requirements.txt b/testdata/xray/jas-config/requirements.txt new file mode 100644 index 000000000..79bfd143b --- /dev/null +++ b/testdata/xray/jas-config/requirements.txt @@ -0,0 +1,2 @@ +PyYAML==5.2 +Werkzeug==1.0.1 \ No newline at end of file diff --git a/testdata/xray/jas-config/sast/flask_webgoat/__init__.py b/testdata/xray/jas-config/sast/flask_webgoat/__init__.py new file mode 100644 index 000000000..9e2f505a6 --- /dev/null +++ b/testdata/xray/jas-config/sast/flask_webgoat/__init__.py @@ -0,0 +1,51 @@ +import os +import sqlite3 +from pathlib import Path + +from flask import Flask, g + +DB_FILENAME = "database.db" + + +def query_db(query, args=(), one=False, commit=False): + with sqlite3.connect(DB_FILENAME) as conn: + # vulnerability: Sensitive Data Exposure + conn.set_trace_callback(print) + cur = conn.cursor().execute(query, args) + if commit: + conn.commit() + return cur.fetchone() if one else cur.fetchall() + + +def create_app(): + app = Flask(__name__) + app.secret_key = "aeZ1iwoh2ree2mo0Eereireong4baitixaixu5Ee" + + db_path = Path(DB_FILENAME) + if db_path.exists(): + db_path.unlink() + + conn = sqlite3.connect(DB_FILENAME) + create_table_query = """CREATE TABLE IF NOT EXISTS user + (id INTEGER PRIMARY KEY, username TEXT, password TEXT, access_level INTEGER)""" + conn.execute(create_table_query) + + insert_admin_query = """INSERT INTO user (id, username, password, access_level) + VALUES (1, 'admin', 'admin', 0)""" + conn.execute(insert_admin_query) + conn.commit() + conn.close() + + with app.app_context(): + from . import actions + from . import auth + from . import status + from . import ui + from . import users + + app.register_blueprint(actions.bp) + app.register_blueprint(auth.bp) + app.register_blueprint(status.bp) + app.register_blueprint(ui.bp) + app.register_blueprint(users.bp) + return app diff --git a/testdata/xray/jas-config/sast/flask_webgoat/ui.py b/testdata/xray/jas-config/sast/flask_webgoat/ui.py new file mode 100644 index 000000000..2b0bd0608 --- /dev/null +++ b/testdata/xray/jas-config/sast/flask_webgoat/ui.py @@ -0,0 +1,25 @@ +import sqlite3 + +from flask import Blueprint, request, render_template +from . import query_db + +bp = Blueprint("ui", __name__) + + +@bp.route("/search") +def search(): + query_param = request.args.get("query") + if query_param is None: + message = "please provide the query parameter" + return render_template("error.html", message=message) + + try: + query = "SELECT username, access_level FROM user WHERE username LIKE ?;" + results = query_db(query, (query_param,)) + # vulnerability: XSS + return render_template( + "search.html", results=results, num_results=len(results), query=query_param + ) + except sqlite3.Error as err: + message = "Error while executing query " + query_param + ": " + err + return render_template("error.html", message=message) diff --git a/testdata/xray/jas-config/sast/result.sarif b/testdata/xray/jas-config/sast/result.sarif new file mode 100644 index 000000000..839f34816 --- /dev/null +++ b/testdata/xray/jas-config/sast/result.sarif @@ -0,0 +1,618 @@ +{ + "runs": [ + { + "tool": { + "driver": { + "name": "USAF", + "rules": [ + { + "id": "python-flask-debug", + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "1295" + } + } + }, + "fullDescription": { + "text": "\n### Overview\nDebug mode in a Flask app is a feature that allows the developer to see detailed\nerror messages and tracebacks when an error occurs. This can be useful for debugging\nand troubleshooting, but it can also create a security vulnerability if the app is\ndeployed in debug mode. In debug mode, Flask will display detailed error messages and\ntracebacks to the user, even if the error is caused by malicious input.\nThis can provide attackers with valuable information about the app's internal workings\nand vulnerabilities, making it easier for them to exploit those vulnerabilities.\n\n### Query operation\nIn this query we look Flask applications that set the `debug` argument to `True`\n\n### Vulnerable example\n```python\nfrom flask import Flask\n\napp = Flask(__name__)\n\n@app.route('/')\ndef hello():\n return 'Hello, World!'\n\nif __name__ == '__main__':\n app.run(debug=True)\n```\nIn this example, the Flask application is set to run in debug mode by passing\n`debug=True` as an argument to the `app.run()` function. This will make the application\nemit potentially sensitive information to the users.\n\n### Remediation\nWhen using `app.run`, omit the `debug` flag or set it to `False` -\n```diff\nif __name__ == '__main__':\n- app.run(debug=True)\n+ app.run()\n```\n", + "markdown": "\n### Overview\nDebug mode in a Flask app is a feature that allows the developer to see detailed\nerror messages and tracebacks when an error occurs. This can be useful for debugging\nand troubleshooting, but it can also create a security vulnerability if the app is\ndeployed in debug mode. In debug mode, Flask will display detailed error messages and\ntracebacks to the user, even if the error is caused by malicious input.\nThis can provide attackers with valuable information about the app's internal workings\nand vulnerabilities, making it easier for them to exploit those vulnerabilities.\n\n### Query operation\nIn this query we look Flask applications that set the `debug` argument to `True`\n\n### Vulnerable example\n```python\nfrom flask import Flask\n\napp = Flask(__name__)\n\n@app.route('/')\ndef hello():\n return 'Hello, World!'\n\nif __name__ == '__main__':\n app.run(debug=True)\n```\nIn this example, the Flask application is set to run in debug mode by passing\n`debug=True` as an argument to the `app.run()` function. This will make the application\nemit potentially sensitive information to the users.\n\n### Remediation\nWhen using `app.run`, omit the `debug` flag or set it to `False` -\n```diff\nif __name__ == '__main__':\n- app.run(debug=True)\n+ app.run()\n```\n" + }, + "shortDescription": { + "text": "Flask Running in Debug" + } + }, + { + "id": "python-stack-trace-exposure", + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "209" + } + } + }, + "fullDescription": { + "text": "\n### Overview\nStack trace exposure is a type of security vulnerability that occurs when a program reveals\nsensitive information, such as the names and locations of internal files and variables,\nin error messages or other diagnostic output. This can happen when a program crashes or\nencounters an error, and the stack trace (a record of the program's call stack at the time\nof the error) is included in the output. Stack trace exposure can provide attackers with\nvaluable information about a program's internal workings and vulnerabilities, making it\neasier for them to exploit those vulnerabilities and gain unauthorized access\nto the system.\n\n### Query operation\nIn this query we look for any stack trace information flowing into the output.\n\n### Vulnerable example\n```python\nimport traceback\n\ndef my_function():\n try:\n # Some code that may raise an exception\n raise ValueError('Something went wrong')\n except ValueError as e:\n traceback.print_tb(e.__traceback__)\n\nmy_function()\n```\nIn this example, the `my_function()` function intentionally raises\na `ValueError` exception.\nThe `traceback.print_tb()` function is then used to print the stack trace\nwhen the exception is caught. The vulnerability lies in using `traceback.print_tb()`\nto output the stack trace directly to the console or any other output stream.\nIf this code were part of a web application or exposed through an API,\nthe stack trace would be exposed in the server logs or potentially returned\nas part of an error response to the client.\n\n### Remediation\nLog the exception to a logging framework or file, instead of outputting directly to the\nconsole-\n\n```python\ndef log_exception(exception):\n logging.exception('An exception occurred', exc_info=exception)\n```\n\n```diff\ndef my_function():\n try:\n # Some code that may raise an exception\n raise ValueError('Something went wrong')\n except ValueError as e:\n- traceback.print_tb(e.__traceback__)\n+ log_exception(e)\n```\n", + "markdown": "\n### Overview\nStack trace exposure is a type of security vulnerability that occurs when a program reveals\nsensitive information, such as the names and locations of internal files and variables,\nin error messages or other diagnostic output. This can happen when a program crashes or\nencounters an error, and the stack trace (a record of the program's call stack at the time\nof the error) is included in the output. Stack trace exposure can provide attackers with\nvaluable information about a program's internal workings and vulnerabilities, making it\neasier for them to exploit those vulnerabilities and gain unauthorized access\nto the system.\n\n### Query operation\nIn this query we look for any stack trace information flowing into the output.\n\n### Vulnerable example\n```python\nimport traceback\n\ndef my_function():\n try:\n # Some code that may raise an exception\n raise ValueError('Something went wrong')\n except ValueError as e:\n traceback.print_tb(e.__traceback__)\n\nmy_function()\n```\nIn this example, the `my_function()` function intentionally raises\na `ValueError` exception.\nThe `traceback.print_tb()` function is then used to print the stack trace\nwhen the exception is caught. The vulnerability lies in using `traceback.print_tb()`\nto output the stack trace directly to the console or any other output stream.\nIf this code were part of a web application or exposed through an API,\nthe stack trace would be exposed in the server logs or potentially returned\nas part of an error response to the client.\n\n### Remediation\nLog the exception to a logging framework or file, instead of outputting directly to the\nconsole-\n\n```python\ndef log_exception(exception):\n logging.exception('An exception occurred', exc_info=exception)\n```\n\n```diff\ndef my_function():\n try:\n # Some code that may raise an exception\n raise ValueError('Something went wrong')\n except ValueError as e:\n- traceback.print_tb(e.__traceback__)\n+ log_exception(e)\n```\n" + }, + "shortDescription": { + "text": "Stack Trace Exposure" + } + }, + { + "id": "python-xss", + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "79" + } + } + }, + "fullDescription": { + "text": "\n### Overview\nXSS, or Cross-Site Scripting, is a type of vulnerability that allows an attacker to\ninject malicious code into a website or web application.\nThis can allow the attacker to steal sensitive information from users, such as their\ncookies or login credentials, or to perform unauthorized actions on their behalf.\n\n### Query operation\nIn the query we look for any user input that flows into\na potential output of the application.\n\n### Vulnerable example\nIn the following example, the Flask application takes a user-supplied parameter (`name`)\nfrom the query string and renders it directly into an HTML template using the\n`render_template_string` function. The issue is that\nthe user input is not properly sanitized or escaped, making it vulnerable to XSS attacks.\n```python\nfrom flask import Flask, request, render_template_string\n\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n name = request.args.get('name', 'Guest')\n message = f'Hello, {name}!'\n return render_template_string('