New proxy example

This commit is contained in:
Julio Castillo 2021-02-15 18:34:31 +01:00
parent 6c08ec012d
commit 5f65fec044
5 changed files with 304 additions and 0 deletions

View File

@ -0,0 +1,16 @@
# Network filtering with Squid
This example shows how to deploy a filtering HTTP proxy to restrict Internet access. Here we show one way to do this using a VPC with two subnets:
- The first subnet (called "apps" in this example) hosts the VMs that will have their Internet access tightly controlled a non-caching filtering forward proxy.
- The second subnet (called "proxy" in this example) hosts a Cloud NAT instance and a Squid Server [Squid](http://www.squid-cache.org/).
The VPC is a Shared VPC and all the service projects will be located under a folder enforcing the `compute.vmExternalIpAccess` (organization policies)[https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints]. This prevents the service projects from having external IPs thus forcing all outbound Internet connections through the proxy.
To allow Internet connectivity to the proxy subnet, a Cloud NAT instance is configured to allow usage from (that subnet only)[https://cloud.google.com/nat/docs/using-nat#specify_subnet_ranges_for_nat]. All other subnets are not allowed to use the Cloud NAT instance.
To simplify the usage of the proxy, a Cloud DNS private zone is created and the IP address of the proxy is exposed with the FQDN `proxy.internal`.
You can optionally deploy the Squid server as (Managed Instance Group)[https://cloud.google.com/compute/docs/instance-groups] by setting the `mig` option to `true`. This option defaults to `false` which results in a standalone VM.
![High-level diagram](squid.png "High-level diagram")

View File

@ -0,0 +1,245 @@
locals {
squid_address = (
var.mig
? module.squid-ilb.0.forwarding_rule_address
: module.squid-vm.internal_ips.0
)
}
###############################################################################
# Top level folder #
###############################################################################
module "folder-netops" {
source = "../../modules/folder"
parent = var.root_node
name = "netops"
}
###############################################################################
# Host project and shared VPC resources #
###############################################################################
module "project-host" {
source = "../../modules/project"
billing_account = var.billing_account
name = "host"
parent = module.folder-netops.id
prefix = var.prefix
services = [
"compute.googleapis.com",
"dns.googleapis.com",
"logging.googleapis.com"
]
shared_vpc_host_config = {
enabled = true
service_projects = []
}
}
module "vpc" {
source = "../../modules/net-vpc"
project_id = module.project-host.project_id
name = "vpc"
subnets = [
{
name = "apps"
ip_cidr_range = var.cidrs.apps
region = var.region
secondary_ip_range = null
},
{
name = "proxy"
ip_cidr_range = var.cidrs.proxy
region = var.region
secondary_ip_range = null
}
]
}
module "firewall" {
source = "../../modules/net-vpc-firewall"
project_id = module.project-host.project_id
network = module.vpc.name
custom_rules = {
allow-ingress-squid = {
description = "Allow squid ingress traffic"
direction = "INGRESS"
action = "allow"
sources = []
ranges = [var.cidrs.apps, "35.191.0.0/16", "130.211.0.0/22"]
targets = [module.service-account-squid.email]
use_service_accounts = true
rules = [{ protocol = "tcp", ports = [3128] }]
extra_attributes = {}
}
}
}
module "nat" {
source = "../../modules/net-cloudnat"
project_id = module.project-host.project_id
region = var.region
name = "default"
router_network = module.vpc.name
config_source_subnets = "LIST_OF_SUBNETWORKS"
# 64512/11 = 5864 . 11 is the number of usable IPs in the proxy subnet
config_min_ports_per_vm = 5864
subnetworks = [
{
self_link = module.vpc.subnet_self_links["${var.region}/proxy"]
config_source_ranges = ["ALL_IP_RANGES"]
secondary_ranges = null
}
]
logging_filter = var.nat_logging
}
module "service-account-squid" {
source = "../../modules/iam-service-account"
project_id = module.project-host.project_id
name = "svc-squid"
iam_project_roles = {
(module.project-host.project_id) = [
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
]
}
}
module "cos-squid" {
source = "../../modules/cloud-config-container/squid"
allow = [
".github.com",
]
clients = [var.cidrs.apps]
}
module "squid-vm" {
source = "../../modules/compute-vm"
project_id = module.project-host.project_id
region = var.region
name = "squid-vm"
instance_type = "e2-medium"
network_interfaces = [{
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/proxy"]
nat = false
addresses = null
alias_ips = null
}]
boot_disk = {
image = "projects/cos-cloud/global/images/family/cos-stable"
type = "pd-standard"
size = 15
}
service_account = module.service-account-squid.email
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
use_instance_template = var.mig
metadata = {
user-data = module.cos-squid.cloud_config
}
}
module "squid-mig" {
count = var.mig ? 1 : 0
source = "../../modules/compute-mig"
project_id = module.project-host.project_id
location = "${var.region}-b"
name = "squid-mig"
target_size = 1
autoscaler_config = {
max_replicas = 10
min_replicas = 1
cooldown_period = 30
cpu_utilization_target = 0.65
load_balancing_utilization_target = null
metric = null
}
default_version = {
instance_template = module.squid-vm.template.self_link
name = "default"
}
health_check_config = {
type = "tcp"
check = { port = 3128 }
config = {}
logging = true
}
auto_healing_policies = {
health_check = module.squid-mig.0.health_check.self_link
initial_delay_sec = 60
}
}
module "squid-ilb" {
count = var.mig ? 1 : 0
source = "../../modules/net-ilb"
project_id = module.project-host.project_id
region = var.region
name = "squid-ilb"
service_label = "squid-ilb"
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/proxy"]
ports = [3128]
backends = [{
failover = false
group = module.squid-mig.0.group_manager.instance_group
balancing_mode = "CONNECTION"
}]
health_check_config = {
type = "tcp"
check = { port = 3128 }
config = {}
logging = true
}
}
module "private-dns" {
source = "../../modules/dns"
project_id = module.project-host.project_id
type = "private"
name = "internal"
domain = "internal."
client_networks = [module.vpc.self_link]
recordsets = [
{
name = "squid"
type = "A"
ttl = 60
records = [local.squid_address]
}
]
}
###############################################################################
# Service project #
###############################################################################
module "folder-apps" {
source = "../../modules/folder"
parent = var.root_node
name = "apps"
policy_list = {
# prevent VMs with public IPs in the apps folder
"constraints/compute.vmExternalIpAccess" = {
inherit_from_parent = false
suggested_value = null
status = false
values = []
}
}
}
module "project-app" {
source = "../../modules/project"
billing_account = var.billing_account
name = "app"
parent = module.folder-apps.id
prefix = var.prefix
services = ["compute.googleapis.com"]
shared_vpc_service_config = {
attach = true
host_project = module.project-host.project_id
}
}

View File

@ -0,0 +1,3 @@
output "squid-address" {
value = local.squid_address
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,40 @@
variable "billing_account" {
description = "Billing account id used as default for new projects."
type = string
}
variable "prefix" {
description = "Prefix used for resources that need unique names."
type = string
}
variable "root_node" {
description = "Root node for the new hierarchy, either 'organizations/org_id' or 'folders/folder_id'."
type = string
}
variable "region" {
description = "Default region for resources"
type = string
}
variable "cidrs" {
description = "CIDR ranges for subnets"
type = map(string)
default = {
apps = "10.0.0.0/24"
proxy = "10.0.1.0/28"
}
}
variable "nat_logging" {
description = "Enables Cloud NAT logging if not null, value is one of 'ERRORS_ONLY', 'TRANSLATIONS_ONLY', 'ALL'."
type = string
default = "ERRORS_ONLY"
}
variable "mig" {
description = "Enables the creation of an autoscaling managed instance group of squid instances."
type = bool
default = false
}