Alexandre Roux
Alexandre Roux

Reputation: 381

How to add an existing public key to authorized_keys file using Ansible and user module?

I'm programming a simple task with Ansible to create a user and add an existing RSA public key. This is the code I wrote:

- name: SYSTEM - Create test user
  tags: system-user
  user: 
        name: "{{ test_user }}"
        state: present
        createhome: yes

- name: SYSTEM - Add existing pub key for test user
  tags: system-user
  copy: 
       content: "{{ test_user_pubkey }}"
       dest: "/tmp/test_user_id_rsa.pub"
       force: no
       owner: "{{ test_user }}"
       group: "{{ test_user }}"
       mode: 0600

- name: SYSTEM - Set authorized key for test_user took from file
  tags: system-user
  authorized_key:
        user: "{{ test_user }}"
        state: present
        key: "{{ lookup('file', '/tmp/test_user_id_rsa.pub') }}"

The code I wrote is not elegant and I think that the best option will be to add the existing RSA public key with the user creation block in order to create and filled up the authorized_keys file.

I've read the Ansible user module but ssh_key_file method does not include the possibility to echo the value of an existing pub key to the authorized_keys file (the end purpose is to be able to remote connect with ssh using the user and the private key).

ssh_key_file = Optionally specify the SSH key filename. If this is a relative filename then it will be relative to the user's home directory.

Is it possible with Ansible to manage this process within the user module?

Upvotes: 9

Views: 27835

Answers (3)

Dunaevsky Maxim
Dunaevsky Maxim

Reputation: 3209

Use ansible.posix.authorized_key module:

---
- name: Add public SSH key for user vagrant
  hosts: all
  tasks:
    - name: Add public SSH key to authorized_keys file
      ansible.posix.authorized_keys:
        user: vagrant
        state: present
        key: "{{ lookup('file', '/path/to/key.pub') }}"

Here /path/to/key.pub is the path to public key file on your local machine.

By default this module manage ~/.ssh/authorized_keys file, but you can define own path with path key.

Upvotes: 0

techraf
techraf

Reputation: 68609

The answer to your problem is:

- name: SYSTEM - Create test user
  tags: system-user
  user: 
    name: "{{ test_user }}"
    state: present
    createhome: yes

- name: SYSTEM - Set authorized key for test_user took from file
  tags: system-user
  authorized_key:
    user: "{{ test_user }}"
    state: present
    key: "{{ test_user_pubkey }}"

That's all that is needed.


Regarding your reading of the documentation, ssh_key_file pertains to generating an SSH key pair, which is not what you want.

Upvotes: 9

Simon V
Simon V

Reputation: 11

So I've been lurking this thread trying to get this wrapped around my head.. And I ended up being able to make my way around this.

First things first, I tend to cram everything in dicts and then use | dict2items whenever I need to loop within jinja2.

My main problem is that once the user module generates the ssh_keys, there are no clean ways to use the authorized_key module with what you just made (or so I think? I am probably not the smartest guy in here) without bending Ansible in ways impossible (slurping? it is impossible to place another variable within a variable (from what I've tried)"{{ slurp_{{ item.key }} | b64decode }}" seem undoable)

So if you are using massive loops and unwilling to copy all keys to your localhost (which honestly is time consuming), I've found this sneaky trick that does not make reading your code an Olympian challenge :

- name: Prepare the SFTP user
  user:
    name: "{{ item.key }}"
    groups: sftp_users
    home: /home/{{ item.key }}
    password: "{{ impossible_sftp_pass }}"
    generate_ssh_key: yes
    ssh_key_file: .ssh/id_rsa
    shell: /bin/nologin
  with_dict: "{{ instances }}"

- name: sneaky way to get the keys right
  shell: cat /home/{{ item.key }}/.ssh/id_rsa.pub > /home/{{ item.key }}/.ssh/authorized_keys
  args:
    creates: /home/{{ item.key }}/.ssh/authorized_keys
  with_dict: "{{ instances }}"

In this example, our goal is to setup an STFP bastion host that will finally rsync SFTP data repos to the appropriate web fronts that are within a private network.

Upvotes: 1

Related Questions