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

在 Ansible 中使用 win_dsc 模块

在 Ansible 中使用 win_dsc 模块

您好,欢迎来到 Ansible + Windows 入门系列的另一篇文章!在本文中,我们将探索什么是“期望状态配置”、它为什么有用以及如何使用它与 Ansible 来管理您的 Windows 节点。

什么是 DSC?

那么什么是“期望状态配置”呢?它基本上是一个系统配置管理平台,使用声明性模型;换句话说,您告诉 DSC “做什么”,它将找出“怎么做”。与 Ansible 类似,DSC 使用推模式执行将配置发送到目标主机。在将资源交付给多个目标时,这一点非常重要。

这个节省时间的工具内置于 PowerShell 中,通过代码定义 Windows 节点设置。它使用本地配置管理器(即在每个节点上运行的 DSC 执行引擎)。

微软鼓励社区共同努力构建和维护各种技术的 DSC 资源。这些努力的结果每月都会在 PowerShell 库中作为 DSC 资源包 发布。如果没有您需要管理的技术的本地 Ansible 模块可用,可能存在一个 DSC 资源。

如何将 DSC 与 Ansible 配合使用?

DSC 资源作为 PowerShell 模块分发,这意味着它的工作方式与 Ansible 类似,只是在不同的方式下实现。win_dsc 模块自 Ansible 2.4 发布以来一直可用,它可以在与 Windows 主机交互时影响现有的 DSC 资源。

要使用此模块,您需要 PowerShell 5.1 或更高版本。确保您的 Windows 节点上安装了正确版本的 PowerShell 后,使用 DSC 就像使用 win_dsc 模块执行任务一样简单。

让我们看看它的实际应用。在此示例中,我们将确保安装了 DNS 服务器,xDnsServer DSC 资源模块存在,并使用其中几个 DSC 资源来定义一个区域和一个 A 记录。

- hosts: Erasmus
  tasks:
  - win_feature:
      name:
      - DNS
      - RSAT-DNS-Server
      state: present
  - win_psmodule:
      name: xDnsServer
      repository: PSGallery
  - win_dsc:
      resource_name: xDnsServerPrimaryZone
      Name: my-arbre.com
  - win_dsc:
      resource_name: xDnsRecord
      Name: test
      Zone: my-arbre.com
      Target: 192.168.17.75
      Type: ARecord

让我们逐步了解上面的剧本中发生了什么:它首先在目标上安装 DNS 服务器,然后安装 xDnsServer DSC 资源模块。现在已经安装了 DSC 资源,调用 xDnsServerPrimaryZone 资源来创建区域,然后使用参数调用 xDnsRecord 资源以填写我们 my-arbre.com 站点的区域详细信息。xDnsServer 资源从 PowerShellGallery.com 下载,该网站为 DSC 资源提供了一个可靠的社区。

请记住,win_dsc 模块旨在驱动单个 DSC 资源提供程序,使其像 Ansible 模块一样工作。它不打算用于定义主机上的 DSC 等效剧本并运行它。

还有几点需要注意

  • 在定义任务时,resource_name 必须设置为已安装在目标上的 DSC 资源的名称。
  • 与文档匹配的大小写是最佳实践;这也便于区分 DSC 资源选项和 Ansible 的 win_dsc 选项。

结论

现在您已经了解了如何通过在 Ansible 剧本中调用 win_dsc 模块来使用 DSC 来管理您的 Windows 节点。要详细了解 Ansible + DSC,请查看我们关于该主题的官方 文档页面

特别感谢我的队友 John Lieske 为本文提供了大量的技术帮助。一如既往,祝您自动化愉快!




工作流作业模板入门

工作流作业模板入门

欢迎来到入门系列的另一篇文章!今天我们将介绍工作流作业模板的主题。如果您不知道 Red Hat Ansible Tower 中的常规作业模板是什么,请阅读之前发布的文章,该文章对它们进行了描述。它将为您提供一些技术细节,这些细节将成为您学习工作流主题的有效起点。

熟悉基本知识后,请继续阅读!我们将介绍工作流作业模板究竟是什么、它们有什么用、如何生成/编辑一个,以及一些额外的提示以及最佳实践,以便充分利用这个很棒的工具。

什么是工作流作业模板?

“工作流”一词概括了一切。Ansible Tower 中的此特定功能(从版本 3.1 开始可用)使用户能够创建由任何组合的作业模板、项目同步和清单同步组成的序列,这些序列彼此链接在一起,以便作为单个单元执行。因此,工作流可以帮助您将剧本和作业模板整理到不同的组中。

工作流有什么用?

通过利用此功能,您可以为不同的团队设置有序的结构。例如,只要两个不同的环境(例如,网络和开发人员)有权访问工作流,它们就可以通过工作流进行交互。参与的每个人都不需要知道哪些作业运行在什么之后,因为该结构是由创建工作流的用户为他们设置的。这连接了不同的作业类型并统一了项目,而无需每个团队都了解对方的全部情况。

工作流另一个用途是,它允许用户将任意数量的剧本“串联”起来,并根据作业的成功或失败情况构建决策树。您可以根据需要使它们尽可能简单或复杂!

如何创建一个工作流?

[进入 Ansible Tower 顶部菜单中的“模板”部分

Getting-Started-Tower-Workflows-13

从那里,点击“添加”,但一定要选择“工作流模板”

Getting-Started-Tower-Workflows-15

您将看到这个新屏幕,您可以在其中随意命名工作流模板并保存它

Getting-Started-Tower-Workflows-10

完成后,进入“编辑工作流”

Getting-Started-Tower-Workflows-1

此屏幕将弹出,您可以在其中添加不同的作业模板,并确保它们在失败、成功或两种结果的情况下运行

Getting-Started-Tower-Workflows-11

请注意,您可以决定在成功时、失败时或始终运行哪些内容。

[**Getting-Started-Tower-Workflows-9

如上一节所述,您可以使 Ansible 工作流尽可能简单……

Getting-Started-Tower-Workflows-4

……或尽可能复杂!

Getting-Started-Tower-Workflows-12

一切设置并保存后,您就可以启动模板了,您可以通过点击您想要运行的工作流旁边的火箭图标来实现

Getting-Started-Tower-Workflows-7

您还可以用工作流做什么?

您可以 安排工作流 在您需要的时候运行!只需点击任何工作流作业模板旁边的日历图标

Getting-Started-Tower-Workflows-5

……并填写您希望指定的工作流自动运行的时间信息

Getting-Started-Tower-Workflows-8   如果您创建了一个对您非常有效的 工作流模板,并且您想复制它,请点击下面突出显示的按钮

Getting-Started-Tower-Workflows-2

请记住,复制工作流不会复制与原始工作流关联的任何权限、通知或计划。

如果您需要为工作流模板中涉及的剧本设置额外的变量和/或允许用户输入授权,那么 设置调查 是最好的方法。要设置一个调查,请选择一个工作流模板,然后点击“添加调查”按钮

Getting-Started-Tower-Workflows-3

将显示一个调查屏幕,您可以在其中填写特定的问题和答案类型

Getting-Started-Tower-Workflows-14

通知 可以让您对特定工作流有更多控制和了解。要激活一个通知,请选择您想要设置通知的工作流,然后点击“通知”按钮

Getting-Started-Tower-Workflows-16

请记住,您必须已经在“通知”列表中设置了一些通知。弹出的屏幕将使您能够选择特定的通知;在下面的示例中,“工作流特定通知”已设置为在成功或失败运行时激活

Getting-Started-Tower-Workflows-6

注意:如果您针对动态清单采取行动,请确保在创建新的工作流作业模板时选择清单上的“启动时更新”!

结论

现在您知道如何将任意数量的剧本组合成一个自定义的决策树,并且能够安排这些作业、添加通知等等。一个额外的优势是,这不是企业独有的功能,因此无论您的 Ansible Tower 许可证类型如何,您都可以登录您的实例,尽情创建工作流!

要详细了解如何创建和修改工作流作业模板,请查看我们关于该主题的 官方文档页面

我希望这篇文章对您有所帮助,并帮助您利用 Ansible Tower 中强大的自动化功能!




Ansible Windows 安全简介

Ansible Windows 安全简介

欢迎来到我们以 Windows 为中心的入门系列的另一篇文章!在之前的文章中,我们讨论了如何连接到 Windows 机器,简要介绍了如何使用 Ansible 与 Active Directory 配合使用,并讨论了使用 Ansible 在 Windows 上进行包管理的选项。在本文中,我们将简要介绍如何将安全方法和实践应用到我们的原始主题中。

三元组

为了讨论与 Ansible 和 Windows 相关的安全问题,我们将应用来自流行的 CIA 三元组的概念:机密性、完整性和可用性。

机密性不言而喻——保护机密性有助于将私有数据限制为仅授权用户,并有助于防止未经授权的用户查看它。实现这一点的方法涉及多种技术,例如身份验证、授权和加密。在使用 Windows 时,这意味着要确保主机知道所有必要身份,每个用户都经过适当的验证,并且数据受到保护(例如,通过加密),以便只有授权方可以访问它。

完整性是指确保数据不被篡改或损坏,使其无法使用。当您在网络上发送数据时,您希望确保数据到达时与发送时的状态相同。这将适用于 Ansible 剧本中的任务、任何可能传输的文件或安装的包(等等!)。

可用性主要指确保数据在授权用户需要访问时可供他们访问。将冗余、弹性、高可用性或集群视为帮助确保系统和数据可用性的方法。

机密性

正如 Bianca 在本系列的第一篇文章中提到的,Ansible 使用 WinRM 并使用变量发送用户名/密码(或者在 Ansible Tower 的情况下,使用凭据)。在下面的示例中,显示了一个包含变量的清单文件,这些变量作为[win:vars],证书被忽略。

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

在 Active Directory 环境中,加入域的宿主不需要忽略证书,这些证书验证您的控制节点是否已设置为信任 Active Directory CS。

完整性

Active Directory(由 John 在第二篇文章中讨论)为凭据添加了更多验证,并为其范围内的域上的证书验证提供了权威。目录服务通过充当权威的凭据存储库,增强了机密性。将宿主加入域建立了其信任,因此只要请求资源的用户有效,那么加入域的宿主就会具有建立的完整性。

Ansible 能够安全地使用有效的域凭据添加和管理用户(win_domain_user)、组(win_domain_group)或宿主(win_domain_membership)。请参阅以下示例,了解如何使用剧本执行这些任务。

- name: Join to domain
  win_domain_membership:
    dns_domain_name: tycho.local
    hostname: mydomainclient
    domain_admin_user: "{{ win_domain_admin_user }}"
    domain_admin_password: "{{ win_domain_admin_password }}"
    domain_ou_path: "OU=Windows,OU=Servers,DC=tycho,DC=local"
    state: domain
  register: domain_state

- name: set group with delete protection enabled
  win_domain_group:
    name: Users
    scope: domainlocal
    category: security
    ignore_protection: no

可用性

在最近的一篇与 Windows 相关的文章中,关于包管理,Jake 提供了一些使用 Ansible 模块 win_packagewin_chocolatey 的示例。这与安全三元组的第三部分相关,因为数据模型的物理层和传输层在可获取性方面受到了很多关注,但快速高效的软件/补丁管理也是维护这种可用性的一个部分。减少更新推出所消耗的时间可以减少停机时间。在推出过程中节省几分钟甚至几秒钟,可以带来更一致的服务交付。

一项重要的与可用性相关的安全功能,可以通过 Ansible 模块执行,与更新有关。顾名思义,win_updates 通过自动化 Windows 更新客户端,同时搜索、下载和安装所有 Windows 宿主上的更新。让我们进一步探讨这个模块。

以下示例取自 示例,它是与安全自动化相关的 Ansible 角色 集的一部分。在这里你可以看到 win_updates 模块的实际应用。

tasks:
 - name: Install security updates
   win_updates:
     category_names:
       - SecurityUpdates
     Notify: reboot windows system

另一个示例显示了如何在剧本中使用此模块来修补 Windows 节点,以及 win_reboot 模块,该模块用于---你猜对了!--- 自动重启 Windows 机器。

– name: Install missing updates
  win_updates:
    Category_names:
       – ServicePacks
       – UpdateRollups
       – CriticalUpdates
    Reboot: yes

结论

安全是一个复杂且不断发展的领域,它取决于每个组织的特定环境、漏洞和特定需求。务必将以上内容视为指南,而不是清单;如果不能持续改进,那么无论实施多少措施,都不会产生任何持久的影响。

我们希望您觉得这些信息有所帮助,并且本五部分系列为您提供了使用 Ansible 为您完成工作,自信地自动化 Windows 宿主的工具!




Red Hat 单点登录与 Ansible Tower 集成

Red Hat 单点登录与 Ansible Tower 集成

您可能知道,Red Hat Ansible Tower 默认支持 SAML 身份验证(N 和 Z)。本文将指导您完成配置这两个产品以将身份验证委托给 RHSSO/Keycloak(Red Hat 单点登录)的步骤。

需求

  • 运行中的 RHSSO/Keycloak 实例
  • Ansible Tower
  • 两个产品的管理员权限
  • DNS 解析

实践实验室

除非您已经拥有自己的证书,否则第一步是创建一个证书。为此,请执行以下命令

openssl req -new -x509 -days 365 -nodes -out saml.crt -keyout saml.key

现在我们需要在 RHSSO 平台上创建 Ansible Tower 领域。转到“选择领域”下拉菜单,然后单击“添加新领域”。

Ansible-Tower-SSO-Screen-16

创建完成后,转到“密钥”选项卡,并删除默认情况下创建的所有证书、密钥等。

现在我们拥有了一个干净的领域,让我们用适当的信息填充它。单击右上角的“添加密钥库”,然后单击 RSA。

Ansible-Tower-SSO-Screen-15

单击保存并创建您的 Ansible Tower 客户端信息。建议从 Tower 配置开始,以便您可以注入元数据文件并自定义一些字段。

以管理员用户身份登录 Ansible Tower,然后转到“设置 > 配置 Tower > 身份验证 > SAML”。在这里,您将找到许多字段(其中两个是只读的),这些字段提供了使此工作正常进行所需的信息。

  • 断言使用者服务
  • 服务提供者的元数据 URL(这将返回您 IDP 的配置)

Ansible-Tower-SSO-Screen-18

现在让我们填写所有必需的字段。

  • SAML 服务提供者的实体 ID:tower.usersys.redhat.com(必须与 RHSSO 上的client_id 名称相同)
  • 公钥:使用 saml.crt(cat saml.crt 并复制/粘贴)
  • 私钥:使用相同的 .key(cat saml.key 并复制/粘贴)

Ansible-Tower-SSO-Screen-17

  • 服务提供者的组织信息
{
  "en-US": {
    "url": "https://rhsso.usersys.redhat.com:8443",
    "displayname": "RHSSO Solutions Engineering",
    "name": "RHSSO"
  }
}

Ansible-Tower-SSO-Screen-4

  • SAML 服务提供者的技术联系人
{
  "givenName": "Juan Manuel Parrilla",
  "emailAddress": "[email protected]"
}

Ansible-Tower-SSO-Screen-7

  • SAML 服务提供者的支持联系人
{
  "givenName": "Juan Manuel Parrilla",
  "emailAddress": "[email protected]"
}

Ansible-Tower-SSO-Screen-7

  • 已启用的 SAML 身份提供者
{
   "RHSSO": {
      "attr_last_name": "last_name",
      "attr_username": "username",
      "entity_id": "https://rhsso.usersys.redhat.com:8443/auth/realms/tower",
      "attr_user_permanent_id": "name_id",
      "url": "https://rhsso.usersys.redhat.com:8443/auth/realms/tower/protocol/saml",
      "attr_email": "email",
      "x509cert": "",
      "attr_first_name": "first_name",
      "attr_groups": "groups"
   }
}

注意:要在 JSON 上提供 x509cert 字段,只需执行此命令并将结果粘贴到 Ansible Tower 界面上

sed ':a;N;$!ba;s/\n//g' saml.crt

Ansible-Tower-SSO-Screen-20

  • 组织 SAML 映射
{
   "Default": {
      "users": true
   },
   "Systems Engineering": {
      "admins": [
         "[email protected]",
         "[email protected]",
         "[email protected]",
         "[email protected]
      ],
      "remove_admins": false,
      "remove_users": false,
      "users": true
   }
}

Ansible-Tower-SSO-Screen-10

推荐步骤和注意事项

  • RHSSO 是选定的名称,可以是您想要的任何名称,并且不与 DNS 或服务器配置绑定。这只是一个视觉标记。
  • 所有attr_ 字段都是必需的,它们将成为我们在下一步中将在客户端上创建的映射器。
  • Entity_id 将指向您的领域。通过 WebUI 转到您的 RHSSO 领域,在“常规”中,您将看到“OpenID 端点配置”。只需单击并获取“颁发者”字段以填写entity_id
  • “用于 url”是一个固定字段;在其中添加您的entity_id,然后添加/protocol/saml
  • 如果您在 RHSSO 中生成了证书/密钥,那么您将拥有它们的一行。要转换为 PEM 格式,您只需将它们包装在“-----BEGIN CERTIFICATE-----”等中,然后使用fold -w64 将单行拆分。

RHSSO 客户端配置

现在您已经在 Ansible Tower 上配置了 SAML,请保存更改并开始进行 RHSSO 客户端配置。

首先,以管理员用户身份登录 RHSSO 平台,然后转到“Tower”领域。从那里,转到“客户端”,然后选择“创建”。单击“选择文件”以导入我们已经在 Ansible Tower 上拥有的数据(要获取配置,请从您的笔记本电脑执行以下命令:curl -L -k https://tower.usersys.redhat.com/sso/metadata/saml/)。通过将其指向tower.usersys.redhat.com来修改客户端 ID,然后将“客户端协议”设置为 SAML,如下所示。

Ansible-Tower-SSO-Screen-19

接下来,修复配置以符合以下屏幕截图。

Ansible-Tower-SSO-Screen-1

最后一步是在 Tower 的 RHSSO 客户端上创建映射器。这样做是为了定义来自 RHSSO 的信息,这些信息将映射到 Ansible Tower 用户。

为此,我们必须转到映射器选项卡。

Ansible-Tower-SSO-Screen-14

以下是必需的映射器。

Ansible-Tower-SSO-Screen-6

以下屏幕截图显示了用户名、姓氏、电子邮件、用户 ID 和姓名的正确配置。

Ansible-Tower-SSO-Screen-22

Ansible-Tower-SSO-Screen-11

Ansible-Tower-SSO-Screen-8

Ansible-Tower-SSO-Screen-9

Ansible-Tower-SSO-Screen-3

注意:“firstName”和“lastName”区分大小写,因为它们映射了 RHSSO 用户属性。

现在您已全部设置好!

让我们使用已经在 RHSSO 上的用户进行测试(我们有将 RHSSO 与用户联合到ldap.example.com 的用户)。为了测试目的,如果您愿意,可以在“管理 > 用户”中创建一个用户。

现在转到 Ansible Tower 登录页面,您应该会看到“使用 S 登录”。

Ansible-Tower-SSO-Screen-21

单击此“S”,您将被重定向到 RHSSO 服务器上的登录页面。

Ansible-Tower-SSO-Screen-2

就是这样!Ansible-Tower-SSO-Screen-5

希望这篇关于 Red Hat 单点登录与 Ansible Tower 集成的指南对您有所帮助!




将 Shell 脚本转换为 Ansible

将 Shell 脚本转换为 Ansible

在最近一次客户访问中,我们被要求帮助将以下脚本迁移到 RHEL 和 AIX 服务器上,以部署集中式 sudoers 文件。这是一个常见的场景,可以提供一些利用高级 Ansible 功能的良好示例。此外,我们可以考虑从执行任务的脚本转变为描述和强制执行项目的幂等状态。

以下是脚本。

#!/bin/sh
# Desc: Distribute unified copy of /etc/sudoers
#
# $Id: $
#set -x

export ODMDIR=/etc/repos

#
# perform any cleanup actions we need to do, and then exit with the
# passed status/return code
#
clean_exit()
{
cd /
test -f "$tmpfile" && rm $tmpfile
exit $1
}

#Set variables
PROG=`basename $0`
PLAT=`uname -s|awk '{print $1}'`
HOSTNAME=`uname -n | awk -F. '{print $1}'`
HOSTPFX=$(echo $HOSTNAME |cut -c 1-2)
NFSserver="nfs-server"
NFSdir="/NFS/AIXSOFT_NFS"
MOUNTPT="/mnt.$$"
MAILTO="[email protected]"
DSTRING=$(date +%Y%m%d%H%M)
LOGFILE="/tmp/${PROG}.dist_sudoers.${DSTRING}.log"
BKUPFILE=/etc/sudoers.${DSTRING}
SRCFILE=${MOUNTPT}/skel/sudoers-uni
MD5FILE="/.sudoers.md5"

echo "Starting ${PROG} on ${HOSTNAME}" >> ${LOGFILE} 2>&1

# Make sure we run as root
runas=`id | awk -F'(' '{print $1}' | awk -F'=' '{print $2}'`
if [ $runas -ne 0 ] ; then
echo "$PROG: you must be root to run this script." >> ${LOGFILE} 2>&1
exit 1
fi

case "$PLAT" in
SunOS)
export PINGP=" -t 7 $NFSserver "
export MOUNTP=" -F nfs -o vers=3,soft "
export PATH="/usr/sbin:/usr/bin"
echo "SunOS" >> ${LOGFILE} 2>&1
exit 0
;;
AIX)
export PINGP=" -T 7 $NFSserver 2 2"
export MOUNTP=" -o vers=3,bsy,soft "
export PATH="/usr/bin:/etc:/usr/sbin:/usr/ucb:/usr/bin/X11:/sbin:/usr/java5/jre/bin:/usr/java5/bin"
printf "Continuing on AIX...\n\n" >> ${LOGFILE} 2>&1
;;
Linux)
export PINGP=" -t 7 -c 2 $NFSserver"
export MOUNTP=" -o nfsvers=3,soft "
export PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"
printf "Continuing on Linux...\n\n" >> ${LOGFILE} 2>&1
;;
*)
echo "Unsupported Platform." >> ${LOGFILE} 2>&1
exit 1
esac

##
## Exclude Lawson Hosts
##
if [ ${HOSTPFX} = "la" ]
then
echo "Exiting Lawson host ${HOSTNAME} with no changes." >> ${LOGFILE} 2>&1
exit 0
fi

##
## * NFS Mount Section *
##

## Check to make sure NFS host is up
printf "Current PATH is..." >> ${LOGFILE} 2>&1
echo $PATH >> $LOGFILE 2>&1
ping $PINGP >> $LOGFILE 2>&1
if [ $? -ne 0 ]; then
echo " NFS server is DOWN ... ABORTING SCRIPT ... Please check server..." >> $LOGFILE
echo "$PROG failed on $HOSTNAME ... NFS server is DOWN ... ABORTING SCRIPT ... Please check server ... " | mailx -s "$PROG Failed on $HOSTNAME" $MAILTO
exit 1
else
echo " NFS server is UP ... We will continue..." >> $LOGFILE
fi

##
## Mount NFS share to HOSTNAME. We do this using a soft mount in case it is lost during a backup
##
mkdir $MOUNTPT
mount $MOUNTP $NFSserver:${NFSdir} $MOUNTPT >> $LOGFILE 2>&1

##
## Check to make sure mount command returned 0. If it did not odds are something else is mounted on /mnt.$$
##
if [ $? -ne 0 ]; then
echo " Mount command did not work ... Please check server ... Odds are something is mounted on $MOUNTPT ..." >> $LOGFILE
echo " $PROG failed on $HOSTNAME ... Mount command did not work ... Please check server ... Odds are something is mounted on $MOUNTPT ..." | mailx -s "$PROG Failed on $HOSTNAME" $MAILTO
exit 1
else
echo " Mount command returned a good status which means $MOUNPT was free for us to use ... We will now continue ..." >> $LOGFILE
fi

##
## Now check to see if the mount worked
##
if [ ! -f ${SRCFILE} ]; then
echo " File ${SRCFILE} is missing... Maybe NFS mount did NOT WORK ... Please check server ..." >> $LOGFILE
echo " $PROG failed on $HOSTNAME ... File ${SRCFILE} is missing... Maybe NFS mount did NOT WORK ... Please check server ..." | mailx -s "$PROG Failed on $HOSTNAME" $MA
ILTO
umount -f $MOUNTPT >> $LOGFILE
rmdir $MOUNTPT >> $LOGFILE
exit 1
else
echo " NFS mount worked we are going to continue ..." >> $LOGFILE
fi


##
## * Main Section *
##

if [ ! -f ${BKUPFILE} ]
then
cp -p /etc/sudoers ${BKUPFILE}
else
echo "Backup file already exists$" >> ${LOGFILE} 2>&1
exit 1
fi

if [ -f "$SRCFILE" ]
then
echo "Copying in new sudoers file from $SRCFILE." >> ${LOGFILE} 2>&1
cp -p $SRCFILE /etc/sudoers
chmod 440 /etc/sudoers
else
echo "Source file not found" >> ${LOGFILE} 2>&1
exit 1
fi

echo >> ${LOGFILE} 2>&1
visudo -c |tee -a ${LOGFILE}
if [ $? -ne 0 ]
then
echo "sudoers syntax error on $HOSTNAME." >> ${LOGFILE} 2>&1
mailx -s "${PROG}: sudoers syntax error on $HOSTNAME" "$MAILTO" << EOF

Syntax error /etc/sudoers on $HOSTNAME.

Reverting changes

Please investigate.

EOF
echo "Reverting changes." >> ${LOGFILE} 2>&1
cp -p ${BKUPFILE} /etc/sudoers
else
#
# Update checksum file
#
grep -v '/etc/sudoers' ${MD5FILE} > ${MD5FILE}.tmp
csum /etc/sudoers >> ${MD5FILE}.tmp
mv ${MD5FILE}.tmp ${MD5FILE}
chmod 600 ${MD5FILE}
fi

echo >> ${LOGFILE} 2>&1

if [ "${HOSTPFX}" = "hd" ]
then
printf "\nAppending #includedir /etc/sudoers.d at end of file.\n" >> ${LOGFILE} 2>&1
echo "" >> /etc/sudoers
echo "## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)" >> /etc/sudoers
echo "#includedir /etc/sudoers.d" >> /etc/sudoers
fi

##
## * NFS Un-mount Section *
##

##
## Unmount /mnt.$$ directory
##
umount ${MOUNTPT} >> $LOGFILE 2>&1
if [ -d ${MOUNTPT} ]; then
rmdir ${MOUNTPT} >> $LOGFILE 2>&1
fi

##
## Make sure that /mnt.$$ got unmounted
##
if [ -f ${SRCFILE} ]; then
echo " The umount command failed to unmount ${MOUNTPT} ... We will not force the unmount ..." >> $LOGFILE
umount -f ${MOUNTPT} >> $LOGFILE 2>&1
if [ -d ${MOUNTPT} ]; then
rmdir ${MOUNTPT} >> $LOGFILE 2>&1
fi
else
echo " $MOUNTPT was unmounted ... There is no need for user intervention on $HOSTNAME ..." >> $LOGFILE
fi

#
# as always, exit cleanly
#
clean_exit 0

这是 212 行代码;没有对 sudoers 文件进行版本控制。客户有一个现有的每周运行一次的过程,以验证文件的校验和以确保安全。虽然脚本引用了 Solaris,但对于此客户,我们不需要迁移 Solaris 需求。

我们从创建角色并使用 Git 对 sudoers 文件进行版本控制的想法开始。这也消除了对 NFS 挂载的需求。

使用copytemplate 模块的“validate”和“backup”参数,我们可以消除备份和恢复文件的代码需求。验证在将文件放置到目标位置之前运行,如果失败,模块将报错。

我们需要为角色创建任务、模板和变量。以下是文件布局。

├── README.md
├── roles
│ └── sudoers
│ ├── tasks
│  └── main.yml
│ ├── templates
│  └── sudoers.j2
│ └── vars
│ └── main.yml
└── sudoers.yml

角色剧本sudoers.yml很简单。

---
##
# Role playbook
##
- hosts: all
  roles:
  - sudoers
...

角色变量位于vars/main.yml 文件中。我已经为校验和文件设置了变量,并包含/排除了变量,这些变量将用于创建逻辑,跳过“Lawson”宿主,并将 sudoers.d 包含项仅添加到“hd”宿主。

以下是vars/main.yml 文件的内容。

---
MD5FILE: /root/.sudoer.md5
EXCLUDE: la
INCLUDE: hd
...

如果我们使用copylineinfile 模块,那么角色将不是幂等的。Copy 将部署基本文件,lineinfile 将不得不重新插入每次运行的包含项。由于此角色将在 Ansible Tower 中进行调度,因此幂等性是必需的。我们将文件转换为 jinja2 模板。

在第一行,我们添加以下内容,以管理空格和缩进

#jinja2: lstrip_blocks: True, trim_blocks: True

请注意,template 模块的较新版本包括trim_blocks 参数(在 Ansible 2.4 中添加)。

以下是将include 行插入文件末尾的代码。

{% if ansible_hostname[0:2] == INCLUDE %}
#includedir /etc/sudoers.d
{% endif %}

我们使用条件语句({% if %}{% endif %})来替换 shell,该 shell 为主机名前两位字符为 "hd" 的主机插入行。我们利用 Ansible 事实和过滤器 [0:2] 来解析主机名。

现在来处理任务。首先,设置一个事实来解析主机名。我们将在条件语句中使用 "parhost" 事实。

---
##
# Parse hostnames to grab 1st 2 characters
##
- name: "Parse hostname's 1st 2 characters"
  set_fact: parhost={{ ansible_hostname[0:2] }}

接下来,我注意到 csum 在标准 RHEL 服务器上不存在。如果需要,我们可以使用另一个事实有条件地设置校验和二进制文件的名称。请注意,如果 AIX、Solaris 和 Linux 之间存在差异,可能需要进一步编码。由于客户不关心 Solaris 主机,因此我跳过了该开发工作。

我们还将处理 AIX 和 RHEL 之间 root 组的差异。

##
# Conditionally set name of checksum binary
##
- name: "set checksum binary"
  set_fact:
    csbin: "{{ 'cksum' if (ansible_distribution == 'RedHat') else 'csum' }}"

##
# Conditionally set name of root group
##
- name: "set system group"
  set_fact:
    sysgroup: "{{ 'root' if (ansible_distribution == 'RedHat') else 'sys' }}"

块将允许我们在任务周围提供一个条件。我们将在块的末尾使用一个条件来排除 "la" 主机。

##
# Enclose in block so we can use parhost to exclude hosts
##
- block:

模板模块验证并部署文件。我们注册结果以便我们可以确定此任务中是否存在更改。使用模块的 validate 参数确保新的 sudoers 文件在到位之前有效。

##
# Validate will prevent bad files, no need to revert
# Jinja2 template will add include line
##
- name: Ensure sudoers file
  template:
    src: sudoers.j2
    dest: /etc/sudoers
    owner: root
    group: "{{ sysgroup }}"
    mode: 0440
    backup: yes
    validate: /usr/sbin/visudo -cf %s
    register: sudochg

如果部署了新的模板,我们将运行 shell 来生成校验和文件。条件语句在部署 sudoers 模板时或校验和文件丢失时更新校验和文件。由于现有流程还监控其他文件,因此我们使用原始脚本中提供的 shell 代码。

- name: sudoers checksum
  shell: "grep -v '/etc/sudoers' {{ MD5FILE }} > {{ MD5FILE }}.tmp ; {{ csbin }} /etc/sudoers >> {{ MD5FILE }} ; mv {{ MD5FILE }}.tmp {{ MD5FILE }}"
  when: sudochg.changed or MD5STAT.exists == false

file 模块强制执行权限。

- name: Ensure MD5FILE permissions
  file:
  path: "{{ MD5FILE }}"
  owner: root
  group: "{{ sysgroup }}"
  mode: 0600
  state: file

由于备份参数未提供任何有关清理旧备份的选项,因此我们将添加一些代码来为我们处理此问题。这也展示了如何利用 "register" 和 "stdout_lines" 功能。

##
# List and clean up backup files. Retain 3 copies.
##
- name: List /etc/sudoers.*~ files
  shell: "ls -t /etc/sudoers*~ |tail -n +4"
  register: LIST_SUDOERS
  changed_when: false

- name: Cleanup /etc/sudoers.*~ files
  file:
  path: "{{ item }}"
  state: absent
  loop: "{{ LIST_SUDOERS.stdout_lines }}"
  when: LIST_SUDOERS.stdout_lines != ""

关闭块。

##
# This conditional restricts what hosts this block runs on
##
when: parhost != EXCLUDE
...

这里预期的用途是在 Ansible Tower 中运行此角色。可以为 Ansible Tower 通知配置通过电子邮件、Slack 或其他方法进行作业失败通知。此角色在 Ansible、Ansible Engine 或 Ansible Tower 中运行。

我们已经压缩了脚本并创建了一个完全幂等的能够强制执行 sudoers 文件所需状态的角色。使用 SCM 提供版本控制、更好的变更管理和问责制。使用 Jenkins 或其他工具进行的 CI/CD 可以为将来的更改提供 Ansible 代码的自动化测试。Ansible Tower 中的审计员角色可以监督和维护组织的合规性要求。

我们可以删除围绕校验和的过程,但客户必须首先与其安全团队进行沟通。如果需要,可以使用 Ansible Vault 来保护 sudoers 模板。最后,可以使用组来替换围绕 includes 和 excludes 的逻辑。

你可以在 GitHub 上找到这个角色