我们希望听到您的意见!帮助我们深入了解 Ansible 生态系统的现状。
参与 Ansible 项目 2024 年调查

网络命令模块深度解析

网络命令模块深度解析

企业客户经常向 Ansible 网络团队询问网络自动化的最常见用例。在这篇博文中,我想谈谈一组最常用(也是用途最广泛)的网络模块:command 模块。命令模块允许您使用 Ansible 运行网络命令,就像网络工程师在命令行中键入它们一样。但是,使用 Ansible,输出不会仅仅在终端窗口中一闪而过并永远丢失;它可以被存储并在后续任务中使用。它还可以捕获到变量中,解析以供其他任务使用,并存储在主机变量中以供将来参考。今天,我们将介绍网络 command 模块的基本用法,包括使用 register 参数保留命令输出。我们还将介绍使用 hostvars 扩展到多个网络设备以及使用 wait_for 参数和三个相关参数(intervalretriesmatch)添加条件要求。这篇博文的要点是,任何可重复的网络操作任务都可以自动化。Ansible 不仅仅是配置管理,它还允许网络运营商从日常任务中解放出来,节省时间。

有各种平台的命令模块,包括网络产品支持的所有模块 supported

网络平台 *os_command 模块
Arista EOS eos_command
Cisco IOS / IOS-XE ios_command
Cisco IOS-XR iosxr_command
Cisco NX-OS nxos_command
Juniper Junos junos_command
VyOS vyos_command

基本命令模块用法

这是一个使用 eos_command 运行 show version 的简单 playbook

---
- name: COMMAND MODULE PLAYBOOK
  hosts: eos
  connection: network_cli

  tasks:
   - name: EXECUTE ARISTA EOS COMMAND
     eos_command:
       commands: show version
     register: output

   - name: PRINT OUT THE OUTPUT VARIABLE
     debug:
       var: output

有两个任务;第一个任务使用 eos_command 和一个名为 commands 的参数。由于我只运行一个命令,因此我可以在与 commands 相同的行上键入 show version。如果我有多个命令,我会在 commands 参数下方单独一行列出每个命令。在本例中,我使用 register 关键字 保存 show version 命令的输出。您可以在任务级别使用任何 Ansible 任务使用 register 参数。register 参数定义一个变量来存储任务的输出,以便在后续任务中使用。在我的 playbook 中,变量名为 output

第二个任务使用 debug 模块 打印上一个任务中变量 output 的内容。在本例中,我将看到与在 EOS 设备上直接在命令行中键入“show version”相同的输出。我的 playbook 在我运行 playbook 的终端窗口中打印此输出。Ansible debug 模块 非常适合检查变量。

以下是运行 playbook 的输出

PLAY [eos] *************************************************************************

TASK [execute Arista eos command] **************************************************
ok: [eos]

TASK [print out the output variable] ***********************************************
ok: [eos] => {
    "output": {
        "changed": false,
        "failed": false,
        "stdout": [
            "Arista vEOS\nHardware version:    \nSerial number:       \nSystem MAC address:  0800.27ec.005e\n\nSoftware image version: 4.20.1F\nArchitecture:           i386\nInternal build version: 4.20.1F-6820520.4201F\nInternal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91\n\nUptime:                 1 day, 3 hours and 23 minutes\nTotal memory:           2017324 kB\nFree memory:            1111848 kB"
        ],
        "stdout_lines": [
            [
                "Arista vEOS",
                "Hardware version:    ",
                "Serial number:       ",
                "System MAC address:  0800.27ec.005e",
                "",
                "Software image version: 4.20.1F",
                "Architecture:           i386",
                "Internal build version: 4.20.1F-6820520.4201F",
                "Internal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91",
                "",
                "Uptime:                 1 day, 3 hours and 23 minutes",
                "Total memory:           2017324 kB",
                "Free memory:            1111848 kB"
            ]
        ]
    }
}

PLAY RECAP *************************************************************************
eos                        : ok=2    changed=0    unreachable=0    failed=0

您可以在上面的输出中看到这两个任务都已成功执行。第一个任务使用默认详细程度没有输出,它只是返回执行任务的主机 eos,以及 ok 和绿色以指示成功。第二个任务使用 debug 模块返回已执行命令的输出。您会看到两种不同格式的信息

  • stdout
  • stdout_lines

stdout 返回人类操作员在命令行上看到的所有内容,作为一个大型字符串。stdout_lines 返回一个字符串列表,使信息更易于阅读。每个项目都是从命令返回的单独一行。

以下是查看其外观的输出

Arista EOS 命令行输出

eos>show vers
Arista vEOS
Hardware version:
Serial number:
System MAC address: 0800.27ec.005e
Software image version: 4.20.1F
Architecture: i386
Internal build version: 4.20.1F-6820520.4201F
Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91
Uptime: 1 day, 3 hours and 56 minutes
Total memory: 2017324 kB
Free memory: 1116624 kB

Ansible stdout_lines

"stdout_lines": [
    [
          "Arista vEOS",
          "Hardware version:",
          "Serial number:",
          "System MAC address: 0800.27ec.005e",
          "",
          "Software image version: 4.20.1F",
          "Architecture: i386",
          "",
          "Internal build version: 4.20.1F-6820520.4201F",
          "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91",
          "",
          "Uptime: 1 day, 3 hours and 23 minutes",
          "Total memory: 2017324 kB",
          "Free memory: 1111848 kB"
        ]

熟悉 JSON 和 YAML 的工程师和人员已经注意到另一个有趣的细节:stdout_lines 以两个左方括号开头

"stdout_lines": [
            [

两个左方括号表明 stdout_lines 实际上返回了一个字符串列表的列表。如果我们稍微修改一下 debug 任务,就可以使用此功能查看输出中的选择。由于输出在列表中只有一个列表,因此整个子列表被引用为列表零,或第一个列表。让我们查看返回值中的一行。我想获取我们测试的 系统 MAC 地址。查看上面的输出,系统 MAC 地址在第四行返回,对应于第 3 行(因为计算机从 0 开始计数)。这意味着我们要获取列表 0 的第 3 行,对应于 output.stdout_lines[0][3]

- name: print out a single line of the output variable
  debug:
  var: output.stdout_lines[0][3]

debug 任务返回了我们所需的内容

TASK [print out a single line of the output variable] ******************************
ok: [eos] => {
    "output.stdout_lines[0][3]": "System MAC address:  0800.27ec.005e"
}

为什么我们要让第一个列表为零,以及具有多个列表的用例是什么?可以使用一个命令任务运行多个命令。这是一个包含三个命令的 playbook

---
- hosts: eos
  connection: network_cli
  tasks:
    - name: execute Arista eos command
      eos_command:
        commands:
          - show version
          - show ip int br
          - show int status
      register: output

    - name: print out command
      debug:
        var: output.stdout_lines

output 的输出现在如下所示

"output.stdout_lines": [
    [
        "Arista vEOS",
        "Hardware version:    ",
        "Serial number:       ",
        "System MAC address:  0800.27ec.005e",
        "",
        "Software image version: 4.20.1F",
        "Architecture:           i386",
        "Internal build version: 4.20.1F-6820520.4201F",
        "Internal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91",
        "",
        "Uptime:                 1 day, 4 hours and 20 minutes",
        "Total memory:           2017324 kB",
        "Free memory:            1111104 kB"
    ],
    [
        "Interface              IP Address        Status    Protocol      MTU",
        "Ethernet1              172.16.1.1/24      up         up          1500",
        "Management1            192.168.2.10/24    up         up          1500"
    ],
    [
        "Port  Name    Status       Vlan    Duplex  Speed  Type     Flags",
        "Et1           connected  routed    full    unconf EbraTestPhyPort   ",
        "Et2           connected    1       full    unconf EbraTestPhyPort   ",
        "Et3           connected    1       full    unconf EbraTestPhyPort   ",
        "Ma1           connected  routed   a-full a-1G   10/100/1000"
    ]
]

列表零对应于 show version 命令,列表一对应于 show ip int br 命令,列表二对应于 show int status 命令。列表编号直接对应于命令运行的顺序。

Arista EOS 命令 相关列表
show version output.stdout_lines[0]
show ip int br output.stdout_lines[1]
show int status output.stdout_lines[2]

扩展命令模块的使用:主机变量

那么,如果我们同时在两个或多个网络设备上运行会发生什么?

diagram of Ansible running multiple network devices

变量 output 作为每个清单主机上的 主机变量 唯一保存。如果我有三个交换机并针对它们运行此 playbook,那么每个唯一主机都会有一个 output 变量。为了进行演示,我们将从上面 show ip int br 命令中获取交换机 switch03 的以太网 1 端口的 IP 地址。show ip int br 对应于我们运行的第二个命令,以太网 1 接口显示在第 2 行,因此我们知道我们需要 stdout_lines[1][1]。要引用有关特定主机的变量,我们使用关键字 hostvars 并对我们想要的主机进行字典查找。

debug 任务将如下所示

- name: debug hostvar
  debug:
    var: hostvars["switch03"].output.stdout_lines[1][1]

输出与我们的预期相符

TASK [debug hostvar] ***************************************************************
ok: [switch03] => {
    "hostvars["switch03"].output.stdout_lines[1][1]": "Ethernet1              172.16.1.3/24      up         up              1500"
}

默认情况下,任务将使用特定于该主机变量,但在使用 hostvars 时,您可以直接引用其他主机变量。

命令模块任务中的条件:wait_for

wait_for 参数在命令运行后直接应用条件逻辑。这意味着在同一个任务中,您可以决定在输出不匹配所需状态时故意失败。默认情况下,在上述任务中,当未指定 wait_for 参数时,任务仅运行一次。但是,如果指定了 wait_for 参数,则任务将一直运行,直到满足条件或达到最大重试次数(默认值为 10 次重试)。如果我打开命令日志记录,我就可以轻松地通过一个专门用于演示目的的 playbook 来查看这一点。

---
- hosts: eos
  connection: network_cli
  tasks:
    - name: execute Arista eos command
      eos_command:
        commands:
          - show int status
        wait_for:
          - result[0] contains DURHAM

此 playbook 将运行 10 次 show int status,因为它永远不会在 show int status 的输出中找到 DURHAM 这个词。

show logging 命令显示该命令确实运行了 10 次

Mar 24 20:33:52 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=17 start_time=1521923632.5 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:53 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=18 start_time=1521923633.71 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:54 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=19 start_time=1521923634.81 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:55 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=20 start_time=1521923635.92 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:56 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=21 start_time=1521923636.99 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:58 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=22 start_time=1521923638.07 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:33:59 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=23 start_time=1521923639.22 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:34:00 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=24 start_time=1521923640.32 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:34:01 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=25 start_time=1521923641.4 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Mar 24 20:34:02 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=26 start_time=1521923642.47 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status

在这里,我们可以查看一个实际示例。对于此 playbook,所有内容都已配置为与另一台设备建立 OSPF 邻接关系,除了 ip ospf area 命令。我们将应用该命令,然后使用 wait_for 参数确保邻接关系建立(由 FULL 指示)。如果在 10 次重试内未找到 full,则任务将失败。

---
- hosts: eos
  connection: network_cli
  tasks:
    - name: turn on OSPF for interface Ethernet1
      eos_config:
        lines:
          - ip ospf area 0.0.0.0
        parents: interface Ethernet1

    - name: execute Arista eos command
      eos_command:
        commands:
          - show ip ospf neigh
        wait_for:
          - result[0] contains FULL

使用 ansible-playbook 命令执行 playbook

  ansible-playbook ospf.yml

PLAY [eos] *********************************************************************************************

TASK [turn on OSPF for interface Ethernet1] *******************************************************
changed: [eos]

TASK [execute Arista eos command] ****************************************************************
ok: [eos]

PLAY RECAP ******************************************************************************************
eos                    : ok=2    changed=1    unreachable=0    failed=0

在命令行上检查确认 playbook 已成功运行

eos#show ip ospf neigh
Neighbor ID     VRF      Pri State             Dead Time   Address         Interface
2.2.2.2         default  1   FULL/DR           00:00:33    172.16.1.2      Ethernet1

除了 contains 之外,我们还可以使用

  • eq:等于
  • neq:不等于
  • gt:大于
  • ge:大于或等于
  • lt:小于
  • le:小于或等于

还有三个参数可以与 wait_for 结合使用。所有这些都在各个模块页面上进行了记录

参数 描述
interval 每次命令重试之间的时间
retries 我们重试任务直到失败(或满足条件)的次数
match 匹配所有条件或仅匹配其中任何一个

让我们快速详细说明一下 match 参数

- name: execute Arista eos command
  eos_command:
    commands:
      - show ip ospf neigh
    match: any
    wait_for:
      - result[0] contains FULL
      - result[0] contains 172.16.1.2

设置 match: any 后,如果结果包含 FULL 或 172.16.1.2,则任务将成功。使用 match: all(这是默认值),在任务成功通过之前,两者都必须为真。如果您有多个条件,则更有可能希望所有条件都满足,而不是仅满足其中一个。

在什么场景下需要使用match: any呢?假设您需要确认数据中心的网络连接是否正常。对于这个特定的数据中心,您有五个 ISP(互联网服务提供商)以及五个数据中心与这些 ISP 之间独立的 BGP 连接。Ansible Playbook 可以检查所有五个 BGP 连接,并在其中**任何**一个连接正常工作时继续执行,而不是全部五个连接都正常工作。请记住,**any** 表示 OR(或),而**all** 表示 AND(与)。

参数 描述
match: any 隐式 OR,任何条件都可以满足
match: all 隐式 AND,所有条件都必须满足

否定条件:处理逆向逻辑

有时您需要在命令输出中查找缺失或其他否定条件。在任何否定场景中使用neq比较很诱人,但它并不总是正确的选择。如果您希望contains的逆向逻辑(此命令的输出不应包含此内容),请考虑使用register关键字存储输出,然后在后续任务中使用when语句。如果您希望在条件不满足时停止 playbook,请考虑简单地使用fail 模块assert 模块,您可以在其中故意失败。上面显示的neq只有在您可以获取确切值(如果您能获得键值对或 JSON)而不是获取字符串或字符串列表时才有意义。否则,您将进行精确的字符串比较。

更进一步

阅读网络模块中关于处理命令输出的文档此处

像 ge、le 等更具体的条件在某些网络平台的 JSON 输出上效果非常好,如文档中的示例所示。




在 5 分钟内连接 Ansible Tower 和 Jenkins

在 5 分钟内连接 Ansible Tower 和 Jenkins

我们经常从客户那里听到他们正在以某种方式使用 Jenkins。由于我是一名顾问,我很幸运能亲耳听到我们的客户正在使用什么以及他们如何需要集成 Ansible Tower。一直以来,都有一种方法可以使用tower-cli来集成 Ansible Tower 和 Jenkins,但我认为可以有一种更简洁、更接近原生方法的方式来实现它。

所以我们开始了。我录制了这段简短的屏幕录制,向您展示它是多么容易。

屏幕录制目前不可用。您可以在下面的链接或 Ansible 社区论坛中找到有用的材料:https://forum.ansible.com/tag/awx

您将在下面找到一些来自视频的链接以及如何试用 Ansible Tower 的链接。

plugins.jenkins.io/ansible-tower

wiki.jenkins.io/display/JENKINS/Ansible+Tower+Plugin




Windows 包管理

Windows 包管理

欢迎来到我们以 Windows 为中心的入门系列的第三部分!

在上一篇文章中,我们介绍了如何使用 Ansible 和 Ansible Tower 来帮助管理您的 Active Directory 环境。这篇文章将介绍如何在您的域中配置其中一些机器。这篇文章的大部分内容都将围绕特定的模块展开。Ansible 拥有大量的 Windows 模块,可以在这里找到。由于时间不是一个循环,我今天无法讨论所有这些模块,而只能讨论一些广泛使用的模块。

MSI 和 win_package 模块

所以您已经建立了域,并且已经向其中添加了机器,现在让我们在这些机器上安装一些东西。在继续讨论我们将要讨论的模块之前,我有一些说明。模块 win_msi 已弃用,将在 Ansible 2.8 中删除(截至本文发布时的当前版本为 2.5)。您可以使用win_package来代替它,我将在本文中使用它。

好了,回到安装东西上来。win_package 模块是首选。它专门用于需要安装或卸载的.msi.exe文件。这些文件也可以来自本地、URL 或网络资源。

模块中的参数增加了很大的灵活性。从 Ansible 2.5 开始,您现在可以列出您的参数,模块将根据需要转义参数。但是,在处理 MSI 包时建议使用字符串,因为 MsiExec 存在独特的转义问题。

下面是一些关于如何使用 win_package 模块的示例。第一个示例显示了如何安装 Visual C++ 并列出参数

- name: Install Visual C thingy with list of arguments instead of a string
  win_package:
    path:
http://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe
    product_id: '{CF2BEA3C-26EA-32F8-AA9B-331F7E34BA97}'
    arguments:
    - /install
    - /passive
    - /norestart

上面,我们看到产品 ID 已列出。虽然 Ansible 可以并且确实会在 MSI 在本地时从中提取 ID,但我们不想强制主机下载 MSI(如果不需要)。当您提供产品 ID 时,Ansible 可以快速检查包是否已安装,而无需首先从互联网下载可能很大的 MSI。您可以在没有产品 ID 的情况下安装。下面是一个示例:

- name: Install Remote Desktop Connection Manager locally omitting the product_id
  win_package:
    path: C:\temp\rdcman.msi
    state: present

如前所述,您还可以从网络共享下载并指定访问该共享所需的凭据。下面的示例显示了它的实际操作,从网络资源安装 7-zip:

- name: Install 7zip from a network share specifying the credentials
  win_package:
    path: \\domain\programs\7z.exe
    product_id: 7-Zip
    arguments: /S
    state: present
    user_name: DOMAIN\User
    user_password: Password

Windows 包管理和 Chocolatey

与大多数 Linux 发行版不同,Windows 没有内置的包管理器。Windows 确实有 Windows 应用商店,但我认为这些产品中没有很多进入数据中心。

但是,有一个名为 Chocolatey 的社区项目为 Windows 用户提供了完整的包管理体验。它有助于消除管理原始setup.exe.msi文件带来的某些痛苦。而且您可能知道,我们有一个模块可以用来实现它!

但在我们开始讨论模块之前,让我们更多地了解一下 Chocolatey。对于可能使用 Mac 的人来说,一个很好的比较是,Chocolatey 类似于 Homebrew。Chocolatey 旨在使用了解版本控制和依赖关系要求的打包框架,轻松处理管理 Windows 软件(安装程序、zip 存档、运行时二进制文件、内部和第三方软件)的各个方面。

Chocolatey 模块的使用方式与其 *nix 对应模块类似,简单而强大。它对版本有一个软性要求。我的意思是,它需要 v. 0.10.5 才能运行,但如果 Chocolatey 没有看到该版本,它会为您更新它。为了使这个甜点更甜,如果机器上不存在 Chocolatey,模块也会在执行分配的任务之前为您安装它。

要开始使用该模块,最简单的示例之一可能是安装一个轻量级的 CLI 工具。让我们使用 git,因为每个人的工作流程都一样,对吧?

- name: Install git
  win_chocolatey:
    name: git
    state: present

抛开玩笑,安装 git 就是这么简单。如果您需要特定版本的某个软件,那么安装其他版本的软件也同样简单。假设您需要 Notepad++ 6.6 版本。它看起来像这样:

- name: Install notepadplusplus version 6.6
  win_chocolatey:
    name: notepadplusplus
    version: '6.6'

在声明版本时需要注意的一件事:确保将其输入为字符串(请参阅 6.6 周围的两个引号)。原因是,如果它没有作为字符串输入,则会被视为 YAML float。许多有效的版本号无法正确转换为 float 并产生相同的结果(例如,对于大多数版本控制方案,'6.10' != '6.1',但作为 float 的 6.10 将变为 6.1),因此养成始终引用版本号的习惯以确保它们不会被重新格式化是一个好习惯。

某些软件包可能需要交互式用户登录才能进行安装。要传递正确的凭据,您可以使用become来实现。下面的示例显示了一个需要使用become安装的软件包。请注意,您可以成为:System,并且它不会要求您提供密码。

- name: Install a package that requires 'become'
  win_chocolatey:
    name: officepro2013
  become: yes
  become_user: Administrator
  become_method: runas

win_chocolatey模块强大而有效,但在某些情况下,如果没有 become 则无法工作。没有简单的方法可以确定软件包是否需要 become,因此最好的方法是在没有 become 的情况下尝试,如果失败则使用become

软件包和 Windows 自动化中的巧克力棒

为了结束这篇博文,我们介绍了两种自动化 Windows 环境软件包安装的方法。无论您是否完全使用 Chocolatey,或者需要安装一些软件包,Ansible 都能以简单易读的格式为您完成所有这些操作以及更多操作。

在“Windows 自动化入门”系列的下一篇文章(也是最后一篇文章)中,我们将讨论使用 Ansible 在 Windows 中进行安全和更新!




连接到 Windows 主机

连接到 Windows 主机

欢迎来到我们以 Windows 为中心的入门系列的第一部分!

您想使用 Red Hat Ansible Tower 自动化一些 Windows 主机,但不知道如何设置所有内容吗?您是否担心 Red Hat Ansible Engine 无法与您的 Windows 服务器通信,而无需安装大量额外的软件?您想轻松自动化每个人最好的朋友 Clippy 吗?

Ansible-Windows-Clippy

我们无法帮助解决最后一件事,但如果您对其他两个问题回答“是”,那么您来对地方了。在这篇文章中,我们将引导您完成设置和使用 Ansible Engine 连接到 Windows 主机所需的所有步骤。

为什么要自动化 Windows 主机?

您可以使用 Ansible Engine 为 Windows 主机执行以下众多操作

  • 启动、停止和管理服务
  • 推送和执行自定义 PowerShell 脚本
  • 使用 Chocolatey 包管理器管理软件包

除了使用本地或域用户连接和自动化 Windows 主机外,您还可以使用runas以管理员身份执行操作(Windows 中的 Linux sudosu替代方案),因此不会丢失任何权限提升功能。

需要什么?

在开始之前,让我们先了解一下基本要求。首先,您的控制机器(Ansible引擎将从中执行您选择的Windows模块的位置)需要运行Linux。其次,Windows支持一直在快速发展,因此请确保使用最新版本的Ansible引擎以获得最新的功能!

对于目标主机,您应该至少运行Windows 7 SP1或更高版本,或Windows Server 2008 SP1或更高版本。您不希望运行像Windows NT这样的90年代的东西,因为可能会发生这种情况

Ansible-Windows-90s

最后,由于Ansible通过使用Windows远程管理 (WinRM)(作为Linux/Unix机器上SSH的替代方案)连接到Windows机器并运行PowerShell脚本,因此应创建并激活WinRM侦听器。好消息是,使用脚本可以非常轻松快捷地连接到您的Windows主机,我们将在下面的小节中讨论。

步骤1:设置WinRM

什么是WinRM?它是Windows Vista及更高版本的一项功能,允许管理员远程运行管理脚本;它通过实现基于简单对象访问协议(通常称为SOAP)的WS-Management协议来处理这些连接。使用WinRM,您可以执行诸如访问、编辑和更新本地和远程计算机上的数据等操作,就像网络管理员一样。

WinRM非常适合与Ansible引擎一起使用的原因是,您可以从在非Windows操作系统(在本例中为Linux)上运行的WS-Management协议实现中获取硬件数据。它基本上就像一个翻译器,允许不同类型的操作系统协同工作。

那么,我们如何连接呢?

在大多数版本的Windows中,WinRM都内置其中,但默认情况下未启用。有一个为Ansible配置远程连接脚本,您可以在远程Windows机器上运行(在PowerShell控制台中以管理员身份运行)以启用WinRM。要设置https侦听器,构建自签名证书并执行PowerShell命令,只需像下面的示例一样运行脚本(如果您在本地机器上存储了.ps1文件)

Ansible-Windows-Powershell

注意:如果您有很多需要在环境中设置的Windows主机,win_psexec模块将帮助您在多台机器上启用WinRM。

有关WinRM和Ansible的更多信息,请查看Windows远程管理文档页面。

步骤2:安装Pywinrm

由于pywinrm依赖项未随Ansible引擎一起提供(并且这些依赖项对于使用WinRM是必要的),因此请确保在安装Ansible的机器上安装与pywinrm相关的库。最简单的方法是在您的终端中运行pip install pywinrm

步骤3:正确设置您的清单文件

为了正确连接到您的Windows主机,您需要确保在清单文件的主机变量部分中加入ansible_connection=winrm,以便Ansible引擎不会一直尝试通过SSH连接到您的Windows主机。

此外,WinRM连接插件默认通过https进行通信,但它支持不同的模式,例如消息加密的http。由于我们之前运行的“为Ansible配置远程连接”脚本使用自签名证书设置了内容,因此我们需要告诉Python:“不要尝试验证此证书,因为它不会来自有效的CA。”因此,为了防止出现错误,您需要放入host vars部分的另一件事是:ansible_winrm_server_cert_validation=ignore

为了让您在一个地方看到它,这里有一个主机文件的示例(请注意,您特定环境的一些详细信息将有所不同)

[win]
172.16.2.5
172.16.2.6

[win:vars]
ansible_user=vagrant
ansible_password=password
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore

步骤4:测试连接

让我们检查一下一切是否正常。为此,请转到控制节点的终端并键入ansible [host_group_name_in_inventory_file] -i hosts -m win_ping。您的输出应该如下所示

Ansible-Windows-Screen-Grab

注意:所有Windows模块上的win_前缀都表示它们是在PowerShell而不是Python中实现的。

WinRM故障排除

由于WinRM可以以多种不同的方式配置,因此看似与Ansible引擎相关的错误实际上可能是由于主机设置问题造成的。您可能会看到的一些WinRM错误示例包括HTTP 401或HTTP 500错误、超时问题或连接拒绝。要获取有关如何解决这些问题的提示,请访问我们Windows设置文档页面上的常见WinRM问题部分。

结论

您现在应该可以使用Ansible自动化您的Windows主机,而无需安装大量额外的软件!但是请记住,即使您按照上述说明操作,某些Windows模块也可能有其他规范(例如,更新的操作系统或更新的PowerShell版本)。确定您是否满足正确要求的最佳方法是检查特定于模块的文档页面。

有关如何使用Ansible引擎自动化Windows主机的更深入信息,请查看我们的Windows常见问题解答Windows支持文档页面,并继续关注更多与Windows相关的博文!




使用Ansible缓解网络漏洞

使用Ansible缓解网络漏洞

即使网络也不例外

就像Windows和Linux服务器一样,网络设备也可能受到其操作系统中发现的漏洞的利用。许多IT组织没有一个全面的策略来缓解跨越多个团队(网络、服务器、存储等)的安全漏洞。由于大多数网络操作仍然是手动的,因此需要跨由数百个网络设备组成的多个平台快速可靠地进行缓解变得极其重要。

在思科的2018年3月思科IOS和IOS XE软件安全建议捆绑出版物半年报中,详细介绍了22个漏洞。虽然Red Hat不报告或跟踪各个网络供应商的CVE,但Red Hat Ansible Engine可用于根据网络供应商提供的说明快速自动化CVE的缓解。

在这篇博文中,我们将逐步介绍CVE-2018-0171,其标题为“Cisco IOS和IOS XE软件智能安装远程代码执行漏洞”。思科将此CVE标记为严重,并提供以下标题摘要

“...思科IOS软件和思科IOS XE软件的智能安装功能中的漏洞可能允许未经身份验证的远程攻击者触发受影响设备的重新加载,从而导致拒绝服务(DoS)状况,或在受影响设备上执行任意代码。”

从网络收集信息

用户利用Ansible模块访问设备、检索信息、执行命令和使用特定关键字处理系统。CVE首先需要的是收集清单。为了缓解CVE,需要网络平台和特定版本的代码。CVE-2018-0171影响IOS和IOS-XE网络操作系统,Ansible可以轻松获取此信息。让我们使用ios_facts模块,它返回键值对以供后续任务使用。例如:ansible_net_model返回模型,ansible_net_image返回设备正在运行的映像文件。有关完整列表,请参阅ios_facts模块的文档页面。

- name: gather facts for ios platforms
  ios_facts:
    gather_subset: all

- name: output facts to terminal window
  debug:
    msg: >
      Device {{ansible_net_hostname}}, model
{{ansible_net_model}}, running {{ansible_net_version}}

执行剧本时,我们会得到如下所示的漂亮输出

ok: [rtr1] => {
    "msg": "Device rtr1, model CSR1000V, running 16.05.02\n"
}
ok: [rtr2] => {
    "msg": "Device rtr2, model CSR1000V, running 16.05.02\n"
}
ok: [switch] => {
    "msg": "Device c3850-1, model WS-C3850-24T, running 16.06.01\n"
}

这使我们能够快速获取有关网络的有用信息,并根据思科安全建议对其进行检查。在GitHub网络自动化项目上的演示中,我们展示了如何使用网络事实快速构建漂亮的HTML报告。

漏洞CVE-2018-0171指定,要查看设备是否容易受到攻击,我们必须运行show vstack config命令。在我的网络中,我有三台运行IOS-XE的设备,两台是CSR1000V设备,一台是3850设备。这两台CSR设备没有该命令,而3850交换机有。为了使我的剧本能够处理命令不存在时的错误,我可以用ignore_errors参数。否则,当目标网络节点无法使用该命令时,剧本将失败并退出。或者,我可以通过使用限制仅在交换机上运行剧本。对于此示例,让我们假设我们正在运行具有show vstack config命令的Cisco 3850。

- name: run show vstack config
    ios_command:
      commands:
        - show vstack config
    register: showvstack

在上面的剧本中,我使用了register: showvstackshowvstack是一个用户定义的术语(我选择的,它不是保留的)。通过注册它,我可以在剧本中稍后使用show vstack config的输出。我们可以使用debug模块查看showvstack变量以了解其格式

ok: [switch] => {
    "showvstack": {
        "changed": false,
        "failed": false,
        "stdout": [
            "Capability: Director | Client\n Oper Mode: Disabled\n Role: NA\n Vstack Director IP address: 0.0.0.0\n\n *** Following configurations will be effective only on director ***\n Vstack default management vlan: 1\n Vstack start-up management vlan: 1\n Vstack management Vlans: none\n Join Window Details:\n\t Window: Open (default)\n\t Operation Mode: auto (default)\n Vstack Backup Details:\n\t Mode: On (default)\n\t Repository:"
        ],

<<rest of output removed for brevity>>

有一个stdout和一个stdout_lines。要详细了解常见的返回值,请参阅文档。接下来,我们将使用我最喜欢的模块,即assert模块。这使我们能够检查给定的表达式是否为真,如果它们不为真则使任务失败。思科提供了两个输出,我们需要在show vstack config命令的结果中检查这两个输出

switch1# show vstack config
Role: Client (SmartInstall enabled)

switch2# show vstack config
Capability: Client
Oper Mode: Enabled
Role: Client

我们可以使用assert模块检查保存在showvstack变量中的文本

- name: Check to make sure Cisco's Smart Install Client Feature is not enabled (1/2)
  assert:
    that:
      - "'SmartInstall enabled' not in showvstack.stdout"
      - "'Role' not in showvstack.stdout"
      - "'Client' not in showvstack.stdout"

在assert模块中添加的每一行都意味着存在一个隐式AND,这意味着所有三个都需要为真才能使任务通过。

类似地,我们可以检查第二个语句

- name: Check to make sure Cisco's Smart Install Client Feature is not enabled (1/1)
  assert:
    that:
      - "'Oper Mode' not in showvstack.stdout"
      - "'Enabled' not in showvstack.stdout"
      - "'Role' not in showvstack.stdout"
      - "'Client' not in showvstack.stdout"

对于此特定CVE,它列出了没有可用的解决方法。在某些CVE中,我们可以使用ios_command或ios_config模块根据供应商提供的说明来缓解CVE。对于此特定CVE,它链接到有关如何使用命令no vstack禁用vstack的文档,该命令可以使用ios_command模块发送。它还建议对于较旧的版本,阻止TCP端口4786上的流量,这可以使用ios_config模块推送。由于CVE上未提供解决方法,因此网络运营商需要根据其环境做出明智的决定。或者,对于CVE-2018-0150,提供了解决方法,并且ios_config可以简单地发送no username cisco来缓解CVE。

Red Hat Ansible Engine和Red Hat Ansible Tower可用于帮助网络运营商和管理员扩展重复性任务,例如检查这数十个CVE并确保其网络免受漏洞的侵害。在服务器端,当系统管理员使用Red Hat Insights时,他们可以自动生成剧本以帮助解决Red Hat Enterprise Linux的漏洞并主动识别对安全、性能和稳定性的威胁。Ansible可以成为在整个IT基础设施中执行任务的通用方法。