2021-09-20 18:45:06 +02:00
# Centralized account management
2021-09-21 07:55:30 +02:00
Up until now most of the services and servers we installed did not need a lot of user accounts to be shared a crossed devices.
2021-09-20 18:45:06 +02:00
Once we venture into [NFS ](https://en.wikipedia.org/wiki/Network_File_System ) it will become quite essential to have some sort of shared *database* to manage users and permissions.
We'll dive into this from the bottom up so let's create a problem first!
## The problem
2021-09-21 07:55:30 +02:00
To create the problem you'll need at least **three** virtual machines running Debian bullseye.
All three machines should have the root password unset during install and should have the same username for the first user created.
2021-09-20 18:45:06 +02:00
They can be as minimal as you want but I would advise to install one with the tools you like, such as `vim-nox` , `htop` , `zsh` etc and make clones from that one.
We don't need a graphical environment for this exercise.
Put the hostnames as follows:
* `nas` for the NFS server
* `client1` for the first client
* `client2` for the second client
### The server
Let's install an NFS server on the VM.
This is very easy to do on Debian.
The command below is enough have an NFS server up and running.
```bash
➜ ~ sudo apt install nfs-kernel-server
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
nfs-kernel-server is already the newest version (1:1.3.4-6).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
➜ ~
```
But we need to define *which* folders are shared on the network.
I created a folder `/home/shared` for all shared files and folders and `chown` it to my *main* user.
```bash
➜ ~ ls -l /home
total 8
drwxr-xr-x 2 waldek waldek 4096 Sep 15 16:21 shared
drwxr-xr-x 4 waldek waldek 4096 Sep 15 16:33 waldek
➜ ~ touch /home/shared/hello
➜ ~ cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
2021-09-21 07:55:30 +02:00
/home/shared 192.168.122.0/24(no_root_squash,rw,sync,no_subtree_check)
2021-09-20 18:45:06 +02:00
➜ ~ sudo exportfs -ar
➜ ~
```
### The first client
On the client we need to `mount` the network share.
This is done with `mount -t nfs` and a source and destination.
Let's observe the *out of the box* behavior.
```bash
➜ ~ mkdir -p media/nfs
➜ ~ sudo mount -t nfs 192.168.122.100:/home/shared media/nfs
mount: /home/waldek/media/nfs: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.< type > helper program.
➜ ~
```
The command is correct but we're missing the helper program to mount NFS shares.
This can be installed with the `nfs-common` package.
```bash
➜ ~ sudo apt install nfs-common
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
nfs-common is already the newest version (1:1.3.4-6).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
➜ ~ sudo mount -t nfs 192.168.122.100:/home/shared media/nfs
➜ ~ ls -l media/nfs
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 15 16:21 hello
```
Wonderful!
We can now copy files to this network share from all connected clients.
Now do the same for the second client.
It should all work as expected, nothing weird here.
But what happens when we add more users?
### Creating the conflict
2021-09-21 07:55:30 +02:00
On the first client we add a user bob.
Once bob is added, let's have him try to write a file to the network share.
It's pretty obvious that bob can't just write to the network share because he doesn't have the right **permissions** .
We can change that by being super loose and set the directory to `777` !
```bash
➜ ~ sudo adduser bob
adduser: The user `bob' already exists.
➜ ~ su bob
Password:
bob@client1:/home/waldek/media/nfs$ touch hello.bob
touch: cannot touch 'hello.bob': Permission denied
bob@client1:/home/waldek/media/nfs$ exit
exit
➜ ~ chmod 777 media/nfs
➜ ~ su bob
Password:
bob@client1:/home/waldek$ touch media/nfs/hello.bob
bob@client1:/home/waldek$ ls -l media/nfs/
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 bob bob 0 Sep 20 19:17 hello.bob
bob@client1:/home/waldek$
```
But what happens on the nfs server?
There is *no* user named bob there!
```bash
➜ ~ ls -l /home/shared
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 1001 1001 0 Sep 20 19:17 hello.bob
➜ ~
```
You can already *see* hint of the problem to come.
The **unknown** user is references by a **user id** number.
Let's right our wrong and **add** bob to the nfs server.
```bash
➜ ~ hostname
nas
➜ ~ sudo adduser bob
adduser: The user `bob' already exists.
➜ ~ ls -l /home/shared
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 bob bob 0 Sep 20 19:17 hello.bob
➜ ~
```
Now let's add alice as well to the nfs server, and to the first client, and add a file owned by her.
First the nfs server, next the client.
```bash
➜ ~ hostname & & ls -l /home/shared
nas
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 alice alice 0 Sep 20 20:36 hello.alice
-rw-r--r-- 1 bob bob 0 Sep 20 19:17 hello.bob
➜ ~
```
```bash
➜ ~ hostname & & ls -l media/nfs
client1
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 alice alice 0 Sep 20 20:36 hello.alice
-rw-r--r-- 1 bob bob 0 Sep 20 19:17 hello.bob
➜ ~
```
As you can see it *kind* of works out but is very cumbersome **and** prone to errors.
Let's create the error now on purpose.
On the **second client** we add both bob and alice **but** the *wrong* way around meaning first we add alice, next we add bob.
The result is a pretty big misunderstanding!
```bash
➜ ~ hostname
client2
➜ ~ tail -n 2 /etc/passwd
alice:x:1001:1001:,,,:/home/alice:/bin/bash
bob:x:1002:1002:,,,:/home/bob:/bin/bash
➜ ~ ls -l media/nfs
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 bob bob 0 Sep 20 20:36 hello.alice
-rw-r--r-- 1 alice alice 0 Sep 20 19:17 hello.bob
➜ ~
```
## The solution
At the core of the system, Linux does not really care about usernames, but users are referred to by their `$UID` .
This can quickly become a huge mess, especially when you start adding groups, group permissions and SETGUID's.
There are a multitude of solutions to this.
### A *manual* solution
The *simplest* solution is actually a stupidly simple one.
You keep track of your users and group ID's in a file or spreadsheet and *manually* set the ID's when adding users to your systems.
Obviously this is very labor intensive and not practical on a large scale deployment but I'm mentioning it out of completeness.
Not every organisation needs a full blown LDAP back end.
Sometimes, easy is the better option.
We can rectify our problem on the second client by swapping the UID's of both alice and bob.
This is done as follows.
It's a two step procedure for both the user and the group.
This will change the ID's of both alice and bob, plus it will `chown` all files under their home to the correct user ID.
```bash
➜ ~ id bob
uid=1001(alice) gid=1001(alice) groups=1001(alice)
uid=1002(bob) gid=1002(bob) groups=1002(bob)
➜ ~ sudo usermod -u 1001 bob
usermod: UID '1001' already exists
➜ ~ sudo usermod -u 1003 bob
➜ ~ sudo usermod -u 1002 alice
➜ ~ sudo usermod -u 1001 bob
➜ ~ id bob
uid=1001(bob) gid=1002(bob) groups=1002(bob)
➜ ~ id alice
uid=1002(alice) gid=1001(alice) groups=1001(alice)
➜ ~ ls -l media/nfs
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 alice bob 0 Sep 20 20:36 hello.alice
-rw-r--r-- 1 bob alice 0 Sep 20 19:17 hello.bob
➜ ~ sudo groupmod -g 1003 bob
➜ ~ sudo groupmod -g 1002 alice
➜ ~ sudo groupmod -g 1001 bob
➜ ~ ls -l media/nfs
total 0
-rw-r--r-- 1 waldek waldek 0 Sep 20 19:12 hello
-rw-r--r-- 1 alice alice 0 Sep 20 20:36 hello.alice
-rw-r--r-- 1 bob bob 0 Sep 20 19:17 hello.bob
➜ ~
```
### An old school centralized solution
The first centralized account management solution we'll discover is called [NIS ](https://en.wikipedia.org/wiki/Network_Information_Service ), an oldie but goodie.
It's not widely used anymore, mostly in favor of [openLDAP ](https://www.openldap.org/ ), but it's a good entry point to understand how all user verification systems integrate *into* a Linux client.
It's worth reading through the [Debian ](https://wiki.debian.org/BullseyeNis ) specific installation page.
It gives modern setup instructions for an old service.
#### The server