Unable to write .zshrc while connected with unprivilegied user
alorence opened this issue · 5 comments
Hi,
I usually perform all administrative tasks on my servers with a user different from "root". Unfortunately, in such case, it is impossible to perform some tasks as another user using Ansible privilege escalation.
The task write .zshrc for users
will fail if it is executed for any user when connected as unprivilegied user:
TASK [gantsign.oh-my-zsh : write .zshrc for users] **************************************************
fatal: [ec2-**-***-***-***.eu-west-3.compute.amazonaws.com]: FAILED! => {}
MSG:
Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chown: changing ownership of '/var/tmp/ansible-tmp-1569230087.9570866-96215917740751/': Operation not permitted
chown: changing ownership of '/var/tmp/ansible-tmp-1569230087.9570866-96215917740751/source': Operation not permitted
}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user
with playbook
- hosts: all
remote_user: my_admin_user
vars:
users:
- username: dummy
oh_my_zsh:
theme: sporty_256
plugins:
- git
- themes
roles:
- gantsign.oh-my-zsh
The error came from the task:
- name: write .zshrc for users
become: yes
become_user: '{{ item.username }}'
template:
src: zshrc.j2
dest: '~{{ item.username }}/.zshrc'
backup: yes
mode: 'u=rw,go=r'
with_items: '{{ users }}'
In Ansible docs, the suggested workarounds are:
- Use pipelining (works for all python modules but copy, fetch, template)
- Install POSIX.1e filesystem acl support on the managed host
- Don’t perform an action on the remote machine by becoming an unprivileged user
I have enabled pipelining (1) in ansible.cfg, to ensure most of the tasks works well (cloning the repository in ~dummy/.oh-my-zsh
can be done by user my_admin_user
). But since the last task use template
module to write .zshrc
, it fails if remote_user
is not root.
I don't know how to do the (2)
Obviously, the (3) should be in your hands...
I wanted to open a Pull Request, modifying the task and using owner: '{{ item.username }}'
instead of become_user: '{{ item.username }}'
, but I discovered this was the case before and has been changed in 02c7f16.
I understand that setting the owner of file is easy, but setting the corresponding primary group is challenging since it is not always the same "word".
I discovered there is some unix commands that can determine the primary group of a user, but I don't know which way to follow to resolve this issue.
What do you think ?
@alorence, thank you for reporting this issue, sorry for the late reply. I think there are two ways to resolve this issue.
- Run this specific role as a privileged user e.g.:
- hosts: servers
roles:
- role: gantsign.oh-my-zsh
become: yes
users:
- username: example
Note: I haven't been able to fully test this but it should be the simplest solution.
- Grant your non-privileged Ansible user sufficient permissions.
I tried the following instructions for testing using a non-privileged user with Molecule https://molecule.readthedocs.io/en/stable/examples.html#docker-with-non-privileged-user and I was able to successfully execute this role. Note: you may want to restrict the sudo permissions (the example grants ALL
sudo permissions).
Unfortunately, Ansible doesn't provide a clean solution for this issue at the moment and the current implementation of this role has proven to be the least worst option.
Thank you very much for answering.
Unfortunately, Solution 1 is not applicable in my case. Remotes I work on forbid root SSH connection for security reasons.
The solution 2 may work, but I must admit I am confused with "privileged" and "non-privileged" terms. What does they mean ? The administrative user who performs all tasks is in "wheel" group (RedHat based systems) or "sudo" group (Debian based systems). What sould I do to grant this user the suficient permissions that will allow him to write a file in another user's home directory ?
FYI: You don't need to SSH to a remote as root
if the user you use for your SSH connection has permissions to execute commands as if they are root
(e.g. using sudo
).
If you're coming from a Windows background think of a "privileged" user as a user with Administrator permissions and a "non-privileged" user as an ordinary user without Administrator permissions. Administrator permissions allow you to install software and edit other users files etc.
Most Linux distributions use sudo (super-user do) as a way of allowing a user with low permissions to perform actions as other users with higher/different permissions (e.g. root
). This is normally what Ansible uses when you use become
and become_user
.
By default, users are not able to use sudo
, access is granted by editing files in /etc/sudoers.d
, editing the /etc/sudoers
file or assigning the user to groups who have been granted permission to use sudo
.
"Variable SUDO_GROUP depends on distribution wheel is used on centos:7." means if your Linux distribution has a default group for users with permission to use sudo
to use that group name (e.g. the group name is wheel
on centos:7
and sudo
on Ubuntu:16.04
).
Configuring specific permissions for sudo
isn't easy, see https://www.sudo.ws/man/1.8.27/sudoers.man.html. If you're using sudo
on you desktop machine you're almost certainly granted ALL
permissions, which is a lot easier to setup.
For this role, you'll need permissions to install software using the package manager (e.g. zsh
and git
). You'll need permission to run git
on behalf of the users you want to install Oh My Zsh for. Change file permissions for that user, change the default shell, and write the .zshrc
.
One thing to be aware of is security professionals will object to installing Oh My Zsh on servers (particularly production). So if you need them to grant you extra permissions they'll likely say no.
Unfortunately, a non-root user cannot write .zshrc file inside home directory of another user, even if it is in sudo
or wheel
group. Cloning .oh-my-zsh diretory works, changing default shell works, but any module that upload a file and change permission will not, as explained in ansible docs:
Pipelining does not work for python modules involving file transfer (for example: copy, fetch, template), or for non-python modules
I re-checked this with a very simple example. I started a fresh Debian Stretch server on Amazon EC2. By default, this server comes with SSH root dissabled, and an admin
user that can do anithing using passwordless sudo
.
I ran this playbook:
---
- hosts: all
remote_user: admin
become: yes
vars:
ansible_become_password_default: ""
users:
- username: admin
oh_my_zsh:
theme: tjkirch
plugins:
- git
- themes
- username: random_user
oh_my_zsh:
theme: jtriley
plugins:
- debian
- virtualenv
roles:
- create_users
- gantsign.oh-my-zsh
with this custom role in roles/create_users/tasks/main.yml
---
- name: Create user {{ item.username }}
user:
state: present
name: "{{ item.username }}"
system: no
append: yes
with_items: "{{ users }}"
See the result:
ansible-playbook -i ec2.hosts setup_zsh.yml
PLAY [all] **********************************************
TASK [Gathering Facts] **********************************
ok: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com]
TASK [create_users : Create user {{ item.username }}] ****************
ok: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'admin', 'oh_my_zsh': {'theme': 'tjkirch', 'plugins': ['git', 'themes']}})
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'random_user', 'oh_my_zsh': {'theme': 'jtriley', 'plugins': ['debian', 'virtualenv']}})
TASK [gantsign.oh-my-zsh : install dependencies] ****************
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item=git)
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item=zsh)
[WARNING]: Updating cache and auto-installing missing dependency: python-apt
[WARNING]: Could not find aptitude. Using apt-get instead
TASK [gantsign.oh-my-zsh : clone oh-my-zsh for users] ****************
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'admin', 'oh_my_zsh': {'theme': 'tjkirch', 'plugins': ['git', 'themes']}})
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'random_user', 'oh_my_zsh': {'theme': 'jtriley', 'plugins': ['debian', 'virtualenv']}})
TASK [gantsign.oh-my-zsh : set permissions of oh-my-zsh for users] ****************
ok: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'admin', 'oh_my_zsh': {'theme': 'tjkirch', 'plugins': ['git', 'themes']}})
ok: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'random_user', 'oh_my_zsh': {'theme': 'jtriley', 'plugins': ['debian', 'virtualenv']}})
TASK [gantsign.oh-my-zsh : set default shell for users] ****************
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'admin', 'oh_my_zsh': {'theme': 'tjkirch', 'plugins': ['git', 'themes']}})
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'random_user', 'oh_my_zsh': {'theme': 'jtriley', 'plugins': ['debian', 'virtualenv']}})
TASK [gantsign.oh-my-zsh : write .zshrc for users] ****************
changed: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com] => (item={'username': 'admin', 'oh_my_zsh': {'theme': 'tjkirch', 'plugins': ['git', 'themes']}})
fatal: [ec2-15-188-47-86.eu-west-3.compute.amazonaws.com]: FAILED! => {}
MSG:
Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chown: changing ownership
of '/var/tmp/ansible-tmp-1569837824.9828672-165693995545428/': Operation not permitted
chown: changing ownership of '/var/tmp/ansible-tmp-1569837824.9828672-165693995545428/source': Operation not permitted
}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user
PLAY RECAP ****************
ec2-15-188-47-86.eu-west-3.compute.amazonaws.com : ok=7 changed=4 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
So apparently, a privileged user (admin
in this case) cannot update the owner of the temp file to another unprivileged user.
When I encounter this issue in my own roles, I often update the task to use owner
and group
arguments of the template
module.
Sorry, it doesn't look like I can fix this without breaking other users or greatly complicating the implementation, I suggest you fork the role.