【連携編】Windows 11 WSL2 で始める Google Cloud + Terraform + Ansible 環境ガイド

Terraform Ansible inventory 自動生成

【連携編】Google Cloud + Terraform + Ansible 環境ガイド

WSL2 + Google Cloud + Terraform + Ansible 連携

前回のガイドで、WSL2 (Ubuntu) 上に環境は整いました。ですので今回はより具体的な連携について記述していきたいと思います。

本稿では、Terraformが定義したインフラの「完成図」を、Ansibleが解釈可能な「名簿(Inventory)」へ自動翻訳する仕組みを構築します。これにより、IPアドレスの手動転記という不条理な作業を排除し、構成情報の「唯一の真実(SSOT)」を維持します。

WSL2からIdentity-Aware Proxy (IAP)を経由し、OS Loginで認証してCompute Engineへ接続する、TerraformとAnsibleの連携構成図。
【図解】IAPによるセキュアな経路確立と、OS Loginによる認証・認可の分離構造
graph TD
    WSL2[WSL2 / Ansible] -- "gcloud IAP Tunnel" --> IAP[Identity-Aware Proxy]
    IAP -- "Port 22 (Internal)" --> GCE[Compute Engine]
    GCE -- "Verify" --> OSLogin[OS Login / IAM]
    
    subgraph "IaC Control Plane"
        TF[Terraform] -- "1. Define Output" --> Out[Output JSON]
        Out -- "2. Parse" --> Inv[Dynamic Inventory]
    end

この構成が解決する課題

  • 踏み台サーバーの完全排除: 外部IPを持たないインスタンスへ、IAP経由で直接Ansibleを流し込みます。
  • SSH鍵の管理放棄: OS Loginの有効化により、公開鍵の手動登録を不要にします。
  • 動的スケーリングへの追従: 台数変更時もAnsible側の設定変更は一切不要です。

1. Terraform × Ansible 連携の設計パターン比較

「動けばいい」ではなく、運用に耐えうる接続方式を論理的に選定します。

方式評価採用可否の理由
tfstate 直接参照状態ファイルの破壊リスクと、ツール間の密結合を招くため非推奨。
GCP Inventory Plugin正統派だが、IAM設計とサービスアカウントの権限管理が複雑化しやすい。
Terraform Output 連携本ガイドで採用。明示的なインターフェースにより、疎結合で堅牢。

💡 LOGIC:
インフラの「出力(Output)」を契約としてAnsibleに渡すことで、Terraform内部の複雑なリソース構造からAnsibleを解放します。

2. Terraform実装:セキュアなOS Login構成

外部IPを完全に排除し、Google Cloudの認証基盤を利用する「本番準拠」の構成をとります。

[PATH] terraform/main.tf
resource "google_compute_instance" "web" {
  count        = 1
  name         = "web-server-${count.index}"
  machine_type = "e2-micro"
  
  metadata = {
    # 💡 LOGIC: OS Loginを有効化し、SSH鍵管理をGoogle Cloud側に委譲
    enable-oslogin = "TRUE"
  }

  network_interface {
    network = "default"
    # ⚠️ CAUTION: 本番環境準拠。外部IP(access_config)は付与せず、IAP経由の接続を前提とする
  }
}

output "ansible_inventory_data" {
  value = {
    web_servers = [
      for instance in google_compute_instance.web : {
        name       = instance.name
        # 💡 LOGIC: 外部IPを持たないため、内部IPのみを出力
        private_ip = instance.network_interface[0].network_ip
        zone       = instance.zone
      }
    ]
  }
}

3. Ansible実装:Dynamic Inventory によるデータ変換

TerraformのJSON出力をパースし、Ansibleが解釈できる形式へ変換します。

[PATH] ansible/inventory/tf_inventory.py
#!/usr/bin/env python3
import json
import subprocess

def get_tf_output():
    # terraform outputをJSON形式で取得
    result = subprocess.check_output(["terraform", "-chdir=../../terraform", "output", "-json"])
    return json.loads(result)

def build_inventory(tf_data):
    # 💡 LOGIC: このインベントリは Ansible 実行時に「毎回オンメモリで生成」されます。
    # Terraform apply 後にファイルを手動更新したり、Gitコミットしたりする必要はありません。
    raw_data = tf_data.get("ansible_inventory_data", {}).get("value", {})
    inventory = {"_meta": {"hostvars": {}}}
    
    for group, hosts in raw_data.items():
        inventory[group] = {"hosts": []}
        for host in hosts:
            hostname = host["name"]
            inventory[group]["hosts"].append(hostname)
            # 💡 LOGIC: ansible_hostにはインスタンス名を指定。
            # IAPトンネルのProxyCommandが名前解決をGCE側で行うため、本構成で疎通可能です。
            inventory["_meta"]["hostvars"][hostname] = {
                "ansible_host": hostname,
                "internal_ip": host["private_ip"],
                "gcp_zone": host["zone"]
            }
    return inventory

if __name__ == "__main__":
    print(json.dumps(build_inventory(get_tf_output())))

4. 実装の急所:IAPトンネルと OS Login ユーザー

OS Login環境ではユーザー名が動的に決まるため、固定値を避け、gcloudコマンドの結果を利用します。

[PATH] ansible/ansible.cfg
[defaults]
inventory = ./inventory/tf_inventory.py
host_key_checking = False

[ssh_connection]
# 💡 LOGIC: ProxyCommand内の %h はAnsibleインベントリの ansible_host(インスタンス名)に置換されます。
# ※ IAPトンネルの確立には、WSL2側に gcloud CLI がインストールされている必要があります。
ssh_args = -o ProxyCommand="gcloud compute start-iap-tunnel %h 22 --listen-on-stdin --project=[PROJECT_ID] --zone=[ZONE]"

5. ⚠️ 実務上の失敗回避:運用アンチパターン

セキュアなインフラ構成は、わずかな理解不足で「接続不能」の迷宮に陥ります。実務で遭遇しやすい3つの罠を整理します。

罠①:IAP と OS Login の「役割」を混同する

「必要な権限を付与したのにログインできない」トラブルの多くは、IAP と OS Login の責務を混同していることに起因します。

項目役割(責務)失敗時の典型的な挙動
IAP 権限VMまでの「通路」を確保(ネットワーク層)接続タイムアウト / Connection refused
OS LoginLinuxユーザーとして認証(OS層)Permission denied (publickey)

💡 LOGIC
IAP はネットワークのゲートウェイを開くだけです。VM 内でコマンドを実行するには、OS Login によるユーザー識別と SSH 鍵検証が別途必要です。

罠②:名前解決ができないと誤解する

WSL2 のローカル環境から ping [インスタンス名] を実行しても応答はありませんが、Ansible 経由の SSH は正常に動作します。

💡 LOGIC
ansible.cfg の ProxyCommand に指定した gcloud compute start-iap-tunnel が、Google Cloud API を通じてインスタンス名の解決とトンネル確立を同時に実行します。

罠③:OS Login 有効化直後の「反映ラグ」

Terraform で enable-oslogin = “TRUE” を適用した直後、数分間は SSH 接続が拒否される場合があります。

⚠️ CAUTION
これは Google Cloud 内部の同期遅延です。設定ミスを疑う前に、深呼吸して3分待つことが実務上の正解です。

6. IAM最小権限のTerraform定義

最小権限の原則(Least Privilege)に基づき、3つの Role を Terraform で定義します。

[PATH] terraform/iam.tf
# 1. IAPトンネルを通るための「通路」権限
resource "google_project_iam_member" "iap_accessor" {
  project = var.project_id
  role    = "roles/iap.tunnelResourceAccessor"
  member  = "user:${var.admin_email}"
}

# 2. OS Loginでログインするための「鍵」権限
# ※ 本ガイドでは権限を最小化するため、sudo権限のない roles/compute.osLogin を採用しています。
resource "google_project_iam_member" "os_login" {
  project = var.project_id
  role    = "roles/compute.osLogin"
  member  = "user:${var.admin_email}"
}

# 3. インスタンスのサービスアカウントを操作する権限
# 💡 LOGIC: IAP/OS Loginはプロジェクト全体へ作用するため project IAM、
# ServiceAccountUserは特定のSAに対する操作に限定するため SA IAM を適用し、スコープを最小化します。
resource "google_service_account_iam_member" "sa_user" {
  service_account_id = google_service_account.instance_sa.name
  role               = "roles/iam.serviceAccountUser"
  member             = "user:${var.admin_email}"
}

7. deploy.sh:一気通貫の実行スクリプト

ここまでの設計・IAM・接続を一つのコマンドに束ね、成功体験を固定化します。

[PATH] deploy.sh
#!/bin/bash
set -e 

# 💡 LOGIC: 環境変数による OS Login ユーザー名の動的解決
export OS_LOGIN_USER=$(gcloud compute os-login describe-profile --format='value(posixAccounts[0].username)')

echo "--- Step 1: Terraform によるインフラ構築と権限付与 ---"
cd terraform
terraform apply -auto-approve

echo "--- Step 2: Ansible による構成管理の実行 ---"
cd ../ansible
# OS Loginの反映ラグ(罠③)を考慮し、ConnectionAttemptsでリトライを担保
ansible-playbook -i inventory/tf_inventory.py site.yml \
    -e "ansible_user=${OS_LOGIN_USER}" \
    --ssh-common-args="-o ConnectionAttempts=5"

echo "--- Deployment Successful! ---"

Google Cloud 公式リファレンス

Terraform / Ansible 公式リファレンス


お問い合わせ・ご相談窓口

ITインフラ、Web活用、セキュリティのことでお悩みなら、ぜひご相談ください。貴社の課題に合わせ、最適な解決策をご提案します。

ランサーズ / クラウドワークスからのご依頼も受付中

Lancers
Crowd Works
メールアドレス
お問合せ内容をご記入ください。

株式会社 十志 / JUICY LTD.をもっと見る

購読すると最新の投稿がメールで送信されます。


コメント

コメントを残す

JUICY LTD.をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む