自宅のDocker Swarmで稼働させているダッシュボードなどの各種Webサービス。外出先からアクセスするためにCloudflare Tunnelを使っている人は多いと思うが、そのまま公開してBasic認証やアプリ側の独自パスワードで守る運用は、セキュリティ的にも管理の手間としても少し不安が残る。

今回は、VPNを使わずに、Cloudflare Access(Zero Trust)とGoogle認証(IdP)を組み合わせたアクセス制御を導入し、さらにその設定のすべてをTerraformでコード化(IaC)した。

結論から言うと、GUIでの手作業を減らしつつ、強力なセキュリティと利便性を両立できる非常に実用的な構成です。

1. なぜVPNやアプリ独自認証をやめるのか?

これまでの自宅サーバー公開における課題は大きく2つあった。

  • VPNの運用が面倒: ルーターのポートを開けたり、スマホやPCごとに専用のVPNソフトを入れたりするのは手間がかかる。
  • パスワード管理の手間: サービスを立ち上げるたびに、独自のパスワードを設定・管理するのは面倒。

Cloudflare Accessを導入すれば、リクエストが自宅のネットワークに到達する前(Cloudflareのサーバー側)でGoogleアカウントなどの認証を強制できる。未許可のユーザーは自宅ネットワークにすら到達できないため、外部からの無差別スキャンに対する不安も無くなる。

2. アーキテクチャと要件

  • インフラ: Docker Swarm + Cloudflare Tunnel(ルーティング設定済み)
  • 認証基盤(IdP): Google OAuth 2.0
  • 管理手法: Terraform(Cloudflare Provider)

3. 実装手順:Google CloudでIdPの準備

まずはGoogle Cloud Consoleで、Cloudflare Accessからの認証要求を受け付けるための「クライアントID」と「シークレット」を発行する。

  1. 「API とサービス」 > 「OAuth 同意画面」を作成。
  2. 「認証情報」から「OAuth クライアント ID(ウェブ アプリケーション)」を作成。
  3. 「承認済みのリダイレクト URI」に https://<自分のチームドメイン>.cloudflareaccess.com/cdn-cgi/access/callback を登録。

これでGoogle側の準備は完了。発行されたIDとシークレットを控えておく。

4. Terraformによるコード化

ダッシュボードから手動で設定することも可能だが、再構築しやすくするためにすべてTerraformで記述する。

# 1. Google IdPの登録
resource "cloudflare_access_identity_provider" "google_oauth" {
  account_id = var.cloudflare_account_id
  name       = "Google Login"
  type       = "google"
  
  config {
    client_id     = var.google_client_id
    client_secret = var.google_client_secret
  }
}

# 2. Access Application (保護対象の定義)
resource "cloudflare_access_application" "internal_app" {
  zone_id                   = var.cloudflare_zone_id
  name                      = "Internal Web Service"
  domain                    = "dashboard.example.com" # Tunnelで公開しているドメイン
  session_duration          = "24h"
  auto_redirect_to_identity = true # ログイン方法の選択画面をスキップ
}

# 3. Access Policy (アクセス許可ルールの定義)
resource "cloudflare_access_policy" "admin_policy" {
  application_id = cloudflare_access_application.internal_app.id
  zone_id        = var.cloudflare_zone_id
  name           = "Allow Admin Access"
  precedence     = "1"
  decision       = "allow"

  # 許可するユーザーを指定
  include {
    email = ["[email protected]"] 
  }
}

これを terraform apply するだけで、アクセス制御の設定が完了する。

5. 実際の挙動

設定後、シークレットブラウザでURLにアクセスすると、すぐにGoogleのログイン画面にリダイレクトされる。自分のアカウントで認証した時だけ対象のサービスが表示され、それ以外のアクセスはCloudflare側で完璧に遮断されました。

auto_redirect_to_identity = true を設定したことで、Cloudflareのログイン画面を挟まずに直接Google認証へ飛べるため、アクセスの際の手間も少ない。

今後はSwarmに新しいサービスを追加する際も、Terraformのコードを数行書き換えるだけで、即座にGoogle認証付きのサービスを公開できる。手軽に安全な環境を作りたい人にはおすすめの構成です。