How to add a user with controlled access to resources¶
Written by Kaan Akşit, 18 August 2025
Disclamer: This article is only tested under Ubuntu 24.10.
We use Linux based servers on our computers dedicated to computational tasks. In a dynamic setting like our research laboratory, there are many students that join and leave the group as they complete their studies. The access to these computational resources is cruical for the students and they needed to be provided an isolated session, where they do not interfere with other users' resources. This guide delves into the user management of students in our servers.
Setting important variables¶
There are two things important in this exercise as variables. These are the username and user directory location:
export USERNAMEGOESHERE="test"
export USERDIRECTORY="/YOURDIRECTORY/$USERNAMEGOESHERE"
Creating a user¶
We can create a new user using the syntax below:
sudo adduser $USERNAMEGOESHERE
To see which groups this newly created user belongs to, we can use the following syntax at our command line:
group $USERNAMEGOESHERE
Some cases demand that the user is restricted in terms of access to certain resources. This could be established by considering various aspects, but one simple aspect is related to user rights. In other terms, it is important to carefully determine which user groups that the user belongs to. In order to add this new user to a specific group, we user the following syntax at our command line:
sudo usermod -aG GROUPNAME $USERNAMEGOESHERE
Deleting or locking a user¶
As a student leaves or a certain resource has to be removed from a certain user, deleting or locking a user account becomes a topic to consider. Let's dive deep into how we can do that in these subsections.
Deletion¶
The created user could be deleted at any time using the following commands:
sudo deluser $USERNAMEGOESHERE
In order to remove the home directory of the user, the following commands should be used instead:
sudo deluser --remove-home $USERNAMEGOESHERE
sudo rm -Rf $USERDIRECTORY
sudo rm -Rf /home/$USERNAMEGOESHERE
Locking and unlocking¶
We can lock a user's password to prevent that user from authenticating. Therefore, the user will not be able to reach their account through graphical user interface or terminal or ssh. To lock a user, the following syntax must be used in a linux shell:
sudo passwd -l $USERNAMEGOESHERE
To unlock the user account at any given time, the following syntax must be used:
sudo passwd -u $USERNAMEGOESHERE
sudo usermod --expiredate "" $USERNAMEGOESHERE
Restricting access to home directory only¶
By default, a new user can only access their own home directory and some system directories (like /tmp). To further restrict access, you can set their shell to a restricted shell or use chmod to limit directory permissions.
Restricting a user's shelll¶
sudo usermod -s /bin/rbash $USERNAMEGOESHERE
Above commands will restrict the user to their home directory and prevent them from using cd to navigate outside of it. To remove this restriction:
sudo usermod -s /bin/bash $USERNAMEGOESHERE
Creating a custom environment¶
Firstly, create directories for the user in their home directory:
sudo mkdir -p $USERDIRECTORY/$USERNAMEGOESHERE/{bin,lib,lib/python3,lib/python3/dist-packages/,lib/x86_64-linux-gnu,lib64,dev,etc,usr,usr/bin,usr/lib,usr/lib/python3.*,usr/lib/x86_64-linux-gnu,usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/,usr/lib/x86_64-linux-gnu/stubs,home,home/%USERNAME}
Collect information on required libraries for your shell:
ldd /bin/bash
At the time of this writing, I have identified the following:
sudo cp -v /lib/x86_64-linux-gnu/libc.so.6 $USERDIRECTORY/$USERNAMEGOESHERE/lib/x86_64-linux-gnu/
sudo cp -v /lib64/ld-linux-x86-64.so.2 $USERDIRECTORY/$USERNAMEGOESHERE/lib64/
sudo cp -v /usr/lib/x86_64-linux-gnu/libcuda.* $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/x86_64-linux-gnu/
sudo cp -v /usr/lib/x86_64-linux-gnu/libnvidia-* $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/x86_64-linux-gnu/
sudo cp -v /lib64/ld-linux-x86-64.so.2 $USERDIRECTORY/$USERNAMEGOESHERE/lib64/
sudo cp -v /usr/lib/x86_64-linux-gnu/{libc.so.6,libpcre2-8.so.0,libselinux.so.1,libtinfo.so.6,libnvidia-ml.so.1,libnvidia-ml.so.560.35.05,librt.so.1,libexpat.so.1,libz.so.1,libpthread.so.0,libdl.so.2,libnvidia-ml.so.1} $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/x86_64-linux-gnu
sudo cp -rv /usr/lib/python3.* $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/
sudo cp -v /usr/lib/x86_64-linux-gnu/stubs/libnvidia-ml.so $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/x86_64-linux-gnu/stubs/
sudo cp -Rv /usr/lib/python3.12 $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib
sudo cp -Rv /usr/lib/python3 $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib
sudo cp -rv /usr/lib/python3.* $USERDIRECTORY/$USERNAMEGOESHERE/usr/lib/
sudo cp -v /usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/libnvidia-ml.so $USERDIRECTORY/$USERNAMEGOESHERE/usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/
We also need the nodes:
sudo mknod -m 666 $USERDIRECTORY/$USERNAMEGOESHERE/dev/null c 1 3
sudo mknod -m 666 $USERDIRECTORY/$USERNAMEGOESHERE/dev/zero c 1 5
sudo mknod -m 666 $USERDIRECTORY/$USERNAMEGOESHERE/dev/random c 1 8
sudo mknod -m 666 $USERDIRECTORY/$USERNAMEGOESHERE/dev/urandom c 1 9
sudo cp -a /dev/nvidia* $USERDIRECTORY/$USERNAMEGOESHERE/dev/
Make sure that the user has the access to the right set of tools:
sudo cp -v /bin/{bash,rbash,nano,vim,ls,mv,clear_console,cp,python3,pip3,nvidia-smi} $USERDIRECTORY/$USERNAMEGOESHERE/bin
sudo cp -v /usr/bin/{pip3,pip,python3} $USERDIRECTORY/$USERNAMEGOESHERE/usr/bin
sudo cp -vf /etc/{passwd,group} $USERDIRECTORY/$USERNAMEGOESHERE/etc/
sudo grep root /etc/passwd | sudo tee $USERDIRECTORY/$USERNAMEGOESHERE/etc/passwd
sudo grep root /etc/group | sudo tee $USERDIRECTORY/$USERNAMEGOESHERE/etc/group
echo "$USERNAMEGOESHERE:x:$(id -u $USERNAMEGOESHERE):$(id -g $USERNAMEGOESHERE):User:$USERDIRECTORY/$USERNAMEGOESHERE:/bin/bash" | sudo tee -a $USERDIRECTORY/$USERNAMEGOESHERE/etc/passwd
Make sure that the rights are also correct for the user directories:
sudo chown -R $USERNAMEGOESHERE:$USERNAMEGOESHERE $USERDIRECTORY/$USERNAMEGOESHERE
sudo chmod 700 $USERDIRECTORY/$USERNAMEGOESHERE
sudo chmod 700 $USERDIRECTORY/$USERNAMEGOESHERE/.ssh
sudo chmod 600 $USERDIRECTORY/$USERNAMEGOESHERE/.ssh/authorized_keys
sudo chown root:root $USERDIRECTORY/$USERNAMEGOESHERE
sudo chmod 755 $USERDIRECTORY/$USERNAMEGOESHERE
Given your user will connect via ssh, you would also need to make sure that ssh is configured correctly, for that modify /etc/ssh/sshd_config
file and append the following at the end of the file:
Match User $USERNAMEGOESHERE
ChrootDirectory $USERDIRECTORY/$USERNAMEGOESHERE
AllowTcpForwarding no
X11Forwarding no
You may also want to make sure that this user is allowed or denied at any time by using the following lines in the /etc/ssh/sshd_config
:
DenyUsers USER0 USER1
AllowUsers USER2, $USERNAMEGOESHERE
Once modified and saved, simply restart the SSH server:
sudo systemctl restart ssh
An automated script to create a user¶
In the light of the above findings and exploration, I have created the following script to create users with GPU access on our computational resources:
#!/bin/bash
USERNAMEGOESHERE="test"
NAMEOFYOURDIRECTORY="FULLPATHGOESHERE"
CRONTABSCRIPT="FULLPATHGOESHERE"
USERDIRECTORY="/$NAMEOFYOURDIRECTORY/$USERNAMEGOESHERE"
UBUNTUCODENAME="plucky"
sudo chown root:root /$NAMEOFYOURDIRECTORY
sudo chown root:root /$USERDIRECTORY
sudo chmod 0755 /$NAMEOFYOURDIRECTORY
sudo chmod 0755 /$USERDIRECTORY
sudo adduser $USERNAMEGOESHERE
sudo usermod -d $USERDIRECTORY $USERNAMEGOESHERE
SSH_KEY0="ssh-ed25519 YOURKEY0 COMPUTER0"
SSH_KEY1="ssh-ed25519 YOURKEY1 COMPUTER1"
sudo debootstrap --variant=minbase --include=python3,git,vim,nano,rsync $UBUNTUCODENAME $USERDIRECTORY
sudo chown root:root $USERDIRECTORY
sudo chmod 0755 $USERDIRECTORY
sudo chroot $USERDIRECTORY /bin/bash -c "echo \"deb http://archive.ubuntu.com/ubuntu $UBUNTUCODENAME main restricted universe multiverse\" | tee -a /etc/apt/sources.list"
sudo chroot $USERDIRECTORY /bin/bash -c "apt update"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install ca-certificates -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install git -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install wget -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install ssh -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install keychain -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install tmux -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install sshfs -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install libglu1-mesa-dev -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install iputils-ping -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install python3-pip -y"
sudo chroot $USERDIRECTORY /bin/bash -c "apt install python3-venv -y"
sudo cp -vf /etc/{passwd,group} $USERDIRECTORY/etc/
sudo grep root /etc/passwd | sudo tee $USERDIRECTORY/etc/passwd
sudo grep root /etc/group | sudo tee $USERDIRECTORY/etc/group
sudo grep $USERNAMEGOESHERE /etc/group | sudo tee $USERDIRECTORY/etc/group
echo "$USERNAMEGOESHERE:x:$(id -u $USERNAMEGOESHERE):$(id -g $USERNAMEGOESHERE):User:$USERDIRECTORY/$USERNAMEGOESHERE:/bin/bash" | sudo tee -a $USERDIRECTORY/etc/passwd
sudo cp -v /bin/nvidia-* $USERDIRECTORY/bin
sudo cp -v /usr/lib/x86_64-linux-gnu/libcuda.* $USERDIRECTORY/usr/lib/x86_64-linux-gnu/
sudo cp -v /usr/lib/x86_64-linux-gnu/libnvidia-* $USERDIRECTORY/usr/lib/x86_64-linux-gnu/
sudo mkdir -p $USERDIRECTORY/usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/
sudo cp -v /usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/libnvidia-ml.so $USERDIRECTORY/usr/local/cuda-12.8/targets/x86_64-linux/lib/stubs/
sudo mkdir -p $USERDIRECTORY/./$USERDIRECTORY
sudo chown -R $USERNAMEGOESHERE:$USERNAMEGOESHER $USERDIRECTORY/$USERDIRECTORY
sudo cp /etc/resolv.conf $USERDIRECTORY/etc/resolv.conf
sudo mount -o bind /dev $USERDIRECTORY/dev
sudo mount -t proc none $USERDIRECTORY/proc
sudo mount -t sysfs none $USERDIRECTORY/sys
sudo mount -t devpts none $USERDIRECTORY/dev/pts
sudo chmod 777 $USERDIRECTORY/dev/shm
sudo mkdir -p $USERDIRECTORY/.ssh
sudo touch $USERDIRECTORY/.ssh/authorized_keys
sudo echo "$SSH_KEY0" | sudo tee -a $USERDIRECTORY/.ssh/authorized_keys
sudo echo "$SSH_KEY1" | sudo tee -a $USERDIRECTORY/.ssh/authorized_keys
sudo chown -R $USERNAMEGOESHERE:$USERNAMEGOESHERE $USERDIRECTORY/.ssh/
sudo echo " " | sudo tee -a /etc/ssh/sshd_config
sudo echo "Match User $USERNAMEGOESHERE" | sudo tee -a /etc/ssh/sshd_config
sudo echo " ChrootDirectory $USERDIRECTORY" | sudo tee -a /etc/ssh/sshd_config
sudo echo " Subsystem sftp /usr/lib/openssh/sftp-server" | sudo tee -a /etc/ssh/sshd_config
sudo echo " AllowTcpForwarding no" | sudo tee -a /etc/ssh/sshd_config
sudo echo " X11Forwarding no" | sudo tee -a /etc/ssh/sshd_config
sudo service ssh restart
sudo touch $USERDIRECTORY/$USERDIRECTORY/.bashrc
sudo touch $USERDIRECTORY/$USERDIRECTORY/.bash_profile
sudo echo "if [ -f ~/.bashrc ]; then" | sudo tee -a $USERDIRECTORY/$USERDIRECTORY/.bash_profile
sudo echo " . ~/.bashrc" | sudo tee -a $USERDIRECTORY/$USERDIRECTORY/.bash_profile
sudo echo "fi" | sudo tee -a $USERDIRECTORY/$USERDIRECTORY/.bash_profile
sudo echo " " | sudo tee -a $CRONTABSCRIPT
sudo echo " " | sudo tee -a $CRONTABSCRIPT
sudo echo "USERDIRECTORY=\"$USERDIRECTORY\"" | sudo tee -a $CRONTABSCRIPT
sudo echo "sudo mount -t devtmpfs devtmpfs $USERDIRECTORY/dev" | sudo tee -a $CRONTABSCRIPT
sudo echo "sudo mount -t devpts devpts $USERDIRECTORY/dev/pts" | sudo tee -a $CRONTABSCRIPT
sudo echo "sudo mount -t proc proc $USERDIRECTORY/proc" | sudo tee -a $CRONTABSCRIPT
sudo echo "sudo mount -t sysfs sysfs $USERDIRECTORY/sys" | sudo tee -a $CRONTABSCRIPT
sudo chown -R $USERNAMEGOESHERE:$USERNAMEGOESHERE $USERDIRECTORY/$USERDIRECTORY/
You may also need to have a separate script to mount required folders at each reboot for a complete setup:
#!/bin/bash
USERDIRECTORY="/users/chroot/directory/goes/here"
sudo mount -t devtmpfs devtmpfs $USERDIRECTORY/dev
sudo mount -t devpts devpts $USERDIRECTORY/dev/pts
sudo mount -t proc proc $USERDIRECTORY/proc
sudo mount -t sysfs sysfs $USERDIRECTORY/sys
You can run the above setup at each boot using crontab
.
Limiting what users can monitor¶
You may want to limit users' ability to monitor other people's login times and active processes belonging to other users. Firstly, you can edit /etc/ssh/sshd_config
by making sure the following values are registered accurately:
PrintMotd no
PrintLastLog no
Secondly, you can mask user names in process monitoring by adding the following line to sudo nano /etc/pam.d/common-session
:
session optional perm_setcred:/etc/xdm/xlock
As you edit these lines, as usual, restart ssh
service by typing sudo service ssh restart
and reboot the operating system using sudo reboot
commands.