てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] PaloAlto(PAN-OS)の API を uri モジュールで実行する

はじめに

Ansible には PaloAlto(PAN-OS) 向けのモジュールがあります。Ansible 2.8 までは標準モジュールとして付属していました。2.9 では Deprecated(非推奨)となり、Collection モジュールを利用することになっています。

ですが、モジュールが用意されていない処理を実装することになるかもしれません。 その場合は、uri モジュール を利用して、API を直接実行する方法があります。

ここでは代表して、前回の記事で行ったカスタム URL オブジェクトの追加と確認uri モジュールを利用して実装します。

f:id:akira6592:20200410210442p:plain:w400
Ansible でカスタムURLオブジェクトを追加する


■ 実装する処理の流れ

実装する処理の大まか流れは以下のとおりです。

  1. API Key の取得
  2. URLカテゴリの追加
  3. URLカテゴリ一覧取得・表示


■ Playbook

早速 Playoobk です。 解説は次にします。

- hosts: panos
  gather_facts: false
  connection: local

  vars:
    panos_user: apiuser
    panos_password: xxx_dummy_xxx
    vsys: vsys1 # 対象 vsys

  tasks:
    # API Key のリクエスト
    - name: get API key response
      uri:
        url: "https://{{ ansible_host }}/api/?type=keygen&user={{ panos_user }}&password={{ panos_password }}"
        method: GET
        validate_certs: false
        return_content: true
      register: result_api_key_res

    # API Key の抜き取り
    - name: xpath
      xml:
        xmlstring: "{{ result_api_key_res.content }}"
        xpath: /response/result/key
        content: text
      register: result_key_api_key

    # API Key の変数セット
    - name: set_fact key
      set_fact:
        pan_key: "{{ result_key_api_key.matches[0].key }}"

    # カスタム URL カテゴリ追加
    - name: add example.com
      uri:
        url: "https://{{ ansible_host }}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys={{ vsys }}&name=example.com"
        method: POST
        validate_certs: false
        return_content: true
        headers:
          X-PAN-KEY: "{{ pan_key }}"
        body: 
          entry:
            - "@name": example.com
              type: URL List
              list:
                member:
                - http://www.example.com
                - http://example.com
        body_format: json
        
    # カスタム URL カテゴリ一覧の取得
    - name: get custom url categories
      uri:
        url: "https://{{ ansible_host }}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys={{ vsys }}"
        method: GET
        validate_certs: false
        return_content: true
        headers:
          X-PAN-KEY: "{{ pan_key }}"
      register: result_url_cat

    # カスタム URL カテゴリ一覧の表示
    - name: debug get custom url categories
      debug:
        msg: "{{ result_url_cat }}"

解説

前述の Playbook を処理の流れに沿って解説します。

1. API Key の取得

まず タスク get API key response で、API Key をリクエストします。

    # API Key のリクエスト
    - name: get API key response
      uri:
        url: "https://{{ ansible_host }}/api/?type=keygen&user={{ panos_user }}&password={{ panos_password }}"
        method: GET
        validate_certs: false
        return_content: true
      register: result_api_key_res

この公式ドキュメントの方法uri モジュールで実装したかたちです。

レスポンス(uriモジュールの戻り値内の content)は 以下のような形式の XML で返ってきます。

<response status = 'success'>
    <result>
        <key>xxxxx_API_KEY_xxxxx</key>
    </result>
</response>

その中から API Key そのものを xml モジュールを利用して抜き出します。

xpath オプションで API Key そのものがあるパスを指定し、content: text で(属性ではなく)テキストの値を取得します。

    # API Key の抜き取り
    - name: xpath
      xml:
        xmlstring: "{{ result_api_key_res.content }}"
        xpath: /response/result/key
        content: text
      register: result_key_api_key

すると xml モジュール実行の戻り値が以下のようになります。

//...(略)...
    "matches": [
      {
        "key": "xxxxx_API_KEY_xxxxx"
        }
    ],
//...(略)...

ここまで絞れ込めたら抽出できたら、 set_facts モジュールで以下のように変数セットします。

    # API Key の変数セット
    - name: set_fact key
      set_fact:
        pan_key: "{{ result_key_api_key.matches[0].key }}"

これで、以降の API 実行に必要な API Key を、変数 pan_key で参照できるようになりました。

2. URLカテゴリの追加

必要な API Key が取得できたので、本当にやりたい処理に進みます。

こちらの記事の「追加」で curl で実行した内容を uri モジュールで実装したかたちです。 headers オプションで、先程取得した API Key を指定します。

    # カスタム URL カテゴリ追加
    - name: add example.com
      uri:
        url: "https://{{ ansible_host }}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys={{ vsys }}&name=example.com"
        method: POST
        validate_certs: false
        return_content: true
        headers:
          X-PAN-KEY: "{{ pan_key }}"
        body: 
          entry:
            - "@name": example.com
              type: URL List
              list:
                member:
                - http://www.example.com
                - http://example.com
        body_format: json

気をつけるべき点は body オプション内で指定する

            - "@name": example.com

です。通常、YAML のキーはクォーテーションで囲いません。しかし、PaloAlto (PAN-OS) の API の仕様で、キーが @ で始まるものがあるため、クォーテーションで囲っています。

json が良い場合は、別途 json を書いたファイルを用意して

        body: "{{ lookup('file','body.json') }}"

のように読み込んで上げればよいです。

3. URLカテゴリ一覧取得・表示

次に、確認作業として、 URLカテゴリ一覧を取得して、標準出力するタスクです。

こちらの記事の「確認」で curl で実行した内容を uri モジュールで実装したかたちです。

    # カスタム URL カテゴリ一覧の取得
    - name: get custom url categories
      uri:
        url: "https://{{ ansible_host }}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys={{ vsys }}"
        method: GET
        validate_certs: false
        return_content: true
        headers:
          X-PAN-KEY: "{{ pan_key }}"
      register: result_url_cat

戻り値内の json 内に、実データが入っているので表示します。

    # カスタム URL カテゴリ一覧の表示
    - name: debug get custom url categories
      debug:
        msg: "{{ result_url_cat.json }}"


■ 実行

Plaubook を実行します。ここでは、カスタム URL カテゴリがないもない状態から始めます。

(nwlab) mbp16:palo akira$ ansible-playbook -i inventory.ini custom_url.yml 

PLAY [panos] *****************************************************************************************************

TASK [get API key response] **************************************************************************************
ok: [panos1]

TASK [xpath] *****************************************************************************************************
ok: [panos1]

TASK [set_fact key] **********************************************************************************************
ok: [panos1]

TASK [add example.com] *******************************************************************************************
ok: [panos1]

TASK [get custom url categories] *********************************************************************************
ok: [panos1]

TASK [debug get custom url categories] ***************************************************************************
ok: [panos1] => {
    "msg": {
        "@code": "19",
        "@status": "success",
        "result": {
            "@count": "1",
            "@total-count": "1",
            "entry": [
                {
                    "@location": "vsys",
                    "@name": "example.com",
                    "@vsys": "vsys1",
                    "list": {
                        "member": [
                            "http://www.example.com",
                            "http://example.com"
                        ]
                    },
                    "type": "URL List"
                }
            ]
        }
    }
}

PLAY RECAP *******************************************************************************************************
panos1                     : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

無事に追加と表示がされました。

もし、lxml が見つからない旨のエラーが表示された pip install lxml でインストールします。

なお、もう一度実行すると、Object Not Unique: Object already exists. というエラーになります。ステータスコード409 です。。

確認

画面でも確認します。

f:id:akira6592:20200410210811p:plain
example.com が追加された

無事に追加されました。


■ おわりに

uri モジュールを利用して PaloAlto(PAN-OS) の API を実行する Playbook をご紹介しました。

モジュールがない場合の実装方法のひとつとして参考になれば幸いです。

ただ、処理のたびに API Key を生成するのより、生成と利用は分けたほうがいい気がします。