はじめに
「VPNを廃止したい」「ZTNAを導入したい」――中小企業の情シス担当者からよく聞く声です。
ただ、エンタープライズ向けZTNAソリューションは高価で、中小企業ではオーバースペック。一方、**Cloudflare One(旧 Cloudflare for Teams)**は、50席まで無料枠で使え、それ以上でも $7/user/month から導入できる中小企業フレンドリーな選択肢です。
本記事では、Cloudflare Access + Tunnel で社内Webアプリ・SSH・RDP・社内ネットワーク全体を脱VPN化する実装を、コード付きで解説します。
全体構成
┌─────────────┐ ┌──────────────────┐
│ Entra ID │ ◄────── OIDC ───►│ Cloudflare │
│ (IdP) │ │ Access │
└─────────────┘ └──────────────────┘
▲ HTTPS/SSH/RDP
│
│
┌──────────────────┐ │
│ リモートユーザー │ ◄───────────── │
│ (Win/Mac/Mobile) │ │
└──────────────────┘ │
│
│ Cloudflare Tunnel
│ (cloudflared on-prem)
│
┌──────────────────────────┐
│ オンプレ社内ネットワーク │
│ - 業務サーバー │
│ - ファイルサーバー │
│ - 管理画面 (192.168.x) │
└──────────────────────────┘
前提条件
- Cloudflareアカウント
- ドメインがCloudflareでDNS管理されている
- Entra ID(または Google Workspace, Okta)が利用可能
- オンプレ側にLinuxサーバー(Ubuntu 22.04想定)
ステップ1: Cloudflare Zero Trust の有効化
- Cloudflareダッシュボード → Zero Trust メニュー
- Team Name を設定(例:
example-corp)→example-corp.cloudflareaccess.com - プランを選択(50席未満なら Free)
ステップ2: IdP(Entra ID)との連携
Cloudflare Access は単独のユーザー管理ではなく、Entra ID / Google / Okta と統合して使います。
Entra IDアプリ登録
Azure ポータルから:
- Entra ID → App registrations → New registration
- Name:
Cloudflare Zero Trust - Redirect URI:
https://<team-name>.cloudflareaccess.com/cdn-cgi/access/callback - API permissions に以下を追加:
- Microsoft Graph → Delegated:
email,openid,profile,User.Read,GroupMember.Read.All
- Microsoft Graph → Delegated:
- Certificates & secrets → New client secret を作成
- Application (client) ID, Directory (tenant) ID, Client Secret をメモ
Cloudflare側の設定
Zero Trust ダッシュボード → Settings → Authentication → Add new
provider: "Azure AD (Entra ID)"
application_id: "<APPLICATION-ID>"
client_secret: "<CLIENT-SECRET>"
directory_id: "<TENANT-ID>"
support_groups: true
「Test」をクリックして接続成功を確認。
ステップ3: Cloudflare Tunnel のセットアップ
社内ネットワークの公開を、インバウンドポート開放なしで実現します。
cloudflared のインストール(Ubuntu)
# Cloudflare GPG key追加
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
# repository追加
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update
sudo apt install cloudflared
Tunnel作成
# Cloudflareに認証
cloudflared tunnel login
# → ブラウザでドメインを選択
# Tunnel作成
cloudflared tunnel create office-tunnel
# Tunnel ID を確認
cloudflared tunnel list
config.yml作成
# /etc/cloudflared/config.yml
tunnel: <TUNNEL-ID>
credentials-file: /etc/cloudflared/<TUNNEL-ID>.json
ingress:
# 社内Webアプリ
- hostname: crm.internal.example.com
service: http://192.168.1.10:8080
# 管理画面
- hostname: admin.internal.example.com
service: http://192.168.1.20:9000
# SSH
- hostname: ssh.internal.example.com
service: ssh://192.168.1.30:22
# RDPサーバー
- hostname: rdp.internal.example.com
service: rdp://192.168.1.40:3389
# 社内ネットワーク全体(WARP経由のフルアクセス)
- service: http_status:404
warp-routing:
enabled: true
DNS設定
# 各ホスト名をTunnelに紐付け
cloudflared tunnel route dns office-tunnel crm.internal.example.com
cloudflared tunnel route dns office-tunnel admin.internal.example.com
cloudflared tunnel route dns office-tunnel ssh.internal.example.com
cloudflared tunnel route dns office-tunnel rdp.internal.example.com
# 社内ネットワークIPレンジをルーティング
cloudflared tunnel route ip add 192.168.1.0/24 office-tunnel
サービス化
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# ステータス確認
sudo systemctl status cloudflared
ステップ4: Access ポリシーの設定
Zero Trust ダッシュボード → Access → Applications → Add an application
Webアプリのポリシー例:CRMシステム
application_type: "Self-hosted"
application_name: "CRM System"
session_duration: "8h"
application_domain: "crm.internal.example.com"
policies:
- name: "営業部のアクセス許可"
action: "Allow"
include:
- identity_provider: "Azure AD"
groups: ["営業部"]
- identity_provider: "Azure AD"
groups: ["IT管理者"]
require:
- purpose_justification: false
- mfa_method: "any"
exclude: []
- name: "コンプライアンス違反端末ブロック"
action: "Block"
include:
- everyone: true
require:
- device_posture:
- "Intune Compliance: Non-compliant"
SSH / RDP のポリシー例
application_type: "Self-hosted"
application_name: "Production SSH"
session_duration: "1h" # 短めに設定
policies:
- name: "SREチーム + MFA + 日本国内"
action: "Allow"
include:
- identity_provider: "Azure AD"
groups: ["SRE Team"]
require:
- country: ["JP"]
- mfa_method: "any"
- device_posture:
- "Intune Compliance: Compliant"
ステップ5: WARP クライアント(フルネットワークアクセス)
Webアプリ単位ではなく、社内ネットワーク全体へのアクセスを提供する場合、WARPクライアントを使います。
WARP クライアント配布
Intune経由でWindows向けに自動配布する例:
# Intune Win32 アプリの構成
# 1. cloudflare-warp-installer.msi をパッケージ化
# 2. 検出ルール
$installPath = "C:\Program Files\Cloudflare\Cloudflare WARP\Cloudflare WARP.exe"
# Intune Install Command
msiexec /i Cloudflare_WARP.msi /quiet ORGANIZATION="example-corp" SERVICE_MODE="warp"
WARP用Device Enrollment Permissions
Zero Trust ダッシュボード → Settings → WARP Client → Device enrollment permissions
policy:
name: "全社員 - Entra ID認証"
rule:
include:
- identity_provider: "Azure AD"
emails_ending_in: "@example.com"
require:
- mfa: true
Split Tunnel設定
社内リソースのみVPNライクにルーティングし、その他はインターネット直接:
split_tunnel_mode: "Include" # 指定したIPのみWARP経由
include_ips:
- "192.168.1.0/24" # オンプレ社内LAN
- "10.0.0.0/8" # オンプレデータセンター
ステップ6: 既存VPNからの段階移行
移行計画(6ヶ月想定)
| Month | やること |
|---|---|
| 1 | Cloudflare Tunnel構築、5アプリ程度をAccessで公開 |
| 2 | 営業・サポート部門にWARP配布、Webアプリは脱VPN |
| 3 | SSH/RDPもAccessに切り替え(SREチーム) |
| 4 | ファイル共有もAccess + WARP経由に |
| 5 | VPNアクセス対象を段階削減(ユーザー単位で切替) |
| 6 | VPN完全廃止、Cloudflare Access のみ |
VPNサーバー側の段階制限
各月の終わりに、VPN接続を許可するユーザーグループを縮小していきます:
# FortiGate例: 月次でVPN許可グループを縮小
config user group
edit "VPN_Users"
unset member
set member <縮小したメンバーグループ>
next
end
ステップ7: ログ・監視
Cloudflare Logpush
すべてのAccessログをS3 / Azure Blob / Splunk等にプッシュ:
# Cloudflare API でLogpushジョブ作成
curl -X POST "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT-ID>/logpush/jobs" \
-H "Authorization: Bearer <API-TOKEN>" \
-H "Content-Type: application/json" \
--data '{
"name": "access-audit-logs",
"destination_conf": "s3://bucket-name/logs/{DATE}?region=ap-northeast-1",
"dataset": "access_requests",
"enabled": true,
"filter": "",
"output_options": {
"field_names": ["timestamp", "user_email", "app_uid", "action", "ip_address", "country"]
}
}'
SIEM連携
CloudflareログをMicrosoft Sentinel等のSIEMに送り、相関分析。
運用上のTips
Tips 1: cloudflaredの冗長化
オンプレ側のcloudflaredはSPOFになりがちです。2台以上で同じTunnel IDを動かすことで自動的に冗長化できます。
# 2台目のサーバーでも同じcredentials-fileを使う
sudo cp /etc/cloudflared/<TUNNEL-ID>.json /etc/cloudflared/<TUNNEL-ID>.json
sudo systemctl start cloudflared
# → 自動的にLoad Balancingされる
Tips 2: ポリシーは「初期は緩く、段階的に厳しく」
最初から「日本国内のみ・コンプライアンス端末のみ」とすると、運用初期に問題が頻発します。
Month 1: 認証のみ
Month 2: + MFA
Month 3: + 国判定
Month 4: + デバイスコンプライアンス
Tips 3: BypassとAllowの違いを理解する
- Allow: 認証OK+条件OKでアクセス許可
- Bypass: 認証なしで通過(公開コンテンツ用、慎重に)
Tips 4: コスト最適化
50席を超えた段階で課金開始ですが、Free Plan 50席 → Pay 50席以上の判断は、
- 社員数50未満ならFreeで継続
- それ以上ならStandard $7/user
- 大規模・コンプライアンス重視ならPremium $10/user
トラブルシューティング
Tunnel接続が失敗する
# cloudflared のログ確認
sudo journalctl -u cloudflared -f
# 接続テスト
cloudflared tunnel info office-tunnel
よくある原因:
- 設定ファイルのYAMLシンタックスエラー
- ホスト側ファイアウォールで443/UDPがブロック
- credentials-fileのパス間違い
Entra ID連携でユーザーが見えない
- Entra ID側のAPI permissionsで
GroupMember.Read.Allを Admin consent済みか確認 - Cloudflare側のSCIM設定(オプション)でグループ同期
WARPが繋がらない
- WARPクライアントが有効になっているか(タスクトレイ確認)
- Device enrollment policyに該当しているか
- 企業内DNSと競合していないか
まとめ
Cloudflare Access + Tunnel は、中小企業が現実的に始められる脱VPN実装として優れた選択肢です。
- ハードウェア不要
- 段階移行可能
- 50席まで無料、それ以上もリーズナブル
- Entra ID等の既存IdPと統合可能
VPNゼロデイ脆弱性のリスクや、ラテラルムーブメントへの構造的な弱点を考えると、2026年現在、VPN継続のコストは見えにくくなっています。
著者
亀田 英佑 / 株式会社BTNコンサルティング 代表取締役
中小企業向け情シスアウトソーシング「情シス365」運営
Cloudflare ZeroTrust 設計・脱VPN支援を多数遂行。50〜500名規模の中小企業に最適な設計を提案します。