diff --git a/src/content/docs/cloudflare-one/connections/connect-networks/deployment-guides/terraform.mdx b/src/content/docs/cloudflare-one/connections/connect-networks/deployment-guides/terraform.mdx index afd2e5edaa0eee0..f65d248b53706c4 100644 --- a/src/content/docs/cloudflare-one/connections/connect-networks/deployment-guides/terraform.mdx +++ b/src/content/docs/cloudflare-one/connections/connect-networks/deployment-guides/terraform.mdx @@ -10,7 +10,7 @@ description: Learn how to deploy a Cloudflare Tunnel using Terraform and our lightweight server-side daemon, cloudflared. --- -import { Render } from "~/components"; +import { Tabs, TabItem, Render } from "~/components"; [Terraform](https://www.terraform.io/) is an infrastructure as code software tool that allows you to deploy services from different providers using a standardized configuration syntax. When creating a Terraform configuration file, you define the final state of the configuration rather than the step-by-step procedure. This allows you to easily deploy, modify, and manage your Tunnels alongside your other infrastructure. @@ -26,6 +26,7 @@ To complete the following procedure, you will need: - [A Google Cloud Project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project) - [A zone on Cloudflare](/fundamentals/setup/manage-domains/add-site/) +- Enabled [one-time PIN login](/cloudflare-one/identity/one-time-pin/) or integrated an [identity provider](/cloudflare-one/identity/idp-integration/) ## 1. Install Terraform @@ -45,7 +46,7 @@ Refer to the [Terraform installation guide](https://developer.hashicorp.com/terr [Create an API token](/fundamentals/api/get-started/create-token/) so that Terraform can interact with your Cloudflare account. At minimum, your token should include the following permissions: -| Permission type | Permission | Access level | +| Type | Item | Permission | | --------------- | ------------------------- | ------------ | | Account | Cloudflare Tunnel | Edit | | Account | Access: Apps and Policies | Edit | @@ -77,33 +78,70 @@ You will need to declare the [providers](https://registry.terraform.io/browse/pr 2. Add the following providers to `providers.tf`. The `random` provider is used to generate a tunnel secret. - ```txt - terraform { - required_providers { - cloudflare = { - source = "cloudflare/cloudflare" - version = ">= 4.40.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" { - } - ``` + + + + ```tf + terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + version = ">= 5.3.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" { + } + ``` + + + + + ```tf + 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" { + } + ``` + + + ### Configure Cloudflare resources @@ -117,79 +155,171 @@ The following configuration will modify settings in your Cloudflare account. 2. Add the following resources to `Cloudflare-config.tf`: - ```txt - # Generates a 64-character secret for the tunnel. - # Using `random_password` means the result is treated as sensitive and, thus, - # not displayed in console output. Refer to: https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password - resource "random_password" "tunnel_secret" { - length = 64 - } - - # Creates a new locally-managed tunnel for the GCP VM. - resource "cloudflare_zero_trust_tunnel_cloudflared" "auto_tunnel" { - account_id = var.cloudflare_account_id - name = "Terraform GCP tunnel" - secret = base64sha256(random_password.tunnel_secret.result) - } - - # 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.auto_tunnel.cname}" - type = "CNAME" - proxied = true - } - - # Creates the configuration for the tunnel. - resource "cloudflare_zero_trust_tunnel_cloudflared_config" "auto_tunnel" { - tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.auto_tunnel.id - account_id = var.cloudflare_account_id - config { - ingress_rule { - hostname = "${cloudflare_record.http_app.hostname}" - service = "http://httpbin:8080" - origin_request { - connect_timeout = "2m0s" - access { - required = true - team_name = "myteam" - aud_tag = [cloudflare_zero_trust_access_application.http_app.aud] - } - } - } - ingress_rule { - service = "http_status:404" - } - } - } - - # Creates an Access application to control who can connect. - resource "cloudflare_zero_trust_access_application" "http_app" { - zone_id = var.cloudflare_zone_id - name = "Access application for http_app.${var.cloudflare_zone}" - domain = "http_app.${var.cloudflare_zone}" - session_duration = "1h" - } - - # Creates an Access policy for the application. - resource "cloudflare_zero_trust_access_policy" "http_policy" { - application_id = cloudflare_zero_trust_access_application.http_app.id - zone_id = var.cloudflare_zone_id - name = "Example policy for http_app.${var.cloudflare_zone}" - precedence = "1" - decision = "allow" - include { - email = [var.cloudflare_email] - } - } - ``` - - To learn more about these resources, refer to the [Cloudflare provider documentation](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs). + + + + ```tf + # 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" + tunnel_secret = random_bytes.tunnel_secret.base64 + } + + # 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 public hostname route 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:8080" + }, + { + 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 + } + ] + } + ``` + + + + ```tf + # 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 public hostname route 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:8080" + } + 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] + } + } + ``` + + + +To learn more about these resources, refer to the [Cloudflare provider documentation](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs). ### Configure GCP resources -The following configuration defines the specifications for the GCP virtual machine and creates a startup script to run upon boot. +The following configuration defines the specifications for the GCP virtual machine and configures a startup script to run upon boot. 1. In your configuration directory, create a `.tf` file: @@ -199,47 +329,99 @@ The following configuration defines the specifications for the GCP virtual machi 2. Add the following content to `GCP-config.tf`: - ```txt - # Selects the OS for the GCP VM. - data "google_compute_image" "image" { - family = "ubuntu-minimal-2004-lts" - project = "ubuntu-os-cloud" - } - - # Sets up a GCP VM instance. - resource "google_compute_instance" "origin" { - 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 the instance ephemeral - scheduling { - preemptible = true - automatic_restart = false - } - // Configures the VM to run a startup script that takes in the Terraform variables. - metadata_startup_script = templatefile("./install-tunnel.tftpl", - { - tunnel_token = cloudflare_zero_trust_tunnel_cloudflared.auto_tunnel.tunnel_token - }) - } - ``` + + + + ```tf + # OS the server will use + data "google_compute_image" "image" { + family = "ubuntu-minimal-2004-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 + }) + } + ``` + + + + + ```tf + # OS the server will use + data "google_compute_image" "image" { + family = "ubuntu-minimal-2004-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 + }) + } + ``` + + ### Create a startup script -The following script will install `cloudflared`, create a permissions and configuration file for the tunnel, and set up the tunnel to run as a service. This example also installs a lightweight HTTP application that you can use to test connectivity. +The following script will install `cloudflared` and run the tunnel as a service. This example also installs a lightweight HTTP application that you can use to test connectivity. + +:::note +If you would prefer to manually install the tunnel, refer to [Install and run the tunnel](/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel-api/#4-install-and-run-the-tunnel). +::: 1. In your configuration directory, create a Terraform template file: @@ -286,9 +468,9 @@ The following script will install `cloudflared`, create a permissions and config -It may take several minutes for the GCP instance and tunnel to come online. You can view your new tunnel, Access application, and Access policy in [Zero Trust](https://one.dash.cloudflare.com). The new DNS records are available in the [Cloudflare dashboard](https://dash.cloudflare.com). +It may take several minutes for the GCP instance and tunnel to come online. You can view your new tunnel, Access application, and Access policy in [Zero Trust](https://one.dash.cloudflare.com). The new DNS records are available in the [Cloudflare dashboard](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/). -:::note +:::note[Remove Terraform resources] If you need to roll back the configuration, run `terraform destroy` to delete everything created through Terraform. Both `terraform apply` and `terraform destroy` prompt for user input before applying the changes. To run without requiring user input, you can add the `-auto-approve` flag to the command. ::: @@ -299,7 +481,7 @@ If you need to roll back the configuration, run `terraform destroy` to delete ev 2. In **Access** > **Applications**, verify that your Cloudflare email is allowed by the Access policy. -3. From any device, open a browser and go to `http_app.` (for example, `http_app.example.com`). +3. From any device, open a browser and go to `http_app.` (for example, `http_app.example.com`). You will see the Access login page if you have not recently logged in. diff --git a/src/content/docs/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel-api.mdx b/src/content/docs/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel-api.mdx index e445b2188b12408..31224cab5a3ed31 100644 --- a/src/content/docs/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel-api.mdx +++ b/src/content/docs/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel-api.mdx @@ -142,7 +142,17 @@ To configure Zero Trust policies and connect as a user, refer to [Connect privat Install `cloudflared` on your server and run the tunnel using the `token` value obtained in [2. Create a tunnel](#2-create-a-tunnel). You can also get the tunnel token using the [Cloudflare Tunnel token](/api/resources/zero_trust/subresources/tunnels/subresources/cloudflared/subresources/token/methods/get/) endpoint. - + + +1. [Download and install](https://pkg.cloudflare.com/index.html) `cloudflared`. + +2. Run the following command: + + ```sh + sudo cloudflared service install + ``` + + 1. [Download and install](/cloudflare-one/connections/connect-networks/downloads/#windows) `cloudflared`. @@ -158,16 +168,6 @@ Install `cloudflared` on your server and run the tunnel using the `token` value 1. [Download and install](/cloudflare-one/connections/connect-networks/downloads/#macos) `cloudflared`. -2. Run the following command: - - ```sh - sudo cloudflared service install - ``` - - - -1. [Download and install](https://pkg.cloudflare.com/index.html) `cloudflared`. - 2. Run the following command: ```sh diff --git a/src/content/partials/cloudflare-one/terraform/input-variables.mdx b/src/content/partials/cloudflare-one/terraform/input-variables.mdx index 4016ef7cbd38883..b7a907b5a5f1fb8 100644 --- a/src/content/partials/cloudflare-one/terraform/input-variables.mdx +++ b/src/content/partials/cloudflare-one/terraform/input-variables.mdx @@ -12,7 +12,7 @@ The following variables will be passed into your GCP and Cloudflare configuratio 2. Open the file in a text editor and copy and paste the following: - ```txt + ```tf # GCP variables variable "gcp_project_id" { description = "Google Cloud Platform (GCP) project ID" @@ -53,7 +53,7 @@ The following variables will be passed into your GCP and Cloudflare configuratio } variable "cloudflare_token" { - description = "Cloudflare API token created at https://dash.cloudflare.com/profile/api-tokens" + description = "Cloudflare API token" type = string sensitive = true } diff --git a/src/content/partials/cloudflare-one/terraform/variable-values.mdx b/src/content/partials/cloudflare-one/terraform/variable-values.mdx index 4ddd1831e068950..2afea4253a0495b 100644 --- a/src/content/partials/cloudflare-one/terraform/variable-values.mdx +++ b/src/content/partials/cloudflare-one/terraform/variable-values.mdx @@ -12,7 +12,7 @@ 2. Add the following variables to `terraform.tfvars`. Be sure to modify the example with your own values. - ```txt + ```tfvars cloudflare_zone = "example.com" cloudflare_zone_id = "023e105f4ecef8ad9ca31a8372d0c353" cloudflare_account_id = "372e67954025e0ba6aaa6d586b9e0b59"