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"