]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - docs/specifications/dirnodes.rst
docs: some changes of 'delete' or 'rm' to 'unlink'. refs #1104
[tahoe-lafs/tahoe-lafs.git] / docs / specifications / dirnodes.rst
1 ==========================
2 Tahoe-LAFS Directory Nodes
3 ==========================
4
5 As explained in the architecture docs, Tahoe-LAFS can be roughly viewed as
6 a collection of three layers. The lowest layer is the key-value store: it
7 provides operations that accept files and upload them to the grid, creating
8 a URI in the process which securely references the file's contents.
9 The middle layer is the filesystem, creating a structure of directories and
10 filenames resembling the traditional unix/windows filesystems. The top layer
11 is the application layer, which uses the lower layers to provide useful
12 services to users, like a backup application, or a way to share files with
13 friends.
14
15 This document examines the middle layer, the "filesystem".
16
17 1.  `Key-value Store Primitives`_
18 2.  `Filesystem goals`_
19 3.  `Dirnode goals`_
20 4.  `Dirnode secret values`_
21 5.  `Dirnode storage format`_
22 6.  `Dirnode sizes, mutable-file initial read sizes`_
23 7.  `Design Goals, redux`_
24
25     1. `Confidentiality leaks in the storage servers`_
26     2. `Integrity failures in the storage servers`_
27     3. `Improving the efficiency of dirnodes`_
28     4. `Dirnode expiration and leases`_
29
30 8.  `Starting Points: root dirnodes`_
31 9.  `Mounting and Sharing Directories`_
32 10. `Revocation`_
33
34 Key-value Store Primitives
35 ==========================
36
37 In the lowest layer (key-value store), there are two operations that reference
38 immutable data (which we refer to as "CHK URIs" or "CHK read-capabilities" or
39 "CHK read-caps"). One puts data into the grid (but only if it doesn't exist
40 already), the other retrieves it::
41
42  chk_uri = put(data)
43  data = get(chk_uri)
44
45 We also have three operations which reference mutable data (which we refer to
46 as "mutable slots", or "mutable write-caps and read-caps", or sometimes "SSK
47 slots"). One creates a slot with some initial contents, a second replaces the
48 contents of a pre-existing slot, and the third retrieves the contents::
49
50  mutable_uri = create(initial_data)
51  replace(mutable_uri, new_data)
52  data = get(mutable_uri)
53
54 Filesystem Goals
55 ================
56
57 The main goal for the middle (filesystem) layer is to give users a way to
58 organize the data that they have uploaded into the grid. The traditional way
59 to do this in computer filesystems is to put this data into files, give those
60 files names, and collect these names into directories.
61
62 Each directory is a set of name-entry pairs, each of which maps a "child name"
63 to a directory entry pointing to an object of some kind. Those child objects
64 might be files, or they might be other directories. Each directory entry also
65 contains metadata.
66
67 The directory structure is therefore a directed graph of nodes, in which each
68 node might be a directory node or a file node. All file nodes are terminal
69 nodes.
70
71 Dirnode Goals
72 =============
73
74 What properties might be desirable for these directory nodes? In no
75 particular order:
76
77 1. functional. Code which does not work doesn't count.
78 2. easy to document, explain, and understand
79 3. confidential: it should not be possible for others to see the contents of
80    a directory
81 4. integrity: it should not be possible for others to modify the contents
82    of a directory
83 5. available: directories should survive host failure, just like files do
84 6. efficient: in storage, communication bandwidth, number of round-trips
85 7. easy to delegate individual directories in a flexible way
86 8. updateness: everybody looking at a directory should see the same contents
87 9. monotonicity: everybody looking at a directory should see the same
88    sequence of updates
89
90 Some of these goals are mutually exclusive. For example, availability and
91 consistency are opposing, so it is not possible to achieve #5 and #8 at the
92 same time. Moreover, it takes a more complex architecture to get close to the
93 available-and-consistent ideal, so #2/#6 is in opposition to #5/#8.
94
95 Tahoe-LAFS v0.7.0 introduced distributed mutable files, which use public-key
96 cryptography for integrity, and erasure coding for availability. These
97 achieve roughly the same properties as immutable CHK files, but their
98 contents can be replaced without changing their identity. Dirnodes are then
99 just a special way of interpreting the contents of a specific mutable file.
100 Earlier releases used a "vdrive server": this server was abolished in the
101 v0.7.0 release.
102
103 For details of how mutable files work, please see `<mutable.rst>`_ in this
104 directory.
105
106 For releases since v0.7.0, we achieve most of our desired properties. The
107 integrity and availability of dirnodes is equivalent to that of regular
108 (immutable) files, with the exception that there are more simultaneous-update
109 failure modes for mutable slots. Delegation is quite strong: you can give
110 read-write or read-only access to any subtree, and the data format used for
111 dirnodes is such that read-only access is transitive: i.e. if you grant Bob
112 read-only access to a parent directory, then Bob will get read-only access
113 (and *not* read-write access) to its children.
114
115 Relative to the previous "vdrive-server" based scheme, the current
116 distributed dirnode approach gives better availability, but cannot guarantee
117 updateness quite as well, and requires far more network traffic for each
118 retrieval and update. Mutable files are somewhat less available than
119 immutable files, simply because of the increased number of combinations
120 (shares of an immutable file are either present or not, whereas there are
121 multiple versions of each mutable file, and you might have some shares of
122 version 1 and other shares of version 2). In extreme cases of simultaneous
123 update, mutable files might suffer from non-monotonicity.
124
125
126 Dirnode secret values
127 =====================
128
129 As mentioned before, dirnodes are simply a special way to interpret the
130 contents of a mutable file, so the secret keys and capability strings
131 described in `<mutable.rst>`_ are all the same. Each dirnode contains an RSA
132 public/private keypair, and the holder of the "write capability" will be able
133 to retrieve the private key (as well as the AES encryption key used for the
134 data itself). The holder of the "read capability" will be able to obtain the
135 public key and the AES data key, but not the RSA private key needed to modify
136 the data.
137
138 The "write capability" for a dirnode grants read-write access to its
139 contents. This is expressed on concrete form as the "dirnode write cap": a
140 printable string which contains the necessary secrets to grant this access.
141 Likewise, the "read capability" grants read-only access to a dirnode, and can
142 be represented by a "dirnode read cap" string.
143
144 For example,
145 URI:DIR2:swdi8ge1s7qko45d3ckkyw1aac%3Aar8r5j99a4mezdojejmsfp4fj1zeky9gjigyrid4urxdimego68o
146 is a write-capability URI, while
147 URI:DIR2-RO:buxjqykt637u61nnmjg7s8zkny:ar8r5j99a4mezdojejmsfp4fj1zeky9gjigyrid4urxdimego68o
148 is a read-capability URI, both for the same dirnode.
149
150
151 Dirnode storage format
152 ======================
153
154 Each dirnode is stored in a single mutable file, distributed in the Tahoe-LAFS
155 grid. The contents of this file are a serialized list of netstrings, one per
156 child. Each child is a list of four netstrings: (name, rocap, rwcap,
157 metadata). (Remember that the contents of the mutable file are encrypted by
158 the read-cap, so this section describes the plaintext contents of the mutable
159 file, *after* it has been decrypted by the read-cap.)
160
161 The name is simple a UTF-8 -encoded child name. The 'rocap' is a read-only
162 capability URI to that child, either an immutable (CHK) file, a mutable file,
163 or a directory. It is also possible to store 'unknown' URIs that are not
164 recognized by the current version of Tahoe-LAFS. The 'rwcap' is a read-write
165 capability URI for that child, encrypted with the dirnode's write-cap: this
166 enables the "transitive readonlyness" property, described further below. The
167 'metadata' is a JSON-encoded dictionary of type,value metadata pairs. Some
168 metadata keys are pre-defined, the rest are left up to the application.
169
170 Each rwcap is stored as IV + ciphertext + MAC. The IV is a 16-byte random
171 value. The ciphertext is obtained by using AES in CTR mode on the rwcap URI
172 string, using a key that is formed from a tagged hash of the IV and the
173 dirnode's writekey. The MAC is written only for compatibility with older
174 Tahoe-LAFS versions and is no longer verified.
175
176 If Bob has read-only access to the 'bar' directory, and he adds it as a child
177 to the 'foo' directory, then he will put the read-only cap for 'bar' in both
178 the rwcap and rocap slots (encrypting the rwcap contents as described above).
179 If he has full read-write access to 'bar', then he will put the read-write
180 cap in the 'rwcap' slot, and the read-only cap in the 'rocap' slot. Since
181 other users who have read-only access to 'foo' will be unable to decrypt its
182 rwcap slot, this limits those users to read-only access to 'bar' as well,
183 thus providing the transitive readonlyness that we desire.
184
185 Dirnode sizes, mutable-file initial read sizes
186 ==============================================
187
188 How big are dirnodes? When reading dirnode data out of mutable files, how
189 large should our initial read be? If we guess exactly, we can read a dirnode
190 in a single round-trip, and update one in two RTT. If we guess too high,
191 we'll waste some amount of bandwidth. If we guess low, we need to make a
192 second pass to get the data (or the encrypted privkey, for writes), which
193 will cost us at least another RTT.
194
195 Assuming child names are between 10 and 99 characters long, how long are the
196 various pieces of a dirnode?
197
198 ::
199
200  netstring(name) ~= 4+len(name)
201  chk-cap = 97 (for 4-char filesizes)
202  dir-rw-cap = 88
203  dir-ro-cap = 91
204  netstring(cap) = 4+len(cap)
205  encrypted(cap) = 16+cap+32
206  JSON({}) = 2
207  JSON({ctime=float,mtime=float,'tahoe':{linkcrtime=float,linkmotime=float}}): 137
208  netstring(metadata) = 4+137 = 141
209
210 so a CHK entry is::
211
212  5+ 4+len(name) + 4+97 + 5+16+97+32 + 4+137
213
214 And a 15-byte filename gives a 416-byte entry. When the entry points at a
215 subdirectory instead of a file, the entry is a little bit smaller. So an
216 empty directory uses 0 bytes, a directory with one child uses about 416
217 bytes, a directory with two children uses about 832, etc.
218
219 When the dirnode data is encoding using our default 3-of-10, that means we
220 get 139ish bytes of data in each share per child.
221
222 The pubkey, signature, and hashes form the first 935ish bytes of the
223 container, then comes our data, then about 1216 bytes of encprivkey. So if we
224 read the first::
225
226  1kB: we get 65bytes of dirnode data : only empty directories
227  2kB: 1065bytes: about 8
228  3kB: 2065bytes: about 15 entries, or 6 entries plus the encprivkey
229  4kB: 3065bytes: about 22 entries, or about 13 plus the encprivkey
230
231 So we've written the code to do an initial read of 4kB from each share when
232 we read the mutable file, which should give good performance (one RTT) for
233 small directories.
234
235
236 Design Goals, redux
237 ===================
238
239 How well does this design meet the goals?
240
241 1. functional: YES: the code works and has extensive unit tests
242 2. documentable: YES: this document is the existence proof
243 3. confidential: YES: see below
244 4. integrity: MOSTLY: a coalition of storage servers can rollback individual
245    mutable files, but not a single one. No server can
246    substitute fake data as genuine.
247 5. availability: YES: as long as 'k' storage servers are present and have
248    the same version of the mutable file, the dirnode will
249    be available.
250 6. efficient: MOSTLY:
251      network: single dirnode lookup is very efficient, since clients can
252        fetch specific keys rather than being required to get or set
253        the entire dirnode each time. Traversing many directories
254        takes a lot of roundtrips, and these can't be collapsed with
255        promise-pipelining because the intermediate values must only
256        be visible to the client. Modifying many dirnodes at once
257        (e.g. importing a large pre-existing directory tree) is pretty
258        slow, since each graph edge must be created independently.
259      storage: each child has a separate IV, which makes them larger than
260        if all children were aggregated into a single encrypted string
261 7. delegation: VERY: each dirnode is a completely independent object,
262    to which clients can be granted separate read-write or
263    read-only access
264 8. updateness: VERY: with only a single point of access, and no caching,
265    each client operation starts by fetching the current
266    value, so there are no opportunities for staleness
267 9. monotonicity: VERY: the single point of access also protects against
268    retrograde motion
269      
270
271
272 Confidentiality leaks in the storage servers
273 --------------------------------------------
274
275 Dirnode (and the mutable files upon which they are based) are very private
276 against other clients: traffic between the client and the storage servers is
277 protected by the Foolscap SSL connection, so they can observe very little.
278 Storage index values are hashes of secrets and thus unguessable, and they are
279 not made public, so other clients cannot snoop through encrypted dirnodes
280 that they have not been told about.
281
282 Storage servers can observe access patterns and see ciphertext, but they
283 cannot see the plaintext (of child names, metadata, or URIs). If an attacker
284 operates a significant number of storage servers, they can infer the shape of
285 the directory structure by assuming that directories are usually accessed
286 from root to leaf in rapid succession. Since filenames are usually much
287 shorter than read-caps and write-caps, the attacker can use the length of the
288 ciphertext to guess the number of children of each node, and might be able to
289 guess the length of the child names (or at least their sum). From this, the
290 attacker may be able to build up a graph with the same shape as the plaintext
291 filesystem, but with unlabeled edges and unknown file contents.
292
293
294 Integrity failures in the storage servers
295 -----------------------------------------
296
297 The mutable file's integrity mechanism (RSA signature on the hash of the file
298 contents) prevents the storage server from modifying the dirnode's contents
299 without detection. Therefore the storage servers can make the dirnode
300 unavailable, but not corrupt it.
301
302 A sufficient number of colluding storage servers can perform a rollback
303 attack: replace all shares of the whole mutable file with an earlier version.
304 To prevent this, when retrieving the contents of a mutable file, the
305 client queries more servers than necessary and uses the highest available
306 version number. This insures that one or two misbehaving storage servers
307 cannot cause this rollback on their own.
308
309
310 Improving the efficiency of dirnodes
311 ------------------------------------
312
313 The current mutable-file -based dirnode scheme suffers from certain
314 inefficiencies. A very large directory (with thousands or millions of
315 children) will take a significant time to extract any single entry, because
316 the whole file must be downloaded first, then parsed and searched to find the
317 desired child entry. Likewise, modifying a single child will require the
318 whole file to be re-uploaded.
319
320 The current design assumes (and in some cases, requires) that dirnodes remain
321 small. The mutable files on which dirnodes are based are currently using
322 "SDMF" ("Small Distributed Mutable File") design rules, which state that the
323 size of the data shall remain below one megabyte. More advanced forms of
324 mutable files (MDMF and LDMF) are in the design phase to allow efficient
325 manipulation of larger mutable files. This would reduce the work needed to
326 modify a single entry in a large directory.
327
328 Judicious caching may help improve the reading-large-directory case. Some
329 form of mutable index at the beginning of the dirnode might help as well. The
330 MDMF design rules allow for efficient random-access reads from the middle of
331 the file, which would give the index something useful to point at.
332
333 The current SDMF design generates a new RSA public/private keypair for each
334 directory. This takes considerable time and CPU effort, generally one or two
335 seconds per directory. We have designed (but not yet built) a DSA-based
336 mutable file scheme which will use shared parameters to reduce the
337 directory-creation effort to a bare minimum (picking a random number instead
338 of generating two random primes).
339
340 When a backup program is run for the first time, it needs to copy a large
341 amount of data from a pre-existing filesystem into reliable storage. This
342 means that a large and complex directory structure needs to be duplicated in
343 the dirnode layer. With the one-object-per-dirnode approach described here,
344 this requires as many operations as there are edges in the imported
345 filesystem graph.
346
347 Another approach would be to aggregate multiple directories into a single
348 storage object. This object would contain a serialized graph rather than a
349 single name-to-child dictionary. Most directory operations would fetch the
350 whole block of data (and presumeably cache it for a while to avoid lots of
351 re-fetches), and modification operations would need to replace the whole
352 thing at once. This "realm" approach would have the added benefit of
353 combining more data into a single encrypted bundle (perhaps hiding the shape
354 of the graph from a determined attacker), and would reduce round-trips when
355 performing deep directory traversals (assuming the realm was already cached).
356 It would also prevent fine-grained rollback attacks from working: a coalition
357 of storage servers could change the entire realm to look like an earlier
358 state, but it could not independently roll back individual directories.
359
360 The drawbacks of this aggregation would be that small accesses (adding a
361 single child, looking up a single child) would require pulling or pushing a
362 lot of unrelated data, increasing network overhead (and necessitating
363 test-and-set semantics for the modification side, which increases the chances
364 that a user operation will fail, making it more challenging to provide
365 promises of atomicity to the user). 
366
367 It would also make it much more difficult to enable the delegation
368 ("sharing") of specific directories. Since each aggregate "realm" provides
369 all-or-nothing access control, the act of delegating any directory from the
370 middle of the realm would require the realm first be split into the upper
371 piece that isn't being shared and the lower piece that is. This splitting
372 would have to be done in response to what is essentially a read operation,
373 which is not traditionally supposed to be a high-effort action. On the other
374 hand, it may be possible to aggregate the ciphertext, but use distinct
375 encryption keys for each component directory, to get the benefits of both
376 schemes at once.
377
378
379 Dirnode expiration and leases
380 -----------------------------
381
382 Dirnodes are created any time a client wishes to add a new directory. How
383 long do they live? What's to keep them from sticking around forever, taking
384 up space that nobody can reach any longer?
385
386 Mutable files are created with limited-time "leases", which keep the shares
387 alive until the last lease has expired or been cancelled. Clients which know
388 and care about specific dirnodes can ask to keep them alive for a while, by
389 renewing a lease on them (with a typical period of one month). Clients are
390 expected to assist in the deletion of dirnodes by canceling their leases as
391 soon as they are done with them. This means that when a client unlinks a
392 directory, it should also cancel its lease on that directory. When the lease
393 count on a given share goes to zero, the storage server can delete the
394 related storage. Multiple clients may all have leases on the same dirnode:
395 the server may delete the shares only after all of the leases have gone away.
396
397 We expect that clients will periodically create a "manifest": a list of
398 so-called "refresh capabilities" for all of the dirnodes and files that they
399 can reach. They will give this manifest to the "repairer", which is a service
400 that keeps files (and dirnodes) alive on behalf of clients who cannot take on
401 this responsibility for themselves. These refresh capabilities include the
402 storage index, but do *not* include the readkeys or writekeys, so the
403 repairer does not get to read the files or directories that it is helping to
404 keep alive.
405
406 After each change to the user's vdrive, the client creates a manifest and
407 looks for differences from their previous version. Anything which was removed
408 prompts the client to send out lease-cancellation messages, allowing the data
409 to be deleted.
410
411
412 Starting Points: root dirnodes
413 ==============================
414
415 Any client can record the URI of a directory node in some external form (say,
416 in a local file) and use it as the starting point of later traversal. Each
417 Tahoe-LAFS user is expected to create a new (unattached) dirnode when they first
418 start using the grid, and record its URI for later use.
419
420 Mounting and Sharing Directories
421 ================================
422
423 The biggest benefit of this dirnode approach is that sharing individual
424 directories is almost trivial. Alice creates a subdirectory that she wants to
425 use to share files with Bob. This subdirectory is attached to Alice's
426 filesystem at "~alice/share-with-bob". She asks her filesystem for the
427 read-write directory URI for that new directory, and emails it to Bob. When
428 Bob receives the URI, he asks his own local vdrive to attach the given URI,
429 perhaps at a place named "~bob/shared-with-alice". Every time either party
430 writes a file into this directory, the other will be able to read it. If
431 Alice prefers, she can give a read-only URI to Bob instead, and then Bob will
432 be able to read files but not change the contents of the directory. Neither
433 Alice nor Bob will get access to any files above the mounted directory: there
434 are no 'parent directory' pointers. If Alice creates a nested set of
435 directories, "~alice/share-with-bob/subdir2", and gives a read-only URI to
436 share-with-bob to Bob, then Bob will be unable to write to either
437 share-with-bob/ or subdir2/.
438
439 A suitable UI needs to be created to allow users to easily perform this
440 sharing action: dragging a folder their vdrive to an IM or email user icon,
441 for example. The UI will need to give the sending user an opportunity to
442 indicate whether they want to grant read-write or read-only access to the
443 recipient. The recipient then needs an interface to drag the new folder into
444 their vdrive and give it a home.
445
446 Revocation
447 ==========
448
449 When Alice decides that she no longer wants Bob to be able to access the
450 shared directory, what should she do? Suppose she's shared this folder with
451 both Bob and Carol, and now she wants Carol to retain access to it but Bob to
452 be shut out. Ideally Carol should not have to do anything: her access should
453 continue unabated.
454
455 The current plan is to have her client create a deep copy of the folder in
456 question, delegate access to the new folder to the remaining members of the
457 group (Carol), asking the lucky survivors to replace their old reference with
458 the new one. Bob may still have access to the old folder, but he is now the
459 only one who cares: everyone else has moved on, and he will no longer be able
460 to see their new changes. In a strict sense, this is the strongest form of
461 revocation that can be accomplished: there is no point trying to force Bob to
462 forget about the files that he read a moment before being kicked out. In
463 addition it must be noted that anyone who can access the directory can proxy
464 for Bob, reading files to him and accepting changes whenever he wants.
465 Preventing delegation between communication parties is just as pointless as
466 asking Bob to forget previously accessed files. However, there may be value
467 to configuring the UI to ask Carol to not share files with Bob, or to
468 removing all files from Bob's view at the same time his access is revoked.
469