Ansible doesn't work when user home directory mounted on NFS volume - linux

Here is the situation. I got a number of hosts that I'd like to maintain via Ansible. The baseline configuration of the hosts like logins/users/etc is controlled by corporate IT overlords, so I can only change things that are related to application not general host setup. Some of the tasks related to application require running as 'root' or some other privileged user.
I do have a password-less sudo access on all the hosts, however all user home directories are located on NFS mounted volume. From my understanding how ansible works it first logs in into the target host as a regular user and places some files into $HOME/.ansible directory, then it switches to root user using sudo and tries to run the stuff from that directory.
But here is the problem. As I mentioned above the home directories are on NFS volume, so after ansible process on the target machine becomes root it can no longer access the $HOME/.ansible directory anymore due to NFS restrictions. Is there a way to tell ansible to put these work files outside of home directory on some non-NFS volume.

There were two parameters for the ansible.cfg configuration file introduced in Ansible 2.1 which allow specifying the location of temporary directory on target and control machines:
remote_tmp
Ansible works by transferring modules to your remote machines, running them, and then cleaning up after itself. In some cases, you may not wish to use the default location and would like to change the path. You can do so by altering this setting:
remote_tmp = ~/.ansible/tmp
local_tmp
When Ansible gets ready to send a module to a remote machine it usually has to add a few things to the module: Some boilerplate code, the module’s parameters, and a few constants from the config file. This combination of things gets stored in a temporary file until ansible exits and cleans up after itself. The default location is a subdirectory of the user’s home directory. If you’d like to change that, you can do so by altering this setting:
local_tmp = $HOME/.ansible/tmp

Related

Unable to write over an SSHFS mounted folder with SLURM jobs

I have the following problematic and I am not sure what is happening. I'll explain briefly.
I work on a cluster with several nodes which are managed via slurm. All these nodes share the same disk memory (I think it uses NFS4). My problem is that since this disk memory is shared by a lots of users, we have a limit a mount of disk memory per user.
I use slurm to launch python scripts that runs some code and saves the output to a csv file and a folder.
Since I need more memory than assigned, what I do is I mount a remote folder via sshfs from a machine where I have plenty of disk. Then, I configure the python script to write to that folder via an environment variable, named EXPERIMENT_PATH. The script example is the following:
Python script:
import os
root_experiment_dir = os.getenv('EXPERIMENT_PATH')
if root_experiment_dir is None:
root_experiment_dir = os.path.expanduser("./")
print(root_experiment_dir)
experiment_dir = os.path.join( root_experiment_dir, 'exp_dir')
## create experiment directory
try:
os.makedirs(experiment_dir)
except:
pass
file_results_dir = os.path.join( root_experiment_dir, 'exp_dir' , 'results.csv' )
if os.path.isfile(file_results_dir):
f_results = open(file_results_dir, 'a')
else:
f_results = open(file_results_dir, 'w')
If I directly launch this python script, I can see the created folder and file in my remote machine whose folder has been mounted via sshfs. However, If I use sbatch to launch this script via the following bash file:
export EXPERIMENT_PATH="/tmp/remote_mount_point/"
sbatch -A server -p queue2 --ntasks=1 --cpus-per-task=1 --time=5-0:0:0 --job-name="HOLA" --output='./prueba.txt' ./run_argv.sh "python foo.py"
where run_argv.sh is a simple bash taking info from argv and launching, i.e. that file codes up:
#!/bin/bash
$*
then I observed that in my remote machine nothing has been written. I can check the mounted folder in /tmp/remote_mount_point/ and nothing appears as well. Only when I unmount this remote folder using: fusermount -u /tmp/remote_mount_point/ I can see that in the running machine a folder has been created with name /tmp/remote_mount_point/ and the file is created inside, but obviously nothing appears in remote machine.
In other words, it seems like by launching through slurm, it bypasses the sshfs mounted folder and creates a new one in the host machine which is only visible once the remote folder is unmounted.
Anyone knows why this happens and how to fix it? I emphasize that this only happens if I launch everything through slurm manager. If not, then everything works.
I shall emphasize that all the nodes in the cluster share the same disk space so I guess that the mounted folder is visible from all machines.
Thanks in advance.
I shall emphasize that all the nodes in the cluster share the same disk space so I guess that the mounted folder is visible from all machines.
This is not how it works, unfortunately. Trying to put it simply; you could say that mount point inside mount points (here SSHFS inside NFS) are "stored" in memory and not in the "parent" filesystem (here NFS) so the compute nodes have no idea there is an SSHFS mount on the login node.
For your setup to work, you should create the SSHFS mount point inside your submission script (which can create a whole lot of new problems, for instance regarding authentication, etc.)
But before you dive into that, you probably should enquiry whether the cluster has another filesystem ("scratch", "work", etc.) where there you could temporarily store larger data than what the quota allows in your home filesystem.

How do I add the local users to my docker container?

I want to know how I can add the local users of my server to a docker container. I don't need to import their files, I just need a username/password/privileges with new home directory in the docker container for every user in my system. For example, suppose my docker container contains the following users:
Host System:
admin: who has root access and rw access to all
bob: a regular non-sudo user
joe: another regular non-sudo user
Then the Docker Container must have users:
admin: who has root access and rw access to all
bob: a regular non-sudo user
joe: another regular non-sudo user
The Docker container and the system are both running linux, though the system is red hat and the container is ubuntu.
EDIT: I don't want to mount /etc/ files if possible, as this can create a two way security vulnerability as pointed out by #caveman
You would have to mount all relevant linux files using -v like /etc/passwd, /etc/shadow, /ect/group, and /etc/sudoers. Though I can't recommend this due to the security risks, if anyone gets root access in the container they can add users on the host or change passwords since he mount works both ways.
The list of files is not exhaustive, for example, you have to also make sure the shell exacutables exist within the container. When testing this I had to make a symbolic link from /usr/bin/zsh to /bin/bash for example since my user has the zsh shell configured which was not present in the docker image.
If you want to use these users to interact with mounted files, you also have to make sure that user namespace remapping is disabled, or specify that you want to use the same user namespace as the host with the --userns=host flag. Again, not recommended since it is a security feature, so use with care.
Note: Once you have done all this you can use su - {username} to switch to all your existing users. The -u options doesn't work since docker checks the /etc/passwd file before mounting and will give an error.

Setcap over SSHFS

I am running a VM on my machine and have mounted a host folder inside VM using sshfs (auto-mounted via fstab).
abc#xyz:/home/machine/test on /home/vm/test type fuse.sshfs (rw,relatime,user_id=0,group_id=0,allow_other)
That folder has an executable which I want to run inside the VM. But I also need some capabilities before running that executable. So my script looks like:
#!/bin/bash
# Some preprocessing.
sudo setcap CAP_DAC_OVERRIDE+ep /home/vm/test/my_exec
/home/vm/test/my_exec
But I am getting below error :
Failed to set capabilities on file `/home/vm/test/my_exec' (Operation not supported)
The value of the capability argument is not permitted for a file. Or the file is not a regular (non-symlink) file
But if I copy executable inside the VM (say in /tmp/), then it works perfectly fine. Is this a known limitation of sshfs or am I missing something here ?
File capabilities are implemented on Linux with extended attributes (specifically the security.capability attribute), and not all filesystems implement extended attributes.
sshfs in particular does not.
sshfs can only perform operations which the remote user is authorized to perform. You're logged into the remote host as abc, so you can only perform actions over sshfs which abc can perform -- which doesn't include setcap, since that operation can only be performed by root. Using sudo on your local machine doesn't change that.

Linux, command line program's config file on home-dir-less setup

Several programs for Linux invoked from terminal/shell use config file where options normally put to program's invocation command line string are put. For instance Vim, for instance curl and their config files ~/.vimrc, ~/.curlrc.
If to take curl and Vim they look for such file in the home directory (it works this way at least according to their man pages).
However I know Linux setups without home directories. For example a NAS.
The known NAS houses several shared volumes / directories to be accessed from client devices via several protocols and by registered users. By default however the NAS does not create home directory for each user newly registered. The administrator hesitate to enable the option "create home directory for this user" if such is needed only for the above purpose.
Is then the usage of program's config file on such setup not possible at all?
To quote from the curl manual:
When curl is invoked, it always (unless -q is used) checks for a
default config file and uses it if found. The default config file is
checked for in the following places in this order:
1) curl tries to find the "home dir": It first checks for the
CURL_HOME and then the HOME environment variables. Failing that, it
uses getpwuid() on Unix-like systems (which returns the home dir given
the current user in your system). On Windows, it then checks for the
APPDATA variable, or as a last resort the '%USERPROFILE%\Application
Data'.
2) On windows, if there is no _curlrc file in the home dir, it checks
for one in the same dir the curl executable is placed. On Unix-like
systems, it will simply try to load .curlrc from the determined home
dir.
So no home directory is needed to store the config files as long, in the case of curl, the variable CURL_HOME, which can point to any location, is set.
Other programs have similar mechanisms.
But I am asking myself: Can one can log in (via ssh?) as a user without a home directory?

Must my pidfile be located in /var/run?

I'm asking in both contexts: technically and stylistically.
Can my application/daemon keep a pidfile in /opt/my_app/run/?
Is it very bad to do so?
My need is this: my daemon runs under a specific user, and the implementor must mkdir a new directory in /var/run, chown, and chgrp it to make my daemon run. Seems easier to just keep the pidfile local (to the daemon).
I wouldn't put a pidfile under an application installation directory such as /opt/my_app/whatever. This directory could be mounted read-only, could be shared between machines, could be watched by a daemon that treats any change there as a possible break-in attempt…
The normal location for pidfiles is /var/run. Most unices will clean this directory on boot; under Ubuntu this is achieved by /var/run an in-memory filesystem (tmpfs).
If you start your daemon from a script that's running as root, have it create a subdirectory /var/run/gmooredaemon and chown it to the daemon-running user before suing to the user and starting the daemon.
On many modern Linux systems, if you start the daemon from a script or launcher that isn't running as root, you can put the pidfile in /run/user/$UID, which is a per-user equivalent of the traditional /var/run. Note that the root part of the launcher, or a boot script running as root, needs to create the directory (for a human user, the directory is created when the user logs in).
Otherwise, pick a location under /tmp or /var/tmp, but this introduces additional complexity because the pidfile's name can't be uniquely determined if it's in a world-writable directory.
In any case, make it easy (command-line option, plus perhaps a compile-time option) for the distributor or administrator to change the pidfile location.
The location of the pid file should be configurable. /var/run is standard for pid files, the same as /var/log is standard for logs. But your daemon should allow you to overwrite this setting in some config file.
/opt is used to install 'self-contained' applications, so nothing wrong here. Using /opt/my_app/etc/ for config files, /opt/my_app/log/ for logs and so on - common practice for this kind of application.
This away you can distribute your applications as a TGZ file instead of maintaining a package for every package manager (at least DEB since you tagged ubuntu). I would recommend this for in-house applications or situations where you have great control over the environment. The reasoning is that it makes no sense if the safe costs more than what you are putting inside (the work required to pack the application should not eclipse the effort required to write the application).
Another convention, if you're not running the script as root, is to put the pidfile in ~/.my_app/my_app.pid. It's simpler this way while still being secure as the home directory is not world-writeable.

Resources