てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 公式ドキュメントの更新状況を追う

この記事は、Ansible Advent Calendar 2022 (Adventar 版) の 19日目の記事です。

はじめに

Ansible の公式ドキュメントは、GitHubリポジトリ ansible/ansible 上で追加や修正されています。

devel ブランチのコミットを追っても分かるといえば分かるのですが、もちろんコードの修正も入るので、ドキュメントの更新だけを追いたい場合はや不向きかと思います。

私がたまに更新状況を追っているのですが、そのときにやっていることをまとめます。

方法1: docs タグがついたプルリクエストを追う

ドキュメントを更新するプルリクエストを送ると bot によって、docs というタグが自動的で付きます()。

なので、docs タグが付いたプルリクエストを追ってくと更新状況を追えます。

方法2: Backportapalooza のプルリクエストを追う

方法1 のプルリクエストを個別に追っていくのは、細かい修正を含むためちょっと大変なときがあります。

そんなときに便利なのが、Backportapalooza のプルリクエストを追う方法です。

Backportapalooza は、月に数回行われている 複数のドキュメント更新のバックポートのプルリクエストが出されるときにつくタイトルです。バックポートというのは、開発ブランチである devel にマージされたプルリクエストを、以前の stable ブランチ(stable-2.14 など) にも、ある種さかのぼって反映させる行為です。

たぶんですが、末尾の apalooza は 〜祭りのニュアンスかなと思います。まとめで出す「バックポート祭り」という感じでしょうか。特に公式で定められてる作法でもなさそうで、最近特定の方によって行われているように見えます。以前は一人ひとりが必要に応じてバックポートを出していましたが、まとめて出してくださって助かっています。

以下が例です。

github.com

上記の例では、説明にある通り 8つの プルリクエストをまとめてバックポートしています。

それぞれのプルリクエストを確認すると、何の更新かが分かります。

それか、ファイルの更新一覧(今回の場合はこちらから)をざっと眺めます。

なお、Backportapalooza のプルリクエストにも docs タグがつくので、方法1のときに出会うときもあります。

おわりに

ドキュメントの更新を追う時に私がやっている方法をまとめました。参考になれば幸いです。

[Ansible] インベントリ変数、set_fact、include_vars などで定義した変数の評価タイミング

この記事は、Ansible Advent Calendar 2022 (Adventar 版) の 18日目の記事です。

はじめに

あらためて考えると「あれ、どうだっけ?」となることの一つに、変数の評価タイミングがあります。

インベントリ変数や、Play変数、vars_filesset_factinclude_vars で定義した変数をそれぞれ2回参照したときの比較結果を、ど忘れしたときのために記しておきます。

  • 環境
    • ansible-core 2.14.1

ファイル構成

.
├── eval_vars.yml        # Playbook
├── host_vars
│   └── localhost.yml    # インベントリ変数
└── vars
    ├── files.yml        # vars_files で指定する対象
    └── included.yml     # include_vars で指定する対象

変数ファイルの中身はそれぞれ以下のとおりです。すべて中身は "{{ now }}" で、変数名だけ定義した場所が区別できるように変えています。

host_vars/localhost.yml

---
now_host_vars: "{{ now() }}"

vars/files.yml (vars_files で指定する対象)

---
now_vars_files: "{{ now() }}"

vars/included.yml (include_vars で指定する対象)

---
now_include_vars: "{{ now() }}"

Playbook

Playbook は以下のとおりです。先程定義した変数ファイルたちをいろいろな方法で読み込みつつ、Play 変数 now_play_varsset_fact で定義する変数 now_set_fact は、Playbook 内で定義します。2回変数を debug で表示しますが、間に 1秒 pause をかけます。これにより、 "{{ now }}" が変わったり変わらなかったりするところ比較するのが目的です。

---
- name: Test evaluating vars
  hosts: localhost
  gather_facts: false
  connection: local

  vars:
    now_play_vars: "{{ now() }}"

  vars_files:
    - files.yml

  tasks:
    - name: set_fact
      ansible.builtin.set_fact:
        now_set_fact: "{{ now() }}"

    - name: include_vars
      ansible.builtin.include_vars:
        file: included.yml

    - name: debug vars 1
      ansible.builtin.debug:
        msg:
          - "{{ now_host_vars }} now_host_vars"
          - "{{ now_play_vars }} now_play_vars"
          - "{{ now_vars_files }} now_vars_files"
          - "{{ now_set_fact }} now_set_fact"
          - "{{ now_include_vars }} now_include_vars"
          
    - name: pause
      ansible.builtin.pause:
        seconds: 1

    - name: debug vars 2
      ansible.builtin.debug:
        msg:
          - "{{ now_host_vars }} now_host_vars"
          - "{{ now_play_vars }} now_play_vars"
          - "{{ now_vars_files }} now_vars_files"
          - "{{ now_set_fact }} now_set_fact"
          - "{{ now_include_vars }} now_include_vars"

実行結果

Playbook の実行結果です。

% ansible-playbook -i localhost, eval_vars.yml

PLAY [Test evaluating vars] *************************************************************************************

TASK [set_fact] *************************************************************************************************
ok: [localhost]

TASK [include_vars] *********************************************************************************************
ok: [localhost]

TASK [debug vars 1] *********************************************************************************************
ok: [localhost] => {
    "msg": [
        "2022-12-18 11:40:59.351505 now_host_vars",
        "2022-12-18 11:40:59.353803 now_play_vars",
        "2022-12-18 11:40:59.355511 now_vars_files",
        "2022-12-18 11:40:59.228503 now_set_fact",
        "2022-12-18 11:40:59.358674 now_include_vars"
    ]
}

TASK [pause] ****************************************************************************************************
Pausing for 1 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

TASK [debug vars 2] *********************************************************************************************
ok: [localhost] => {
    "msg": [
        "2022-12-18 11:41:00.455484 now_host_vars",
        "2022-12-18 11:41:00.458050 now_play_vars",
        "2022-12-18 11:41:00.460399 now_vars_files",
        "2022-12-18 11:40:59.228503 now_set_fact",
        "2022-12-18 11:41:00.462725 now_include_vars"
    ]
}

PLAY RECAP ******************************************************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

set_fact で取得した now() だけが変化しなかったことが分かります。

[Ansible] AWS 系コレクションは 2つある(amazon.aws、community.aws)

この記事は、Ansible Advent Calendar 2022 の 14日目の記事です。

はじめに

もともと Ansible 本体とセットだったモジュール類の多くが、ansible(-base) 2.10 でコレクションに移行しました。

少しややこしく感じるかもしれませんが AWS の各種リソースを操作できるコレクションは以下の2つがあります。

  • amazon.aws
  • community.aws

それぞれの違いを簡単ですがまとめます。

比較

amazon.aws コレクション community.aws コレクション
メンテナンス主体 Maintained and Supported By : Red Hat Ansible `This collection is maintained by the Ansible community
Ansible 公式ドキュメント上のページ(モジュール一覧含む) amazon.aws community.aws
Ansible Galaxy のページ amazon.aws community.aws
GitHub リポジトリ ansible-collections/amazon.aws ansible-collections/community.aws

両コレクションとも、古いバージョンの ansible-core のサポート切ってきているのは共通です。各コレクションのバージョン 5.0.0 で、ansible-core 2.11 未満のサポートを切っています。

Support for ansible-core<2.11 has also been dropped.

(amazon.aws 側 CHANGELOGcommunity.aws 側 CHANGELOG)

含まれるモジュールも異なる

それぞれに含まれるモジュールも異なります。

たとえば、EC2 インスタンスを操作するモジュールは amazon.aws コレクションにある amazon.aws.ec2_instance モジュールです。 EC2 の情報を動的に扱えるインベントリプラグイン amazon.aws.aws_ec2 inventoryも同様です。

一方、ルートテーブルを操作するモジュールは community.aws コレクションにある community.aws.ec2_vpc_route_table モジュール です。

コレクション間でモジュール類が引っ越すこともある

モジュール類がコレクション間で引っ越す(移行)ことがあります。

例えば最近では、多くのモジュール類が community.aws コレクション から amazon.aws コレクションに移行しました。

それぞれのコレクションのバージョン 5.0.0 のタイミングです。

詳細はそれぞれの CHANGELOG を参照してください。

  • amazon.aws 5.0.0 CHANGELOG
      • ec2_eip - The module has been migrated from the community.aws collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use amazon.aws.ec2_eip.

  • community.aws 5.0.0 CHANGELOG
      • ec2_eip - The module has been migrated from the community.aws collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use amazon.aws.ec2_eip

現状はリダイレクトの定義()があって、意識しなくてもいいケースあるかも知れませんが、症例的に定義が消えるかも知れません。

どのモジュールがどのコレクションあるかは意識して、リダイレクトに頼らないほうがトラブル防止になると思います。

おわりに

ほかにも、ansible.windowsと、ommunity.windowsのように、コレクションが別れているものがいくつかあります。

モジュールを探す場合は、両コレクションを探すのが良さそうです。

[Ansible] ansible-config dump コマンドで設定を JSON や YAML で表示する (ansible-core 2.14.0 から)

この記事は Ansible Advent Calendar 2022 6日目の記事です。

はじめに

ansible-core 2.14.0 で、ansible-config dump コマンドにで出力フォーマットを指定する -f--format オプションが追加されました。

ansible community package のバージョンとしては 7.0.0 からです。

ansible-config dump コマンドは、カレントディレクトリにおいて、反映されている設定内容を表示するコマンドです。

これまでは、シンプルな「設定項目名 = 設定値」という形式でしたが、JSONYAML でも表示できるようになりました。

試した結果をまとめます。

動作確認環境

  • ansible-core 2.14.0

おためし

普通に ansible-config dump だけだと表示量が多いので、デフォルトからの変更点だけ表示される --only-changed とあわせてためします。

JSON-f json

コマンド

$ ansible-config dump --only-changed -f json

表示

[
    {
        "name": "CONFIG_FILE",
        "origin": "",
        "type": null,
        "value": "/home/sakana/ansible/ansible.cfg"
    },
    {
        "name": "DUPLICATE_YAML_DICT_KEY",
        "origin": "/home/sakana/ansible/ansible.cfg",
        "type": null,
        "value": "error"
    },
    {
        "name": "HOST_KEY_CHECKING",
        "origin": "/home/sakana/ansible/ansible.cfg",
        "type": null,
        "value": false
    },
    {
        "name": "HOST_PATTERN_MISMATCH",
        "origin": "/home/sakana/ansible/ansible.cfg",
        "type": null,
        "value": "error"
    },
    {
        "name": "INVENTORY_ANY_UNPARSED_IS_FAILED",
        "origin": "/home/sakana/ansible/ansible.cfg",
        "type": null,
        "value": true
    }
]

YAML-f yaml

コマンド

$ ansible-config dump --only-changed -f yaml

表示

- name: CONFIG_FILE
  origin: ''
  type: null
  value: /home/sakana/ansible/ansible.cfg
- name: DUPLICATE_YAML_DICT_KEY
  origin: /home/sakana/ansible/ansible.cfg
  type: null
  value: error
- name: HOST_KEY_CHECKING
  origin: /home/sakana/ansible/ansible.cfg
  type: null
  value: false
- name: HOST_PATTERN_MISMATCH
  origin: /home/sakana/ansible/ansible.cfg
  type: null
  value: error
- name: INVENTORY_ANY_UNPARSED_IS_FAILED
  origin: /home/sakana/ansible/ansible.cfg
  type: null
  value: true

デフォルト (-f display

デフォルトは -f display 扱いです。これまでもあった、おなじみの形式です。

コマンド

$ ansible-config dump --only-changed -f display

表示

CONFIG_FILE() = /home/sakana/ansible/ansible.cfg
DUPLICATE_YAML_DICT_KEY(/home/sakana/ansible/ansible.cfg) = error
HOST_KEY_CHECKING(/home/sakana/ansible/ansible.cfg) = False
HOST_PATTERN_MISMATCH(/home/sakana/ansible/ansible.cfg) = error
INVENTORY_ANY_UNPARSED_IS_FAILED(/home/sakana/ansible/ansible.cfg) = True

おわりに

ちょっとその場で確認する場合は今までの表示で十分だと思います。一方で、設定値をテンプレートファイルに流し込んでドキュメントを生成したいような場合は、JSONYAML のようなフォーマットだと便利かもしれません。

参考

2.14.0 の Changelog

github.com

ansible-config adds JSON and YAML output formats for list and dump actions.

関連 issue

github.com

関聯 PR

github.com

[Ansible] Ansible動画 をみんなで観て語る会 #6 参加レポート(Introducing Ansible Network Validated Content)

この記事は Ansible Advent Calendar 2022 4日目の記事です。

はじめに

2022/12/01 に開催開催された「Ansible 動画 をみんなで観て語る会 #6」参加しました。

ansible-users.connpass.com

どんなことをどんな流れでやっていったのか、レポートします。

Ansible 動画 をみんなで観て語る会とは?

Ansible 動画 をみんなで観て語る会は、Ansible Fest などのアーカイブ動画をスタッフが画面共有で流し、みんなで観みたあとにコメントしたりディスカッションしたりするイベントです。

画面共有と音声チャットを組み合わせて行う都合上、Discord を利用します。

観る動画は、現在のところ英語版に日本語字幕をつけたものが選択されます。なので、英語がダメでも問題ありません。

当日の流れ

Discord への入り方

申込みをすると、Connpass のイベントページの「参加者への情報」欄に Discord に入るためのリンクが表示されます(もくもく会と同じです)。

Discord にログインして「ANSIBLE動画観て語る会」グループ内の、テキストチャット「ansible動画観て語る会」を開き、ボイスチャット「Ansible動画観て語る会」に入って待機します。待機している間に、Discord の音声の設定を確認しておくと良いと思います。

テキストチャットとボイスチャット

ボイスチャットに入ると、このように入ってる人のアイコンが並びます。

これは一人だけ入っている例

上図ではマイクはオフ、スピーカーはオン、という状態です。この状態ならスタッフの声が聞こえてくるはずです。もし自分だけ聞こえない場合は、設定(ギアアイコン)で調整します。

後述のガイダンスをするために画面共有しているスタッフのアイコンの横には「ライブ」と表示されます。

akira6592 が画面共有している例

この人のアイコンをクリックすると「配信を見る」というボタンが表示されるので、このボタンを押して共有された画面を見て待機します。

ガイダンス

時間になると、スタッフからボイスチャットでこの会の趣旨や流れの説明がされます。

また、もくもく会と同様に、Google Doc によるメモ帳のURLがテキストチャットで共有されます。このメモ帳に進行に必要な情報が書かれています。

今回は、3つある動画の候補のうち、どの動画を見るか決めるところからスタートしました。多数決の結果、今回は「Introducing Ansible Network Validated Content」という動画に決まりました。

AnsibleFest 2022 でのセッションのアーカイブです。

events.experiences.redhat.com

みんなで動画視聴

ガイダンスが終わったら、みんなで動画視聴する時間です。今回は動画が30分ほどでした(確か)。

聞きながら、テキストチャット「ansible動画観て語る会」で疑問や気づき、情報共有などの書き込みもありました。

動画は、スタッフが画面共有で音声付きで流してくれるので、ボイスチャットの画面共有の画面を開いておけば大丈夫です。

グループ分けとグループごとのディスカッション

ディスカッションに適した人数(4人くらい?)にグループ分けがなされます。今回は2グループに分かれました。

「〇〇さんは、グループ1にお願いします」のような案内があるので、該当のボイスチャットに移動します。以下の図はグループ1に一人いる状態です。

グループ1に一人いる状態

グループに分かれたあとは、全員マイクもオンにして「ファーストインプレッションはどうでした?」「どういうことだったんだろう?」などの切り口でディスカッションしていきます。

ここで、例のメモ帳に色々書いていきます。特に担当は決まっていませんので、グループ内みんなで協力していくスタイルです。

内容

話された内容のうち個人的なポイントをまとめます。

  • validated ってどういう意味だろう・・?
    • Certified ともまた違うよう
  • なにができるもの?
    • ネットワークのベンダーもコマンドも抽象化して情報収集、設定できる
    • ここでいう content の実体はコレクションの中のロールみたいだ。さらに ansible_network_os に応じた、各ベンダーのネットワークリソースモジュールが呼ばれているようだった(例 junipernetworks.junos.junos_bgp_global)
    • ある種のラッパー
  • どういうユースケース
    • 原始的な構成管理的なイメージに見えた
    • スプレッドシートでのパラメーターシートの代わりに YAML で定義して、それをそのまま Playbook で実機に反映。もし YAML が読みにくければ YAML を元ネタにして、見やすい別のビューを作ればよいか
    • ネットワークリソースモジュールが扱える範囲の設定で、YAMLを直接触るのに抵抗がなければはまるかもしれない
  • どこから入手する?名前空間は?
    • Ansible Galaxy にも Automation Hub にもない
    • AAP2.3 のブログでは This valuable content is pre-installed on your private automation hub node to allow you to quickly get up and start on a variety of different use-cases. とある
    • 名前空間的には network.basenetwork.bgp のようだ
    • AAP 2.3 バンドル版を解凍すると、そのコレクションの tar.gz があった
      • $ ls -1 ansible-automation-platform-setup-bundle-2.3-1/bundle/collections/validated
        
        cloud-aws_ops-1.0.2.tar.gz
        cloud-aws_troubleshooting-1.0.2.tar.gz
        infra-aap_utilities-2.2.2.tar.gz
        infra-ah_configuration-0.9.2.tar.gz
        infra-controller_configuration-2.1.9.tar.gz
        infra-ee_utilities-2.0.1.tar.gz
        infra-osbuild-1.0.0.tar.gz
        network-base-1.2.0
        network-base-1.2.0.tar.gz
        network-bgp-1.2.0
        network-bgp-1.2.0.tar.gz
        network-vpn-1.3.0.tar.gz
        requirements.yml
        security-firewall_mgmt-1.2.0.tar.gz
        

ディスカッション終了の時間になると、テキストチャットのほうで案内されるので、ボイスチャット「Ansible動画観て語る会」の方に戻ります。

グループごとの簡単な発表・まとめ

グループディスカッションから戻ってきたら、グループごとにどんな会話がなされたのかを簡単に発表します。大体はメモ帳に書かれたことを、簡単になぞっていけば大丈夫です。

今回はグループ1がネットワーク寄りの人、グループ2がサーバー寄りの人、という感じだったので、異なった意見がされていたのが興味深かかったです。

おわりに

以上、Ansible 動画 をみんなで観て語る会 #6 の参加レポートでした。

どんな形式で行われるのか分からず、不安で入りにくいと思った方がいらしたら、参考にしていただければと思います。

一人で観るよりも何倍もインプットができてとてもいいイベントだと思います。

Ansible Fest のように大きなイベントのあとに開催される傾向があり、直近では次回は 2022/12/09 に開催されます。

観る動画は「Mastering Ansible content quality control」です。ansible-lint を使って室の高いPlaybookにしていこう、というような内容になっています。もし興味があればぜひご参加を!

ansible-users.connpass.com

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 以外で操作するには以下のような方法があるようです。

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

[Ansible] paramiko と ansible-pylibssh のどっちが使われたか確認する方法

はじめに

ネットワークモジュールが長らく内部的に利用している SSH クライアントライブラリとして、paramiko があります。

最近は ansible-pylibssh というもの新しいものもあります。登場した経緯は Ansible の公式ブログの記事に書かれています。

そして、各ネットワークモジュールが内部的に利用している ansible.netcommon コレクションのデフォルトの動作は自動(auto)です。ansible.netcommon.network_cli コネクションプラグインでいうと、ssh_type パラメーターの値によって決まります。paramikolibssh のように、明示指定もできます。

明示的に指定ないと、結局どっちが使われたんだろう?とあいまいになるケースもあるかもしれません。

そんなときに確認する方法です。

  • 確認環境
    • ansible-core 2.13.5
    • ansible.netcommon コレクション 4.0.0

どちらが使われているか確認する方法

ansible-playbook コマンドで -v を4つ以上(-vvvv)つけると、paramikoansible-pylibssh のどっちが結局使われてるのかが分かります。

ssh_typeautoparamiko が使われた場合:

$ ansible-playbook -i inventory.ini ios_show.yml -vvvv 
...(略)...
<192.168.1.11> ssh type is set to auto
<192.168.1.11> autodetecting ssh_type
[WARNING]: ansible-pylibssh not installed, falling back to paramiko
<192.168.1.11> ssh type is now set to paramiko
...(略)...

上記の WARNING についてはこちらの記事を参照してください。

ssh_typeautoansible-pylibssh が使われた場合:

$ ansible-playbook -i inventory.ini ios_show.yml -vvvv 
...(略)...
<192.168.1.11> ssh type is set to auto
<192.168.1.11> autodetecting ssh_type
<192.168.1.11> ssh type is now set to libssh
...(略)...