はじめに
Cloudflare One(Zero Trust)を組織展開していると、
- WARP クライアントをまだ有効化していない(未導入の)ユーザーは誰か
- WARP を導入済みだが、今この瞬間オフにしているユーザーは誰か
を把握したくなります。ダッシュボードからも一部見られますが、定期的な棚卸しや全社レポートには API での抽出が便利です。
本記事では、Cloudflare の API でこれらを抽出する方法を整理しています。
結論を先に言うと、「過去に WARP を有効化したか」と「今まさに接続中か」は別々の APIで取ります。前者は Access Users API の
gateway_seat、後者は DEX(Digital Experience Monitoring)の fleet-status API です。
全体像:3階層で考える
「Cloudflare One を使っているか」は、粒度の異なる3つの問いに分解できます。それぞれ担当する API が違います。
| 知りたいこと | API | 主なフィールド |
|---|---|---|
| WARP を一度でも有効化したか(静的) | GET /accounts/{id}/access/users |
gateway_seat |
| デバイス登録と最終通信時刻 | GET /accounts/{id}/devices/registrations |
last_seen_at |
| 今まさに WARP が接続中か(デバイス + email 単位) | GET /accounts/{id}/dex/fleet-status/devices |
status / personEmail
|
| 接続状況の全体集計のみ | GET /accounts/{id}/dex/fleet-status/live |
deviceStats.byStatus ほか |
| WARP の ON/OFF・設定変更の履歴 |
GET /accounts/{id}/dex/warp-change-events / Logpush |
Status / UserEmail
|
ポイントは、REST のデバイス API には「現在接続中」を表すフラグが存在しないことです。取れるのは last_seen_at(最後に通信した時刻)まで。リアルタイムに近い接続状態は DEX が担当します。
1. WARP を有効化したか ― Access Users API
GET /accounts/{account_id}/access/users
Zero Trust に登録された各ユーザーの状態を返します。判定に使う主なフィールド:
| フィールド | 意味 | 使い方 |
|---|---|---|
gateway_seat |
WARP クライアントにログイン済みなら true |
false = WARP 未導入
|
active_device_count |
登録済みアクティブデバイス数 |
0 = デバイス未登録 |
access_seat |
Cloudflare Access で認証済みか | Access のみ / WARP なしの切り分け |
last_successful_login |
最終ログイン日時 | 休眠ユーザー判定 |
email / name / uid / seat_uid
|
識別子 | 抽出結果のキー |
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/users?per_page=50" \
-H "Authorization: Bearer $CF_API_TOKEN"
- ページネーション:
page/per_page、フィルタ:email/name/search -
未導入ユーザーの抽出条件:
gateway_seat == false(またはactive_device_count == 0) -
access_seat == true && gateway_seat == falseを見れば「Access は使っているが WARP は未導入」のユーザーをピンポイントで洗い出せます。
注意:このAPIの母集団は「Zero Trust に登録された人」です。まだ一度も登録していない社員まで含めたい場合は、IdP(Azure AD / Okta 等)や
GET /accounts/{id}/membersの全ユーザーと email で突合し、差集合を取ります。
2. 現在の接続状態 ― DEX fleet-status API
「今 WARP が active か」は Digital Experience Monitoring (DEX) の fleet-status エンドポイントで取得します。
① デバイス単位の現在状態(本命)
GET /accounts/{account_id}/dex/fleet-status/devices
| 項目 | 内容 |
|---|---|
status |
現在の接続状態:connected / disconnected / paused / connecting
|
personEmail |
ユーザーのメール(誰のデバイスか特定可能) |
deviceId / deviceName
|
デバイス識別子 |
mode |
WARP モード(warp+doh, proxy 等) |
platform / version / colo / timestamp
|
OS / クライアントバージョン / 接続コロ / 時刻 |
ハマりどころ:from / to が実質必須
ドキュメント上は全パラメータが optional に見えますが、from / to(時間範囲)を付けないと次のエラーになります。
{ "code": 11004, "message": "dex.api.parameter.missing" }
→ from / to を ISO 8601 形式(またはエポックミリ秒)で必ず指定します。source=last_seen を付けると「直近60分の最終状態」、source=hourly で最大7日まで遡及できます。
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/dex/fleet-status/devices?source=last_seen&from=2026-06-23T00:00:00Z&to=2026-06-23T01:00:00Z&per_page=50" \
-H "Authorization: Bearer $CF_API_TOKEN"
抽出としては、status != connected のデバイス(+ personEmail) が「今 WARP が active でない」対象になります。
② 全体集計だけ欲しい場合
GET /accounts/{account_id}/dex/fleet-status/live (必須: since_minutes)
返るのは 集計カウントのみ(deviceStats.byStatus / byColo / byPlatform / byVersion / uniqueDevicesTotal)。個別デバイス情報は含まれません。全体の接続状況サマリ向けです。
③ ON/OFF・設定変更の履歴
-
GET /accounts/{account_id}/dex/warp-change-events… toggle / config 変更イベント - 大量・SIEM 連携なら Logpush のデータセット:
-
dex_device_state_events(Status,Mode,TunnelType,HandshakeLatencyMs(-1 で切断),DeviceID,WarpColoCode…) -
warp_toggle_changes(UserEmail付き)
-
3. 必要な API トークン権限
いずれも Read / Account スコープ でOKです(書き込み不要)。
| 用途 | 必要な権限 |
|---|---|
access/users |
Access: Organizations, Identity Providers, and Groups : Read |
devices/*・dex/*
|
Zero Trust : Read |
発行手順
- ダッシュボード右上のプロフィール → My Profile → API Tokens → Create Token
- Create Custom Token を選択
- 上記2つの権限を追加(Account スコープ)
- Account Resources を対象アカウントに限定
- (任意)Client IP / TTL を制限して発行
4. 抽出ロジックと突合の考え方
2つの API の結果を email をキーに突合し、ユーザーを3分類するのが基本方針です。コードに落とすまでもなく、手順は次の通りです。
-
GET /accounts/{id}/access/usersをpage/per_pageでページネーション取得し、ユーザーごとのgateway_seatを得る。 -
GET /accounts/{id}/dex/fleet-status/devices(source=last_seen+from/to)を取得し、status == connectedのデバイスのpersonEmailを集合に入れる。 - ユーザーを email で照合して分類する。
| 分類 | 条件 |
|---|---|
| 未導入(WARP未ログイン) | gateway_seat == false |
| 接続中 |
gateway_seat == true かつ 現在 connected なデバイスを持つ |
| 導入済みだが現在オフ/未接続 |
gateway_seat == true だが現在接続中のデバイスなし |
CSV に落とす際は、Excel での文字化け対策として UTF-8 BOM + CRLF を付けておくと無難です。
出力イメージ
ユーザー単位の一覧に email / gateway_seat / last_successful_login / 分類結果などを並べると棚卸しが一目で済みます。例えば実際の組織では「導入済みだが現在オフ/未接続:19名」「未導入(WARP未ログイン):4名」といった内訳が得られ、後者の4名が優先的に導入を促すべき対象だと分かります。
まとめ
-
「WARP を有効化したか」 は
access/usersのgateway_seat。falseが未導入。 -
「今まさに接続中か」 は DEX の
dex/fleet-status/devicesのstatus。REST のデバイス API には現在状態フラグがなく、取れるのはlast_seen_atまで。 - DEX の
fleet-status/devicesはfrom/toが実質必須(無いと11004 dex.api.parameter.missing)。 - トークンは Zero Trust : Read と Access: Organizations… : Read の Read 2点でカバー可能。
- 未導入者(
gateway_seat=false)と「導入済みだが現在オフ」(DEX でstatus != connected)を分けて見ると、棚卸しの精度が上がる。
参考
- Cloudflare API Reference: https://developers.cloudflare.com/api/
- Get users(Access Users): https://developers.cloudflare.com/api/resources/zero_trust/subresources/access/subresources/users/methods/list/
- Devices API: https://developers.cloudflare.com/api/resources/zero_trust/subresources/devices/
- DEX(Digital Experience Monitoring): https://developers.cloudflare.com/cloudflare-one/insights/dex/
- Seat management: https://developers.cloudflare.com/cloudflare-one/team-and-resources/users/seat-management/
- API token permissions: https://developers.cloudflare.com/fundamentals/api/reference/permissions/