この記事は エーピーコミュニケーションズ Advent Calendar 2022 の1日目の記事です。
はじめに
Cloudflare Zero Trust が 50ユーザーまで無料というプラン があるとのことで、試すにちょうどいいと思って少し触っていました。
触ってまもなく、API あるかな?どんな感じかな?と気になったので試してみました。
試す機能の対象は、Gateway にしました。
SWG (Secure Web Gateway )に分類されるものでしょうか。UTM やコンテンツフィルター的なものをクラウド 上のサービスとして利用できるもの、と捉えています。
(ゼロトラスト自身に詳しくないので間違っていたらすみません)
Cloudflare Zero Trust のサービスの概要や設定手順は、公式以外では以下の記事を参考にさせていただきました。ありがとうございます。
Gateway の機能のうち、HTTP によるポリシーをAPI で操作してみます。
なお、今回の環境では TLS decryption
は有効化してあります。
下調べ・準備
API を叩くぞというときに、認証はどうやるのか、権限はどうなってるのかなどの基本的なお作法を知るのは避けて通れないですよね。個人的にはこのフェーズがなかなか苦手です・・・。なので少し細かく書き残しておきます。
API ドキュメント
Cloudflare の API 系ドキュメントは以下のページが見つかりました。こちらに各エンドポイントの説明やお作法などが掲載されていました。ドキュメントがしっかりしているのは助かりますね。
なお、リファレンは最初 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 リクエス トに必要なトーク ンを作成します。
https://dash.cloudflare.com/
にログインし、右上のアイコンをクリックして表示されたメニューの My Profile
をクリックします
左メニューから API Tokens
をクリックします
API Token をクリック
Create Token
をクリックします
Create Token をクリック
Custom token
セクションの Create Custom Token
欄の Get started
をクリックします(Zero Trust の操作に該当するちょうどいいテンプレートがないため)
Create Custom Token の Get started をクリック
Permissions
で Account
、Zero Trust
、Edit
をそれぞれ選択し、ページ下部の Continue to summary
をクリックします
API token permissions
には、Zero Trust
が見当たりませんが、おそらくこの設定で、GET も
POST もいけるだろうという目論見です
他にも、アカウントや IP アドレス制限、TTL を制限できるようですが、とりあえずデフォルトのままで試します
ポリシー設定を入力
確認画面が表示されるので Create Token
をクリックします
Create Token をクリック
トーク ンが表示されるので、後で使うために何かに控えておきます
トーク ンを控える
ここまでで、トーク ンが作成できました。トーク ン作成画面の最後で、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 22
が Shopping & 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 73
、82
、 88
、148
と名前が確認できます。
{
"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 以外で操作するには以下のような方法があるようです。
また気が向いたら触ってみたいと思います。