Warning
During the beta period, the master branch may be unstable. The master branch will likely include unreleased code, and may not build at all. Please use the latest release for a stable build.
Note
During the beta, your feedback is greatly appreciated! We'd love to hear about your use-cases and how you're running Relay inside of your customer environments — from networking to deployment. Feel free to open a discussion, or reach out to us on Discord.
Relay is an offline-first on-premise licensing server backed by Keygen. Use Relay to securely manage distribution of cryptographically signed and encrypted license files across nodes in an offline or air-gapped environment. Relay does not require or utilize an internet connection — it is meant to be used stand-alone in an offline or air-gapped network.
Relay has a vendor-facing CLI that can be used to onboard a customer's air-gap environment. An admin can initialize Relay with N licenses to be distributed across M nodes, ensuring that only N nodes are licensed at one time.
Relay provides an app-facing REST API that allows nodes to claim a lease on a license and release it when no longer needed.
Relay was born out of a limitation in Keygen — and really, a limitation in all licensing APIs — the limitation being that implementing a node-based licensing model, e.g. floating licenses, is hard in an air-gapped or otherwise offline environment using an external API, due to the nature of APIs needing an internet connection. Whether self-hosting Keygen EE, or using Keygen Cloud, the issue remains the same.
Since Keygen is an API, it can't communicate to the nodes inside these isolated environments, and that means it can't easily track which nodes are being used and which nodes are not. It also has no visibility into how many nodes there are currently vs how many nodes are allowed in total. Some vendors may be able to whitelist Keygen in the customer's firewall, but that's rare.
In the past, we've seen workarounds for this problem. Most of them consist of using an intermediary between the offline world and the online world — typically a mobile device or a tablet. In this case, the intermediary acts on behalf of the offline node, activating it via an online portal, and passing on a signed payload, e.g. a license file, for verification.
As an alternative, some customers have even asked if they can self-host Keygen on-premise for customers — but that's inherently unsafe, since customers would have full access to Keygen, thus access to granting themselves licenses, adjusting policy rules, etc.
While the aforementioned intermediary-based workaround can work — it's brittle. And it requires human intervention, which just doesn't really work in the age of cloud computing and autoscaling. For example, you couldn't use this workaround to license on-premise software, where you wanted to only allow the customer to use 20 concurrent processes at one time — it just wouldn't be feasible to ask a human to hop on their phone and activate nodes in an autoscaling k8s cluster as it autoscales.
Thus, the idea for Relay was born — a bridge between Keygen and the offline universe, secured via cryptography.
To install Relay, you can follow the instructions and run the command below. Alternatively, you can install manually by downloading a prebuilt binary and following the install instructions here.
Automatically detect and install relay
on the current platform:
curl -sSL https://raw.pkg.keygen.sh/keygen/relay/latest/install.sh | sh
This will install relay
in /usr/local/bin
.
Missing a platform? Open an issue.
For all available commands and flags, run relay --help
.
The CLI can be used by the vendor to setup and manage customer environments.
You can add a new license to the pool using the add
command:
relay add --file license.lic --key xxx --public-key xxx
The add
command supports the following flags:
Flag | Description |
---|---|
--file |
Path to the license file to add to the pool. |
--key |
License key for decryption. |
--public-key |
Your account public key for license verification. |
To delete a license from the pool, use the del
command:
relay del --license xxx
The del
command supports the following flags:
Flag | Description |
---|---|
--license |
The unique ID of the license to delete from the pool. |
To list all the licenses in the pool, use the ls
command:
relay ls
The ls
command supports the following flags:
Flag | Description |
---|---|
--plain |
Print results non-interactively in plaintext. |
To retrieve the status of a specific license, use the stat
command:
relay stat --license xxx
The stat
command supports the following flags:
Flag | Description |
---|---|
--license |
The unique ID of the license to retrieve info about. |
--plain |
Print results non-interactively in plaintext. |
To start the relay server, use the following command:
relay serve --port 6349
The serve
command supports the following flags:
Flag | Description | Default |
---|---|---|
--port , -p |
Specifies the port on which the relay server will run. | 6349 |
--no-heartbeats |
Disables the heartbeat system. When this flag is enabled, the server will not automatically release inactive or dead nodes, and leases cannot be extended. | false |
--strategy |
Specifies the license distribution strategy. Options: fifo , lifo , rand . |
fifo |
--ttl , -t |
Sets the time-to-live for leases. Licenses will be automatically released after the time-to-live if a node heartbeat is not maintained. Options: e.g. 30s , 1m , 1h , etc. |
30s |
--cull-interval |
Specifies how often the server should check for and deactivate inactive or dead nodes. | 15s |
--database |
Specify a custom database file for storing the license and node data. | ./relay.sqlite |
E.g. to start the server on port 8080
, with a 30 second node TTL and FIFO
distribution strategy:
relay serve --port 8080 --ttl 30s --strategy fifo
The API can be consumed by the vendor's application to claim a lease on a license, and also release the lease, on behalf of a node.
The Relay server's health can be checked with the following endpoint:
curl -v -X GET "http://localhost:6349/v1/health"
Returns a 200 OK
status code.
Nodes can claim a lease on a license by sending a PUT
request to the
/v1/nodes/{fingerprint}
endpoint:
curl -v -X PUT "http://localhost:6349/v1/nodes/$(cat /etc/machine-id)"
Accepts a fingerprint
, an arbitrary string identifying the node.
Returns 201 Created
with a license_file
and license_key
for new nodes. If
a lease already exists for the node, the lease is extended by --ttl
and the
server will return 202 Accepted
, unless heartbeats are disabled and in that
case a 409 Conflict
will be returned. If no licenses are available to be
leased, i.e. no licenses exist or all are being actively leased, the server
will return 410 Gone
.
{
"license_file": "LS0tLS1CRUdJTiBMSUNFTlNFIEZJTEUtLS0tL...S0NCg0K",
"license_key": "9A96B8-FD08CD-8C433B-7657C8-8A8655-V3"
}
The license_file
will be base64 encoded.
Nodes can release a license when no longer needed by sending a DELETE
request
to the same endpoint:
curl -v -X DELETE "http://localhost:6349/v1/nodes/$(cat /etc/machine-id)"
Accepts a fingerprint
, the node fingerprint used for the lease.
Returns 204 No Content
with no content. If a lease does not exist for the
node, the server will return a 404 Not Found
.
Relay comes equipped with audit logs out-of-the-box, allowing the full history
of the Relay server to be audited. They can be viewed using a sqlite3
client,
providing the path to the Relay database file:
sqlite3 ./relay.sqlite
-- recent events
SELECT
audit_logs.*
FROM
audit_logs
ORDER BY
audit_logs.created_at DESC
LIMIT
25;
-- recently leased licenses
SELECT
audit_logs.*
FROM
audit_logs
JOIN
event_types ON event_types.id = audit_logs.event_type_id
WHERE
event_types.name = 'license.leased'
ORDER BY
audit_logs.created_at DESC
LIMIT
5;
-- entire history in chronological order
SELECT
datetime(audit_logs.created_at, 'unixepoch') AS created_at,
event_types.name AS event_type,
entity_types.name AS entity_type,
audit_logs.entity_id
FROM
audit_logs
JOIN
event_types ON event_types.id = audit_logs.event_type_id
JOIN
entity_types ON entity_types.id = audit_logs.entity_type_id
ORDER BY
audit_logs.created_at ASC;
If you have concerns about storage, or do not wish to keep audit logs, use
Relay's --no-audit
flag to disable them.
To build Keygen Relay from the source, clone this repository and run:
go build -o relay ./cmd/relay
# or...
make build
Alternatively, you can build binaries for specific platforms and architectures
using the provided make
commands:
make build
# or specific platform...
make build-linux-amd64
# or all platforms...
make build-all
To cut and publish a new release of Relay, update the VERSION
file and run
the following make
command:
make release
Releases are uploaded and published using the Keygen CLI. Releases are hosted and distributed by Keygen Cloud. You will need credentials and permission to upload to our production Keygen Cloud account.
Keygen Relay comes with a suite of tests, including integration tests that verify behavior with the real server.
To run regular tests:
make test
To run integration tests, tagged with // +build integration
:
make test-integration
This project is licensed under the MIT License. See the LICENSE file for details.
If you discover an issue, or are interested in a new feature, please open an issue. If you want to contribute code, feel free to open a pull request. If the PR is substantial, it may be beneficial to open an issue beforehand to discuss.
The CLA is available here.
We take security at Keygen very seriously. If you believe you've found a
vulnerability, please see our SECURITY.md
file.