Access Control & Permissioning

Dune Network provides several access control features:

  • to control access to the services of the node (RPCs)
  • to control access to the the network (for private/permissioned networks).
  • to control access to the accounts (KYC)

Access Control to RPCs

Dune nodes provide a large set of RPCs to allow clients to interact with them. Some of these RPCs can expose the node to attackers, as they allow to change the settings of the node, or require expensive computations leading to possible D-DOS attacks.

Server-side Parameters

To protect nodes from such attacks, Dune provides two parameters that can be set in the node configuration file, in the rpc section:

  • The allow_public_access parameter can be used to decide whether anybody should have access to the node ;
  • The users parameter can be used to define a list of login+password pairs that can have full access to the node;

Both parameters work together:

  • If allow_public_access is false (default), and users is empty (default), the node RPCs can only be accessed from the local host. This setting has become the default mode for the node;
  • If allow_public_access is false, and users is not empty, the node RPCs can only be accessed by the users in users ;
  • If allow_public_access is true, and users is empty, all the node RPCs are available from anywhere and anybody. This was the former default setting for the node;
  • If allow_public_access is true, and users is not empty, only the users specified in users can access all the node RPCs, but a subset of the node RPCs is made available for public access. This subset has been chosen to include only computation-friendly requests, and non-sensible information. The public RPCs includes most of the ones needed for dune-client and dune-baker.

For now, authentication for the users parameter is done using the Basic HTTP Authentication, supported by all browsers and web clients. Since it sends the password in clear in the request, it is advised to use https:// to encrypt the communication to the node.

Client-side Settings

On the client side, dune-client provides a new parameter users in its configuration file. This parameter is a list of associations between hosts and user-password pairs. Each pair is written as one string with a : between the user and password.

The argument --user LOGIN:PASSWORD can also be used directly on the command-line.

Full Example

The first thing we will do for this example is create a self-signed TLS certificate to encrypt RPCs. It’s not mandatory, and can make the requests slower, but it’s an additional level of security. For that, we use the OpenSSL library and tools:

openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

This command will ask you many questions to generate a self-signed certificate for your node. The most important one is the Common Name, which should be your computer name or IP address. It generates two files key.pem and certificate.pem.

Now, let’s write the configuration of our server in ~/.dune-node/config.json:

{ "rpc":
  { "listen-addrs": [ "127.0.0.1:8733" ],
    "cors-origin": [ "*" ],
    "cors-headers": [ "content-type" ],
    "key":"key.pem",
    "crt": "certificate.pem",
    "allow_public_access": false,
    "users": [ [ "admin", "admXrpcX" ] ] },
    "p2p": { "listen-addr": "[::]:9733" },
  "shell":
  { "chain_validator": { "bootstrap_threshold": 1 },
    "history_mode": "archive" }
}

In the rpc section, the parameters key and crt have been set to point to the TLS certificate files (in a real setting, these should be absolute paths). We set allow_public_access to false, and we define one user "admin" with his password "admXrpcX".

We can now run the server: dune-node run We can then test a simple RPC:

wget --no-check-certificate https://localhost:8733/network/version
--2020-01-21 17:02:02--  https://localhost:8733/network/version
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:8733... failed: Connection refused.
Connecting to localhost (localhost)|127.0.0.1|:8733... connected.
WARNING: The certificate of 'localhost' is not trusted.
WARNING: The certificate of 'localhost' hasn't got a known issuer.
HTTP request sent, awaiting response... 401 Unauthorized
Username/Password Authentication Failed.

The request complained about the self-signed certificate, of course (we added --no-check-certificate to avoid an immediate exit), but finally, it fails because of the lack of authentication. Note that this particular RPC would have succeeded if allow_public_access was true, because it’s not a sensible one.

We can now test again with a user/password:

wget --user admin:admXrpcX --no-check-certificate https://localhost:8733/network/version
--2020-01-21 17:06:04--  https://localhost:8733/network/version
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:8733... failed: Connection refused.
Connecting to localhost (localhost)|127.0.0.1|:8733... connected.
WARNING: The certificate of 'localhost' is not trusted.
WARNING: The certificate of 'localhost' hasn't got a known issuer.
HTTP request sent, awaiting response... 401 Unauthorized
Authentication selected: Basic realm="Dune"
Reusing existing connection to localhost:8733.
HTTP request sent, awaiting response... 200 OK
Length: 102 [application/json]
Saving to: 'version'

This time, the request succeeded.

Let’s try now with dune-client. We can first try directly, using command line arguments for TLS (-S) and user (--user):

dune-client -S --user admin:admXrpcX get balance for baker
Config: Testnet. Revision: 3
User config: "$HOME/.dune-client/config"
Node: https://localhost:8733 (user:admin)
470137.151878 đ

We can also modify the client configuration file ~/.dune-client/config:

{ "base_dir": "$HOME/.dune-client",
  "node_addr": "localhost", "node_port": 8733,
  "web_port": 8080, "confirmations": 0,
  "tls": true,
  "users": [ [ "localhost:8733", "admin:admXrpcX" ] ]
}

We have set the tls option to true to force https://, and added a user to be used for host localhost:8733 with the users parameter.

We can now use a much simpler version on the command line:

dune-client get balance for baker
Config: Testnet. Revision: 3
User config: "$HOME/.dune-client/config"
Node: https://localhost:8733 (user:admin)
470137.151878 đ

Private/Permissioned Networks

Dune provides several ways to create a private network. The former way was to use the Private Mode that forced to statically specify the IP+port addresses of all the nodes in the network.

The following 3 new ways to create a private network have been added. They give more flexibility and expressiveness than the former mode:

  • Shared Secret: a node can only connect to another one if it knows a shared secret with the other node;
  • Closed Network: each node reads a configuration with the list of node identifiers allowed in the network;
  • On-chain Access Control: the list of node identifiers is maintained on-chain. Any node can connect to another node, but not read data from the chain if its identifier is not in the list of allowed identifiers for that chain.

Note that the 3 mechanisms can be used separately or together. For all these mechanisms, a node will reject any node that is not using the same mechanisms, i.e. an open node will reject any connection from a closed-network node, and vice-versa. This prevents badly-configured nodes from entering a private network.

As an exception to the previous rule, it is possible to specify a list of node identifiers without being in a closed network. This mechanism can be used to limit a specific node to connect to a restricted set of other nodes. If used in combination with the Private Mode, all the node identifiers are marked as trusted.

Privacy by Shared Secret

The simplest form of access control for a private network is the Shared Secret: any node that knows the secret can access the network. It is good enough to start with, but it’s a bit weak as it is not possible to revoke a compromised node. Instead, the shared secret must be changed and propagated again to all trusted nodes. Such a change can take some time, during which the network will be forked between nodes using the former secret and nodes using the new one.

There are two ways to configure a private network to use a shared secret:

  • Use the p2p_secret option in the network configuration (the file pointed by DUNE_CONFIG).
  • Use the p2p_secret option in the p2p section of the node configuration file.

In both cases, the value must be a string, containing the shared secret. To prevent brute force attacks, the string should be at least of length 10.

If the option is set in the network configuration, then it is not possible to remove it in the node configuration. However, it is possible to change it to a different secret in the node configuration.

When the p2p_secret option is given a value, the node will reject any incoming or outgoing connection with a node that does not know the secret, even if the node address was provided as a trusted node (bootstrap peer or command line --peer option).

Privacy by Closed Network

The second form of access control is more dynamic: when a network is configured as a Closed Network, the identity (node identifier) of every node must be known beforehand and listed in a configuration file. Revoking a node only requires to remove, on every other node, its identifier from the list and restarting the other node. Such an operation can be done without any risk of forking the network.

To configure a private network to become a Closed Network, the option closed_network must be set to true in the network configuration (the JSON file pointed to by DUNE_CONFIG).

A file must contain the identifiers of all the nodes that can be connected to a node of the network. The name of that file must be put in the nodes_list option of the p2p section of the node configuration. The filename can also be set in the nodes_list option of the network configuration, but it’s probably less convenient.

The nodes_list file must contain a list of JSON nodes objects, corresponding to the nodes, with two fields:

  • A mandatory peer_id field associated to a string containing the identifier of the node (itself starting with id..., and found in the peer_id field of the identity.json file of the node).
  • An optional addr field, associated to a string containing the address (IP or hostname, plus port) of the corresponding node.

Note that the addr field is only used to find the node on the network, it will not allow any node at this address to connect if their identifier is not known.

A node in a Closed Network will only accept connections to and from nodes that are also in Closed Network mode, and with matching identifiers. However, there is no guarrantee that the list of nodes is the same one on all the nodes.

It is also possible to use the nodes_list option to secure a node in a public network (i.e. closed_network is false). In that case, the node will only accept connections from the nodes list. All nodes in the nodes list will be added to the set of trusted peers (and trusted addresses if their addresses are provided).

Privacy by On-Chain Access Control

The last way to create a private network is to use the on-chain access control feature. The main benefit of on-chain access control is that the list of nodes is automatically maintained on-chain, so that all nodes have the same configuration, for any given block of the chain. Also, this feature does not prevent unauthorized nodes from connecting to nodes in the network. Instead, it prevents them from downloading the chain data and from sending data to the chain.

To use this feature, one of the two following options must be set to true:

  • The access_control option in the network configuration file (file pointed to by DUNE_CONFIG).
  • The access_control field of the p2p section of the node configuration file.

Once the access_control field is set to true, the node will only accept connections from other nodes with also the access_control field set. This feature can be combined with the Shared Secret mode to keep the network cleaner.

Once in On-Chain Access Control mode, the node will only send any chain data to a node if it belongs to a list of identifiers. This list of identifiers being updated on-chain, the access to data depends on the list value at the level when a message is received or sent. In particular, a node that has been revoked might still have access to the chain state before the time when it was revoked, if the node has not yet received the blocks where it was revoked.

To change the list of peer identifiers (empty at the beginning), Manage_accounts operations must be used (by superadmin accounts), with two different fields:

  • The peer identifiers in the allow_peer_ids field will be added to the list
  • The peer identifiers in the revoke_peer_ids field will be removed from the list

It is also possible to control the list of allowed peer identifiers from a smart contract.

  • In Michelson, the two instructions ALLOW_PEERS and REVOKE_PEERS have the following type:

    ALLOW_PEERS: string list : S -> operation : S
    REVOKE_PEERS: string list : S -> operation : S
    

    They take a list of peer identifiers as argument, and return an operation to return that will add or revoke these peers.

The list of allowed peers at any given block can be retrieved from the node using the following RPC:

dune-client rpc get /chains/main/blocks/head/allowed_peer_ids

Access-Control for Accounts

In a private network, it is sometimes required to control precisely which accounts can send operations or receive tokens. A typical example is the need for the user to fill a KYC before accessing his account. Other examples are the superadmin role or the baker role in a private network.

Superadmin Account (Network Administration)

Dune Network can be administered using superadmin accounts. The superadmin accounts are the only ones authorized to perform the following operations:

  • The Activate_protocol operation to change the protocol or the protocol constants
  • The Manage_accounts operation to change accounts’ rights

Initially, the superadmin account is specified in the network configuration, in the genesis_key field.

It is possible to add/revoke superadmin accounts, especially smart contracts (for multisig validation for example). For that, the current superadmin must use the actions field of the Manage_accounts operation, with actions add_superadmin or remove_superadmin:

{
  "actions": [
    [ "add_superadmin", "0", [ "dn1X1..", "dn1X2.." ] ],
    [ "remove_superadmin", "0", [ "dn1X3..", "dn1X4.." ] ]
  ]
}

Baker Authorization (Proof-of-Authority)

It is possible to restrict which accounts can validate blocks in a private network, to get a Proof-of-Authority consensus (PoA).

For that, the option only_allowed_bakers must be set to true in the network configuration (the file pointed to by DUNE_CONFIG).

When this option is set:

  • Bakers in the bootstrap accounts (accounts created when activating the protocol after the genesis block) are automatically added to the list of allowed bakers
  • The Manage_accounts operation can be used to trigger actions add_allowed_bakers and remove_allowed_bakers to add or revoke allowed bakers.

Note that, to properly remove a baker, the maxrolls parameter of the baker should first be set to 0, 7 cycles before removing it from the allowed bakers set. Otherwise, the baker will still have baking rights, but will be prevented from baking.

In PoA, a baker can only register itself as a baker after being added to the allowed bakers.

In PoA, allowed bakers do not receive rewards for baking, and they don’t have to deposit.

Account Authorization (KYC)

To enable this feature, the kyc_level option must be set to one of these values in the network configuration file:

  • open means that there is no KYC on the network. It is the default on the public network;
  • source means that the source account (dn1/2/3) of any signed operation must be authorized for the operation to succeed;
  • both means that the source account of any signed operation, and the destination (dn1/2/3) of any transfer, must be authorized for the operation to succeed.

To authorize or revoke authorized accounts, Manage_accounts operations must be used by superadmin accounts with the following fields:

  • The actions field can contain several actions kyc_accounts, the KYC level to authorize, and a list of accounts whose KYC should be changed

For example:

{
  "actions": [
    [ "kyc_accounts", "1", [ "dn1X1..", "dn1X2.." ] ],
    [ "kyc_accounts", "0", [ "dn1X3..", "dn1X4.." ] ],
    [ "kyc_accounts", "255", [ "dn1X5..", "dn1X6.." ] ]
  ]
}

The KYC level can be:

  • 0 means that the account is not authorized
  • 255 means that the account is authorized to do everything

It is possible to set the KYC using a binary-or between the following values:

  • 1 means that the account is authorized to reveal its public key
  • 2 means that the account is authorized to receive tokens (only checked in both mode)
  • 4 means that the account is authorized to transfer or call
  • 8 means that the account is authorized to delegate
  • 16 means that the account is authorized to originate contracts
  • 32 means that the account is authorized to manage its parameters
  • 64 and 128 are not yet used

A smart contract can use the following instructions to manage KYC:

  • In Michelson, the instruction ADMIN_ACCOUNTS has the type:

    ADMIN_ACCOUNTS:    string : mudun : address list : S -> operation : S
    

    and can be called with the string "kyc_accounts" and an amount corresponding to the value of the KYC.