如何通过ansible生成主机SSH密钥?


11

我正在尝试通过ansible(和ssh-keygen)在少数远程服务器上重新生成ssh主机密钥,但是文件似乎没有显示出来。剧本运行正常,但遥控器上的文件未更改。

我需要诉诸echo -e黑客,因为这些远程设备正在运行Ubuntu 14.04,并且没有python-pexpect可用版本的正确版本(根据ansible)。

我想念什么?我的剧本和输出如下:

剧本

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
    - name: Generate /etc/ssh/ RSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

    - name: Generate /etc/ssh/ DSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

    - name: Generate /etc/ssh/ ECDSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

输出

$ ansible-playbook ./playbooks/ssh-hostkeys.yml -l myhost.mydom.com, 
SUDO password: 

PLAY [all] **********************************************************************************************

TASK [Generate /etc/ssh/ RSA host key] ******************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C  -N "
    ]
}

TASK [Generate /etc/ssh/ DSA host key] ******************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C  -N "
    ]
}

TASK [Generate /etc/ssh/ ECDSA host key] ****************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C  -N "
    ]
}

PLAY RECAP **********************************************************************************************
myhost.mydom.com : ok=6    changed=3    unreachable=0    failed=0  

Answers:


14

据我所知,您需要将“ y”传递给ssh-keygen的唯一原因是您的命令是否正在替换现有文件。我认为这不是从配置管理工具执行操作的好方法。

您应该调整任务以使其具有幂等性。具体来说,如果您在creates: filename命令中添加,则仅在新键不存在时才创建新键,而不是在每次运行该剧本时都将其替换。

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
  - name: Generate /etc/ssh/ RSA host key
    command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_rsa_key

  - name: Generate /etc/ssh/ DSA host key
    command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_dsa_key

  - name: Generate /etc/ssh/ ECDSA host key
    command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_ecdsa_key

如果由于某种原因您想替换这些键,例如,如果它们太旧,或者您可能想要添加其他任务以将其删除。这是一个简单的删除

- file:
    state: absent:
    path: "{{item}}"
  loop:
  - /etc/ssh/ssh_host_rsa_key
  - /etc/ssh/ssh_host_dsa_key
  - /etc/ssh/ssh_host_ecdsa_key

如果要删除某个时间之前生成的文件,则可以使用stat模块检索有关此文件的详细信息,并设置when条件以有选择地删除它们(如果它们早于某个日期或某个日期)。


很好的例子,感谢您对保持幂等的想法。对于我的用例,我正在调配克隆的虚拟机,因此总会有要覆盖的密钥。我有点需要核选项才能删除和更换。
服务器故障

如果您始终希望将其删除,那么我可能会采用将file: state:absent ...内容填充到ssh-keygen的方法。尽管可能没有太大区别。
Zoredache '18年

喔好吧。这更有意义。我absent几天前都不知道。有效地,这将在重新生成密钥之前删除文件。这是一种更加清晰的方法。谢谢。
服务器故障

6

ansible command模块 不会通过shell传递命令。这意味着您不能使用外壳运算符(例如管道),这就是为什么在输出中看到管道符号的原因。就ansible而言,它已将echo其余所有行作为的参数执行了该命令echo

如果需要外壳程序处理命令行,请使用shell代替command

而且,应该有一种更好的方法来重新生成ssh主机密钥,但是我现在找不到一个...


感谢您提供的Shell vs.命令提示(现在可以正常运行),我不知道-还是很新的Ansible
服务器故障

关于最后一条语句(至少在CentOS / RHEL上),如果您删除了旧密钥并重新启动守护程序主机密钥,则会为您重新生成。无论如何,您都需要重新启动服务,因此这看起来似乎更好。
亚伦·科普利

@AaronCopley我比发行服务更多地是指Ansible角色。我知道大多数主要发行版都具有systemd服务,该服务生成ssh主机密钥。不幸的是,该服务具有特定于发行版的细微差别(CentOS和Fedora之间甚至有所不同)。角色是封装所有内容的一种好方法,但是我找不到一个有用的东西。
迈克尔·汉普顿

不用担心,只是以为我会提到它。(您可能知道,但OP可能没有。)
Aaron Copley

@AaronCopley-顺便说一句,这就是我最终要做的。在echo ...第二次运行后,该位不起作用(我正在测试/tmp/第一次没有键的情况下)。正如您提到的,我首先采取了删除主机密钥的方法,并生成了新的主机密钥。至于自动重新生成密钥,这取决于您的分布,对吗?并非所有Linux发行版都使用systemd。
服务器故障

2

使用特殊模块执行此任务:

- name: Generate an OpenSSH keypair with the default values (4096 bits, rsa)
  openssh_keypair:
    path: /home/youruser/.ssh/id_rsa
    owner: youruser
    group: youruser

- name: Fix owner of the generated pub key
  file:
    path: /home/youruser/.ssh/id_rsa.pub
    owner: youruser
    group: youruser

这些不是ssh主机密钥
KumZ

1

抱歉,但是我无法在任务中使用“创建”。我得到了以下错误:

ERROR! 'creates' is not a valid attribute for a Task

因此,我使用以下任务:

- name: remove existing ssh_host keys
  file: path={{ item }} state=absent
  with_items:
    - "/etc/ssh/ssh_host_rsa_key"
    - "/etc/ssh/ssh_host_dsa_key"
    - "/etc/ssh/ssh_host_ecdsa_key"

- name: Generate /etc/ssh/ RSA host key
  command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""

- name: Generate /etc/ssh/ DSA host key
  command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""

- name: Generate /etc/ssh/ ECDSA host key
  command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""

2
使用当前版本的Ansible。
迈克尔·汉普顿'18

没错,我的Ansible版本有点旧:2.0.0.2 ...(在Ubuntu 16.04上)。我必须改变!
MaxiReglisse

1

@Zoredache的答案正确,但对于Ansible的最新版本却失败(@MaxiReglisse指出)。请使用以下代码:

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
  - name: Generate /etc/ssh/ RSA host key
    command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_rsa_key

1

另一种选择是使用用户模块。积极的一面是您将获得幂等的任务。这是一个示例如何在本地主机上生成ssh密钥的示例:

- name: Generate ssh keys
  local_action:
    module: "user"
    name: "{{ lookup('env','USER') }}"
    generate_ssh_key: true
    ssh_key_type: "{{ item.0 }}"
    ssh_key_bits: "{{ item.1 }}"
    ssh_key_file: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
  with_together:
  - [ 'rsa', 'dsa' ]
  - [ 2048, 1024 ]
  loop_control:
    label: "{{ item.0 }}_{{ item.1 }}_key"

- name: Copy generated ssh keys to remote machine
  copy:
    src: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
    dest: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"
  with_nested:
  - [ 'rsa', 'dsa' ]
  - [ '', '.pub' ]
  notify:
  - Restart sshd
  loop_control:
    label: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"

1
这不是用户密钥,不是主机密钥吗?
-MadHatter

您也可以将其用于主机密钥,因为实际上这是同一回事。只是如果您以强制模式使用SELinux,别忘了还原selinux上下文
HeroFromEarth

从文档中对我来说还不清楚。如果您要重写答案,以便明确显示正在创建的主机密钥,那么我将删除我的下注。
MadHatter

好吧,也许还不清楚。我添加了另一个任务来解释如何在远程计算机上复制这些密钥。当然,这只是我的情况(我在群集的几台计算机上需要相同的密钥,因此我需要在本地主机上生成它们),而且我很确定您可以使用“用户”模块为ssh服务器上的密钥生成密钥远程计算机(请查看“ ssh_key_file”)
HeroFromEarth,

我仍然不确定是不是骇客行为(至少是因为它使一个用户拥有主机私钥的副本!),但至少现在它可以按要求回答问题了,所以我删除了我的下注。
MadHatter

0

使用openssh_keypair和authorized_key模块可以同时创建和部署密钥,而无需将其保存到您的ansible主机中。

- openssh_keypair:
    group: root
    owner: root
    path: /some/path/in/your/server
    register: ssh_key

- name: Store public key into origin
  delegate_to: central_server_name
  authorized_key:
     key: "{{ssh_key.public_key}}"
     comment: "{{ansible_hostname}}"
     user: any_user_on_central
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.