Aranya Beta
Introduction
A product specification of the standalone Aranya daemon. The goal
is to provide a commercial off the shelf solution for integrating Aranya. Customers
should be able to download the Aranya daemon, setup a team, and begin using Aranya.
Primary Goals:
- Provide a low friction solution customers can use to better secure their infrastructure.
- Easily setup a team and onboard users.
- Implement a default policy that works well enough for a wide variety of situations
that customers can relate to.
- Provide stable APIs that allow devices and users to interact with Aranya.
- Expose an API for point to point high performance encrypted communication using IPv4 for transport.
Secondary internal goals:
- Design for the ability to swap out policies in a future version.
- Design for future improvements, like additional data planes and configurable roles.
Design
Aranya is a decentralized message delivery platform with authorization built in. Below are some basic requirements for running the beta version of Aranya:
System Requirements:
- We will target x86, ARM, and ARM64 running Linux.
- We will assume there is IPv4 connectivity.
After the beta is working, the following values should be measured to estimate system requirements:
- Memory usage
- Disk requirements:
- Storage amount
- Storage device write speed
- Storage device seek speed
Architecture
There will be two subsystems as part of Aranya:
- The daemon
- The client library
The daemon is a standalone process that runs Aranya and exposes the control plane API via
IPC. The daemon will periodically sync with peers and handle commands as they are synced.
The current design does not require any disk-persisted effects, so on startup the daemon
should start from a clean state (aside from loading accounts) every time it is started.
This includes clearing any shared memory on startup to avoid collisions/stale data.
The client library exists inside the user’s process and is used to interact with the
daemon. The client library also includes a light wrapper around AFC allowing the user
to encrypt data and send messages to peers.
Both subsystems are limited to a single KeyBundle per process to limit the possibility of
leaking device keys. This still enables the daemon to participate in multiple teams
by using the same keybundle for every team.
For V1, we will initially design for the C API. The Rust client library is a bonus that
we gain from the Rust -> C compilation. The C API should include autogenerated docs.
Config
On startup, the daemon requires the work directory as well as the path to the
UDS socket that should be created. All other config values are provided
when a client context is initialized and passed to the daemon over the UDS socket.
This approach allows the user API to drive the configuration of the daemon, and
can help reduce errors in config mismatch by minimizing the number of duplicate
config values.
Components
The system is made up of multiple components:
The “client API” is the top level component and contains local operations such as
enabling/disabling syncing or initializing a new device.
The Access Control Plane is the top level control plane, enabling IDAM operations
and other on-graph operations. The Access Control Plane is used to manage keys,
address assignment, roles, and labels as set out in the policy.
For the beta, the AFC Plane will be build to provide a simple API for sending
and receiving messages using AFC. The AFC Plane contains its own control plane for
control messages, as well as the main data plane for moving data between devices.
Component structure:
- Local Client API: syncing, local device management
- Access control plane (IDAM control plane): IDAM lifecycle
- AFC plane (Beta)
- AFC control plane
- AFC data plane
- Broker plane (later…)
- Broker control plane
- Broker data plane
- On graph messaging (later…)
- graph messaging control plane (or implicit)
- data plane (on graph messages)
- … additional planes in future versions
Client APIs
The client APIs are local only API endpoints that do not create commands
on the graph. They are mostly used to manage the local state.
- InitDevice() -> device_id - init a device if not exists, generate keys,
create the API instance, etc.
- GetKeyBundle() -> keybundle - returns the current device’s public key bundle.
- GetDeviceId() -> device_id - returns the device’s device ID.
- AddTeam(team_id) -> bool - add an existing team to the local device store. Not an Aranya action/command.
- RemoveTeam(team_id) -> bool - remove a team from the local device store. Not an
Aranya action/command.
- SerializeKeyBundle(scheme, keybundle) -> bytes - serialize a keybundle to a
given format/scheme. Ideally, this can be used to serialize to either human readable or
machine readable formats.
- DeserializeKeyBundle(scheme, bytes) -> keybundle - desrialize a keybundle
from a given format/scheme.
- SerializeId(scheme, id) -> bytes - serialize an ID to a given format/scheme.
- DeserializeId(scheme, bytes) -> id - deserialize an ID from a given format/scheme.
Sync API:
No policy command associated with these commands.
- AddSyncPeer(address, team_id, rate) -> bool - add a peer to start syncing with at a
specific rate. Syncing should support DNS resolution in the case a domain name is used.
- RemoveSyncPeer(address, team_id) -> bool - remove a sync peer associated with the given address,
team_id.
Onboarding API
Beta:
Easy to implement, key moving is done by integration.
- Create Device (NewDevice)
- Get Device Key (Current device KeyBundle (what you give to the admin))
- Give KeyBundle to admin on team (integration problem)
- Admin does AddDevice(user_key_bundle)
- Get team_id from admin (integration detail)
- Add team_id to client (AddTeam)
- Sync with device on team (AddSyncPeer)
MVP:
We will provide an additional optional onboarding API:
TODO: we need a flow chart or just event sequence for these.
- CreateInvite(server address, team_id) -> Invite code - create an invite code that
will be sent to a device to onboard.
- PollInvite(server address, Invite Code) -> Option - check the status of an invite code,
returns the device ID of the device that joined using that code.
- Join(server address, Invite Code, Device Key) -> Result - join a team using an invite code,
returns the team_id of the team that was joined.
The goal of this onboarding API is to simplify the process of onboarding a
user/device by providing an invite code instead of passing a KeyBundle.
IDAM Control Plane API
The IDAM control plane is for managing identity and authorization by interacting
with the graph. Each endpoint creates one or more commands on the graph.
- CreateTeam(owner) -> team_id - initialize the graph, creating the team with
the author as the owner.
- CloseTeam(team_id) - close the team and stop all operations on the graph.
- AddDevice(team_id, keybundle, common_name) -> device_id - add a device to the team with the default role
- RemoveDevice(team_id, device_id) - remove a device from the team
- AssignRole(team_id, device_id, role) -> bool - assign a role to a device
- RevokeRole(team_id, device_id, role) -> bool - remove a role from a device
- AssignNetworkName(team_id, device_id, net_identifier) -> bool - associate a network address to a device
for use with AFC. If the address already exists for this device, it is replaced with the new
address. Capable of resolving addresses via DNS, required to be statically mapped to IPv4.
For use with CreateChannel and receiving messages. Can take either DNS name or IPv4. MVP
would need reverse lookup. More work required on the address assignment, especially
post-beta. Currently one name per device.
- RevokeNetworkName(team_id, device_id, net_identifier) -> bool - disassociate a network address from a device.
- CreateLabel(team_id, label) -> bool - create a label
- DeleteLabel(team_id, label) -> bool - delete a label
- AssignLabel(team_id, device_id, label) -> bool - assign a label to a device so that it can be used for AFC
- RevokeLabel(team_id, device_id, label) -> bool - revoke a label from a device
The IDAM control plane will be managed by the daemon process which will be accessed
with the previous APIs via an IPC mechanism. The daemon will be responsible for syncing
state with peers. To enable, these two additional APIs will be provided to add and remove
peers to sync from:
Initially, UDS and shm will be used for IPC between the daemon and client library.
Role APIs need improvement post beta (to support custom roles?).
AFC Plane API
The AFC plane is split in two different sub-planes: the AFC control plane
and the AFC data plane. The AFC control plane is responsible for any Aranya
command or ephemeral commands, while the AFC data plane contains only
data related APIs.
AFC Control Plane
- CreateChannel(team_id, net_identifier, label) -> channel_id - Open a channel to the dest with the given label. The user API transparently handles sending the ephemeral command to the
peer. Channel keys are automatically rotated after a specific byte count.
- DeleteChannel(team_id, channel_id) -> bool - Close a channel with the given ID. The user API transparently handles sending the ephemeral command to the peer.
AFC Data Plane
- PollData(timeout) -> bool - blocks with timeout, returns true if there is AFC data to read using
ReadData
.
- ReadData(bytes_buffer) -> Result<(len_written, remote_net_identifier, label, channel_id)> - read the AFC data, returning the plaintext, sender, and label (or an error). Returns a single AFC message at a time.
- SendData(bytes, channel_id, timeout) -> bool - encrypts and sends the data
to the given channel with a timeout. This call is blocking until the timeout
is complete.
For the initial implementation in the beta, AFC control messages should be handled
transparently by the client library. In the future, control messages can be passed
to the user to be manually forwarded to the daemon using a different API.
Roles & Permissions
There will be 4 different user roles with the following set of permissions for each.
owner
- root user (all permissions excluding sending data on AFC label)
- create/close team
- add/remove devices
- elevate/revoke permissions for devices up to and including
owner
- define/undefine AFC labels
- assign/remove addresses/names for AFC
- assign/revoke AFC labels
- sync
admin
- elevate/revoke permissions for devices up to a max level of
operator
- define/undefine AFC labels
- assign/remove addresses/names for AFC
- cannot send data on AFC labels
- sync
operator
- add (new) / rm user in team
- assign user role to users in team
- assign/revoke AFC labels
- assign/remove addresses/names for AFC
- cannot send data on AFC labels
- sync
user
sync-role
Notes:
- Devices can always remove and demote themselves
- Devices of equal role cannot remove or demote each other (hence, capabilities
of an owner can only be self-reduced)
Documentation
API documentation must be provided for the client API covering the functions
and behavior of each API call. Most likely, this will take the form of a doxygen-like
web page. Developers can use this to look up language agnostic functions for operating
the client API. The documentation should also include tutorials and a quickstart
to get developers up and running with Aranya as soon as possible. Documentation
should also be provided for the daemon so that developers and sysadmins can
understand the requirements and operations of the daemon.
Glossary
AFC
- the library used to do high performance encryption using keys managed by Aranya
.
Aranya
- the main library that drives the control plane and policy execution.
daemon
- a long-lived process, typically running in the background, that
handles commands and keeps state.
device
- a computer, sometimes associated with a user but can also be independent.
In this model, we consider devices
instead of users directly to accommodate
autonomous entities.
IPC
- inter-process communication.
policy
- an Aranya policy, containing the logic and rules of the system.
sync
- a request to synchronize the commands on the control plane. Syncs are currently
pull only, so the device that requests a sync receives commands from the requestee.
team
- a group of devices with an associated policy.
UDS
- Unix Domain Sockets, used for communication between processes.
user
- a person who may operate a device.
Verb pairs
- Add/Remove
- Assign/Revoke
- Create/Delete
Additional Notes