てくなべ (tekunabe)

ansible / network automation / 学習メモ

Cloudflare Zero Trust を API で操作してみた(トークン作成・Gateway ポリシー取得・追加)

この記事は エーピーコミュニケーションズ Advent Calendar 2022 の1日目の記事です。

はじめに

Cloudflare Zero Trust が 50ユーザーまで無料というプランがあるとのことで、試すにちょうどいいと思って少し触っていました。

触ってまもなく、API あるかな?どんな感じかな?と気になったので試してみました。

API を試す対象は Gateway のポリシー操作

試す機能の対象は、Gateway にしました。

SWG (Secure Web Gateway)に分類されるものでしょうか。UTM やコンテンツフィルター的なものをクラウド上のサービスとして利用できるもの、と捉えています。

(ゼロトラスト自身に詳しくないので間違っていたらすみません)

Cloudflare Zero Trust のサービスの概要や設定手順は、公式以外では以下の記事を参考にさせていただきました。ありがとうございます。

Gateway の機能のうち、HTTP によるポリシーをAPIで操作してみます。

なお、今回の環境では TLS decryption は有効化してあります。


下調べ・準備

API を叩くぞというときに、認証はどうやるのか、権限はどうなってるのかなどの基本的なお作法を知るのは避けて通れないですよね。個人的にはこのフェーズがなかなか苦手です・・・。なので少し細かく書き残しておきます。

API ドキュメント

Cloudflare の API 系ドキュメントは以下のページが見つかりました。こちらに各エンドポイントの説明やお作法などが掲載されていました。ドキュメントがしっかりしているのは助かりますね。

内容 URL
お作法 https://developers.cloudflare.com/fundamentals/api/
リファレンス https://developers.cloudflare.com/api
Cloudflare Zero Trust のドキュメントの API and Terraform https://developers.cloudflare.com/cloudflare-one/api-terraform/
Cloudflare Zero Trust 自体のドキュメント https://developers.cloudflare.com/cloudflare-one/

なお、リファレンは最初 https://api.cloudflare.com/ の方にたどり着きましたが、https://api.cloudflare.com/ は古くて、2023 年のはじめに非推奨になるようです。なので、特に理由がなければ 新しい https://developers.cloudflare.com/api を参照するのが良さそうです。ただ、古い方にはその操作がどのプランでできるか明記がありますが、新しい方には見当たりませんでした。

現在は version 4.0.0 というバージョンで、エンドポイントの Base URL は https://api.cloudflare.com/client/v4 とのことです。

トークンの作成

Create an API token を参考にしながら、API リクエストに必要なトークンを作成します。

  1. https://dash.cloudflare.com/ にログインし、右上のアイコンをクリックして表示されたメニューの My Profile をクリックします
  2. 左メニューから API Tokens をクリックします
    API Token をクリック
  3. Create Token をクリックします
    Create Token をクリック
  4. Custom token セクションの Create Custom Token 欄の Get started をクリックします(Zero Trust の操作に該当するちょうどいいテンプレートがないため)
    Create Custom Token の Get started をクリック
  5. PermissionsAccountZero TrustEdit をそれぞれ選択し、ページ下部の Continue to summary をクリックします
    • API token permissionsには、Zero Trust が見当たりませんが、おそらくこの設定で、GET も POST もいけるだろうという目論見です
    • 他にも、アカウントや IP アドレス制限、TTLを制限できるようですが、とりあえずデフォルトのままで試します
      ポリシー設定を入力
  6. 確認画面が表示されるので Create Token をクリックします
    Create Token をクリック
  7. トークンが表示されるので、後で使うために何かに控えておきます
    トークンを控える

ここまでで、トークンが作成できました。トークン作成画面の最後で、curl によるトークンの正常性確認コマンドが例示されていました。

(Base URL)/user/tokens/verify というエンドポイントを利用するようです。

例示されている他コマンドに少しだけ手を加えて実行してみます。

ここではトークンを dummy_token_xxxxxxxxxxxxxxxxxxxxxxxxxxxx とします。

curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
     -H "Authorization: Bearer dummy_token_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     -H "Content-Type:application/json" | jq .

実行結果(正常)は以下のとおりです。ステータスコード200 でした。

{
  "result": {
    "id": "6d9448f698dd3873fc3b603e3b0e0507",
    "status": "active"
  },
  "success": true,
  "errors": [],
  "messages": [
    {
      "code": 10000,
      "message": "This API Token is valid and active",
      "type": null
    }
  ]

なお、意図的に誤ったトークンを指定すると以下のようなエラーになりました。ステータスコード400 でした。

{
  "success": false,
  "errors": [
    {
      "code": 6003,
      "message": "Invalid request headers",
      "error_chain": [
        {
          "code": 6111,
          "message": "Invalid format for Authorization header"
        }
      ]
    }
  ],
  "messages": [],
  "result": null
}

ここまでで、API を利用するための最低限の準備が無事にできたようです。


おためし

Gateway のポリシーを API で参照、設定する操作をためします。

GET: ポリシーの一覧表示

Gateway のポリシーを参照する方法を API ドキュメントで調べるべく、Policy / Policies という言葉を探しましたが、当初は分かりませんでした。やりたいことは Zero Trust Gateway Rules という括りにありました。

Gateway のポリシーの一覧表示のメソッドとエンドポイントは以下のとおりです。

GET https://api.cloudflare.com/client/v4/accounts/{identifier}/gateway/rules

ドキュメントはこちら。 Cloudflare API Documentation

ちょっと準備に逆戻り

エンドポイントのうち、{identifier} の部分は何を指定するのか分かりませんでした。accounts/ のあとの {identifier} なのでアカウントの識別子的なものを指定するのだと思いました。そうえいば、Create an API token のページの前提条件として find your zone and account IDs とあって、そのリンク先に Find zone and account IDs というページがあります。ドメインを選択とありますが、私の Cloudflare のサービス利用状況的にはドメインはないため、この方法では探せませんでした。

いろいろ試した結果、https://dash.cloudflare.com/ にログインしたあとにリダイレクトされる URL のうち、https://dash.cloudflare.com/ のあとの 32文字の英数字(少なくとも私の場合は)が アカウントID のようでした。本記事の説明上は dummy_account_id_xxxxxxxxxxxxxxx とします。

ただ、確認方法はサービスの利用状況によって異なるかもしれませんので、正確なことは公式ドキュメントを参照していただければと思います。

事前に GUI でポリシーを入力(後で確認する用)

何か設定が入ってる状態で一覧を表示したいので、事前に GUI でポリシーを入力することにしました。

こんな感じで、1つのポリシーが1つあるだけです。Shopping & Auctions カテゴリ(と配下のいくつかのサブカテゴリ)をブロックするポリシーです。

設定済みのポリシー

ポリシー一覧表示の実行

準備ができたところで、いよいよ実際にポリシーの一覧表示を試します。

リクエストは以下のとおりです。

curl -X GET "https://api.cloudflare.com/client/v4/accounts/dummy_account_id_xxxxxxxxxxxxxxx/gateway/rules" \
     -H "Authorization: Bearer dummy_token_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     -H "Content-Type: application/json"

実行結果は以下のとおりです。

{
  "result": [
    {
      "id": "116dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "name": "block_shopping",
      "description": "",
      "precedence": 11000,
      "enabled": true,
      "action": "block",
      "filters": [
        "http"
      ],
      "created_at": "2022-11-23T13:07:12Z",
      "updated_at": "2022-11-27T07:49:03Z",
      "deleted_at": null,
      "traffic": "any(http.request.uri.content_category[*] in {22 73 82 88 148})",
      "identity": "",
      "device_posture": "",
      "version": 1,
      "rule_settings": {
        "block_page_enabled": false,
        "block_reason": "gomen nasai",
        "override_ips": null,
        "override_host": "",
        "l4override": null,
        "biso_admin_controls": {
          "dp": false,
          "dcp": false,
          "dd": false,
          "du": false,
          "dk": false
        },
        "add_headers": {},
        "ip_categories": false,
        "check_session": null,
        "insecure_disable_dnssec_validation": false
      }
    }
  ],
  "success": true,
  "errors": [],
  "messages": []
}

大体は雰囲気でわかりますが、特徴的なのは以下の traffic の箇所です。

      "traffic": "any(http.request.uri.content_category[*] in {22 73 82 88 148})",

このあたりの書式は Cloudflare Zero Trust のポリシーのフィルタリングの説明ページにありました。

カテゴリの ID と名前の関連を調べる(ドキュメント・API

レスポンスに含まれる traffic のルールでは、カテゴリが 22 のように ID で表記されています。ドキュメントの Category and subcategory IDsに対応表がまとまっています。これを見ると ID がどの名前かが分かります。ID 22Shopping & Auctions というカテゴリで、他の ID はこのカテゴリに含まれるサブカテゴリのようです。

せっかくなので、カテゴリとサブカテゴリの関係を API でも調べてみました。https://api.cloudflare.com/client/v4 /accounts/{account_id}/gateway/categories を見れば分かるようです。カテゴリの ID 22 で絞り込むために、以下のようにリクエストしてみました。

curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/dummy_account_id_xxxxxxxxxxxxxxx/gateway/categories" \
     -H "Authorization: Bearer dummy_token_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     -H "Content-Type: application/json" | jq ".result[] | select (.id==22)"

実行結果は以下のとおりです、カテゴリID 22 と配下に含まれるサブカテゴリの ID 738288148 と名前が確認できます。

{
  "name": "Shopping & Auctions",
  "id": 22,
  "description": "Sites related to ecofmmerce, coupons, shopping, auctions and marketplaces.",
  "class": "premium",
  "subcategories": [
    {
      "name": "Auctions & Marketplaces",
      "id": 73,
      // ...(略)...
    },
    {
      "name": "Coupons",
      "id": 82,
     // ...(略)...
    },
    {
      "name": "Ecommerce",
      "id": 88,
      // ...(略)...
    },
    {
      "name": "Shopping",
      "id": 148,
      // ...(略)...
    }
  ],
  "beta": false,
  "deprecated": false
}

ここまでで、参照系の API としてポリシーの一覧表示を試せました。

POST: ポリシーの追加

続いて、設定系としてポリシーの追加を試します。要件は以下のとおりです。

  • Policy name: block_YouTube
  • Action: Block
  • Expression
  • Block page customised text: suman
  • 位置: 先程 GUI で追加した HTTP のポリシーの下(低い優先度)

方式は以下の通り(参考: Create Zero Trust Gateway Rule)。

POST https://api.cloudflare.com/client/v4/accounts/{identifier}/gateway/rules

ペイロードの組み立て

重要なのはペイロードですね。ドキュメントや、ポリシー一覧の結果などを参考におためしペイロードを組み立てます。

GUIで追加したポリシーはカテゴリーによるフィルタリングでしたが、今回追加したいのはアプリケーションによるフィルタリングです。なので、traffic の書き方が変わるはずです。

調べたらこちらのドキュメントに例がありました。

http.request.uri.content_category[*] ではなく、app.ids[*] という Selector を指定するようです。今回は id 644 にマッチさせたいので "traffic": "any(app.ids[*] in {644})" です。

precedence は、ドキュメントによると、値が小さい方が優先度が高い(Lower values indicate higher precedence)とのことです。設定済みルールは 11000 で、これより優先度低くする要件としたため 12000 にすることにします。(あとで試してみると precedence 未指定の場合は、既存の最大 precedence + 1000 になりました)

ペイロード全体としては、以下のとおりです。payload.json というファイルとして保存しておきます。

{
  "name": "block_YouTube2",
  "description": "new policy",
  "enabled": true,
  "action": "block",
  "filters": [
    "http"
  ],
  "traffic": "any(app.ids[*] in {644})",
  "rule_settings": {
    "block_page_enabled": true,
    "block_reason": "suman"
  }
}

なお、必須のパラメータは、API ドキュメント上に Required と記載があります。

ポリシー追加の実行

ペイロード payload.json が準備できたので、実際にリクエストを実行してます。

curl -X POST "https://api.cloudflare.com/client/v4/accounts/dummy_account_id_xxxxxxxxxxxxxxx/gateway/rules" \
     -d @payload.json \
     -H "Authorization: Bearer dummy_token_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     -H "Content-Type: application/json"

レスポンスは以下のとおりです。ステータスコード200 でした(予想は 201 でしたが)。

{
  "result": {
    "id": "31f0xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "block_YouTube",
    "description": "new policy",
    "precedence": 12000,
    "enabled": true,
    "action": "block",
    "filters": [
      "http"
    ],
    "created_at": "2022-11-27T11:12:44Z",
    "updated_at": "2022-11-27T11:12:44Z",
    "deleted_at": null,
    "traffic": "any(app.hosts_ids[*] in {644})",
    "identity": "",
    "device_posture": "",
    "version": 1,
    "rule_settings": {
      "block_page_enabled": true,
      "block_reason": "suman",
      "override_ips": null,
      "override_host": "",
      "l4override": null,
      "biso_admin_controls": null,
      "add_headers": null,
      "ip_categories": false,
      "check_session": null,
      "insecure_disable_dnssec_validation": false
    }
  },
  "success": true,
  "errors": [],
  "messages": []
}

追加後の確認

GUI でポリシー一覧を確認します。

無事追加された

続いて、 WARP を入れて保護下にしたクライアントのブラウザから https://www.youtube.com/ にアクセスします。

無事にブロックされた

無事にブロックされました。(実際は反映まで少し時間がかかりました)

(参考)エラー集

既存のポリシーと name が重複すると以下のエラーになりました。(ステータコード 409

{
  "result": null,
  "success": false,
  "errors": [
    {
      "code": 2010,
      "message": "A rule with this name already exists."
    }
  ],
  "messages": []
}

一方 precedence が重複すると以下のエラーになりました。(ステータコード 409

{
  "result": null,
  "success": false,
  "errors": [
    {
      "code": 2011,
      "message": "A rule with this precedence already exists."
    }
  ],
  "messages": []
}

トークンに対する Permissions が Write ではなく Read だと以下のエラーになりました。(ステータコード 403

{
  "success": false,
  "errors": [
    {
      "code": 10000,
      "message": "Authentication error"
    }
  ]
}

ここまでで、設定系の API としてポリシーの追加を試せました。


その他のポリシー操作エンドポイント

今回は試せていませんが、ポリシーを操作するエンドポイントには以下のものもあります。

  • ポリシーの詳細表示
  • ポリシーの削除
  • ポリシーの更新

いずれも uuid の部分は、ポリシーの id の部分を指定するようです。


おわりに

Cloudflare Zero Trust の機能のうち、Gateway のポリシーの一覧表示と追加をする API を試してみました。

設定系の操作は、いずれもポリシーの一つ一つを対象にした操作であり、ポリシー一式をまとめて操作する方法はないようでした。

ドキュメントの見方はなんとなく分かってきたので、サービス側の仕様をある程度理解した上であれば使えそうな気がします。

今回ためした操作を同じことができる Ansible のモジュールはなさそうですが、ansible.builtin.uri モジュールを利用すればおそらくできると思います。

他、全く触れていないので Zero Trust サービスの操作ができるかは分かりませんが、Cloudflare のサービスを GUI 以外で操作するには以下のような方法があるようです。

また気が向いたら触ってみたいと思います。