Skip to content

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.