【问题标题】:Ansible Inventory Specifying the Same Host with Different Users and Keys for Initial SSH User Setup and Disabling Root AccessAnsible Inventory 为初始 SSH 用户设置和禁用根访问指定具有不同用户和密钥的同一主机
【发布时间】:2022-01-08 01:56:25
【问题描述】:

我正在尝试让 playbook 运行一次以设置新用户并禁用 root ssh 访问。

目前,我通过两次申报所有库存来做到这一点。每个主机都需要一个以 root 用户访问的条目,用于创建新用户、设置 ssh 设置,然后禁用 root 访问。

然后,每个主机都需要另一个包含新用户的条目。

我目前的库存看起来像这样。目前只有一个主机,但如果库存更大,重复只会占用大量不必要的空间:

---
# ./hosts.yaml
---
all:
  children:
    master_roots:
      hosts:
        demo_master_root:
          ansible_host: a.b.c.d  # same ip as below
          ansible_user: root
          ansible_ssh_private_key_file: ~/.ssh/id_rsa_infra_ops
    masters:
      hosts:
        demo_master:
          ansible_host: a.b.c.d  # same ip as above
          ansible_user: infraops
          ansible_ssh_private_key_file: ~/.ssh/id_rsa_infra_ops

有没有更简洁的方法来做到这一点?

这是一种反模式吗?它不是幂等的。如果以这样一种方式运行,即两次运行相同的剧本总是具有相同的输出 - “成功”或“没有变化”,那就太好了。

我正在使用 DigitalOcean,他们有一个功能可以在 VM 首次启动之前通过 bash 脚本完成此操作,但我更喜欢独立于平台的解决方案。

这是设置用户和 ssh 设置以及禁用 root 访问的剧本

---
# ./initial-host-setup.yaml
---
# References

# Digital Ocean recommended droplet setup script:
# - https://docs.digitalocean.com/droplets/tutorials/recommended-setup
# Digital Ocean tutorial on installing kubernetes with Ansible:
#  - https://www.digitalocean.com/community/tutorials/how-to-create-a-kubernetes-cluster-using-kubeadm-on-debian-9
# Ansible Galaxy (Community) recipe for securing ssh:
# - https://github.com/vitalk/ansible-secure-ssh
---
- hosts: master_roots
  become: 'yes'
  tasks:
    - name: create the 'infraops' user
      user:
        state: present
        name: infraops
        password_lock: 'yes'
        groups: sudo
        append: 'yes'
        createhome: 'yes'
        shell: /bin/bash

    - name: add authorized keys for the infraops user
      authorized_key: 'user=infraops key="{{item}}"'
      with_file:
        '{{ hostvars[inventory_hostname].ansible_ssh_private_key_file }}.pub'

    - name: allow infraops user to have passwordless sudo
      lineinfile:
        dest: /etc/sudoers
        line: 'infraops ALL=(ALL) NOPASSWD: ALL'
        validate: visudo -cf %s

    - name: disable empty password login for all users
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: '^#?PermitEmptyPasswords'
        line: PermitEmptyPasswords no
      notify: restart sshd

    - name: disable password login for all users
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: '^(#\s*)?PasswordAuthentication '
        line: PasswordAuthentication no
      notify: restart sshd

    - name: Disable remote root user login
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: '^#?PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: restart sshd

  handlers:
    - name: restart sshd
      service:
        name: sshd
        state: restarted

此后的所有内容都将使用 masters 库存。

编辑

经过一些研究,我发现 AWS、GCP 和 DigitalOcean 可能通过 cloud-init 支持“初始化脚本”/“启动脚本”/“用户数据”脚本(这是 DigitalOcean 使用的,没有研究其他),这足以让我坚持使用 bash 初始化脚本解决方案。

如果有人为此提供了一个仅 Ansible 的杀手级解决方案,我仍然会感兴趣和好奇,尽管我不确定是否有一个很好的方法可以在没有预初始化脚本的情况下实现这一点。

不管有什么 ansible 限制,似乎如果不使用 cloud init 脚本,你就不能拥有这个。如果服务器以 root 或类似用户启动来执行这些操作,或者服务器启动时没有具有这些权限的用户,那么您将无法执行这些操作。

此外,我还看到了 Ansible 剧本和 bash 脚本,它们试图通过测试 root ssh 访问权限来解决所需的“幂等性”(即使 root 已被禁用也没有错误),然后回退给另一个用户,但是“我can't ssh with root”对于“是否禁用 root 用户”是一个糟糕的测试,因为即使服务器仍配置为允许 root 进行 ssh,您的 ssh 访问也有很多方法可能会失败。

EDIT 2 将其放在这里,因为我无法在回复评论时使用换行符:

β.εηοιτ.βε 回复了我的断言:

”但是“我不能使用 root 进行 ssh”对于“是否禁用 root 用户”来说是一个糟糕的测试,因为即使服务器仍然配置为允许 root,您的 ssh 访问也有很多方法可能会失败ssh

然后,尝试使用 infraops 进行 ssh 并断言 PermitRootLogin no 在 ssh 守护进程配置文件中?"

听起来建议是:

- attempt ssh with root 
  - if success, we know user/ssh setup tasks have not completed, so run those tasks
  - if failure, attempt ssh with infraops
    - if success, go ahead and run everything except the user creation again to ensure ssh config is as desired
    - if failure... ? something else is probably wrong, since I can't ssh with either user

我不确定这种 if-then 故障恢复在 Ansible 脚本中实际上是什么样子的

【问题讨论】:

  • 但是“我不能使用 root 进行 ssh”对于“是否禁用 root 用户”来说是一个糟糕的测试,因为即使服务器仍在运行,您的 ssh 访问也有很多方法可能会失败配置为允许root ssh > 然后,尝试使用infraopsassert ssh,PermitRootLogin no 在 ssh 守护程序配置文件中?
  • 查看我的第二个帖子编辑,我试图在评论中回复,但需要换行符和格式来勾勒出来

标签: ssh ansible virtual-machine ansible-inventory


【解决方案1】:

您可以使用varsoverwrite 指定播放的主机变量。

- hosts: masters
  become: 'yes'
  
  vars:
    ansible_ssh_user: "root"
    ansible_ssh_private_key_file: "~/.ssh/id_rsa_infra_ops"

  tasks:

【讨论】:

  • 这很好,我绝对更喜欢这个而不是重复库存声明。它不能解决幂等性问题,但我认为这需要一个更复杂的剧本。
【解决方案2】:

您只能在运行时定义demo_master 组并更改ansible_useransible_ssh_private_key_file,使用命令标志--user--private-key

所以 host.yaml 包含

all:
  children:
    masters:
      hosts:
        demo_master:
          ansible_host: a.b.c.d  # same ip as above
          ansible_user: infraops
          ansible_ssh_private_key_file: ~/.ssh/id_rsa_infra_ops

并在- hosts: master 上运行,例如,第一次运行将与

ansible-playbook initial-host-setup.yaml \
  --user root \
  --private-key ~/.ssh/id_rsa_root

当随后的运行将简单地通过

ansible-playbook subsequent-host-setup.yaml

因为所有必需的值都已在库存中。

【讨论】:

  • 谢谢 - 这当然有效,但我的缺点是成功执行这些剧本的方法不再 100% 用代码表示,除非我将需要额外变量的命令包装在 Makefile 中或类似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 2023-04-03
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 2013-09-10
相关资源
最近更新 更多