]>
Commit | Line | Data |
---|---|---|
a9dabd68 LP |
1 | --- |
2 | title: Home Directories | |
5fe63895 | 3 | category: Users, Groups and Home Directories |
a9dabd68 LP |
4 | layout: default |
5 | --- | |
6 | ||
7 | # Home Directories | |
8 | ||
9 | [`systemd-homed.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-homed.service.html) | |
10 | manages home directories of regular ("human") users. Each directory it manages | |
11 | encapsulates both the data store and the user record of the user so that it | |
12 | comprehensively describes the user account, and is thus naturally portable | |
13 | between systems without any further, external metadata. This document describes | |
14 | the format used by these home directories, in context of the storage mechanism | |
15 | used. | |
16 | ||
17 | ## General Structure | |
18 | ||
19 | Inside of the home directory a file `~/.identity` contains the JSON formatted | |
20 | user record of the user. It follows the format defined in [`JSON User | |
e5e529c3 | 21 | Records`](https://systemd.io/USER_RECORD). It is recommended to bring the |
a9dabd68 LP |
22 | record into 'normalized' form (i.e. all objects should contain their fields |
23 | sorted alphabetically by their key) before storing it there, though this is not | |
24 | required nor enforced. Since the user record is cryptographically signed the | |
25 | user cannot make modifications to the file on their own (at least not without | |
26 | corrupting it, or knowing the private key used for signing the record). Note | |
27 | that user records are stored here without their `binding`, `status` and | |
28 | `secret` sections, i.e. only with the sections included in the signature plus | |
29 | the signature section itself. | |
30 | ||
31 | ## Storage Mechanism: Plain Directory/`btrfs` Subvolume | |
32 | ||
33 | If the plain directory or `btrfs` subvolume storage mechanism of | |
34 | `systemd-homed` is used (i.e. `--storage=directory` or `--storage=subvolume` on | |
35 | the | |
36 | [`homectl(1)`](https://www.freedesktop.org/software/systemd/man/homectl.html) | |
37 | command line) the home directory requires no special set-up besides including | |
38 | the user record in the `~/.identity` file. | |
39 | ||
40 | It is recommended to name home directories managed this way by | |
41 | `systemd-homed.service` by the user name, suffixed with `.homedir` (example: | |
42 | `lennart.homedir` for a user `lennart`) but this is not enforced. When the user | |
43 | is logged in the directory is generally mounted to `/home/$USER` (in our | |
44 | example: `/home/lennart`), thus dropping the suffix while the home directory is | |
45 | active. `systemd-homed` will automatically discover home directories named this | |
46 | way in `/home/*.homedir` and synthesize NSS user records for them as they show | |
47 | up. | |
48 | ||
49 | ## Storage Mechanism: `fscrypt` Directories | |
50 | ||
51 | This storage mechanism is mostly identical to the plain directory storage | |
52 | mechanism, except that the home directory is encrypted using `fscrypt`. (Use | |
53 | `--storage=fscrypt` on the `homectl` command line.) Key management is | |
54 | implemented via extended attributes on the directory itself: for each password | |
55 | an extended attribute `trusted.fscrypt_slot0`, `trusted.fscrypt_slot1`, | |
56 | `trusted.fscrypt_slot2`, … is maintained. It's value contains a colon-separated | |
57 | pair of Base64 encoded data fields. The first field contains a salt value, the | |
58 | second field the encrypted volume key. The latter is encrypted using AES256 in | |
59 | counter mode, using a key derived from the password via PBKDF2-HMAC-SHA512 | |
60 | together with the salt value. The construction is similar to what LUKS does for | |
61 | `dm-crypt` encrypted volumes. Note that extended attributes are not encrypted | |
62 | by `fscrypt` and hence are suitable for carry the key slots. Moreover, by using | |
63 | extended attributes the slots are directly attached to the directory and an | |
64 | independent sidecar key database is not required. | |
65 | ||
66 | ## Storage Mechanism: `cifs` Home Directories | |
67 | ||
68 | In this storage mechanism the home directory is mounted from a CIFS server and | |
69 | service at login, configured inside the user record. (Use `--storage=cifs` on | |
70 | the `homectl` command line.) The local password of the user is used to log into | |
71 | the CIFS service. The directory share needs to contain the user record in | |
72 | `~/.identity` as well. Note that this means that the user record needs to be | |
73 | registered locally before it can be mounted for the first time, since CIFS | |
74 | domain and server information needs to be known *before* the mount. Note that | |
75 | for all other storage mechanisms it is entirely sufficient if the directories | |
76 | or storage artifacts are placed at the right locations — all information to | |
77 | activate them can be derived automatically from their mere availability. | |
78 | ||
79 | ## Storage Mechanism: `luks` Home Directories | |
80 | ||
81 | This is the most advanced and most secure storage mechanism and consists of a | |
82 | Linux file system inside a LUKS2 volume inside a loopback file (or on removable | |
83 | media). (Use `--storage=luks` on the `homectl` command line.) Specifically: | |
84 | ||
85 | * The image contains a GPT partition table. For now it should only contain a | |
86 | single partition, and that partition must have the type UUID | |
87 | `773f91ef-66d4-49b5-bd83-d683bf40ad16`. It's partition label must be the | |
88 | user name. | |
89 | ||
90 | * This partition must contain a LUKS2 volume, whose label must be the user | |
91 | name. The LUKS2 volume must contain a LUKS2 token field of type | |
92 | `systemd-homed`. The JSON data of this token must have a `record` field, | |
93 | containing a string with base64-encoded data. This data is the JSON user | |
94 | record, in the same serialization as in `~/.identity`, though encrypted. The | |
95 | JSON data of this token must also have an `iv` field, which contains a | |
96 | base64-encoded binary initialization vector for the encryption. The | |
97 | encryption used is the same as the LUKS2 volume itself uses, unlocked by the | |
98 | same volume key, but based on its own IV. | |
99 | ||
100 | * Inside of this LUKS2 volume must be a Linux file system, one of `ext4`, | |
101 | `btrfs` and `xfs`. The file system label must be the user name. | |
102 | ||
103 | * This file system should contain a single directory named after the user. This | |
104 | directory will become the home directory of the user when activated. It | |
105 | contains a second copy of the user record in the `~/.identity` file, like in | |
106 | the other storage mechanisms. | |
107 | ||
108 | The image file should either reside in a directory `/home/` on the system, | |
109 | named after the user, suffixed with `.home`. When activated the container home | |
110 | directory is mounted to the same path, though with the `.home` suffix dropped — | |
111 | unless a different mount point is defined in the user record. (e.g.: the | |
112 | loopback file `/home/waldo.home` is mounted to `/home/waldo` while activated.) | |
113 | When the image is stored on removable media (such as a USB stick) the image | |
114 | file can be directly `dd`'ed onto it, the format is unchanged. The GPT envelope | |
115 | should ensure the image is properly recognizable as a home directory both when | |
116 | used in a loopback file and on a removable USB stick. (Note that when mounting | |
117 | a home directory from an USB stick it too defaults to a directory in `/home/`, | |
118 | named after the username, with no further suffix.) | |
119 | ||
120 | Rationale for the GPT partition table envelope: this way the image is nicely | |
121 | discoverable and recognizable already by partition managers as a home | |
122 | directory. Moreover, when copied onto a USB stick the GPT envelope makes sure | |
123 | the stick is properly recognizable as a portable home directory | |
124 | medium. (Moreover it allows to embed additional partitions later on, for | |
125 | example for allowing a multi-purpose USB stick that contains both a home | |
126 | directory and a generic storage volume.) | |
127 | ||
128 | Rationale for including the encrypted user record in the the LUKS2 header: | |
129 | Linux kernel file system implementations are generally not robust towards | |
130 | maliciously formatted file systems; there's a good chance that file system | |
131 | images can be used as attack vectors, exploiting the kernel. Thus it is | |
132 | necessary to validate the home directory image *before* mounting it and | |
133 | establishing a minimal level of trust. Since the user record data is | |
134 | cryptographically signed and user records not signed with a recognized private | |
135 | key are not accepted a minimal level of trust between the system and the home | |
136 | directory image is established. | |
137 | ||
138 | Rationale for storing the home directory one level below to root directory of | |
139 | the contained file system: this way special directories such as `lost+found/` | |
140 | do not show up in the user's home directory. | |
141 | ||
142 | ## Algorithm | |
143 | ||
144 | Regardless of the storage mechanism used, an activated home directory | |
145 | necessarily involves a mount point to be established. In case of the | |
146 | directory-based storage mechanisms (`directory`, `subvolume` and `fscrypt`) | |
147 | this is a bind mount, in case of `cifs` this is a CIFS network mount, and in | |
148 | case of the LUKS2 backend a regular block device mount of the file system | |
149 | contained in the LUKS2 image. By requiring a mount for all cases (even for | |
86b52a39 | 150 | those that already are a directory) a clear logic is defined to distinguish |
a9dabd68 LP |
151 | active and inactive home directories, so that the directories become |
152 | inaccessible under their regular path the instant they are | |
153 | deactivated. Moreover, the `nosuid`, `nodev` and `noexec` flags configured in | |
154 | the user record are applied when the bind mount is established. | |
155 | ||
156 | During activation, the user records retained on the host, the user record | |
157 | stored in the LUKS2 header (in case of the LUKS2 storage mechanism) and the | |
158 | user record stored inside the home directory in `~/.identity` are | |
159 | compared. Activation is only permitted if they match the same user and are | |
160 | signed by a recognized key. When the three instances differ in `lastChangeUSec` | |
161 | field, the newest record wins, and is propagated to the other two locations. | |
162 | ||
163 | During activation the file system checker (`fsck`) appropriate for the | |
164 | selected file system is automatically invoked, ensuring the file system is in a | |
165 | healthy state before it is mounted. | |
166 | ||
167 | If the UID assigned to a user does not match the owner of the home directory in | |
168 | the file system, the home directory is automatically and recursively `chown()`ed | |
169 | to the correct UID. | |
170 | ||
171 | Depending on the `discard` setting of the user record either the backing | |
172 | loopback file is `fallocate()`ed during activation, or the mounted file system | |
173 | is `FITRIM`ed after mounting, to ensure the setting is correctly enforced. |