Skip to content

GoogleCloudPlatform/local-dns-poc

Local DNS Terraform PoC

This Terraform code provides a standardized, well-documented, and easily deployable Infrastructure as Code (IaC) solution for integrating local DNS servers with Google Cloud. It automates the deployment of core GCP infrastructure, including local BIND DNS servers for a functional Proof of Concept (PoC). The solution addresses challenges faced by customers with strict compliance needs and intricate network designs, such as forwarding restrictions and multi-VPC outbound forwarding issues, aiming to reduce DNS query latency and provide a robust, standardized hub-and-spoke DNS integration.

Architecture

This Terraform project deploys a PoC environment in Google Cloud to demonstrate a hybrid DNS resolution strategy. It establishes a hub-and-spoke network topology whith local BIND DNS servers which are deployed in the hub VPC, provide authoritative resolution for a specific domain and override specific public domains for private access, while forwarding all other queries.

The deployed architecture consists of the following key components:

  1. Hub-and-Spoke Network:

    • A central Hub VPC that hosts shared services.
    • Two Spoke VPCs (prd and dev) representing different environments.
    • VPC Peering connects each spoke to the hub, allowing private communication.
  2. Local DNS Resolution:

    • Two BIND9 DNS servers are deployed in the Hub VPC for high availability.
    • These servers are authoritative for a custom internal domain (e.g., acme.local) and for googleapis.com to enable Private Google Access.
    • A "catch-all" Cloud DNS Forwarding Zone (.) in the hub directs all DNS queries to the BIND servers.
  3. DNS Peering:

    • The spoke networks are configured with Cloud DNS Peering Zones that point to the hub's forwarding zone, allowing VMs in the spokes to resolve names using the central BIND servers.
  4. Secure Access and Firewall:

    • Network Firewall Policies and Secure Tags are used to enforce granular security rules.
    • Rules are defined to allow SSH via IAP, HTTP/S to web servers, and DNS traffic to the BIND servers.
  5. Compute Instances:

    • Various GCE instances are deployed across the hub and spokes to test connectivity and DNS resolution.
    • Some spoke VMs are configured to use the central BIND servers, while others use the default VPC DNS resolver to demonstrate different resolution paths.

Prerequisites

Before you begin, ensure you have the following:

  • Terraform v1.3+ installed.
  • A Google Cloud Organization, a valid billing account and a baseline project.
  • A dedicated identity with the necessary permissions:
    • Optional (for 00-state-bucket stage):
      • roles/storage.admin at the project where the state bucket will be created.
    • Required (for the entire solution):
      • At the organization level:
        • roles/resourcemanager.tagAdmin
        • roles/resourcemanager.tagUser
      • At the "hub," "spoke_prd," and "spoke_dev" projects levels:
        • roles/serviceusage.serviceUsageAdmin
        • roles/compute.networkAdmin
        • roles/compute.instanceAdmin.v1
        • roles/dns.admin
        • roles/compute.securityAdmin
        • roles/iam.serviceAccountAdmin
        • roles/iam.serviceAccountUser

Deployment

  1. Clone the repository:

    git clone <repository-url>
    cd <repository-directory>
  2. Optional: Create the TF state bucket: Under the 00-state-bucket folder, you will find out the Terraform code to create a GCS bucket (in a dedicated project) that will be used as a state backend for the solution. Create a terraform.tfvars file (use as a reference the terraform.tfvars.example file) and make sure to run the following commands under this folder:

    terraform init
    terraform apply
  3. Update the backend.tf Indicate a GCS bucket that will be used to store the TF state, manually update the backend.tf file and replace the UPDATE_ME string with the GCS bucket name.

  4. Configure Variables: Create a terraform.tfvars file and populate it with your desired configuration values for each one of the required inputs (use as a reference the terraform.tfvars.example file).

  5. Initialize Terraform:

    terraform init
  6. Apply the Configuration:

    terraform apply

Requirements

Name Version
terraform >= 1.3
google >= 4.64, < 8
google-beta >= 4.64, < 8
time 0.9.1

Providers

Name Version
google 6.44.0
google-beta 6.44.0
time 0.9.1

Modules

Name Source Version
vpcs terraform-google-modules/network/google 11.1.1

Resources

Name Type
google-beta_google_compute_network_firewall_policy_association.project_policy_associations resource
google_compute_instance.hub_dns_server_vms resource
google_compute_instance.spoke_dev_cli_vms resource
google_compute_instance.spoke_prd_cli_vms resource
google_compute_instance.vm-hub-cli1 resource
google_compute_instance.vm-hub-www1 resource
google_compute_network_firewall_policy.project_policies resource
google_compute_network_firewall_policy_rule.allow_http_https_to_web_servers resource
google_compute_network_firewall_policy_rule.allow_spoke_to_dns_servers resource
google_compute_network_firewall_policy_rule.allow_ssh_via_iap resource
google_compute_network_peering.hub_to_spoke_dev resource
google_compute_network_peering.hub_to_spoke_prd resource
google_compute_network_peering.spoke_dev_to_hub resource
google_compute_network_peering.spoke_prd_to_hub resource
google_compute_router.nat_router resource
google_compute_router_nat.nat_gateway resource
google_dns_managed_zone.hub_root_forwarding_zone resource
google_dns_managed_zone.spoke_root_peering_zone resource
google_project_service.apis resource
google_tags_tag_key.application_role_tag_key resource
google_tags_tag_key.environment_tag_key resource
google_tags_tag_key.security_role_tag_key resource
google_tags_tag_value.app_web_server_tag_value resource
google_tags_tag_value.env_prd_tag_value resource
google_tags_tag_value.ssh_via_iap_tag_value resource
time_sleep.wait_for_vm_startup resource

Inputs

Name Description Type Default Required
dns_server_vms A map of DNS server identifiers to their fixed internal IP addresses.
map(object({
ip_address = string
zone_suffix = string
}))
{
"vm-hub-dns1": {
"ip_address": "10.0.0.11",
"zone_suffix": "a"
},
"vm-hub-dns2": {
"ip_address": "10.0.0.12",
"zone_suffix": "b"
}
}
no
domain_name The FQDN of your domain (e.g., 'your-company.com'). string n/a yes
enable_secure_boot If true, enables Secure Boot on Shielded VM instances. bool true no
hub_cli1_vm Configuration for the vm-hub-cli1 instance.
object({
ip_address = string
zone_suffix = string
})
{
"ip_address": "10.0.0.31",
"zone_suffix": "a"
}
no
hub_dns_zone_name The name for the Hub's private forwarding DNS zone. string "onprem-forwarder" no
hub_subnet_ip The IP range for the Hub subnet. string "10.0.0.0/24" no
hub_subnet_name The name for the Hub subnet. string "hub-subnet-01" no
hub_vm_machine_type Machine type for Hub VMs. string "e2-medium" no
hub_vpc_name The name for the Hub VPC network. string "hub-vpc" no
hub_www1_vm Configuration for the vm-hub-www1 instance.
object({
ip_address = string
zone_suffix = string
})
{
"ip_address": "10.0.0.21",
"zone_suffix": "b"
}
no
instance_image The OS image for the VMs. string "debian-cloud/debian-11" no
organization_id The ID of the GCP organization (e.g., '123456789012'). string n/a yes
projects A map of logical project names to their details, including the actual GCP project ID and a list of APIs to enable.
map(object({
project_id = string
apis = list(string)
}))
n/a yes
region The GCP region for the subnets and VMs. string "us-central1" no
spoke_dev_cli_vms A map of development client VMs to create, with their specific IP and zone.
map(object({
ip_address = string
zone_suffix = string
}))
{} no
spoke_dev_subnet_ip The IP range for the Spoke DEV subnet. string "10.2.0.0/24" no
spoke_dev_subnet_name The name for the Spoke DEV subnet. string "spoke-dev-subnet-01" no
spoke_dev_vm_machine_type Machine type for Spoke DEV VMs. string "e2-small" no
spoke_dev_vpc_name The name for the Spoke DEV VPC network. string "spoke-dev-vpc" no
spoke_prd_cli_vms A map of production client VMs to create, with their specific IP and zone.
map(object({
ip_address = string
zone_suffix = string
}))
{} no
spoke_prd_subnet_ip The IP range for the Spoke PRD subnet. string "10.1.0.0/24" no
spoke_prd_subnet_name The name for the Spoke PRD subnet. string "spoke-prd-subnet-01" no
spoke_prd_vm_machine_type Machine type for Spoke PRD VMs. string "e2-medium" no
spoke_prd_vpc_name The name for the Spoke PRD VPC network. string "spoke-prd-vpc" no

Outputs

Name Description
hub_dns_server_ips Details of the hub DNS server VMs, including IP, project, and zone.
hub_utility_vm_ips Details of the hub utility VMs, including IP, project, and zone.
spoke_dev_cli_vm_ips Details of the spoke development client VMs, including IP, project, and zone.
spoke_prd_cli_vm_ips Details of the spoke production client VMs, including IP, project, and zone.

Disclaimer

This project is intended for demonstration purposes only. It is not intended for use in a production environment.

About

PoC Terraform code to integrate DNS servers with Google Cloud.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors