掌握权限提升:become

Ansible 使用了现有的权限提升系统,来以 root 权限或另一用户的权限执行任务。因为该特性允许咱们 “成为” 不同于登录到机器用户(远程用户)的另一用户,所以我们称之为 becomebecome 这个关键字,使用了现有的权限提升工具,如 sudosupfexecdoaspbrundzdoksurunasmachinectl 等。

使用 become

咱们可通过 playtask 指令、连接变量或命令行等,控制 become 的使用。若咱们以多种方式,设置了权限提升属性,请查看 一般优先规则,以了解何种设置将被使用。

Ansible 中包含的所有插件完整列表,可在 插件列表 中找到。

become 指令

咱们可以在 play 或任务级别,设置控制 become 的指令。可以通过设置连接变量,咱们可覆盖这些指令,不同主机的连接变量往往不同。这些变量和指令是独立的。例如,设置 become_user 并不会设置 become

  • become 设置为 true 以激活权限提升;

  • become_user 设置为有着所需权限的用户 - 咱们要 成为 的用户,而 不是 咱们登录的用户。这 意味着在主机级别允许设置的 become:true,Does NOT imply become: true, to allow it to be set at the host level。默认值为 root

  • become_method (于 play 或任务级别)覆盖 ansible.cfg 中设置的默认方式,设置为使用某种 become 插件

  • become_flags (于 play 或任务级别)允许对任务或角色,使用特定开关。一种常见的用法是,当 shell 被设置为 nologin 时,将用户更改为 nobody。是在 Ansible 2.2 中添加的。

例如,以非 root 用户身份连接时,要管理某项系统服务(需要 root 权限),就可使用 become_user 的默认值(root):

    - name: Ensure the nginx service is running
      service:
        name: nginx
        state: started
      become: true

apache 用户身份运行一条命令:

    - name: Run a command as the apache user
      command: somecommand
      become: true
      become_user: apache

当 shell 为 nologin 时,以 nobody 用户身份执行某些操作:

    - name: Run a command as nobody
      command: somecommand
      become: true
      become_method: su
      become_user: nobody
      become_flags: '-s /bin/sh'

要为 sudo 指定密码,就要使用 --ask-become-pass (简写为 -K)运行 ansible-playbook。若咱们要运行某个使用了 become 的 playbook,而该 playbook 似乎挂起了,则很可能是卡在了权限提升提示符上。就要用 CTRL-c 停止他,然后用 -K 和适当密码执行该 playbook。

become 的连接变量

咱们可为各个托管节点或组,定义不同的 become 选项。咱们可在仓库中定义这些变量,或者将他们作为普通变量使用。

  • ansible_become 会覆盖 become 指令,并决定是否使用权限提升;

  • ansible_become_method 应使用何种权限提升方法;

  • ansible_become_user 设置咱们通过权限提升所成为的用户;并未暗示 ansible_become: true

  • ansible_become_password 设置权限提升的密码。有关如何避免使用明文秘密的详细信息,请参阅 使用加密变量和文件

  • ansible_common_remote_group 决定出在 setfaclchown 都失败时,Ansible 是否应尝试将临时文件 chgrp 到某个组。更多信息,请参阅 成为非特权用户的风险。这是在 2.10 版中添加的。

例如,如果咱们打算在名为 webserver 的服务器上,以 root 用户身份运行所有任务,但只能以 manager 用户身份连接,那么咱们可使用下面这样的一个仓库条目:

webserver ansible_user=manager ansible_become=true

注意:上面定义的变量,对所有 become 插件都是通用的,但也可以设置一些特定于插件的变量。请参阅各个插件的文档,了解该插件具备的所有选项列表,以及如何定义这些选项。Ansible 中 become 插件的完整列表,请参见 become 插件

become 的命令行选项

  • --ask-become-pass-K 询问权限提升密码;这并不意味着将运用 become。请注意,该密码将用于所有主机;

  • --become-b 使用 become 运行操作(不带密码暗示);

  • --become-method=BECOME_METHOD 要使用的权限提升方法(default=sudo),有效选项: [ sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas | machinectl ]

  • --become-user=BECOME_USER 以该用户身份运行操作(default=root),并未暗示 --become/-b

become 的风险与局限

尽管特权提升大多是直观的,但其工作原理有些限制。用户应意识到这些,以避免出现意外。

成为非特权用户的风险

Ansible 的模组在远端机器上被执行时,是首先将一些参数替换到模组文件中,然后将文件复制到远端机器上,最后在远端机器上执行的。

如果模组文件在不使用 become 下执行,或者 become_user 为 root 用户,或者以 root 用户身份连接的远端机器,则一切相安无事。在这些情况下,Ansible 会创建出权限为仅允许该用户与 root,或仅允许由所切换到的无特权用户读取权限的模组文件。

但是,当连接用户和 become_user 都是非特权用户时,模组文件会以 Ansible 连接用户身份(remote_user)写入,而文件却需要由 Ansible 设置为 become 的用户读取。Ansible 解决这个问题的细节因平台而异。不过,在 POSIX 系统上,Ansible 以如下方式解决这个问题:

首先,若安装了 setfacl 并在远端的 PATH 中可用,且远端主机上的临时目录挂载,且支持 POSIX.1e 的文件系统 ACL1,那么 Ansible 将使用 POSIX ACL,与第二名非特权用户共享模组文件。

接下来,若 POSIX ACL 可用或 setfacl 无法运行,Ansible 将尝试使用 chown 更改模组文件的所有权(对那些支持以非特权用户身份这样做的系统)。

作为 Ansible 2.11 中的新特性,此刻 Ansible 将尝试使用 chmod +a,这种 MacOS 特有的文件 ACL 设置方式。

而作为 Ansible 2.10 的新特性,如果上述操作都失败了,Ansible 就将检查配置设置 ansible_common_remote_group 的值。许多系统都允许某名给定用户,将文件的组所有权更改为该用户所在的组。因此,若第二名非特权用户(即 become_user)与 Ansible 连接的用户(即 remote_user)有着共同的 UNIX 组,且 ansible_common_remote_group 被定义为了该组,那么 Ansible 就可以尝试使用 chgrp,将模组文件的组所有权更改为该组,从而使该模组文件成为 become_user 可以读取的文件。

到这里,如果定义了 ansible_common_remote_group,并且尝试了 chgrp 并返回成功,那么 Ansible 就会认为(但重要的是,并不检查)新的组所有权已经足够,而不会进一步回退了。也就是说,Ansible 不会检查 become_user 是否确实与 remote_user 共享了某个组;只要该命令(chgrp)成功退出,Ansible 就会认为结果是成功的,而不会继续检查下面的 world_readable_temp

而如果 ansible_common_remote_group 未被设置,且上面的 chown 失败了,或者设置了 ansible_common_remote_group,但 chgrp(或下面的组权限 chmod)返回了某个非成功的退出代码,Ansible 将最后检查这个 world_readable_temp 选项。如果设置了该选项,Ansible 会将模组文件放到某个全局可读的临时目录中,in a world-readable temporary directory,并赋予其全局可读的权限,以允许 become_user(以及系统中的其他用户)读取文件内容。如果传递给模组的任何参数带有敏感性质,而咱们又不信任远端机器,那么这就是个潜在的安全风险

一旦该模组执行完毕,Ansible 就会删除临时文件。

有几种可以完全避免上述逻辑流程的方法:

  • 使用 管道化,pipelining。启用流水线后,Ansible 就不会将模组保存到客户端的临时文件中。相反,他会将模组管道传递给远端 Python 解释器的 stdin。管道化不适用于那些涉及文件传输的 Python 模组(例如:copyfetchtemplate 等),也不适用于那些非 Python 的模组;
  • 避免成为非特权用户。在咱们 become root,或不使用 become 时,临时文件会受 UNIX 的文件权限保护。在 Ansible 2.1 及以上版本中,如果咱们以 root 用户身份连接到托管机器,然后使用 become 访问某个非特权账户,UNIX 文件权限同样是安全的。

警告

  • 尽管 Solaris 的 ZFS 文件系统具备文件系统 ACL,但这些 ACL 并非 POSIX.1e 的文件系统 ACL(而是 NFSv4 的 ACL2)。Ansible 无法使用这些 ACL,管理临时文件权限,因此如果远端机器使用了 ZFS,咱们就可能不得不使用 world_readable_temp 选项

版本 2.1 中已变更

Ansible 令到难于在不知情的情况下,不安全地使用 become。从 Ansible 2.1 开始,如果无法安全地以 become 执行,Ansible 默认会发出一条错误消息。如果咱们不能使用管道化或 POSIX ACL,必须以非特权用户身份连接,必须使用 become 以另一非特权用户身份执行,并且明确了咱们的托管节点足够安全,以至咱们打算在那里运行的模组是全局可读的,那么咱们可以打开 world_readable_temp 选项,而这将会把错误变成一条警告,并允许任务像 2.1 版本之前那样运行。

版本 2.1 中已变更

Ansible 2.10 引入了上述的 ansible_common_remote_group 回退。如上所述,其被启用后,当 remote_userbecome_user 均为非特权用户时,就会用到他。有关该回退何时发生的详情,请参阅上文。

警告

  • 如上所述,若同时启用了 ansible_common_remote_groupworld_readable_temp,那么全局可读回退就不大可能发生,但 Ansible 可能仍然无法访问模组文件。这是因为在组所有权变更成功后,Ansible 就不会进一步回退了,也不会做任何检查来确保 become_user 确实是那个 “公共组” 的成员。做出这个决定的原因是,进行这样的检查需要再次往返连接远端机器,耗费大量时间。不过,在这种情况下,Ansible 会发出一条警告。

并非受所有连接插件支持

这些特权提升方式,还必须受所使用的连接插件支持。若不支持 become,大多数连接插件都会发出警告。而有些则会忽略,因为他们总是以 root 身份运行(jailchroot 等)。

一台主机上只会启用一种方法

become 方法不能串联。咱们不能使用 sudo /bin/su - 来成为某名用户,咱们需要具备在 sudo 中以该用户身份运行命令的权限,或能够直接 su 到该用户(pbrunpfexec 或其他受支持的方法也是如此)。

权限提升必须具有普遍性

咱们不能将权限提升,限制到某些命令。Ansible 并不总是使用某条特定命令执行某些操作,而是会从某个临时文件名运行模组(代码),而临时文件名每次都会改变。若咱们将 '/sbin/service''/bin/chmod' 作为允许的命令,就将导致 Ansible 失败,因为这些路径与 Ansible 为运行模组而创建的临时文件不匹配。若咱们有着某些限制 sudo/pbrun/doas 环境,只能运行特定的命令路径的安全规则,就要以不受此限制的特殊账户,使用 Ansible,或使用 AWX 或 Red Hat AAP 管理对 SSH 凭据的间接访问。

可能访问不到由 pamd_systemd 产生的环境变量

对于大多数将 systemd 用作启动程序的 Linux 发行版来说,become 所使用的默认方法,不会打开 systemd 意义上的新 “会话”。由于 pam_systemd 模组不会完整地初始化出一个新会话,因此与通过 ssh 打开的普通会话相比,咱们可能会遇到一些意外情况:由 pam_systemd 设置的一些环境变量,尤其是 XDG_RUNTIME_DIR,就不会为该新用户产生出来,而是会继承到或仅仅是空白的。

这可能会在尝试调用那些依赖 XDG_RUNTIME_DIR 访问总线的 systemd 命令时,造成麻烦:

$ echo $XDG_RUNTIME_DIR

$ systemctl --user status
Failed to connect to bus: Permission denied

要强制 become 打开一个新的会历经 pam_systemdsystemd 会话,咱们可使用 become_method:machinectl

更多信息,请参见 这个 systemd 问题

解决临时文件错误消息

  • "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user"
  • 安装提供 setfacl 命令的软件包,可以解决这个错误。(这通常是 acl 软件包,但请查阅操作系统文档。)

become 与网络自动化

从 2.6 版开始,Ansible 支持在所有受 Ansible 维护的平台上,使用 become 进行权限提升(进入 enable 模式或特权的 EXEC 模式)。使用 become 取代了 provider 字典中的 authorizeauth_pass 选项

在网络设备上,咱们必须将连接类型,设置为 connection: ansible.netcommon.network_cliconnection: ansible.netcommon.httpapi,才能使用 become 进行权限提升。详情请查看 平台选项 文档。

咱们可以只在需要提升权限的特定任务、整个 play 或全部 play 中,使用提升的权限。添加 become: truebecome_method: enable,就可以指示 Ansible 在执行设置了这些参数的任务、play 或 playbook 之前,进入 enable 模式。

若咱们看到下面这个错误信息,则表示产生出此错误信息的任务,需要 enable 模式才能成功:

Invalid input (privileged mode required)

要为某个特定任务设置 enable 模式,请在任务级别添加 become

    - name: Gather facts (eos)
      arista.eos.eos_facts:
        gather_subset:
          - "!hardware"
      become: true
      become_method: enable

要为某单个 play 中的所有任务,设置 enable 模式,请在 play 级别添加 become

- hosts: eos-switches
  become: true
  become_method: enable

  tasks:
    - name: Gather facts (eos)
      arista.eos.eos_facts:
        gather_subset:
          - "!hardware"

为所有任务设置 enable 模式

通常,咱们会希望所有 play 中的所有任务,都使用特权模式运行,通过使用 group_vars 可最好实现这一点:

group_vars/eos.yml

ansible_connection: ansible.netcommon.network_cli
ansible_network_os: arista.eos.eos
ansible_user: myuser
ansible_become: true
ansible_become_method: enable

enable 模式的密码

若咱们需要密码进入 enable 模式,则可以以下两种方式之一指定出来:

  • 提供 --ask-become-pass 命令行选项;
  • 设置 ansible_become_password 连接变量。

警告

  • 需要提醒的是,密码绝不能以纯文本形式存储。有关使用 Ansible Vault 加密密码及其他机密的信息,请参阅 Ansible Vault

authorizeauth_pass

对于旧有的网络 playbook,Ansible 仍然支持 connection: local 下的 enable 模式。要进入 connection: local 下的 enable 模式,请使用模组选项 authorizeauth_pass

- hosts: eos-switches
  ansible_connection: local
  tasks:
    - name: Gather facts (eos)
      eos_facts:
        gather_subset:
          - "!hardware"
      provider:
        authorize: true
        auth_pass: " {{ secret_auth_pass }}"

我们(作者)建议将咱们的 playbook,更新为始终使用 become 获取网络设备的 enable 模式。authorizeauth_pass 字典这种用法将在今后弃用。有关详细信息,请查阅 平台选项 文档。

become 与 Windows 系统

自 Ansible 2.3 起,便可通过 runas 方式,在 Windows 主机上使用 become 了。Windows 上的 become 与非 Windows 主机上的 become,使用相同的仓库设置和调用参数,因此除 become_user 外,其他设置和变量名,都与本文档中定义的相同。这是因为在 Windows 上,使用 become 时无需有意义的 become_user 默认值。详情请参阅 ansible.builtin.runas become 插件

虽然 become 可以用来假定另一用户的身份,在 Windows 主机上他还有别的用途。其中一个重要用途,是绕过在 WinRM 上运行时的一些限制,如受限的网络授权,或访问某些如 WUA API 这样的受禁系统调用。咱们可将 becomeansible_user 相同的用户一起使用,来绕过这些限制,而运行一些通常在 WinRM 会话中无法访问的命令。

注意:在 Windows 系统中,咱们无法使用低权限账户连接并使用 become 来提升权限。只有当连接账户已经是目标主机的管理员时,才能使用 become

管理员权限

Administrative rights

Windows 中的许多任务,都需要管理员权限才能完成。使用 runas 这个 become 方法时,Ansible 会尝试使用 become 用户的全部权限运行模组。若 Anisble 提升用户令牌失败,他将在执行过程中继续使用有限令牌。

用户必须具有 SeDebugPrivilege(调试权限),才能以提升权限运行某个 become 进程。该权限默认是分配给管理员的。若没有调试权限,则 become 进程将以一组有限权限和组运行。

要确定出 Ansible 所能够获取到的令牌类型,请运行以下任务:

    - name: Check my username
      ansible.windows.win_whoami:
      become: true

译注:因为任务是针对 Windows 主机,因此需要在仓库中将该 Windows 设置为如下这样。

win_servers:
  hosts:
    win10-133:
      ansible_host: 192.168.122.133
      ansible_connection: ssh
      ansible_shell_type: powershell
      ansible_user: 'Hector PENG'
      ansible_ssh_pass: 'mypass'

并在 play 中作如下设置。

- name: Ansible on Windows demo
  hosts: win10-133
  become_method: runas
  become_user: 'Hector PENG'
  gather_facts: no

  tasks:
    - name: Check my username
      ansible.windows.win_whoami:
      become: true

否则会报出下面这些错误:

  • The powershell shell family is incompatible with the sudo become plugin

  • No setting was provided for required configuration plugin_type: become plugin: runas setting: become_user

输出将看起来类似于下面这样:

ok: [windows] => {
    "account": {
        "account_name": "vagrant-domain",
        "domain_name": "DOMAIN",
        "sid": "S-1-5-21-3088887838-4058132883-1884671576-1105",
        "type": "User"
    },
    "authentication_package": "Kerberos",
    "changed": false,
    "dns_domain_name": "DOMAIN.LOCAL",
    "groups": [
        {
            "account_name": "Administrators",
            "attributes": [
                "Mandatory",
                "Enabled by default",
                "Enabled",
                "Owner"
            ],
            "domain_name": "BUILTIN",
            "sid": "S-1-5-32-544",
            "type": "Alias"
        },
        {
            "account_name": "INTERACTIVE",
            "attributes": [
                "Mandatory",
                "Enabled by default",
                "Enabled"
            ],
            "domain_name": "NT AUTHORITY",
            "sid": "S-1-5-4",
            "type": "WellKnownGroup"
        },
    ],
    "impersonation_level": "SecurityAnonymous",
    "label": {
        "account_name": "High Mandatory Level",
        "domain_name": "Mandatory Label",
        "sid": "S-1-16-12288",
        "type": "Label"
    },
    "login_domain": "DOMAIN",
    "login_time": "2018-11-18T20:35:01.9696884+00:00",
    "logon_id": 114196830,
    "logon_server": "DC01",
    "logon_type": "Interactive",
    "privileges": {
        "SeBackupPrivilege": "disabled",
        "SeChangeNotifyPrivilege": "enabled-by-default",
        "SeCreateGlobalPrivilege": "enabled-by-default",
        "SeCreatePagefilePrivilege": "disabled",
        "SeCreateSymbolicLinkPrivilege": "disabled",
        "SeDebugPrivilege": "enabled",
        "SeDelegateSessionUserImpersonatePrivilege": "disabled",
        "SeImpersonatePrivilege": "enabled-by-default",
        "SeIncreaseBasePriorityPrivilege": "disabled",
        "SeIncreaseQuotaPrivilege": "disabled",
        "SeIncreaseWorkingSetPrivilege": "disabled",
        "SeLoadDriverPrivilege": "disabled",
        "SeManageVolumePrivilege": "disabled",
        "SeProfileSingleProcessPrivilege": "disabled",
        "SeRemoteShutdownPrivilege": "disabled",
        "SeRestorePrivilege": "disabled",
        "SeSecurityPrivilege": "disabled",
        "SeShutdownPrivilege": "disabled",
        "SeSystemEnvironmentPrivilege": "disabled",
        "SeSystemProfilePrivilege": "disabled",
        "SeSystemtimePrivilege": "disabled",
        "SeTakeOwnershipPrivilege": "disabled",
        "SeTimeZonePrivilege": "disabled",
        "SeUndockPrivilege": "disabled"
    },
    "rights": [
        "SeNetworkLogonRight",
        "SeBatchLogonRight",
        "SeInteractiveLogonRight",
        "SeRemoteInteractiveLogonRight"
    ],
    "token_type": "TokenPrimary",
    "upn": "vagrant-domain@DOMAIN.LOCAL",
    "user_flags": []
}

label 键下,account_name 条目决定了用户是否具有管理员权限。以下是可能返回的标签及其代表的内容:

  • Medium:Ansible 未能获得提升令牌,只能在有限令牌下运行。在模组执行期间,只有分配给用户的权限子集可用,且该用户没有管理权限;
  • High:在模组执行过程中,使用了提升的令牌,且分配给该用户的全部权限都可用;
  • System:使用了 NT AUTHORITY\System 账户,且有着最高级别的权限。

输出还将显示出已授予给该用户的权限列表。当某项权限的值为 disabled 时,表示该项权限已分配给登录令牌,但尚未启用。在大多数情况下,这些权限在需要时都会自动启用。

若咱们是在早于 2.5 版本的 Ansible 上运行,或正常的 runas 升级过程失败,则可通过以下方式,获取提升的令牌:

  • become_user 设置为对操作系统有着完全控制的 System
  • 在 WinRM 上授予 Ansible 连接用户 SeTcbPrivilege 权限。SeTcbPrivilege 是种可授予对操作系统的完全控制的高级别权限。默认情况下,没有用户会被赋予此项权限,因此在咱们授予用户或用户组此权限时,应小心谨慎。有关此权限的更多信息,请参阅 Act as part of the operating system。咱们可使用以下任务,在 Windows 主机上设置此权限:
    - name: grant the ansible user the SeTcbPrivilege right
      ansible.windows.win_user_right:
        name: SeTcbPrivilege
        users: '{{ansible_user}}'
        action: add
  • 再次尝试成为该用户前,关闭主机上的 UAC 并重启。UAC 是种设计用于以 least privilege (最小权限)原则,运行账户的安全协议。运行以下任务即可关闭 UAC:
    - name: turn UAC off
      win_regedit:
        path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system
        name: EnableLUA
        data: 0
        type: dword
        state: present
      register: uac_result

    - name: reboot after disabling UAC
      win_reboot:
      when: uac_result is changed

注意:授予 SeTcbPrivilege 权限或关闭 UAC,可能会导致 Windows 安全漏洞,因此在采取这些步骤时应小心谨慎。

本地服务账户

Local service accounts

在 Ansible 2.5 版之前,become 只能在 Windows 系统以本地或域用户账户运作。在那些旧版本中,如 SystemNetworkService这样的本地服务账户,不能用作 become_user。自 Ansible 2.5 版本后,这一限制已被取消。可以在 become_user 下设置的三个服务账户是:

  • System
  • NetworkService
  • LocalService

由于本地服务账户没有密码,因此就不需要 ansible_become_password 参数,若指定了该参数,也会被忽略。

无需设置密码的 become

自 Ansible 2.8 起,无需某个 Windows 本地或域帐户,即可使用 become 成为该账户。要使用此方法,必须满足以下要求:

  • 连接用户已分配了 SeDebugPrivilege 权限;
  • 连接用户属于 BUILTIN\Administrators 组;
  • become_user 有着 SeBatchLogonRightSeNetworkLogonRight 用户权限。

使用无需密码的 become,是通过以下两种不同方法之一实现的:

  • 若该账户已登录,则复制现有的登录会话令牌;
  • 使用 S4U3 生成一个仅在远端主机上有效的登录令牌。

在第一种情况下,become 进程是从该用户账户的另一登录中产生的。这可能是现有的 RDP 登录或控制台登录,但不能保证每次都这样。这与某个计划任务的 Run only when user is logged on 选项类似。

become 账户的另一登录不存在时,则会使用 S4U 创建一个新的账户登录,并通过该次登陆运行模组。这与某个计划任务 Do not store password 选项下的 Run whether user is logged on or not 类似。在这种情况下,become 进程将无法像某个普通 WinRM 进程那样,访问任何网络资源。

为区分出使用无需密码的 become,与成为没有密码的账户,就要确保将 ansible_become_password 设为 undefined,或设置ansible_become_password:

注意:由于无法保证 Ansible 运行时,用户的现有令牌存在,所以 become 进程很可能只能访问本地资源。如果任务需要访问网络资源,请使用带密码的 become

不带密码的账户

警告

  • 作为一般的安全最佳实践,咱们应避免放行没有密码的账户。

Ansible 可以用于成为某个无密码的 Windows 账户(如 Guest 账户)。要成为无密码的账户,只需像正常一样设置变量,但要设置 ansible_become_password:''

成为这样的账户前,必须禁用本地策略 Accounts: Limit local account use of blank passwords to console logon only 。这既可通过一个组策略对象 (GPO),也可通过下面的 Ansible 任务实现:

    - name: allow blank password on become
      ansible.windows.win_regedit:
        path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
        name: LimitBlankPasswordUse
        data: 0
        type: dword
        state: present

注意:这只适用于没有密码的账户。若 become_user 有密码,则咱们仍需在 ansible_become_password 下设置该账户的密码。

Window 的 become 标志

Become flags for Windows

Ansible 2.5 开始为 runas 这种 become 方法,添加了 become_flags 参数。可以使用 become_flags 任务指令设置该参数,也可在 Ansible 配置中,使用 ansible_become_flags 设置该参数。该参数最初支持的两个有效值,分别是 logon_typelogon_flags

注意:只有在成为某个普通用户账户,而非 LocalSystem 这样的本地服务账户时,才应设置这些标志。

logon_type 设置了到平台登录操作的类型。该值可设置为以下之一:

  • interactive:是默认的登录类型。进程将在与本地运行进程相同的上下文中运行。这将绕过所有 WinRM 限制,且是推荐使用的方法;
  • batch:在类似于设置了密码的计划任务的批处理上下文中,运行进程。这可绕过大多数 WinRM 限制,且在 become_user 不被允许交互式登录的情况下,非常有用;
  • new_credentials:在与调用用户的相同凭据下运行,但出站连接会在 become_userbecome_password 的上下文下运行,这类似于 runas.exe /netonly。此时 logon_flags 标志应同时设置为 netcredentials_only。若进程需要使用不同凭证访问网络资源(如某个 SMB 共享),就要使用此标记;
  • network:在一个无任何缓存凭据的网络上下文下,运行进程。这会产生出,与运行某个无凭据委派的普通 WinRM 进程,相同类型的登录会话,且会在同样限制条件下运行;
  • network_cleartext:与 network 登录类型类似,但会缓存凭据从而会话能够访问网络资源。这种登录会话类型,与运行带有凭据委派的正常 WinRM 进程相同。

更多信息,请参阅 dwLogonType

logon_flags 键则指定了 Windows 在创建新进程时,如何登录用户。该值可设置为 none,也可以设置为下列多项中的多项:

  • with_profile:默认的登录标志集。进程会将 HKEY_USERS 注册表键中的用户配置文件,加载到 HKEY_CURRENT_USER
  • netcredentials_only:进程将使用与调用者同样的令牌,但在访问某项远程资源时,将使用 become_userbecome_password。这在没有信任关系的域间场景中非常有用,且应与 new_credentials 登录类型一起使用。

默认情况下,设置了 logon_flags=with_profile;若无需加载用户配置文件,则要设置 logon_flags=,而若应与 netcredentials_only 一起加载配置文件,就要设置 logon_flags=with_profile,netcredentials_only

更多信息,请参阅 dwLogonFlags

下面是些如何在 Windows 任务中,使用 become_flags 的示例:

    - name: copy a file from a fileshare with custom credentials
      ansible.windows.win_copy:
        src: \\192.168.122.5\shared\file.txt
        dest: C:\temp\file.txt
        remote_src: true
      vars:
        ansible_become: true
        ansible_become_method: runas
        ansible_become_user: WORKGROUP\hector
        ansible_become_password: my_pass
        ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only

Windows 上 become 的局限性

  • 在 Windows Server 2008、2008 R2 和 Windows 7 上,仅在使用 Ansible 2.7 或更新版本时,才能使用 asyncbecome 运行任务;
  • 默认情况下,become 的用户会以交互会话方式登录,因此他必须在 Windows 主机上有这样的权限。若没有继承 SeAllowLogOnLocally 权限或继承了 SeDenyLogOnLocally 权限,则 become 进程将失败。要么添加该权限,要么设置 logon_type 标志,来更改所用的登录类型;
  • 在 2.3 版 Ansible 之前,只有当 ansible_winrm_transportbasiccredssp 时,become 才能工作。自 2.4 版 Ansible 开始,除 Windows Server 2008(非 R2 版本)外的所有主机,都取消了这一限制;
  • 要使用 ansible_become_method: runas,必须辅助登录服务 seclogon 4 必须运行;
  • 要使用 runas,连接用户必须已是 Windows 主机上的管理员。但所成为的目标用户,不需要是管理员。

参考

1

2

3

4

(End)

Last change: 2025-02-23, commit: 0663119

小额打赏,赞助 xfoss.com 长存......

微信 | 支付宝

若这里内容有帮助到你,请选择上述方式向 xfoss.com 捐赠。