diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bc24ad7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,115 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + if [ -f Gopkg.toml ]; then + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + dep ensure + fi + + - name: Set env + run: | + echo '::set-env name=GO111MODULE::on' + # Release tag comes from the github reference. + RELEASE_TAG=$(echo ${GITHUB_REF} | sed -e 's!.*/!!') + echo "::set-env name=RELEASE_TAG::${RELEASE_TAG}" + echo "::set-output name=RELEASE_TAG::${RELEASE_TAG}" + # Ensure the release tag has expected format. + echo ${RELEASE_TAG} | grep -q '^v' || exit 1 + # Release version is same as release tag without leading 'v'. + RELEASE_VERSION=$(echo ${GITHUB_REF} | sed -e 's!.*/v!!') + echo "::set-env name=RELEASE_VERSION::${RELEASE_VERSION}" + echo "::set-output name=RELEASE_VERSION::${RELEASE_VERSION}" + + - name: Build + run: go build -v -ldflags="-X github.com/attestantio/dirk/cmd.ReleaseVersion=${RELEASE_VERSION}" . + + - name: Test + run: go test -v . + + - name: Fetch xgo + run: | + go get github.com/suburbandad/xgo + + - name: Cross-compile + run: xgo -v -x -ldflags="-X github.com/attestantio/dirk/cmd.ReleaseVersion=${RELEASE_VERSION}" --targets="linux/amd64,linux/arm64,windows/amd64" github.com/attestantio/dirk + + - name: Create windows zip file + run: | + mv dirk-windows-4.0-amd64.exe dirk.exe + zip --junk-paths dirk-${RELEASE_VERSION}-windows-exe.zip dirk.exe + + - name: Create linux AMD64 tgz file + run: | + mv dirk-linux-amd64 dirk + tar zcf dirk-${RELEASE_VERSION}-linux-amd64.tar.gz dirk + + - name: Create linux ARM64 tgz file + run: | + mv dirk-linux-arm64 dirk + tar zcf dirk-${RELEASE_VERSION}-linux-arm64.tar.gz dirk + + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ env.RELEASE_VERSION }} + draft: false + prerelease: false + + - name: Upload windows zip file + id: upload-release-asset-windows + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./dirk-${{ env.RELEASE_VERSION }}-windows-exe.zip + asset_name: dirk-${{ env.RELEASE_VERSION }}-windows-exe.zip + asset_content_type: application/zip + + - name: Upload linux AMD64 tgz file + id: upload-release-asset-linux-amd64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./dirk-${{ env.RELEASE_VERSION }}-linux-amd64.tar.gz + asset_name: dirk-${{ env.RELEASE_VERSION }}-linux-amd64.tar.gz + asset_content_type: application/gzip + + - name: Upload linux ARM64 tgz file + id: upload-release-asset-linux-arm64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./dirk-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz + asset_name: dirk-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz + asset_content_type: application/gzip diff --git a/README.md b/README.md index b7b5983..8ea583f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# dirk +# Dirk [![Tag](https://img.shields.io/github/tag/attestantio/dirk.svg)](https://github.com/attestantio/dirk/releases/) [![License](https://img.shields.io/github/license/attestantio/dirk.svg)](LICENSE) @@ -26,201 +26,15 @@ go get github.com/attestantio/dirk ``` ## Usage - `dirk` provides an interface to wallet operations such as listing accounts and signing requests. The daemon provides a number of security measures to avoid unauthorised uses of the private keys, and protection against invalid actions (_e.g._ slashing events). -## Architecture - -### Configuration directory and files - -By default `dirk` looks for its configuration in the file `.dirk.json` in the user's home directory. A different base directory for `dirk` can be given with the `--base-dir` flag, in which case it will look for a file `dirk.json` in that directory. - -### Example - -The architecture we want to achieve is shown below: - -![Validator architecture](images/architecture.png) - -In this architecture we have three validators clients. Validator clients 1 and 2 are in a cluster, and between them manage accounts 1, 2, and 3. Validator client 3 is standalone, and manages account 4. - -#### Creating wallets and accounts -The first step is to create some wallets and validator keys for said wallets, using [ethdo](https://github.com/wealdtech/ethdo): - -``` -$ ethdo wallet create --wallet=wallet1 -$ ethdo account create --account=wallet1/account1 --passphrase=secret -$ ethdo account create --account=wallet1/account2 --passphrase=secret -$ ethdo account create --account=wallet1/account3 --passphrase=secret -$ ethdo wallet create --wallet=wallet2 -$ ethdo account create --account=wallet2/account4 --passphrase=secret -``` - -Here we have two wallets, one for each set of validator clients. It is possible for different wallets to have different features, such as level of security and location, but for the purposes of this example they are both standard (non-deterministic) wallets (see ethdo documentation for other options). - -#### Creating certificates -We need a certificate for the wallet daemon. We could use a certificate from a well-known certificate authority such as LetsEncrypt, or we could create our own; we will create our own using [certstrap](https://github.com/square/certstrap). - -First, we create the certificate authority. Note the key created in this process is critical to the security of your deposits and should be protected with all reasonable measures; this should include a passphrase when promted. -``` -$ certstrap --depot-path . init --common-name "dirk authority" --expires "3 years" -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Created ./dirk_authority.key (encrypted by passphrase) -Created ./dirk_authority.crt -Created ./dirk_authority.crl -``` - -The server needs its own certificate. We use the sample name `server.example.com` here but you should replace this with the name of your server. If you are testing `dirk` locally you can use `localhost` instead of the server name. -``` -$ certstrap --depot-path . request-cert --common-name server.example.com -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Created ./server.example.com.key -Created ./server.example.com.csr -$ certstrap --depot-path . sign --CA "dirk authority" --expires="3 years" server.example.com -Enter passphrase for CA key (empty for no passphrase): -Created ./server.example.com.crt from ./server.example.com.csr signed by ./dirk_authority.key -``` - -Next, we create and sign certificates for the three clients that will be connecting to the daemon. Note the keys created here should not have a passphrase supplied; they will reside with the valdiator clients so use of the key is should be possible without requiring human intervention (to allow for server restarts _etc._). For the first client: - -``` -$ certstrap --depot-path . request-cert --common-name client1 -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Created ./client1.key -Created ./client1.csr -$ certstrap --depot-path . sign --CA "dirk authority" --expires="3 years" client1 -Enter passphrase for CA key (empty for no passphrase): -Created ./client1.crt from ./client1.csr signed by ./dirk_authority.key -``` - -and the same commands can be used for the other clients, using "client2" and "client3" in place of "client1". At this point you should have the following files: - - - `client1.crt`: the signed certificate for client1; needs to be moved to the server running client1 - - `client1.csr`: the signing request for client1; can be deleted - - `client1.key`: the key for client1; needs to be moved to the server running client1 - - `client2.crt`: the signed certificate for client2; needs to be moved to the server running client3 - - `client2.csr`: the signing request for client2; can be deleted - - `client2.key`: the key for client2; needs to be moved to the server running client3 - - `client3.crt`: the signed certificate for client3; needs to be moved to the server running client3 - - `client3.csr`: the signing request for client3; can be deleted - - `client3.key`: the key for client3; needs to be moved to the server running client3 - - `server.example.com.crt`: the certificate for `dirk`; needs to be moved to the server running `dirk` - - `server.example.com.csr`: the signing request for `dirk`; can be deleted - - `server.example.com.key`: the key for `dirk`; needs to be moved to the server running `dirk` - - `dirk_authority.crl`: the certificate revocation list for dirk; needs to be copied to the server running `dirk` - - `dirk_authority.crt`: the certificate for dirk; needs to be copied to all clients - - `dirk_authority.key`: the key for dirk; needs to be copied to the server running `dirk` - -To provide the certificates for `dirk` make a directory `dirk/security` in your home directory and copy the `server.example.com.crt` and `server.example.com.key` files in to it. Also copy `dirk_authority.crt` to the same directory with the name `ca.crt`. The contents of the `security` directory in your configuration directory should be: - - - `ca.crt`: copy of `dirk_authority.crt` from the previous step - - `server.example.com.crt`: copy of `server.example.com.crt` from the previous step - - `server.example.com.key`: copy of `server.example.com.key` from the previous step - -At this point you also need a minimal configuration file so `dirk` knows which certificates to use. Create a file `dirk.json` in your home directory with the following contents: - -```json -{ - "server": { - "id": 212483780, - "name": "server.example.com", - "listen-address": "localhost:9091", - "cert-path": "security" - } -} -``` - -(The `id` and `listen-address` fields here will be explained later). - -You can confirm the configuration of the certificates by running the command `dirk --show-certificates` which should return suitable information about the generated certificates: - -```sh -$ dirk --show-certificates -Server certificate issued by: Dirk authority -Server certificate expires: 2023-03-24 13:47:19 +0000 UTC -Server certificate issued to: server.example.com - -Certificate authority certificate is: Dirk authority -Certificate authority certificate expires: 2023-03-24 13:47:20 +0000 UTC -``` - -#### Adding permissions -The next step is to configure `dirk` to know which clients have access to which accounts, and which operations on those accounts. To do so, replace the `dirk.json` file above with the following: - -``` -{ - "server": { - "id": 212483780, - "name": "server.example.com", - "listen-address": "localhost:9091", - "cert-path": "security" - }, - "permissions": { - "client1": { - "wallet1": "All" - }, - "client2": { - "wallet1": "All" - }, - "client3": { - "wallet2": "All" - } - } -} -``` - -Once this is in place it can be confirmed by running `dirk --show-permissions`: - -``` -$ dirk --show-permissions -Permissions for "client1": - - accounts matching the path "wallet1" can carry out all operations -Permissions for "client2": - - accounts matching the path "wallet1" can carry out all operations -Permissions for "client3": - - accounts matching the path "wallet2" can carry out all operations -``` - -Permissions can be used to restrict the access of clients to wallets, accounts, and operations. More details can be found in ther permissions documentation. - -#### Starting `dirk` - -To start `dirk` type: - -```sh -$ dirk -{"level":"info","version":"v0.1.0","time":"2020-07-27T23:20:51+01:00","message":"Starting dirk"} -{"level":"warn","time":"2020-07-27T23:20:51+01:00","message":"No stores configured; using default"} -{"level":"info","service":"api","impl":"grpc","address":"localhost:9091","time":"2020-07-27T23:20:51+01:00","message":"Listening"} -{"level":"info","time":"2020-07-27T23:20:51+01:00","message":"All services operational"} -``` - -At this point `dirk` is operational on port 9091 and can accept requests for key generation, signing _etc._ - -#### Testing client permissions -`ethdo` interacts with the dirk using additional options: - - `--remote` the address of the Dirk instance - - `--client-cert` and `--client-key` the path to the certificate and keyfile for the client - - `--ca-cert` the path to the certificate for the server authority - -For example, to list accounts accessible in `wallet1` with the `client1` certificate: - -```sh -$ ethdo --remote=server.example.com:9091 --client-cert=client1.crt --client-key=client1.key --server-ca-cert=dirk_authority.crt wallet accounts --wallet=wallet1 -account1 -account3 -account2 -``` - -As would be expected from the configured permissions, `client3` cannot access the accounts in `wallet1`: - -```sh -$ ethdo --remote=server.example.com:9091 --client-cert=client3.crt --client-key=client3.key --server-ca-cert=Wallet_daemon_authority.crt wallet accounts --wallet=wallet1 -``` +## Documentation +The following documentation is available: -At this point it has been confirmed that the client permissions operate as expected, and that dirk is appropriately configured. The client certificates can now be used by validators to remotely access their keys. + - [Getting started](docs/getting_started.md) an introduction to configuring Dirk + - [Prometheus metrics](docs/metrics/prometheus.md) Prometheus metrics + - [Configuration](docs/configuration.md) Sample annotated configuration file + - [Permissions](docs/permissions.md) Details information about Dirk's permissions ## Maintainers diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 0000000..281698b --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,190 @@ +# Getting started + +This document provides steps to set up a Dirk instance able to sign and protect multiple accounts. + +### Example + +The architecture we want to achieve is shown below: + +![Validator architecture](images/architecture.png) + +In this architecture we have three validators clients. Validator clients 1 and 2 are in a cluster, and between them manage accounts 1, 2, and 3. Validator client 3 is standalone, and manages account 4. + +#### Creating wallets and accounts +The first step is to create some wallets and validator keys for said wallets, using [ethdo](https://github.com/wealdtech/ethdo): + +``` +$ ethdo wallet create --wallet=wallet1 +$ ethdo account create --account=wallet1/account1 --passphrase=secret +$ ethdo account create --account=wallet1/account2 --passphrase=secret +$ ethdo account create --account=wallet1/account3 --passphrase=secret +$ ethdo wallet create --wallet=wallet2 +$ ethdo account create --account=wallet2/account4 --passphrase=secret +``` + +Here we have two wallets, one for each set of validator clients. It is possible for different wallets to have different features, such as level of security and location, but for the purposes of this example they are both standard (non-deterministic) wallets (see ethdo documentation for other options). + +#### Creating certificates +We need a certificate for the wallet daemon. We could use a certificate from a well-known certificate authority such as LetsEncrypt, or we could create our own; we will create our own using [certstrap](https://github.com/square/certstrap). + +First, we create the certificate authority. Note the key created in this process is critical to the security of your deposits and should be protected with all reasonable measures; this should include a passphrase when promted. +``` +$ certstrap --depot-path . init --common-name "dirk authority" --expires "3 years" +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Created ./dirk_authority.key (encrypted by passphrase) +Created ./dirk_authority.crt +Created ./dirk_authority.crl +``` + +The server needs its own certificate. We use the sample name `server.example.com` here but you should replace this with the name of your server. If you are testing `dirk` locally you can use `localhost` instead of the server name. +``` +$ certstrap --depot-path . request-cert --common-name server.example.com +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Created ./server.example.com.key +Created ./server.example.com.csr +$ certstrap --depot-path . sign --CA "dirk authority" --expires="3 years" server.example.com +Enter passphrase for CA key (empty for no passphrase): +Created ./server.example.com.crt from ./server.example.com.csr signed by ./dirk_authority.key +``` + +Next, we create and sign certificates for the three clients that will be connecting to the daemon. Note the keys created here should not have a passphrase supplied; they will reside with the valdiator clients so use of the key is should be possible without requiring human intervention (to allow for server restarts _etc._). For the first client: + +``` +$ certstrap --depot-path . request-cert --common-name client1 +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Created ./client1.key +Created ./client1.csr +$ certstrap --depot-path . sign --CA "dirk authority" --expires="3 years" client1 +Enter passphrase for CA key (empty for no passphrase): +Created ./client1.crt from ./client1.csr signed by ./dirk_authority.key +``` + +and the same commands can be used for the other clients, using "client2" and "client3" in place of "client1". At this point you should have the following files: + + - `client1.crt`: the signed certificate for client1; needs to be moved to the server running client1 + - `client1.csr`: the signing request for client1; can be deleted + - `client1.key`: the key for client1; needs to be moved to the server running client1 + - `client2.crt`: the signed certificate for client2; needs to be moved to the server running client3 + - `client2.csr`: the signing request for client2; can be deleted + - `client2.key`: the key for client2; needs to be moved to the server running client3 + - `client3.crt`: the signed certificate for client3; needs to be moved to the server running client3 + - `client3.csr`: the signing request for client3; can be deleted + - `client3.key`: the key for client3; needs to be moved to the server running client3 + - `server.example.com.crt`: the certificate for `dirk`; needs to be moved to the server running `dirk` + - `server.example.com.csr`: the signing request for `dirk`; can be deleted + - `server.example.com.key`: the key for `dirk`; needs to be moved to the server running `dirk` + - `dirk_authority.crl`: the certificate revocation list for dirk; needs to be copied to the server running `dirk` + - `dirk_authority.crt`: the certificate for dirk; needs to be copied to all clients + - `dirk_authority.key`: the key for dirk; needs to be copied to the server running `dirk` + +To provide the certificates for `dirk` make a directory `dirk/security` in your home directory and copy the `server.example.com.crt` and `server.example.com.key` files in to it. Also copy `dirk_authority.crt` to the same directory with the name `ca.crt`. The contents of the `security` directory in your configuration directory should be: + + - `ca.crt`: copy of `dirk_authority.crt` from the previous step + - `server.example.com.crt`: copy of `server.example.com.crt` from the previous step + - `server.example.com.key`: copy of `server.example.com.key` from the previous step + +At this point you also need a minimal configuration file so `dirk` knows which certificates to use. Create a file `dirk.json` in your home directory with the following contents: + +```json +{ + "server": { + "id": 212483780, + "name": "server.example.com", + "listen-address": "localhost:9091", + "cert-path": "security" + } +} +``` + +(The `id` and `listen-address` fields here will be explained later). + +You can confirm the configuration of the certificates by running the command `dirk --show-certificates` which should return suitable information about the generated certificates: + +```sh +$ dirk --show-certificates +Server certificate issued by: Dirk authority +Server certificate expires: 2023-03-24 13:47:19 +0000 UTC +Server certificate issued to: server.example.com + +Certificate authority certificate is: Dirk authority +Certificate authority certificate expires: 2023-03-24 13:47:20 +0000 UTC +``` + +#### Adding permissions +The next step is to configure `dirk` to know which clients have access to which accounts, and which operations on those accounts. To do so, replace the `dirk.json` file above with the following: + +``` +{ + "server": { + "id": 212483780, + "name": "server.example.com", + "listen-address": "localhost:9091", + "cert-path": "security" + }, + "permissions": { + "client1": { + "wallet1": "All" + }, + "client2": { + "wallet1": "All" + }, + "client3": { + "wallet2": "All" + } + } +} +``` + +Once this is in place it can be confirmed by running `dirk --show-permissions`: + +``` +$ dirk --show-permissions +Permissions for "client1": + - accounts matching the path "wallet1" can carry out all operations +Permissions for "client2": + - accounts matching the path "wallet1" can carry out all operations +Permissions for "client3": + - accounts matching the path "wallet2" can carry out all operations +``` + +Permissions can be used to restrict the access of clients to wallets, accounts, and operations. More details can be found in ther permissions documentation. + +#### Starting `dirk` + +To start `dirk` type: + +```sh +$ dirk +{"level":"info","version":"v0.1.0","time":"2020-07-27T23:20:51+01:00","message":"Starting dirk"} +{"level":"warn","time":"2020-07-27T23:20:51+01:00","message":"No stores configured; using default"} +{"level":"info","service":"api","impl":"grpc","address":"localhost:9091","time":"2020-07-27T23:20:51+01:00","message":"Listening"} +{"level":"info","time":"2020-07-27T23:20:51+01:00","message":"All services operational"} +``` + +At this point `dirk` is operational on port 9091 and can accept requests for key generation, signing _etc._ + +#### Testing client permissions +`ethdo` interacts with the dirk using additional options: + - `--remote` the address of the Dirk instance + - `--client-cert` and `--client-key` the path to the certificate and keyfile for the client + - `--ca-cert` the path to the certificate for the server authority + +For example, to list accounts accessible in `wallet1` with the `client1` certificate: + +```sh +$ ethdo --remote=server.example.com:9091 --client-cert=client1.crt --client-key=client1.key --server-ca-cert=dirk_authority.crt wallet accounts --wallet=wallet1 +account1 +account3 +account2 +``` + +As would be expected from the configured permissions, `client3` cannot access the accounts in `wallet1`: + +```sh +$ ethdo --remote=server.example.com:9091 --client-cert=client3.crt --client-key=client3.key --server-ca-cert=Wallet_daemon_authority.crt wallet accounts --wallet=wallet1 +``` + +At this point it has been confirmed that the client permissions operate as expected, and that dirk is appropriately configured. The client certificates can now be used by validators to remotely access their keys. diff --git a/images/architecture.png b/docs/images/architecture.png similarity index 100% rename from images/architecture.png rename to docs/images/architecture.png diff --git a/images/architecture.svg b/docs/images/architecture.svg similarity index 100% rename from images/architecture.svg rename to docs/images/architecture.svg diff --git a/docs/metrics/prometheus.md b/docs/metrics/prometheus.md index e5e9ca4..058ed71 100644 --- a/docs/metrics/prometheus.md +++ b/docs/metrics/prometheus.md @@ -4,8 +4,8 @@ Dirk provides a number of metrics to check the health and performance of its act ## Health Health metrics provide a mechanism to confirm if Dirk is active and able to serve requests. -`dirk_start_time_secs` is the Unix timestamp at which Dirk was started. This value will remain the same throughout a run of Dirk; if it increments it implies that Dirk has restarted. -`dirk_ready` is a flag stating if Dirk is ready to serve requests. This value is 1 if Dirk is ready to serve requests, otherwise 0. + - `dirk_start_time_secs` is the Unix timestamp at which Dirk was started. This value will remain the same throughout a run of Dirk; if it increments it implies that Dirk has restarted. + - `dirk_ready` is a flag stating if Dirk is ready to serve requests. This value is 1 if Dirk is ready to serve requests, otherwise 0. ## Operations Operations metrics provide information about the number of operations taking place within Dirk. diff --git a/docs/permissions.md b/docs/permissions.md index 270cba1..22abe50 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -1,10 +1,27 @@ # Permissions Dirk has a permissions system that allows fine-grained control of access to Dirk's operations. +Dirk permissions have three components: the client, the account, and the operation. + +## Clients +Client names are embedded in the certificate that is used to connect to Dirk. These certificates must be issued by either the local certificate authority known to Dirk, or one of the trusted root certificate authorities. + +Client names should be fully qualified (_i.e._ server.example.com rather than just server) to avoid potential confusion with multiple clients of the same name in different domains. + +## Accounts +Accounts are standard `ethdo` account specifiers of the form `wallet/account`. It is possible for either or both of `wallet` and `account` to be regular expressions. Some examples of account specifiers are: + + - `Wallet1` would specify all accounts in "Wallet1" + - `Wallet1/Acc.*` would specify all accounts in "Wallet1" that begin with "Acc" + - `Test.*` would specify all accounts in all wallets that begin with "Test" + - `.*/.*Test.*` would specify all accounts in all wallets, as long as the account contains "Test" + - `Wallet2/.*[02468]` would specify all accounts in "Wallet2" that end in an even number + ## Operations +An operation is a category of action. The operations that Dirk supports are explained below: ### All -All is a qualifier to allow all operations. Because this is a very broad permisisons, it should only be used where the client is fully trusted. +All is a qualifier to allow all operations. Because this is a very broad permissions, it should only be used where the client is fully trusted. ### None None is a qualifier to disallow all operations. Note that all lists of permissions have an implicit "None" at the end of them _i.e._ if the operation is not explicitly allowed it is denied. @@ -19,33 +36,56 @@ Sign beacon proposal is the operation of signing a proposed beacon block. Sign is the generic signing operation. Because there are no specific anti-slashing required for signing entities other than beacon attestations and proposals the data requirements for these operations are lower: only the data root and the signing domain are required. ### Access account - // ActionAccessAccount is the action of accessing an account. +Access account is the operation to access the account, for example to list all accounts in a wallet or to obtain the account's public key. + ### Create account - // ActionCreateAccount is the action of creating an account. +Create account is the operation to create a new account. Accounts will follow the rules of the wallet in which they are created, for example creating an account in a hierarchical deterministic wallet will create that wallet at the next index in the wallet's path. + ### Lock wallet - // ActionLockWallet is the action of locking a wallet. +Lock wallet is the operation to lock a wallet. Wallets must be unlocked before carrying out any write operations, for example creating a new account. Note that Dirk will attempt to unlock wallets automatically if such an operation is requested, using the `unlocker` service. + ### Unlock wallet - // ActionUnlockWallet is the action of unlocking a wallet. +Unlock wallet is the operation to unlock a wallet. Wallets must be unlocked before carrying out any write operations, for example creating a new account. Note that Dirk will attempt to unlock wallets automatically if such an operation is requested, using the `unlocker` service. + ### Lock account - // ActionLockAccount is the action of locking an account. +Lock account is the operation to lock an account. Accounts must be unlocked before carrying out any signing operations. Note that Dirk will attempt to unlock accounts automatically if such an operation is requested, using the `unlocker` service. + ### Unlock account - // ActionUnlockAccount is the action of unlocking an account. +Unlock account is the operation to unlock an account. Accounts must be unlocked before carrying out any signing operations. Note that Dirk will attempt to unlock accounts automatically if such an operation is requested, using the `unlocker` service. -### All +## Structure +Each client has a list of accounts, and each account has a list of permissions. For example: -### All +``` + client1.example.com: + Wallet1/Account1: Access account,Sign,Sign beacon proposal,Sign beacon attestation + Wallet1/Account2: Access account,Sign,Sign beacon proposal,Sign beacon attestation + client2.example.com: + Wallet2: Access account,Sign,Sign beacon proposal,Sign beacon attestation + server.example.com: + .*: Access account,Create account +``` + +Here, `client1.example.com` is able to server + +### Implicit denial +Dirk adds an implicit denial at the end of each list of permissions, for example the permission list: + +``` + Unlock account, Unlock wallet +``` + +is read by Dirk as "allow unlocking account, allow unlock wallet, _deny everything else_". Implicit denial ensures that mis-configurations are more likely to end up in denying expected operations, rather than allowing unexpected operations. This is important in two areas: firstly, if a new operation is introduced it is by default not allowed, and secondly if a mis-configuration does take place it is more likely to result in a safe, if non-optimal, set of permissions. -## Explicit denial -In addition to an implicit denial, where none of the rules match the operation, it is possible to have explicit denials. Explicit denials are useful when you want to say things like "allow all operations _except_..." +### Explicit denial +In addition to an implicit denial, it is possible to have explicit denials. Explicit denial -Explicit denial is configured by prepending the ~ symbol to the operation, for example permissions of: +Explicit denial is configured by prepending the ~ symbol to the operation, for example the permission list: ``` ~Voluntary exit, All ``` -read as: - - do not allow voluntary exits - - allow all other operations +is read by Dirk as "do not allow voluntary exits, allow all other operations". Explicit denials are useful when you want your permissions to be of the form "allow all operations _except_..." diff --git a/rules/standard/storage.go b/rules/standard/storage.go index 3af1e19..4a5ec93 100644 --- a/rules/standard/storage.go +++ b/rules/standard/storage.go @@ -45,6 +45,32 @@ func NewStore(base string) (*Store, error) { }, nil } +// FetchAll fetches a map of all keys and values. +func (s *Store) FetchAll(ctx context.Context) (map[[49]byte][]byte, error) { + items := make(map[[49]byte][]byte) + err := s.db.View(func(txn *badger.Txn) error { + it := txn.NewIterator(badger.DefaultIteratorOptions) + defer it.Close() + for it.Rewind(); it.Valid(); it.Next() { + item := it.Item() + err := item.Value(func(v []byte) error { + var key [49]byte + copy(key[:], item.Key()) + items[key] = v + return nil + }) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + return nil, err + } + return items, nil +} + // Fetch fetches a value for a given key. func (s *Store) Fetch(ctx context.Context, key []byte) ([]byte, error) { span, _ := opentracing.StartSpanFromContext(ctx, "storage.Fetch")