将Ansible复制SSH密钥从一个主机到另一个主机

49
我系统中有2个应用服务器,前面有一个负载均衡器和1个数据库服务器。 我正在使用Ansible进行配置。 应用服务器使用Nginx + Passenger运行Rails应用程序。 将使用Capistrano进行部署,但我遇到了有关ssh密钥的问题。 我的git存储库位于另一台服务器上,并且我必须在应用程序服务器上生成ssh公钥并将其添加到Git服务器(authorized_keys文件)。 我如何在ansible playbook中执行此操作?
注意:我可能会有多于2个应用服务器。

你能详细说明一下如何在Git服务器上管理密钥吗?这是一个GitLab实例吗?您只需要将密钥添加到authorized_keys文件中吗? - leucos
我只需要将密钥添加到authorized_keys文件中。 - beydogan
7个回答

36

这对我很有用,它会收集节点上的公共SSH密钥,并在所有节点之间分发。这样它们就可以相互通信。

- hosts: controllers
  gather_facts: false
  remote_user: root
  tasks:
    - name: fetch all public ssh keys
      shell: cat ~/.ssh/id_rsa.pub
      register: ssh_keys
      tags:
        - ssh

    - name: check keys
      debug: msg="{{ ssh_keys.stdout }}"
      tags:
        - ssh

    - name: deploy keys on all servers
      authorized_key: user=root key="{{ item[0] }}"
      delegate_to: "{{ item[1] }}"
      with_nested:
        - "{{ ssh_keys.stdout }}"
        - "{{groups['controllers']}}"
      tags:
        - ssh

信息:这是给用户 root 的。


2
我采用了这个想法,但使用了 local_action: ssh-agent -L 并写了一篇博客:http://dannyman.toldme.com/2016/07/01/ansible-use-ssh-add-to-set-authorized_key/ 所以非常感谢你! - dannyman
3
好的,这个方法可行,但我不明白为什么你使用了 shell: user=root key... 而不是 authorized_key: user=root key...。我尝试了这段代码,但无法通过 shell 使它工作,而使用 authorized_key 却非常顺利。 - Thomas8
@Thomas8:可能是我犯的错误,发现得好! - Jonas Libbrecht
1
@dannyman 你可能是指 ssh-add(而不是 ssh-agent)就像你在博客文章中所说的那样。 - jneuendorf

31

查看authorized_key模块以获取有关管理公钥的信息。

我能想到最简单的解决方案是为应用程序生成一个新的密钥对,以在所有应用实例之间共享。 这可能会有安全问题(确实在所有实例之间共享密钥!),但它将大大简化配置过程。

您还需要在每个应用机器上拥有部署用户,在部署过程中稍后使用。 您需要在每个部署用户的authorized_keys中放置自己的公钥(或者Jenkins的公钥)。

一个概要的playbook:

---
- name: ensure app/deploy public key is present on git server
  hosts: gitserver
  tasks:
    - name: ensure app public key
      authorized_key: 
        user: "{{ git_user }}" 
        key: app_keys/id_dsa.pub 
        state: present

- name: provision app servers
  hosts: appservers
  tasks:
    - name: ensure app/deploy user is present
      user: 
        name: "{{ deploy_user }}"
        state: present

    - name: ensure you'll be able to deploy later on
      authorized_key:
        user: "{{ deploy_user }}" 
        key: "{{ path_to_your_public_key }}" 
        state: present

    - name: ensure private key and public one are present
      copy: 
        src: keys/myapp.private 
        dest: "/home/{{ deploy_user }}/.ssh/{{ item }}" 
        mode: 0600
      with_items:
        - app_keys/id_dsa.pub
        - app_keys/id_dsa

4
我创建了一个参数化角色,以确保在源远程主机上生成SSH密钥对,并将其公钥复制到目标远程主机上的目标用户中。
您可以在源和目标主机列表的嵌套循环中调用该角色,如下所示:
---
#****h* ansible/ansible_roles_ssh_authorize_user
# NAME
#   ansible_roles_ssh_authorize_user - Authorizes user via ssh keys
#
# FUNCTION
#
#   Copies user's SSH public key from a source user in a source host
#   to a target user in a target host
#
# INPUTS
#
#   * ssh_authorize_user_source_user
#   * ssh_authorize_user_source_host
#   * ssh_authorize_user_target_user
#   * ssh_authorize_user_target_host
#****
#****h* ansible_roles_ssh_authorize_user/main.yml
# NAME
#   main.yml - Main playbook for role ssh_authorize_user
# HISTORY
#   $Id: $
#****

- assert:
    that:
      - ssh_authorize_user_source_user != ''
      - ssh_authorize_user_source_host != ''
      - ssh_authorize_user_target_user != ''
      - ssh_authorize_user_target_host != ''
  tags:
    - check_vars
- name: Generate SSH Keypair in Source
  user:
    name: "{{ ssh_authorize_user_source_user }}"
    state: present
    ssh_key_comment: "ansible-generated for {{ ssh_authorize_user_source_user }}@{{ ssh_authorize_user_source_host }}"
    generate_ssh_key: yes
  delegate_to: "{{ ssh_authorize_user_source_host }}"
  register: source_user
- name: Install SSH Public Key in Target
  authorized_key:
    user: "{{ ssh_authorize_user_target_user }}"
    key: "{{ source_user.ssh_public_key }}"
  delegate_to: "{{ ssh_authorize_user_target_host }}"
- debug:
    msg: "{{ ssh_authorize_user_source_user }}@{{ ssh_authorize_user_source_host }} authorized to log in to {{ ssh_authorize_user_target_user }}@{{ ssh_authorize_user_target_host }}"

在循环中调用角色:

- name: Authorize User
  include_role:
    name: ssh_authorize_user
  vars:
    ssh_authorize_user_source_user: "{{ git_user }}"
    ssh_authorize_user_source_host: "{{ item[0] }}"
    ssh_authorize_user_target_user: "{{ git_user }}"
    ssh_authorize_user_target_host: "{{ item[1] }}"
  with_nested:
    - "{{ app_server_list }}"
    - "{{ git_server_list }}"

1

我会创建一个部署用户,并将其限制为对你的存储库进行拉取访问。你可以通过http或者有几个选项可以通过ssh完成允许此操作。

如果您不关心将用户限制为只读访问存储库,则可以创建普通的ssh用户。用户创建后,你可以使用Ansible将用户的公钥添加到git服务器上授权密钥文件中,你可以使用授权密钥模块

设置好后,你有两个选择:

  1. 如果使用ssh,请使用ssh密钥转发,使用于运行Ansible任务的用户将其公钥发送到开发服务器。

  2. 暂时传输密钥,并使用ssh_optsgit模块选项来使用部署用户的公钥。


0

这是我用来在多个主机之间交换RSA密钥的工具(多对多)。我有一些变体,可以创建带有密钥对的用户帐户,并处理“一对多”和“多对一”的情况。

#:TASK: Exchange SSH RSA keys between multiple hosts (many to many)
#:....: RSA keypairs are created as required at play (1)
#:....: authorized_keys updated at play <root user (2a.1 & 2a.2)>, <non root user (2b.1)>
#:....: -- We need a 2a or 2b option becasue there is a 'chicken & egg' issue for the root user!
#:....: known_hosts files are updated at play (3)
#:REQD: *IF* your security policy allows:
#:....: -- Add 'host_key_checking = False' to ansible.cfg
#:....: -- Or use one of the variations of 'StrictHostKeyChecking=no' elsewhere:
#:....: e.g. inventory setting - ansible_ssh_common_args='-o StrictHostKeyChecking=no'
#:....: - or - host variable - ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
#:USER: RUN this as the 'root' user; it hasn't been tested or adapted to be run as any other user
#:EXEC: ansible-playbook <playbook>.yml -e "nodes=<inventory_hosts> user=<username>"
#:VERS: 20230119.01
#
---
- name: Exchange RSA keys and update known_hosts between multiple hosts
  hosts: "{{ nodes }}"
  vars:
    ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
  tasks:
    - name: (1) Generate an SSH RSA key pair
      community.crypto.openssh_keypair:
        path: "~{{ user }}/.ssh/id_rsa"
        comment: "{{ user }}@{{ ip }}"
        size: 2048

    - name: (2) Retrieve RSA key/s then exchange it with other hosts
      block:
        - name: (2a.1) Retrieve client public RSA key/s to a variable
          slurp:
            src: ".ssh/id_rsa.pub"
          register: rsa_key

          # Using the debug module here seems to make the slurp above more reliable
          # as during testing not all hosts that were slurped worked.
        - debug:
            msg: "{{ rsa_key['content'] | b64decode }} / {{ ip }} / {{ user }}"

        - name: (2a.2) Exchange RSA keys between hosts and update authorized_key files
          delegate_to: "{{ item }}"
          authorized_key:
            user: "{{ user }}"
            key: "{{ rsa_key['content'] | b64decode }}"
          with_items:
            - "{{ ansible_play_hosts }}"
          when: item != inventory_hostname
      when: user == "root"

    - name: (2b.1) Exchange RSA keys between hosts and update authorized_key files
      block:
        - delegate_to: "{{ item }}"
          authorized_key:
            user: "{{ user }}"
            key: "{{ rsa_key['content'] | b64decode }}"
          with_items:
            - "{{ ansible_play_hosts }}"
          when: item != inventory_hostname
      when: user != "root"

    - name: (3) Ensure nodes are present in known_hosts file
      become: yes
      become_user: "{{ user }}"
      known_hosts:
        name: "{{ item }}"
        path: "~{{ user }}/.ssh/known_hosts"
        key: "{{ lookup('pipe', 'ssh-keyscan -t rsa {{ item }}') }}"
      when: item != inventory_hostname
      with_items:
        - "{{ ansible_play_hosts }}"

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

将创建和/或确保您服务器上的ssh密钥可以启用ssh连接到central_server_name


0

我想通过删除 shell 模块并使用 slurp 来贡献这段代码。非常感谢 Jonas Libbrecht 提供的代码,它非常有用。

- name: Get ssh keys
  slurp:
    src: /home/nsbl/.ssh/id_ed25519.pub
  register: ssh_keys
  tags:
    - ssh

- name: Check keys
  debug: msg="{{ ssh_keys['content'] | b64decode }}"
  tags:
    - ssh

- name: deploy keys on nodes 1
  authorized_key: 
    user: root 
    key: "{{ item[1]  }}"
  delegate_to: "{{ item[0] }}"
  with_nested:
    - "{{ groups['cluster'] }}"
    - "{{ ssh_keys['content'] | b64decode }}"
  tags:
    - ssh

感谢社区。


谢谢。我已经删除了与问题无关的部分。该代码通过减少Ansible playbook中的shell命令使用,提出了对问题解决方案的改进建议。 - Juan Islas
感谢您以建设性的方式接受批评。玩得开心! - Yunnosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接