如何使用 RouterOS API 连接 RouterOS 设备

您可以使用 community.routeros.api 模块 通过 RouterOS API 连接到 RouterOS 设备。修改特定条目的更具体的模块是 community.routeros.api_modifycommunity.routeros.api_find_and_modify 模块。community.routeros.api_info 模块 允许检索特定预定义路径上的信息,这些信息可用作 community.routeros.api_modify 模块的输入,而 community.routeros.api_facts 模块 允许使用 RouterOS API 检索 Ansible facts。

无需特殊设置;该模块需要在能够连接到设备 API 的主机上运行。最常见的情况是模块在 localhost 上运行,方法是在 playbook 中使用 hosts: localhost,或者为任务使用 delegate_to: localhost。以下示例显示如何运行等效于 /ip address print 的命令

---
- name: RouterOS test with API
  hosts: localhost
  gather_facts: false
  vars:
    hostname: 192.168.1.1
    username: admin
    password: test1234
  tasks:
    - name: Get "ip address print"
      community.routeros.api:
        hostname: "{{ hostname }}"
        password: "{{ password }}"
        username: "{{ username }}"
        path: "ip address"
        # The following options configure TLS/SSL.
        # Depending on your setup, these options need different values:
        tls: true
        validate_certs: true
        validate_cert_hostname: true
        # If you are using your own PKI, specify the path to your CA certificate here:
        # ca_path: /path/to/ca-certificate.pem
      register: print_path

    - name: Show IP address of first interface
      ansible.builtin.debug:
        msg: "{{ print_path.msg[0].address }}"

这将产生以下输出

PLAY [RouterOS test] *********************************************************************************************

TASK [Get "ip address print"] ************************************************************************************
ok: [localhost]

TASK [Show IP address of first interface] ************************************************************************
ok: [localhost] => {
    "msg": "192.168.2.1/24"
}

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

查看 community.routeros.api 模块 的文档,了解选项的详细信息。

使用 community.routeros.api 模块默认组

为了避免必须在每个任务中为所有基于 API 的模块指定常用参数,您可以使用 community.routeros.api 模块默认组

---
- name: RouterOS test with API
  hosts: localhost
  gather_facts: false
  module_defaults:
    group/community.routeros.api:
      hostname: 192.168.1.1
      password: admin
      username: test1234
      # The following options configure TLS/SSL.
      # Depending on your setup, these options need different values:
      tls: true
      validate_certs: true
      validate_cert_hostname: true
      # If you are using your own PKI, specify the path to your CA certificate here:
      # ca_path: /path/to/ca-certificate.pem
  tasks:
    - name: Gather facts
      community.routeros.api_facts:

    - name: Get "ip address print"
      community.routeros.api:
        path: "ip address"

    - name: Change IP address to 192.168.1.1 for interface bridge
      community.routeros.api_find_and_modify:
        path: ip address
        find:
          interface: bridge
        values:
          address: "192.168.1.1/24"

此处所有三个任务都将使用为模块默认组设置的选项。

设置加密

建议始终使用 tls=true 通过 API 连接,即使您只是通过受信任的网络连接到设备。以下选项控制如何使用 TLS/SSL

force_no_cert:

设置为 true 将连接到设备而无需证书。不建议在生产环境中使用此选项,因为它容易受到中间人攻击,但在设置设备时可能有用。默认值为 false

validate_certs:

设置为 false 将禁用任何证书验证。不建议在生产环境中使用此选项,但在设置设备时是必需的。默认值为 true

validate_cert_hostname:

设置为 false(默认)将禁用证书验证期间的主机名验证。如果证书中指定的主机名与用于连接的主机名(通常是设备的 IP)不匹配,则需要此设置。建议正确设置证书并将此设置为 true;默认值 false 是为了向后兼容模块的旧版本而选择的。

ca_path:

如果您没有使用商业可信的 CA 证书来签署设备的证书,或者没有将您的 CA 证书包含在 Python 的信任库中,则需要将此选项指向 CA 证书。

我们建议创建一个用于签署 RouterOS 设备证书的 CA 证书,并使证书包含正确的主机名(包括设备的 IP)。这样,您可以完全启用 TLS 并确保始终与正确的设备通信。

设置 PKI

请按照 community.crypto 如何创建小型 CA 指南中的说明设置 CA 证书并为您的路由器签署证书。您应该为 IP 地址(例如 IP:192.168.1.1)和 - 如果可用 - 为 DNS 名称(例如 DNS:router.local)添加主题替代名称到证书中。

在 MikroTik 路由器上安装证书

最好使用 SSH 连接来安装证书。(有关更多信息,请参阅 如何使用 SSH 连接 RouterOS 设备 指南。)安装证书并启用 HTTPS API 后,使用 API 会更容易,因为它存在的问题要少得多,并且会以 JSON 对象而不是您首先必须解析的文本形式返回数据。

首先,您必须将证书及其私钥转换为 PKCS #12 包。这可以使用 community.crypto.openssl_pkcs12 完成。以下 playbook 假设证书可用作 keys/{{ inventory_hostname }}.pem,其私钥可用作 keys/{{ inventory_hostname }}.key。它生成一个随机密码来保护 PKCS#12 文件。

---
- name: Install certificates on devices
  hosts: routers
  gather_facts: false
  tasks:
    - block:
        - set_fact:
            random_password: "{{ lookup('community.general.random_string', length=32, override_all='0123456789abcdefghijklmnopqrstuvwxyz') }}"

        - name: Create PKCS#12 bundle
          openssl_pkcs12:
            path: keys/{{ inventory_hostname }}.p12
            certificate_path: keys/{{ inventory_hostname }}.pem
            privatekey_path: keys/{{ inventory_hostname }}.key
            friendly_name: '{{ inventory_hostname }}'
            passphrase: "{{ random_password }}"
            mode: "0600"
          changed_when: false
          delegate_to: localhost

        - name: Copy router certificate onto router
          ansible.netcommon.net_put:
            src: 'keys/{{ inventory_hostname }}.p12'
            dest: '{{ inventory_hostname }}.p12'

        - name: Install router certificate and clean up
          community.routeros.command:
            commands:
              # Import certificate:
              - /certificate import name={{ inventory_hostname }} file-name={{ inventory_hostname }}.p12 passphrase="{{ random_password }}"
              # Remove PKCS12 bundle:
              - /file remove {{ inventory_hostname }}.p12
              # Show certificates
              - /certificate print
          register: output

        - name: Show result of certificate import
          debug:
            var: output.stdout_lines[0]

        - name: Show certificates
          debug:
            var: output.stdout_lines[2]

      always:
        - name: Wipe PKCS12 bundle
          command: wipe keys/{{ inventory_hostname }}.p12
          changed_when: false
          delegate_to: localhost

    - name: Use certificate
      community.routeros.command:
        commands:
          - /ip service set www-ssl address={{ admin_network }} certificate={{ inventory_hostname }} disabled=no tls-version=only-1.2
          - /ip service set api-ssl address={{ admin_network }} certificate={{ inventory_hostname }} tls-version=only-1.2

该 playbook 还假设 admin_network 描述了可以访问 HTTPS 和 API 接口的网络。例如,这可以是 192.168.1.0/24

成功完成此剧本后,您应该能够使用 HTTPS 管理界面(可通过浏览器访问 https://192.168.1.1/,请插入正确的 IP 地址),以及启用 TLS 和证书验证的community.routeros.api 模块

- community.routeros.api:
    ...
    tls: true
    validate_certs: true
    validate_cert_hostname: true
    ca_path: /path/to/ca-certificate.pem