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.
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:
-
Hub-and-Spoke Network:
- A central Hub VPC that hosts shared services.
- Two Spoke VPCs (
prdanddev) representing different environments. - VPC Peering connects each spoke to the hub, allowing private communication.
-
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 forgoogleapis.comto enable Private Google Access. - A "catch-all" Cloud DNS Forwarding Zone (
.) in the hub directs all DNS queries to the BIND servers.
-
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.
-
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.
-
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.
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.adminat the project where the state bucket will be created.
- Required (for the entire solution):
- At the organization level:
roles/resourcemanager.tagAdminroles/resourcemanager.tagUser
- At the "hub," "spoke_prd," and "spoke_dev" projects levels:
roles/serviceusage.serviceUsageAdminroles/compute.networkAdminroles/compute.instanceAdmin.v1roles/dns.adminroles/compute.securityAdminroles/iam.serviceAccountAdminroles/iam.serviceAccountUser
- At the organization level:
- Optional (for 00-state-bucket stage):
-
Clone the repository:
git clone <repository-url> cd <repository-directory>
-
Optional: Create the TF state bucket: Under the
00-state-bucketfolder, 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 aterraform.tfvarsfile (use as a reference theterraform.tfvars.examplefile) and make sure to run the following commands under this folder:terraform init terraform apply
-
Update the backend.tf Indicate a GCS bucket that will be used to store the TF state, manually update the
backend.tffile and replace theUPDATE_MEstring with the GCS bucket name. -
Configure Variables: Create a
terraform.tfvarsfile and populate it with your desired configuration values for each one of the required inputs (use as a reference theterraform.tfvars.examplefile). -
Initialize Terraform:
terraform init
-
Apply the Configuration:
terraform apply
| Name | Version |
|---|---|
| terraform | >= 1.3 |
| >= 4.64, < 8 | |
| google-beta | >= 4.64, < 8 |
| time | 0.9.1 |
| Name | Version |
|---|---|
| 6.44.0 | |
| google-beta | 6.44.0 |
| time | 0.9.1 |
| Name | Source | Version |
|---|---|---|
| vpcs | terraform-google-modules/network/google | 11.1.1 |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| dns_server_vms | A map of DNS server identifiers to their fixed internal IP addresses. | map(object({ |
{ |
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({ |
{ |
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({ |
{ |
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({ |
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({ |
{} |
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({ |
{} |
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 |
| 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. |
This project is intended for demonstration purposes only. It is not intended for use in a production environment.
