Ansible は、インフラを大規模に管理できるソフトウェアです。エージェントレスで、対象へ SSH できることと、対象に Python がインストールされていることだけが必要です。
Ansible は Terraform と組み合わせて、Cloudflare Tunnel のセットアップを効率化します。このガイドでは、Terraform で Google Cloud 上に SSH サーバーをデプロイし、インターネットから利用できる ローカル管理トンネル を作成します。Terraform は、サーバー上で cloudflared をインストールして設定する Ansible playbook を自動実行します。
このガイドの手順を完了するには、次が必要です。
- Google Cloud Project ↗ と、インストールおよび認証済みの GCP CLI ↗。
- Terraform の基礎知識 と インストール済みの Terraform。
- Cloudflare 上のゾーン。
Cloudflare TunnelとDNSの権限を持つ Cloudflare API トークン。
Ansible のインストール手順 ↗ を参照してください。
Terraform と Ansible が GCP サーバーへ接続するには、暗号化されていない SSH キーが必要です。キーがない場合は、次の手順で生成できます。
-
ターミナルを開き、次のコマンドを実行します。
ssh-keygen -t rsa -f ~/.ssh/gcp_ssh -C <username in GCP> -
パスフレーズを求められたら、
Enterキーを 2 回押して空のままにします。Terraform は暗号化された秘密鍵を復号できません。
2 つのファイルが生成されます。秘密鍵の gcp_ssh と、公開鍵の gcp_ssh.pub です。
-
Terraform と Ansible の設定ファイル用フォルダーを作成します。
mkdir ansible-tunnel -
新しいディレクトリへ移動します。
cd ansible-tunnel
次の変数は、GCP と Cloudflare の構成に渡されます。
-
構成ディレクトリに
.tfファイルを作成します。touch variables.tf -
テキストエディターでファイルを開き、次の内容をコピーして貼り付けます。
# 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 }
-
設定ディレクトリに
.tfvarsファイルを作成します。touch terraform.tfvarsファイル名が
terraform.tfvarsであれば、Terraform はこれらの変数を自動的に使います。それ以外の名前の場合は、変数ファイルを手動で渡す必要があります。 -
次の変数を
terraform.tfvarsに追加します。例は自分の値に書き換えてください。cloudflare_zone = "example.com" cloudflare_zone_id = "023e105f4ecef8ad9ca31a8372d0c353" cloudflare_account_id = "372e67954025e0ba6aaa6d586b9e0b59" cloudflare_email = "user@example.com" cloudflare_token = "y3AalHS_E7Vabk3c3lX950F90_Xl7YtjSlzyFn_X" gcp_project_id = "testvm-123" zone = "us-central1-a" machine_type = "e2-medium"
インフラをプロビジョニングするために使う プロバイダー ↗ を宣言します。
-
設定用ディレクトリに
.tfファイルを作成します。touch providers.tf -
次のプロバイダーを
providers.tfに追加します。randomプロバイダーは、トンネルシークレットの生成に使います。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" { }
次の設定は、Cloudflare アカウントの設定を変更します。
-
設定用ディレクトリに
.tfファイルを作成します。touch Cloudflare-config.tf -
次のリソースを
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 = "Ansible 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://localhost:80" }, { service = "http_status:404" } ] } }
次の設定は、GCP 仮想マシンの仕様を定義し、マシンに Python3 をインストールします。Python3 があれば、起動時に スタートアップスクリプト を実行しなくても、Ansible で GCP インスタンスを設定できます。
-
設定用ディレクトリに
.tfファイルを作成します。touch GCP-config.tf -
テキストエディターでファイルを開き、次の例をコピーして貼り付けます。GCP のユーザー名と SSH キーペアは、自分の値に置き換えてください。
# Selects the OS for the GCP VM. data "google_compute_image" "image" { family = "ubuntu-2204-lts" project = "ubuntu-os-cloud" } # Sets up a GCP VM instance. resource "google_compute_instance" "http_server" { name = "ansible-inst" 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 } } scheduling { preemptible = true automatic_restart = false } // Installs Python3 on the VM. provisioner "remote-exec" { inline = [ "sudo apt update", "sudo apt install python3 -y", "echo Done!" ] connection { host = self.network_interface.0.access_config.0.nat_ip user = "<username in GCP>" type = "ssh" private_key= file("<path to private key>") } } provisioner "local-exec" { // If specifying an SSH key and user, add `--private-key <path to private key> -u var.name` command = "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u <username in GCP> --private-key <path to private key> -i ${self.network_interface.0.access_config.0.nat_ip}, playbook.yml" } metadata = { cf-email = var.cloudflare_email cf-zone = var.cloudflare_zone ssh-keys = "<username in GCP>:${file("<path to public key>")}" } depends_on = [ local_file.tf_ansible_vars_file ] }
次の Terraform リソースは、トンネルトークン とその他の変数を tf_ansible_vars_file.yml へエクスポートします。Ansible はこのトンネルトークンを使い、サーバー上で cloudflared を設定して実行します。
-
設定用ディレクトリに新しい
tfファイルを作成します。touch export.tf -
次の内容を
export.tfにコピーして貼り付けます。resource "local_file" "tf_ansible_vars_file" { content = <<-DOC # Ansible vars_file containing variable values from Terraform. tunnel_id: ${cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.id} tunnel_name: ${cloudflare_zero_trust_tunnel_cloudflared.gcp_tunnel.name} tunnel_token: ${data.cloudflare_zero_trust_tunnel_cloudflared_token.gcp_tunnel_token.token} DOC filename = "./tf_ansible_vars_file.yml" }
Ansible playbook は、Ansible がデプロイする構成を宣言する YAML ファイルです。
-
新しい
.ymlファイルを作成します。touch playbook.yml -
テキストエディターでファイルを開き、次の内容をコピーして貼り付けます。
---
- hosts: all
become: yes
# Import tunnel variables into the VM.
vars_files:
- ./tf_ansible_vars_file.yml
# Execute the following commands on the VM.
tasks:
- name: Download the cloudflared Linux package.
shell: wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
- name: Depackage cloudflared.
shell: sudo dpkg -i cloudflared-linux-amd64.deb
- name: Install the tunnel as a systemd service.
shell: "cloudflared service install {{ tunnel_token }}"
- name: Start the tunnel.
systemd:
name: cloudflared
state: started
enabled: true
masked: no
- name: Deploy an example Apache web server on port 80.
shell: apt update && apt -y install apache2
- name: Edit the default Apache index file.
copy:
dest: /var/www/html/index.html
content: |
<!DOCTYPE html>
<html>
<body>
<h1>Hello Cloudflare!</h1>
<p>This page was created for a Cloudflare demo.</p>
</body>
</html>キーワード ↗ は、Ansible が構成をどう実行するかを定義します。上の例では、vars_files キーワードが変数定義の保存場所を指定し、tasks キーワードが Ansible の実行内容を指定します。
モジュール ↗ は、完了するタスクを指定します。この例では、copy モジュールがファイルを作成し、内容を書き込みます。
設定ファイルを作成したら、Terraform でデプロイできます。Ansible のデプロイは、ansible-playbook コマンドが実行されるときに、Terraform のデプロイ内で行われます。
-
設定用ディレクトリを初期化します。
terraform init -
(任意)作成される内容を事前に確認します。
terraform plan -
構成をデプロイします。
terraform apply
GCP インスタンスとトンネルがオンラインになるまで、数分かかることがあります。新しいトンネルは、Cloudflare ダッシュボード の Networking > Tunnels で確認できます。
テストするには、ブラウザーで http://http_app.<CLOUDFLARE_ZONE>.com(例: http_app.example.com)を開きます。Hello Cloudflare! のテストページが表示されます。