diff --git a/README.md b/README.md index 7ea77f1..44c1303 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ It allows securely storing and retrieving arbitrary data locally, and serving it - Data is encrypted at rest and in transit using modern cryptography (NaCl, TLS 1.3). - Flexible authorization using role-based access control. - Namespacing support for separating environments (development, staging, production, etc.). -- Granular subscribe/notify support of data changes ([coming soon!](https://github.com/hackfixme/disco/issues/3)). - Cross-platform: runs on Linux, macOS and Windows. You can see planned work on the [roadmap](https://github.com/orgs/hackfixme/projects/1/views/1). Please vote on issues by giving them a :thumbsup:. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..ea0d24a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,22 @@ +# Disco documentation + +Welcome to the Disco documentation! + +> [!NOTE] +> The project is in early development, and the documentation is a work in progress. +> Some information could be missing or different from the version of Disco +> you're using. + + +## Index + +- [Getting started guide](./get_started.md): a short guide to using Disco. + New users should start here. + +- [System](./system.md): system architecture and behavior. + +- [Roles](./roles.md): role-based access control features. + +- [CLI](./cli.md): command-line usage reference. + +- [Troubleshooting](./troubleshooting.md): solution suggestions to common problems. diff --git a/docs/cli.md b/docs/cli.md deleted file mode 100644 index 3386022..0000000 --- a/docs/cli.md +++ /dev/null @@ -1,122 +0,0 @@ -# Disco - Command-line interface - -## Quick start - -### Setting and getting values -```sh -# Use a forward slash as key separator to create hierarchies. -$ disco set myapp/mykey myvalue - -$ disco get myapp/mykey -myvalue -``` - -List all keys: -```sh -$ disco ls -myapp/mykey -``` - - -### Namespaces - -Namespaces are created automatically when used. They are supported by the `get`, -`set` and `ls` commands. - -Unless specified, the `default` namespace is used. To change this, set the value of the `DISCO_NAMESPACE` environment variable, or set the `--namespace` option. - -- Set a value in a specific namespace: - ```sh - $ disco set --namespace myns myapp/mykey myvalue - ``` - -- List all keys in all namespaces: - ```sh - $ disco ls --namespace='*' - default:myapp/mykey - myns:myapp/mykey - ``` - - The namespace of the key is shown as a prefix. - - -### Roles -- List all roles: - ```sh - $ disco role ls - NAME NAMESPACES ACTIONS TARGET - admin * * * - node * read store:* - user * * store:* - ``` - -- Create a new role that can only read store keys and values in the `myapp` hierarchy in all namespaces: - ```sh - $ disco role add myrole 'r:*:store:myapp/*' - ``` - -- Update the role so that it can read, write and delete all store keys and values in the `dev` and `staging` namespaces, and write store keys and values in the `myapp` hierarchy in the `prod` namespace: - ```sh - $ disco role update myrole 'rwd:dev,staging:store:*' 'w:prod:store:myapp/*' - ``` - - -### Users - -- Add a new user with the `myrole` role: - ```sh - $ disco user add myuser --roles myrole - ``` - -- List all users: - ```sh - $ disco user ls - NAME ROLES - myuser myrole - ``` - -- Create an invite key for a specific user: - ```sh - $ disco user invite myuser - Invite key: KxI7jh7rkHw7MMNqLF7cJmzjLS9o0EI/MAYF... - Expires: 2024-03-01 16:32:20 UTC - ``` - - -### Server - -- Start the HTTP server so that the client can connect: - ```sh - $ disco serve --address 10.0.0.10:8080 - ``` - - -### Remotes - -- On the client machine, add a new remote node using the invite key: - ```sh - $ disco remote add myserver 10.0.0.10:8080 KxI7jh7rkHw7MMNqLF7cJmzjLS9o0EI/MAYF... - ``` - -- Then use the `--remote` option on `get` or `set` commands: - ```sh - $ disco get --remote myserver --namespace myns myapp/mykey - myvalue - ``` - - -## Commands - -### `get` - -### `set` - -### `ls` - -### `remote` - -### `role` - -### `serve` - -### `user` diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 0000000..0c78868 --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,15 @@ +# Command reference + +### `get` + +### `set` + +### `ls` + +### `remote` + +### `role` + +### `serve` + +### `user` diff --git a/docs/get_started.md b/docs/get_started.md new file mode 100644 index 0000000..073d919 --- /dev/null +++ b/docs/get_started.md @@ -0,0 +1,229 @@ +# Getting Started Guide + +After you've [installed Disco](/README.md#installation), confirm the version you installed by running: + +```sh +disco --version +``` + +It should output something like: +``` +Disco v0.1.0 (commit/c2d4d8807b, go1.22.0, linux/amd64) +``` + +If you get an error like `command not found`, see the [Troubleshooting page](./troubleshooting.md). + + +## First-time initialization + +Before running any other commands, the Disco data stores and local encryption keys need to be created. This is done once by running: + +```sh +disco init +``` + +This will create the data stores in your system's default data store directory: `~/.local/share/disco` on Linux, `~/Library/Application Support/disco` on macOS, and `C:\Users\\AppData\Local\disco` on Windows. You can change this by setting the `--data-dir` option, or `DISCO_DATA_DIR` environment variable. + +It should output something like: +``` +New encryption key: 6uVB3iXnfdE3aR52vGQGtBHAfKTXx48PwhGwyQdRr4Ey + +Make sure to store this key in a secure location, such as a password manager. + +It will only be shown once, and you won't be able to access the data on this node without it! +``` + +You should follow that suggestion, and store the encryption key in a secure location. + + +## Setting the encryption key + +Most Disco commands require the encryption key to read and write data. You can pass it via the `--encryption-key` option, or by setting the `DISCO_ENCRYPTION_KEY` environment variable. For example: + +```sh + export DISCO_ENCRYPTION_KEY=6uVB3iXnfdE3aR52vGQGtBHAfKTXx48PwhGwyQdRr4Ey +``` + +> [!WARNING] +> Be aware that on Linux the CLI arguments and process environment can be read by any +> other process run by the same user via the `/proc` filesystem, which means another +> process could read the Disco encryption key. If this is a concern for your use +> case, consider running Disco from a container instead (an official OCI image will +> be provided soon), or another isolation mechanism. +> +> Also, be careful with your shell history. Depending on your shell configuration, +> the Disco encryption key could be stored in your shell history. If using the +> `--encryption-key` option, prefer reading directly from your password manager. +> For example, using 1Password: `--encryption-key="$(op item get Disco)"`. +> If setting the `DISCO_ENCRYPTION_KEY` environment variable, ensure that your +> shell is configured to not store commands in history that begin with a space +> character. In Bash, you can set `HISTCONTROL=ignorespace` (or `ignoreboth`) +> in your `~/.bashrc`, and on Zsh add `setopt histignorespace` to your `~/.zshrc`. +> This way running ` export DISCO_ENCRYPTION_KEY=...` (note the leading space) won't +> be saved in your `~/.bash_history` or `~/.zsh_history` file. + + +## Setting and getting values + +To store a value in the data store, use the `set` command. For example: + +```sh +disco set myapp/mykey myvalue +``` + +Use a forward slash as key separator to group keys and create logical hierarchies. + +Then to retrieve the value, use the `get` command: + +``` +$ disco get myapp/mykey +myvalue +``` + + +## Listing keys + +To list stored keys use the `ls` command: + +```sh +$ disco ls +myapp/mykey +``` + + +## Deleting keys + +To delete keys use the `rm` command: + +```sh +disco rm myapp/mykey +``` + + +## Namespaces + +Namespaces allow separating keys according to their purpose, or any other criteria. For example, it's common to separate keys that belong to different environments like development, staging and production. This way access to each environment can be controlled separately. + +There are no naming or usage restrictions for namespaces, so feel free to use them however makes most sense for your use case. + +Namespaces are created automatically when used, so it's not necessary to manage them manually. + +They are supported by the `get`, `set` and `ls` commands with the `--namespace` option, or by setting the `DISCO_NAMESPACE` environment variable. Unless specified, the `default` namespace is used. + +Here are some common operations involving namespaces: + +- Setting a value in a specific namespace: + ```sh + disco set --namespace myns myapp/mynskey mynsvalue + ``` + +- Getting a value from a specific namespace: + ```sh + $ disco get --namespace myns myapp/mynskey + mynsvalue + ``` + +- Listing keys in a specific namespace: + ```sh + $ disco ls --namespace myns + myapp/mynskey + ``` + +- Listing keys in all namespaces: + ```sh + $ disco ls --namespace='*' + NAMESPACE KEY + default myapp/mykey + myns myapp/mynskey + ``` + + Note that the asterisk needs to be quoted or escaped so that it's not interpreted by the shell. + + +## Roles + +Roles allow controling access to Disco resources. They consist of a set of permissions that define the actions [users](#users) are allowed to perform on specific targets. + +See more detailed information on the [Roles page](./roles.md). + +- List all roles: + ```sh + $ disco role ls + NAME NAMESPACES ACTIONS TARGET + admin * * * + node * read store:* + user * * store:* + ``` + + These are the default roles created with `disco init`. + +- Create a new role that can only read store keys and values in the `myapp` hierarchy in all namespaces: + ```sh + $ disco role add myrole 'r:*:store:myapp/*' + ``` + +- Update the role so that it can read, write and delete all store keys and values in the `dev` and `staging` namespaces, and write store keys and values in the `myapp` hierarchy in the `prod` namespace: + ```sh + $ disco role update myrole 'rwd:dev,staging:store:*' 'w:prod:store:myapp/*' + ``` + + +## Users + +Users can be added to allow remote access to Disco resources. They should have one or more associated roles that control which resources they can access. + +- Add a new user with the `myrole` role: + ```sh + $ disco user add myuser --roles myrole + ``` + +- List all users: + ```sh + $ disco user ls + NAME ROLES + myuser myrole + ``` + +- Update the roles of a user: + ```sh + $ disco user update myuser --roles=node,user + ``` + +- Remove a user: + ```sh + $ disco user rm myuser + ``` + + +## Invites and remotes + +Invites are created for users, and allow remote Disco nodes to connect to the node that created the invite. + +- Create an invite token for a specific user: + ```sh + $ disco invite user myuser + Token: 5RMduyPEncYL6EH9c3gzpzDbYq3vjE... + Expires: 2024-04-18 23:54:10 (1h0m0s) + ``` + + Note that an invite token is sensitive information, and should be transmitted securely to the invited node. + +- On the client node, add a `remote` object using the generated token, and specifying the [server](#server) address of the node that issued the invite: + ```sh + $ disco remote add myserver 10.0.0.10:2020 5RMduyPEncYL6EH9c3gzpzDbYq3vjE... + ``` + +- Then the client node can use the `--remote` option on `get`, `set` and `ls` commands: + ```sh + $ disco get --remote myserver --namespace myns myapp/mykey + myvalue + ``` + + +## Server + +Before a client node can redeem their invite token, or access Disco resources remotely, the web server needs to be started: + +```sh +$ disco serve --address 10.0.0.10:2020 +``` diff --git a/docs/roles.md b/docs/roles.md index 534e461..eb7996e 100644 --- a/docs/roles.md +++ b/docs/roles.md @@ -20,7 +20,7 @@ They consist of two concepts: actions and targets. **Actions** dictate _how_ resources can be accessed. There are 3 possible actions: - `read` (`r`): allows reading resource data. - `write` (`w`): allows writing resource data, including creating new data. -- `delete` (`d**): allows deleting resource data. +- `delete` (`d`): allows deleting resource data. **Targets** dictate _which_ objects that are part of the resource can be accessed. They can be granular and specific to a single key or object within the resource, or global for all objects, or even all resources. Targets are specified as `:`. @@ -41,13 +41,31 @@ Roles are a collection of permissions, assigned to one or more users. | user | * | * | store:* | These roles are created by default when running `disco init`. + The `admin` role allows any action, on any target, in any namespace. This role is assigned to the local CLI user, but be careful with assigning it to any remote users, as it effectively gives unrestricted access to all data on the node. + The `node` role allows reading any store data in any namespace. This is a generic role that can be used for remote nodes that only need read permissions. It would be more secure to add more restrictive roles with a granular target for specific keys or key hierarchies instead. + The `user` role allows any action on any store data in any namespace. This is a generic role for users that can manage store data, but as with the `node` role, it would be more secure to create a more granular role. ## Custom roles +The `role add` command allows adding roles with custom permissions. + +The syntax for defining role permissions is: +``` +::: +``` +Where: +- `actions` is a combination of `r` (read), `w` (write/create), and `d` (delete). +- `namespaces` is one or more comma-separated list of namespaces, or `*` to apply for all namespaces. +- `resource` is one of `store`, `user`, `role` or `invite`. +- `target` is a comma-separated list of objects unique for each resource. + + +### Examples + - ```sh disco role add myrole 'rwd:dev,prod:store:app1/*,app2/value' ``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..9e4e94e --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,8 @@ +# Troubleshooting + +### `command not found` when running `disco` + +If you installed Disco by extracting the binary from a pre-built package, make sure that you placed the binary in a directory on your `$PATH`. On Linux/macOS you can confirm this with `which disco`. + +If you installed Disco via `go install`, make sure that you precisely follow the [Go installation instructions](https://go.dev/doc/install) for your platform. +Specifically, ensure that the `$GOPATH/bin` directory is part of your `$PATH`. For example, you might want to add this to your shell's initialization file: `export PATH=$(go env GOPATH)/bin:$PATH`. See [this article](https://go.dev/wiki/SettingGOPATH) for more information.