Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible: Copy file into another users home directory

I am new to Ansible so this may be a silly question. Thank you for your patience.

I have two users on my child node: ubuntu and ansible

I have one user on my control node: ubuntu

I created the ansible user on my child node to test out multiple users/isolate ansible. Maybe this is not a good idea?

I am trying to copy a test file from my control node to my child node. I am connecting as the ansible user (because I've granted them passwordless sudo in the sudoers file, I don't want to do this for the ubuntu user). However I cannot copy the file into ubuntu user's home folder. I am able to copy into ansible user's home folder.

Is what I'm trying to do possible? I couldn't find much reading on this so I am guessing I am approaching this the wrong way... is there a better way to do this?

Here is my playbook:

---
- name: script transfer practice
  hosts: devdebugs
  remote_user: ansible

  tasks:
  - name: Copy file with owner and permissions
    ansible.builtin.copy:
      src: /home/ubuntu/files/test.txt
      dest: /home/ubuntu/test.txt
      owner: ubuntu
      group: ubuntu
      mode: '0600'
...

Note: It works with dest /home/ansible/test.txt. It does not work with dest /home/ubuntu/test.txt

like image 666
Bix Avatar asked Oct 21 '25 03:10

Bix


2 Answers

I created the Ansible user on my child node to test out multiple users/isolate Ansible. Maybe this is not a good idea?

Having a specific user for your deployments with full escalation rights on your target host is the most common setup to run ansible.

Is what I'm trying to do possible?

Absolutely. If you have correctly set escalation rights to your Ansible user as mentioned, all you are missing in your task or play is become: true. At play level, it will affect all task for that play:

---
- name: script transfer practice
  hosts: devdebugs
  remote_user: ansible
  become: true

  # here goes the rest of your play....

At task level, it will only affect the given task.

  - name: Copy file with owner and permissions
    ansible.builtin.copy:
      src: /home/ubuntu/files/test.txt
      dest: /home/ubuntu/test.txt
      owner: ubuntu
      group: ubuntu
      mode: '0600'
    become: true

As reported by @SipSeb in the comments, you can also set the become flag for an entire playbook at runtime using the -b/--become flag on the ansible(-playbook) command line.

I couldn't find much reading on this

Probably because you are new to Ansible and do not know exactly what to look for. For this particular subject, a good starting point is understanding Ansible privilege escalation

like image 151
Zeitounator Avatar answered Oct 24 '25 08:10

Zeitounator


FWIW (I already commented it in another answer) I needed a single play to put 2 files into the HOME of 3 different users with the proper ownership.

Everything is dynamic, hence the users may change, the $HOMEs may be on arbitrary even possibly automounted locations and so on. So I cannot use absolute paths or similar and it must be autodetected.

Here is what I came up with. This is a YAML to be included as it needs the user and key set.

See also: https://github.com/hilbix/ansible/tree/master/roles/ssh-id/tasks

roles/ssh-id/task/ssh-id-user-key.yml looks like this:

- name: "create ~{{ user }}/.ssh/id_{{ key }}"
  ansible.builtin.copy:
    src: "files/ssh-id/{{ key }}{{ item.0 }}"
    dest: "~/.ssh/id_{{ key }}{{ item.2 }}"                                                                                                    
    owner: "{{ user }}"
    mode: "{{ item.1 }}"
  become: true
  become_user: "{{ user }}"
  loop:
    - [ .key, '0600', '' ]
    - [ .pub, '0644', .pub ]

Notes:

  • The owner: line probably is redundant.
  • Directory ~/.ssh/ must already exist.
    • The ~ probably only works on Unix type OS
  • A relative destination path .ssh/ sadly does not work here.
    • At the time of writing I do not know why.
    • Perhaps we can use a fact or lookup to get the proper $HOME independently from the target OS type

roles/ssh-id/task/ssh-id-user.yml uses this:

- name: "create .ssh/id_XXXX for {{ user }}"
  include_tasks: ssh-id-user-key.yml
  loop: "{{ keys is string | ansible.builtin.ternary([keys], keys) }}"
  loop_control:                                                                                                                             
    loop_var: key

roles/ssh-id/task/main.yml uses that:

- name: Update .ssh/id_XXX
  include_tasks: ssh-id-user.yml
  loop: "{{ users is string | ternary([users], users | default([lookup('env', 'USER')])) }}"
  loop_control:
    loop_var: user

And this then can be used like this:

  - role: ssh-id
    keys:
      - service1
      - service2
    users:
      - root
      - user1
      - user2

Or like this:

  - role: ssh-id
    keys:
      - root1

The keyfiles are kept under files/ssh-id/, where the pub key is called {{ key }}.pub but the SSH-identy file is named {{ key }}.key as it is a PITA to have files without a proper extension, like in the ~/.ssh/id*-file standard.

like image 25
Tino Avatar answered Oct 24 '25 06:10

Tino