⚠️ Warning: This documentation refers to the proof-of-concept implementation of Wildland client (opens new window) which is no longer maintained. We are currently working on a new Wildland client written in Rust. To learn more about Wildland and the current status of its development, please visit the Wildland.io webpage (opens new window).

# Access Control and Sharing

What's fundamental to Wildland's access control is that every manifest object (i.e. a container, storage, user or bridge object) has an owner. An owner is just a regular user who claims ownership of a manifest; thus digitally signs it using his private key.

This concept prevents these signed manifests from being tampered with and, in effect, secures the integrity of the manifest files. Every manifest file used in Wildland must be signed -- there are no exceptions to that.

# Manifests ownership

Each time you create an object, that object is signed by an owner. By default, it is signed by the default-owner, specified in ~/.config/wildland/config.yaml Wildland configuration file.

Create your own user first:

alice@wildland-client:~$ wl user create alice
Generated key: 0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a # <- Alice's fingerprint
No path specified, using: /users/alice
Created: /home/user/.config/wildland/users/alice.user.yaml
Using 0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a as @default
Using 0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a as @default-owner
Adding 0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a to local owners

Then, import user manifest of the user with whom you want to share your container (i.e. Bob's user manifest).

alice@wildland-client:~$ wl user im ~/Downloads/bob.user.yaml
Created: /home/user/.config/wildland/users/bob.user.yaml
Created: /home/user/.config/wildland/bridges/bob.bridge.yaml
alice@wildland-client:~$ wl container create mycontainer
Created: /home/user/.config/wildland/containers/mycontainer.container.yaml

alice@wildland-client:~$ wl container dump mycontainer
object: container
owner: '0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a' # <- Alice's fingerprint
paths:
- /.uuid/4f33d065-4cfe-438a-9541-6b8e5f130b9b
backends:
  storage: []
title: null
categories: []
version: '1'

Note that you cannot create a container, where the owner is a user, which you don't own.

alice@wildland-client:~$ wl container create another-container --owner bob
Error: Secret key not found: 0xcb8678980faaf04cf7a88fc1310c93ace186be8de3e978c533d788435bdd2bba

# Manifests encryption

In the examples above the wl container dump command has been used to print the container's contents. However, if you tried to simply read the container's file content, the result would be the following:

alice@wildland-client:~$ cat ~/.config/wildland/containers/mycontainer.container.yaml
signature: |
0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a:gm4Pk0LvbV+u82SQZFA+nNj1e505VCbwNOQ70XGZXUWZKpqQenvcS79YiTOsnMYo34+Z+HV/1dZcYaFaZPcjDg==
---
encrypted:
  encrypted-data: kuvZU28UpjHGCibUeXibcYMo9zCGhEoMTKXRIdxQ6SKkH7o/sMF/5U6f2iFl7jcvnEtPR2eY9r7+cTx9tAzmAs/3zBi5xpcbp11O4RMI12qu0JI5asfMoMH08HLqAAxQlt3BgUqiVWvbZ5bSUuGYnKStJV9Ur7FQjJ0m+a1VWKumOwyplEifMo4UYzHd4TLJjW2Vwzrs1Xuq4yS6ad+tE1GtSlI4K35a3x2ej2fmc5ZL4rmStvU3kV3fMizuDOtlrkzqLMfypIZu0HSbWLPsFdhRDbeAActD61LvktIkHnPTvgV1hny3Hpb0LKmb407h45fSNP9yqTk0NUM=
  encrypted-keys:
  - VkcXCwEs/dCACFcBt9sYsSAyJXhOrLo6PjWO4vhZPhcvCrxZ6QezZuq+Ju4+dJ72J1xqbjckV/LmU4eCVzbQ/vTgEuOCvaHL+cnoKUDW+IQ=

Nowhere close to a pretty output from the previous section. That is because, by default, every manifest file is encrypted using the owner's public key. In consequence, only the owner is now be able to decrypt the contents.

If the manifest was to be shared publicly, you wouldn't want to encrypt it at all. To disable this protection, use the following command:

alice@wildland-client:~$ wl container modify --no-encrypt-manifest mycontainer
Saved: /home/user/.config/wildland/containers/mycontainer.container.yaml
re-publishing container /.uuid/4f33d065-4cfe-438a-9541-6b8e5f130b9b...

alice@wildland-client:~$ cat ~/.config/wildland/containers/mycontainer.container.yaml
signature: |
0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a:SB14LrxF4Scq9uL9h0xWZ4r3SbqzXgyKNKKzcaYhlNJYMyHNRfiWE2kpBeHbwIBZuUj1FsEgV1coGoo5Jo2QDQ==
---
object: container
owner: '0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a'
paths:
- /.uuid/4f33d065-4cfe-438a-9541-6b8e5f130b9b
backends:
  storage: []
title: null
categories: []
version: '1'
access:
- user: '*'

Note that the manifest contents are now in plain text (thanks to the access field which wasn't present in the wl container dump from the previous section). Nonetheless, the integrity of the manifest contents is still protected by the signature field.

The same result could be achieved by using the --no-encrypt-manifest flag when creating a container.

alice@wildland-client:~$ wl container create unencrypted-container --no-encrypt-manifest
Created: /home/user/.config/wildland/containers/unencrypted-container.container.yaml

alice@wildland-client:~$ cat ~/.config/wildland/containers/unencrypted-container.container.yaml
signature: |
0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a:IYQZ1wRGT+kpJZ1NRp3FlxsvmaM6PzGsr8959qj+x2ozHSZ/nZ+JElJkgsVvofeCewIj1Z1rrILWZxyGrSCdCA==
---
object: container
owner: '0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a'
paths:
- /.uuid/1323436a-5044-44ef-b8cf-9ad91e3ca123
backends:
  storage: []
title: null
categories: []
version: '1'
access:
- user: '*'

# Selective access control

The previous sections have shown that the manifest can either be encrypted by the manifest owner or unencrypted. This section shows that you can also define access selectively, by specifying users who may read the contents of an encrypted file by using the --access flag.

Note: If you have already followed Forest Creation in Quick Start Guide, the container will automatically be published to Alice's infrastructure unless the --no-publish flag is passed.

alice@wildland-client:~$ wl container create alice-and-bob --access bob --path /very/secret
Created: /home/user/.config/wildland/containers/alice-and-bob.container.yaml

Let's add some dummy storage to the container so that it's not mounting a void:

alice@wildland-client:~$ wl storage create dummy --container alice-and-bob
Using container: /home/user/.config/wildland/containers/alice-and-bob.container.yaml (/.uuid/b1cffd57-f0c2-4b04-911d-5e709dd53a30)
Adding storage e09e7cb0-db67-4888-9753-afd96b901a21 to container.
Saved container /home/user/.config/wildland/containers/alice-and-bob.container.yaml

alice@wildland-client:~$ cat ~/.config/wildland/containers/alice-and-bob.container.yaml
signature: |
0xed4d4d28c275c4c2d611a7fac4a32193a5a85d1c9ea53dddc3110270563ceb7a:kMJUCbajjgAArIzLS6uzrUCVVLxRd++SfJPsFpvgwixXBX+k5YaWPKXAHT9IeK9cShZXeTeCcEnAeDfsakR7Ag==
---
encrypted:
  encrypted-data: 7KltiablURhv/hKZROQblr4SS6QTbHwBegmuHSxb499LkeKVw/1yvDcczyJMmO5svtFJAsEkc0dOm9CvSXGzFTJSmOQk0EmnzNVeDVUmQxXmAIKtGdIzJEz+2AA1Y9R22+Ac0O32DNcnnqHGidBxfHIpGIdCWeh3uFuA+4E08Mixjw9TzpP6jmk8KMIULklcYctd1AQ0hR39VxpMkGbQswHx48YbnLmvYcbaa0cnE60ueg7lMQuk1Jhq+ekm0U7r8SQPruXbxYTbbKk2OXbFQmdZcd8NZ271She5EWwIZ2wChAzJcBcS7po4rvDnhTvhDtS+LIoqM1wVrGDdTnK5SvLam0vDIRWlEBFMWiCcjQXTL1GGNYl366bKNQyGAAQp24WGIw1ZY8EU2I6KTsSyOdDmRWKhvxOlenM8bHjQ6dIdgE6ZmrzhwGeSxFnvLXvTpJ+R9Lvxggf3bDVHG6OH
  encrypted-keys:
  - M4+7tAy26MEhEs2i7x6Xz/jthhMm+IIDHXhLM4Scg1M+lsInDktax3AznivQAxvqbDc4Gd8WHQskPDZK02y5kt9uTQ3HQNwNRBKNb+zdSBQ=
  - yKcdhW9/QrtCsfQuotsDBUNL+2ySoiV5WFr1vRO61iHqCrd6MLwqx0zkE4bCtYJQ8CqjCkGFklzKnPdolyYqsz+Iv9I7oAeb5CYI3gQaW98=

The container created above was created with --access bob but the container was called alice-and-bob. That is because Alice is the default-owner of every container (unless overridden by the --owner flag) and every encrypted container will always be encrypted with the container owner's public key. Using the --access bob flag merely allowed Bob additional access to the container instead of granting him exclusive access to read the contents.

The reason for such mechanics is that Alice is signing the contents of the container using her private key; hence she'd definitely like to know what she is signing, which she wouldn't know, if she wasn't able to decrypt the contents.

Note that the encrypted-keys field has two entries which implies that there are two users, who are able to decrypt the encrypted-data block. Is it not possible though to know to whom those encrypted keys belong.

# Sharing a container

After creating the alice-and-bob container, Alice would now like to share this container with Bob. She would not just send the file to bob via email for two reasons:

  • The container is still owned by Alice so bob wouldn't be able to make any changes to it,
  • Every time alice makes some changes to that container, she would have to send it to Bob again. This would be even more difficult if the container was shared by more than just Alice and Bob.

Instead, Alice** wants to use her Forest's catalog to publish her container. A catalog is a special usecase for a Wildland container, and its purpose is to store the containers of a particular user (ie. Alice's). A catalog is automatically created and appended to a user's manifest during Forest Creation so make sure you have already set up a Forest before moving to the next section. Suggested storage would be a remote one (i.e. not local) so that Bob can access it from his own PC (unless Alice and Bob share a local filesystem's catalog, e.g. via sshfs).

When creating Alice's forest, make sure to also include the --access bob flag, otherwise Bob will not have access to it. You can do it like this:

alice@wildland-client:~$ wl forest create --access bob ...

See the "Infrastructure-level control" section below for more details.

# Container publishing

Alice can now publish her container to the catalog's storage:

alice@wildland-client:~$ wl container publish alice-and-bob
publishing container /.uuid/b1cffd57-f0c2-4b04-911d-5e709dd53a30...

If you got the following error:

Error: Cannot find any container suitable as publishing platform:

it means that your user does not have writable storage in their manifests-catalog. Make sure you created the Forest by following Forest Creation.

# Accessing shared container

Once Alice has shared her user manifest with Bob, he can now import her user file and access the containers shared by her. Make sure that Bob has sufficient access to read the catalog container as well as the user manifests-catalog within Alice's user manifest.

bob@wildland-client:~$ wl user import --path /forests/alice ~/Downloads/alice.user.yaml
Created: /home/user/.config/wildland/users/alice.user.yaml
Created: /home/user/.config/wildland/bridges/alice.bridge.yaml

Bob can now mount the container shared by Alice:

bob@wildland-client:~$ wl container mount :/forests/alice:/very/secret:
Loading containers. Loaded 1...

Mounting 1 container

# Infrastructure-level control

One of the very important things to consider before exposing your Forest into the world, is to make sure that the containers (ie. your Forest) you're exposing publicly do not reveal secret credentials to unauthorized people.

In the publishing example above Alice must have had her Forest already created. Let's assume she used WebDAV as a storage template to provision her Forest. If that was the only storage she used to create her Forest, there's a great chance that if she wants to share that Forest with the world, she'll be granting read-write (RW) access to that Forest due to the fact that most WebDAV implementations are either full-read-only (full-RO) or full-RW. If that was Alice's intention to share RW access with Bob, then she wouldn't have to change anything apart from making sure that all of the container's storages are encrypted using her key (by default) as well as Bob's key.

Another scenario would be that Alice wants to share her Forest with a public audience for RO but she wants to keep the RW access to herself (obviously). In such a scenario, she would have to create her Forest using a storage template with at least two storages -- one being RO storage with --access set to *, and one being RW storage with access set to Alice.

In order to do that, let's pick a storage backend that natively supports RO/RW access control, for example S3, and create a template pointing to the same bucket, but with different credentials and access control. You can follow the S3 storage guide to learn how to create such a bucket.

To distinguish the new use case, in this section we'll use Caroline/Daniel instead of Alice/Bob.

caroline@wildland-client:~$ wl user create caroline

Generated key: 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298
No path specified, using: /users/caroline
Created: /home/user/.config/wildland/users/caroline.user.yaml
Using 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298 as @default
Using 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298 as @default-owner
Adding 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298 to local owners
caroline@wildland-client:~$ wl template create s3 carolines-s3 \
    --s3-url s3://carolines-bucket \
    --access-key <RW_KEY> \
    --secret-key <RW_SECRET> \
    --access caroline

Storage template [carolines-s3] created in /home/user/.config/wildland/templates/carolines-s3.template.jinja

caroline@wildland-client:~$ wl template add s3 carolines-s3 \
    --s3-url s3://carolines-bucket \
    --access-key <RO_KEY> \
    --secret-key <RO_SECRET> \
    --access '*' \
    --read-only

Appended to an existing storage template [carolines-s3]

Now create a Forest using the newly created template:

caroline@wildland-client:~$ wl forest create --access '*' carolines-s3
Created base path: /.manifests/3779a663-1099-4a11-9ae3-55e27eecf15d
Adding storage a3e57467-90f7-4916-92f0-d5b6479b783c to container.
Saved container /home/user/.config/wildland/containers/caroline-forest-catalog.container.yaml
Adding storage fb335029-125a-4a5f-bcad-7a75127c2e57 to container.
Saved container /home/user/.config/wildland/containers/caroline-forest-catalog.container.yaml
Saved: /home/user/.config/wildland/users/caroline.user.yaml
Saved: /home/user/.config/wildland/users/caroline.user.yaml

The next step would be creating an unencrypted (as it's supposed to be publicly readable) container, using the same storage template Caroline used for her Forest. She definitely could use a different bucket to store her Forest's manifests and actual data, but for this demo we will use the same bucket.

caroline@wildland-client:~$ wl container create hello-world \
    --no-encrypt-manifest \
    --path /hello/world \
    --template carolines-s3

Created: /home/user/.config/wildland/containers/hello-world.container.yaml
Created base path: /ba4e53a2-d049-4bf9-92b4-c15f340fd28f
Adding storage df71a0fb-6c3f-4658-8234-e7a5eceace14 to container.
Saved container /home/user/.config/wildland/containers/hello-world.container.yaml
Adding storage 9c224edb-36dc-4082-a8a3-7bfa6b8ceafb to container.
Saved container /home/user/.config/wildland/containers/hello-world.container.yaml
publishing container /.uuid/ba4e53a2-d049-4bf9-92b4-c15f340fd28f...

Caroline now mounts her newly created container to feed it with some data:

caroline@wildland-client:~$ wl c mount :/hello/world:
Loading containers. Loaded 1...

Mounting 1 container

caroline@wildland-client:~$ echo 'It works!' > ~/wildland/hello/world/Hello-World.md

It's time to share the Forest with others. To do that, we need to somehow distribute Caroline's manifest publicly, similar to how Golem Foundation's Ariadne Forest is shared. Before we do that, let's take a look at Caroline's user manifest file.

caroline@wildland-client:~$ cat ~/.config/wildland/users/caroline.user.yaml

signature: |
  0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298:IANX1QStKc1F3CZe8mGDELF//bo1QzYMXX2cIQ6W/NQjaoNz+GP5aWeHK+Sf2WYTUZq0IK2F2oaanE2yBXPiDQ==
---
object: user
owner: '0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298'
paths:
- /users/caroline
manifests-catalog:
- object: link
  file: /.manifests.yaml
  storage:
    encrypted:
      encrypted-data: Otm4eFpF8Jo4OY5OJ0GmbGS6UYQjmiXfxd4EEnRSMHsAViqNCrnTF07k/1WdoXHpVitTr4ryucQZEhPsfyrmCB3oxOQJgbe9NUw24I5Lg4G+YlyasYwAWiZYjgL6/1iUj512U+6EPFkF9cf597nTWj+xS1DnrIbYVYlJ3/FJy4n5uYD1uWjeTgM8bGGL8i/orWpbiFbH3nACFgmf8pAbTvY/4QUioDoZveu8gRXIUIQvy5ftB4NYdQMJ1/e23GQamBTAyIIOsPokAJF9gEtvlE0/WygnFHb7Rsty+XF/cjq8D7FKN6NnoTuz7N66IN4beh+59L6xt48W0GUrX7BbBcGXIVrDL6D3d0FHl1K3q01UZAu6PKgwUd0GOXyOX13tW5y3ZMZ4gDrmj2KBMAxQH4PPOl4A37CPMDKquaZGvmsAxQvXkRG5vhQFWbhLqKtchaWusOaS9yI8trdUFt3B+A29xvQbHzBkdlIRwGwlg8vTyzQ5ZSD9FhAm8ucg9MHQNT9Ztnuqa4XELotEMpPV5ZDFbw+ELTiNLgjoUusSbAhCiXwyAHoaz/CeXmFN5qx5UbD78ii59i/79yoTwxYHJG3bwNNcFibGJgPtNRLawXsljbk1fFHm+GFN
      encrypted-keys:
      - OX6vj4O787WjVQL9L2YJC6ulPwi3ZvH+kCWu6jmA+X72sLTtNVrCm07rG+mumSLc667jNDky7HNmJHnuIxredpkpX67xFBf97GrABSttItQ=
- object: link
  file: /.manifests.yaml
  storage:
    access:
    - user: '*'
    credentials:
      access-key: <REDACTED>
      secret-key: <REDACTED>
    read-only: true
    s3_url: s3://carolines-bucket/.manifests/3779a663-1099-4a11-9ae3-55e27eecf15d
    type: s3
    with-index: false
    backend-id: fb335029-125a-4a5f-bcad-7a75127c2e57
    manifest-pattern:
      type: glob
      path: /*.yaml
pubkeys:
- RWQXe4H8E4l3zz9il7pfbCMbR8uK/f//2qixKbMpsn005zRGoHkhRbC/0vOr94MM5DtErsRj8oLeVg2UCqLOhBo4
version: '1'

As you can see, the top storage is encrypted, and that's Caroline's RW storage. The RO storage is unencrypted, and for that reason it's going to be accessible by anyone who gets hold of the user's manifest.

Now let's move to Daniel's machine, who's already downloaded Caroline's user manifest.

daniel@wildland-client:~$ wl user import ~/Downloads/caroline.user.yaml \
    --path /f/caroline

Created: /home/user/.config/wildland/users/caroline.user.yaml
WARNING:user:User 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298: cannot load manifests catalog entry: Cannot decrypt manifest: decryption key unavailable
Created: /home/user/.config/wildland/bridges/caroline.bridge.yaml

Note: The WARNING presented in the output above indicates that there was a RW storage which Daniel couldn't decrypt. This warning, unfortunately, is a work in progress and will be present in many commands that operate on Caroline's Forest. These warnings do not interrupt the flow of accessing the Forest.

Time to mount the Forest and see if Daniel has RO access:

daniel@wildland-client:~$ wl forest mount :/f/caroline:

User 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298 already exists. Forcing user import.
Created: /home/user/.config/wildland/users/caroline.user.yaml
WARNING:user:User 0xeb0c9dc091eee7797e27f6ee50a6ab24c6bb38bf2ce9dff0e831825fe43d1298: cannot load manifests catalog entry: Cannot decrypt manifest: decryption key unavailable
Loading containers. Loaded 2...

Mounting 2 containers

daniel@wildland-client:~$ cd ~/wildland/f/caroline\:/hello/world/

daniel@wildland-client:~/wildland/f/caroline:/hello/world$ cat Hello-World.md
It works!

daniel@wildland-client:~/wildland/f/caroline:/hello/world$ echo 'Can I write here?' > daniels.md
bash: daniels.md: Permission denied

Caroline has securely shared her Forest with the world!