INTEGRITY Dokumentace

Terraform

Terraform ↗ je nástroj infrastructure as code, který vám umožňuje definovat tunely a spravovat je spolu s ostatní infrastrukturou. Tento návod nasadí:

Předpoklady

1. Nainstalujte Terraform

Viz Průvodce instalací Terraformu ↗ pro váš operační systém.

2. Nainstalujte gcloud CLI

  1. Instalace gcloud CLI ↗ tak, aby Terraform mohl pracovat s vaším účtem GCP.

  2. Ověřte se pomocí CLI spuštěním:

    gcloud auth application-default login

3. Vytvořte token Cloudflare API

Vytvořte token API tak, aby Terraform mohl pracovat s vaším účtem Cloudflare. Token by měl obsahovat minimálně následující oprávnění:

Typ Položka Oprávnění
Účet Cloudflare Tunnel Úprava
Účet Access: aplikace a zásady Úprava
Zóna DNS Úprava

4. Vytvořte konfigurační adresář

Terraform funguje prostřednictvím pracovního adresáře, který obsahuje konfigurační soubory. Konfiguraci můžete uložit do více souborů nebo jen do jednoho: Terraform vyhodnotí všechny konfigurační soubory v adresáři, jako by byly v jediném dokumentu.

  1. Vytvořte složku pro konfiguraci Terraform:

    mkdir cloudflare-tf
  2. Přejděte do adresáře:

    cd cloudflare-tf

5. Vytvořte konfigurační soubory Terraform

Definujte vstupní proměnné

Následující proměnné budou předány do konfigurace GCP a Cloudflare.

  1. Ve svém konfiguračním adresáři vytvořte .tf soubor:

    touch variables.tf
  2. Otevřete soubor v textovém editoru a zkopírujte a vložte následující:

    # GCP variables
    variable "gcp_project_id" {
      description = "Google Cloud Platform (GCP) project ID"
      type        = string
    }
    
    variable "zone" {
      description = "Geographical zone for the GCP VM instance"
      type        = string
    }
    
    variable "machine_type" {
      description = "Machine type for the GCP VM instance"
      type        = string
    }
    
    # Cloudflare variables
    variable "cloudflare_zone" {
      description = "Domain used to expose the GCP VM instance to the Internet"
      type        = string
    }
    
    variable "cloudflare_zone_id" {
      description = "Zone ID for your domain"
      type        = string
    }
    
    variable "cloudflare_account_id" {
      description = "Account ID for your Cloudflare account"
      type        = string
      sensitive   = true
    }
    
    variable "cloudflare_email" {
      description = "Email address for your Cloudflare account"
      type        = string
      sensitive   = true
    }
    
    variable "cloudflare_token" {
      description = "Cloudflare API token"
      type        = string
      sensitive   = true
    }

Přiřaďte hodnoty proměnným

  1. Ve svém konfiguračním adresáři vytvořte .tfvars soubor:

    touch terraform.tfvars

    Terraform tyto proměnné automaticky použije, pokud je soubor pojmenován terraform.tfvars, jinak bude nutné soubor s proměnnými předat ručně.

  2. Přidejte následující proměnné do terraform.tfvars. Nezapomeňte upravit příklad podle svých vlastních hodnot.

    cloudflare_zone           = "example.com"
    cloudflare_zone_id        = "023e105f4ecef8ad9ca31a8372d0c353"
    cloudflare_account_id     = "372e67954025e0ba6aaa6d586b9e0b59"
    cloudflare_email          = "[email protected]"
    cloudflare_token          = "y3AalHS_E7Vabk3c3lX950F90_Xl7YtjSlzyFn_X"
    gcp_project_id            = "testvm-123"
    zone                      = "us-central1-a"
    machine_type              = "e2-medium"

Nakonfigurujte poskytovatele Terraform

Budete muset deklarovat poskytovatelé ↗ použitý k zajištění infrastruktury.

  1. Ve svém konfiguračním adresáři vytvořte .tf soubor:

    touch providers.tf
  2. Přidejte následující poskytovatele do providers.tf. random poskytovatel se používá k vygenerování tajného klíče tunelu.

    terraform {
    	required_providers {
    		cloudflare = {
    			source = "cloudflare/cloudflare"
    			version = ">= 5.8.2"
    		}
    		google = {
    			source = "hashicorp/google"
    		}
    	}
    	required_version = ">= 1.2"
    }
    
    # Providers
    provider "cloudflare" {
    	api_token    = var.cloudflare_token
    }
    provider "google" {
    	project    = var.gcp_project_id
    }
    provider "random" {
    }
    terraform {
    	required_providers {
    		cloudflare = {
    			source = "cloudflare/cloudflare"
    			version = ">= 4.40.0, < 5.0.0"
    		}
    		google = {
    			source = "hashicorp/google"
    		}
    		random = {
    			source = "hashicorp/random"
    		}
    	}
    	required_version = ">= 1.2"
    }
    
    # Providers
    provider "cloudflare" {
    	api_token    = var.cloudflare_token
    }
    provider "google" {
    	project    = var.gcp_project_id
    }
    provider "random" {
    }

Nakonfigurujte prostředky Cloudflare

Následující konfigurace upraví nastavení ve vašem účtu Cloudflare.

  1. Ve svém konfiguračním adresáři vytvořte .tf soubor:

    touch Cloudflare-config.tf
  2. Přidejte následující prostředky do Cloudflare-config.tf:

    
    # Creates a new remotely-managed tunnel for the GCP VM.
    resource "cloudflare_zero_trust_tunnel_cloudflared" "gcp_tunnel" {
    	account_id    = var.cloudflare_account_id
    	name          = "Terraform GCP tunnel"
    	config_src    = "cloudflare"
    }
    
    # Reads the token used to run the tunnel on the server.
    data "cloudflare_zero_trust_tunnel_cloudflared_token" "gcp_tunnel_token" {
    	account_id 	= var.cloudflare_account_id
    	tunnel_id 	= cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id
    }
    
    # Creates the CNAME record that routes http_app.${var.cloudflare_zone} to the tunnel.
    resource "cloudflare_dns_record" "http_app" {
    	zone_id = var.cloudflare_zone_id
    	name    = "http_app"
    	content = "${cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id}.cfargotunnel.com"
    	type    = "CNAME"
    	ttl     = 1
    	proxied = true
    }
    
    # Configures tunnel with a published application for clientless access.
    resource "cloudflare_zero_trust_tunnel_cloudflared_config" "gcp_tunnel_config" {
    	tunnel_id  = cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id
    	account_id = var.cloudflare_account_id
    	config     = {
    		ingress 	= [
    			{
    				hostname = "http_app.${var.cloudflare_zone}"
    				service  = "http://httpbin:80"
    			},
    			{
    				service  = "http_status:404"
    			}
    		]
    	}
    }
    
    # (Optional) Routes internal IP of GCP instance through the tunnel for private network access using WARP.
    resource "cloudflare_zero_trust_tunnel_cloudflared_route" "example_tunnel_route" {
    account_id         = var.cloudflare_account_id
    tunnel_id          = cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id
    network            = google_compute_instance.http_server.network_interface.0.network_ip
    comment            = "Example tunnel route"
    }
    
    # Creates a reusable Access policy.
    resource "cloudflare_zero_trust_access_policy" "allow_emails" {
    	account_id   = var.cloudflare_account_id
    	name         = "Allow email addresses"
    	decision     = "allow"
    	include      = [
    		{
    			email = {
    				email = var.cloudflare_email
    			}
    		},
    		{
    			email_domain = {
    				domain = "@example.com"
    			}
    		}
    	]
    }
    
    # Creates an Access application to control who can connect to the public hostname.
    resource "cloudflare_zero_trust_access_application" "http_app" {
    	account_id       = var.cloudflare_account_id
    	type             = "self_hosted"
    	name             = "Access application for http_app.${var.cloudflare_zone}"
    	domain           = "http_app.${var.cloudflare_zone}"
    	policies = [
    		{
    			id = cloudflare_zero_trust_access_policy.allow_emails.id
    			precedence = 1
    		}
    	]
    }
    # Generates a 32-byte secret for the tunnel.
    resource "random_bytes" "tunnel_secret" {
    	byte_length = 32
    }
    
    # Creates a new remotely-managed tunnel for the GCP VM.
    resource "cloudflare_zero_trust_tunnel_cloudflared" "gcp_tunnel" {
    	account_id = var.cloudflare_account_id
    	name       = "Terraform GCP tunnel"
    	secret     = random_bytes.tunnel_secret.base64
    }
    
    # Creates the CNAME record that routes http_app.${var.cloudflare_zone} to the tunnel.
    resource "cloudflare_record" "http_app" {
    	zone_id = var.cloudflare_zone_id
    	name    = "http_app"
    	content   = "${cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.cname}"
    	type    = "CNAME"
    	proxied = true
    }
    
    # Configures tunnel with a published application for clientless access.
    resource "cloudflare_zero_trust_tunnel_cloudflared_config" "gcp_tunnel_config" {
    	tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id
    	account_id = var.cloudflare_account_id
    	config {
    		ingress_rule {
    			hostname = "${cloudflare_record.http_app.hostname}"
    			service  = "http://httpbin:80"
    		}
    		ingress_rule {
    			service  = "http_status:404"
    		}
    	}
    }
    
    # (Optional) Route internal IP of GCP instance through the tunnel for private network access using WARP.
    resource "cloudflare_zero_trust_tunnel_route" "example_tunnel_route" {
    account_id         = var.cloudflare_account_id
    tunnel_id          = cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id
    network            = google_compute_instance.http_server.network_interface.0.network_ip
    comment            = "Example tunnel route"
    }
    
    # Creates an Access application to control who can connect to the public hostname.
    resource "cloudflare_zero_trust_access_application" "http_app" {
    	account_id          = var.cloudflare_account_id
    	name             = "Access application for http_app.${var.cloudflare_zone}"
    	domain           = "http_app.${var.cloudflare_zone}"
    }
    
    # Creates a (legacy) Access policy for the Access application.
    resource "cloudflare_zero_trust_access_policy" "allow_emails" {
    	application_id = cloudflare_zero_trust_access_application.http_app.id
    	account_id        = var.cloudflare_account_id
    	name           = "Example policy for http_app.${var.cloudflare_zone}"
    	precedence     = "1"
    	decision       = "allow"
    	include {
    		email = [var.cloudflare_email]
    	}
    }

Chcete-li se dozvědět více o těchto zdrojích, přečtěte si Dokumentace poskytovatele Cloudflare ↗.

Nakonfigurujte prostředky GCP

Následující konfigurace definuje specifikace virtuálního počítače GCP a nastavuje spouštěcí skript, který se spustí při startu.

  1. Ve svém konfiguračním adresáři vytvořte .tf soubor:

    touch GCP-config.tf
  2. Přidejte následující obsah do GCP-config.tf:

    # OS the server will use
    data "google_compute_image" "image" {
    	family  = "ubuntu-2204-lts"
    	project = "ubuntu-os-cloud"
    }
    
    # GCP Instance resource
    resource "google_compute_instance" "http_server" {
    	name         = "test"
    	machine_type = var.machine_type
    	zone         = var.zone
    	tags         = []
    	boot_disk {
    		initialize_params {
    			image = data.google_compute_image.image.self_link
    		}
    	}
    
    	network_interface {
    		network = "default"
    		access_config {
    			//Ephemeral IP
    		}
    	}
    	// Optional config to make instance ephemeral
    /*  scheduling {
    		preemptible       = true
    		automatic_restart = false
    	} */
    
    	// Pass the tunnel token to the GCP server so that the server can install and run the tunnel upon startup.
    	metadata_startup_script = templatefile("./install-tunnel.tftpl",
    		{
    			tunnel_token = data.cloudflare_zero_trust_tunnel_cloudflared_token.gcp_tunnel_token.token
    		})
    }
    # OS the server will use
    data "google_compute_image" "image" {
    	family  = "ubuntu-2204-lts"
    	project = "ubuntu-os-cloud"
    }
    
    # GCP Instance resource
    resource "google_compute_instance" "http_server" {
    	name         = "test"
    	machine_type = var.machine_type
    	zone         = var.zone
    	tags         = []
    	boot_disk {
    		initialize_params {
    			image = data.google_compute_image.image.self_link
    		}
    	}
    
    	network_interface {
    		network = "default"
    		access_config {
    			//Ephemeral IP
    		}
    	}
    	// Optional config to make instance ephemeral
    /*  scheduling {
    		preemptible       = true
    		automatic_restart = false
    	} */
    
    	// Pass the tunnel token to the GCP server so that the server can install and run the tunnel upon startup.
    	metadata_startup_script = templatefile("./install-tunnel.tftpl",
    		{
    			tunnel_token = cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.tunnel_token
    		})
    }

Vytvořit spouštěcí skript

Následující skript nainstaluje cloudflared a spusťte tunel jako službu. Tento příklad také nainstaluje odlehčenou aplikaci HTTP, kterou můžete použít k otestování konektivity.

  1. Ve svém konfiguračním adresáři vytvořte soubor šablony Terraform:

    touch install-tunnel.tftpl
  2. Otevřete soubor v textovém editoru a zkopírujte a vložte následující bash skript:

    # Script to install Cloudflare Tunnel and Docker resources
    
    # Docker configuration
    cd /tmp
    sudo apt-get install software-properties-common
    # Retrieving the docker repository for this OS
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
    # The OS is updated and docker is installed
    sudo apt update -y && sudo apt upgrade -y
    sudo apt install docker docker-compose -y
    # Add the HTTPBin application and run it on localhost:8080.
    cat > /tmp/docker-compose.yml << "EOF"
    version: '3'
    services:
      httpbin:
        image: kennethreitz/httpbin
        restart: always
        container_name: httpbin
        ports:
          - 8080:80
    
      cloudflared:
        image: cloudflare/cloudflared:latest
        restart: always
        container_name: cloudflared
        command: tunnel run --token ${tunnel_token}
    EOF
    cd /tmp
    sudo docker-compose up -d

6. Nasaďte Terraform

Chcete-li nasadit konfigurační soubory:

  1. Inicializujte svůj konfigurační adresář:

    terraform init
  2. Zobrazte náhled všeho, co bude vytvořeno:

    terraform plan
  3. Použijte konfiguraci:

    terraform apply

Aktivace instance GCP a tunelu může trvat několik minut. Nový tunel si můžete zobrazit na kartě Cloudflare dashboard ↗ v části Sítě > Tunnels.

7. Otestujte připojení

  1. V Cloudflare dashboard ↗, přejděte na Sítě > Tunnels a ověřte, že váš tunel je Aktivní.

  2. (Volitelné) Pokud jste nakonfigurovali Access, přejděte do Security > Access > Aplikace a ověřte, že zásada Access povoluje váš e-mail Cloudflare.

  3. Z libovolného zařízení otevřete prohlížeč a přejděte na http_app.<CLOUDFLARE_ZONE> (například http_app.example.com).

    Pokud jste nakonfigurovali Access, zobrazí se přihlašovací stránka Access. Přihlaste se pomocí svého e-mailu Cloudflare.

  4. Mělo by se zobrazit domovská stránka HTTPBin, což potvrzuje, že tunel správně směruje provoz.