Access Control¶
Authentication¶
In nixbuild.net, users authenticate either using an SSH key, or using an auth token. When using the Nix client to interact with nixbuild.net (running builds or using it as a Nix store), you can either use SSH keys or auth tokens for authentication. When using the nixbuild.net's HTTP API you must use auth tokens.
Both SSH keys and auth tokens have their strengths and weaknesses, and you must yourself find out what fits your use case best. As a general advice, sticking with SSH keys is usually easier until you need the additional flexibility that auth tokens provide.
Using SSH Keys¶
SSH keys are the default authentication method in nixbuild.net. When you create an account, you must provide a public SSH key which is tied to your account. After account creation, you can add or remove SSH keys as you like, using the administration shell.
If you're a team, you can add each team member's personal SSH key to your nixbuild.net account. That way, all members can use nixbuild.net as a remote builder and, since they all share the same nixbuild.net account, they can reuse build inputs and outputs.
On your Nix clients, you set up your SSH config to use the corresponding keys
when connecting to eu.nixbuild.net
. This does not differ from using regular
remote Nix builders, or using SSH in general. You can see step-by-step
instructions in the Getting Started guide.
Using Auth Tokens¶
To be able to use an auth token for authentication, you first need to create
one using the tokens create
command in the administration
shell. When creating a token you must assign it an
expiration date and a set of permissions. The permissions are
decribed in more detail below. If you want to create an auth token that should
be valid for 30 days and only be allowed to query, pull and push store paths
from nixbuild.net (not start any builds), you invoke the command like this:
nixbuild.net> tokens create --ttl-seconds 2592000 -p store:read -p store:write
Revoking Auth Tokens¶
Auth tokens should be treated as secrets and stored in a sensible way. If you
ever need to revoke a token, you can run tokens revoke
in the administration
shell, with the token you want to revoke as its only argument:
nixbuild.net> tokens revoke EpYCCqsBCgxhY2NvdW50OnJlYWQKDWFjY291bnQ6d3JpdGUKCmJ1aWxkOnJlYWQKC2J1aWxkOndyaXRlCgpzdG9yZTpyZWFkCgtzdG9yZTp3cml0ZRgDIggKBggHEgIQBCImCiQIBBIgOh4KAxiACAoDGIEICgMYgggKAxiDCAoDGIQICgMYhQgyJgokCgIIGxIGCAUSAggFGhYKBAoCCAUKCAoGIJesxKkGCgQaAggAEiQIABIg_vub4yDKe3X_ZYwW1OPNcQhBzm9aCFq87JuDioh3Iz4aQF-D8EMnLkyTnuqCGc7MLK7HOLcPAGNViWZc5jeQPt83SbY1K9Hot5GHelpHwLVQAUmlJwmkIgy8mkCTYZLssA8atQEKSwoKb3BlcmF0aW9ucwoDb3BzGAMyNgo0CgIIGxIICIYIEgMIhwgaJAoFCgMIhwgKCQoHOgUKAxiBCAoEGgIIBQoEEgIIAQoEEgIIABIkCAASIO--7mSwDxqhhL4O6K6DtqYDfKJUH0JvYM2OErB0a2jhGkBWHj5nDRyU7w8oItWMd5A2c5SuJy-3tSqNXmPRJvuz9rfhu4BNF2YIJ9OkuMg6Ob3onzT5OlZLdYh94GiN_eIPIiIKIO6HoXcsjkDS8eE1nPsigbmq_YfTUykRL9JWqWHL9Ftj
The provided token has been revoked
When revoked, the token will no longer work, but existing builds or operations that have been started using the token will not be cancelled. You can also revoke attenuated tokens, in which case only the attenuated token will be revoked, not the original token. On the other hand, if you revoke a token, any attenuated tokens that originated from the revoked token will also be revoked automatically.
Accessing the HTTP API using an Auth Token¶
To access the HTTP API using an auth token, you must provide an
Authorization
header in your requests. The header value should be set to
Bearer: <TOKEN>
.
Using the Nix Client with an Auth Token¶
To make the Nix client use an auth token when performing builds and other store operations in nixbuild.net, you need some specific SSH configuration:
Host eu.nixbuild.net
User authtoken
PreferredAuthentications none
SetEnv token=<TOKEN>
ServerAliveInterval 60
IPQoS throughput
The important settings above are User
, PreferredAuthentications
and
SetEnv
. Setting up your SSH client configuration like above bypasses the
normal SSH authentication, and sends the auth token to nixbuild.net in the
environment passed along when the SSH connection is initiated. When
nixbuild.net gets such a connection request, it will not look at the public SSH
key at all. Instead it will decode and verify the auth token provided in the
token
SSH environment variable. If the token is valid, nixbuild.net will use
the account embedded inside the token to perform authentication.
Authorization¶
Once authentication is done, and nixbuild.net has figured out which account a request belongs to, an authorization phase starts. Authorization in nixbuild.net is centered around a few simple permissions, but there is also support for implementing more complex access policies, if auth tokens are used. We will demonstrate this below.
Authorization with SSH Keys¶
When an SSH key is used for authenticating to nixbuild.net, the permissions that take effect are decided by the value of the default-permissions setting. This means you can lock down specific SSH keys to a specific set of permissions, but it is not possible to implement more complex access policies. In most cases, assigning permissions to SSH keys is perfectly adequate, though.
Authorization with Auth Tokens¶
Each auth token has a set of permissions built-in. Those permissions are assigned during token creation, as shown above.
In addition to building-in permissions, you can further weaken the permissions of tokens through an operation called attenuation. The key advantage of this operation is that it does not need involvement of nixbuild.net at all. You would first create one or more root tokens with wide capabilities, through the nixbuild.net administration shell. Then you could create much less capable sub-tokens by attenuation, completely offline from nixbuild.net. This functionality is possible since nixbuild.net auth tokens are Biscuit tokens.
Token Attenuation¶
To perform attenuation, you need to use the
biscuit-cli command line tool
which provides the biscuit
executable. This tool is available in
nixpkgs. Lets walk
through the complete process of creating and attenuating an auth token.
We create a new token, with all permissions enabled and an expiration time of 30 days:
nixbuild.net> tokens create --ttl-seconds 2592000 --all-permissions
-------------------------------------------------------------
EpYCCqsBCgxhY2NvdW50OnJlYWQKDWFjY291bnQ6d3JpdGUKCmJ1aWxkOnJlYWQKC2J1aWxkOndyaXRlCgpzdG9yZTpyZWFkCgtzdG9yZTp3cml0ZRgDIggKBggHEgIQBCImCiQIBBIgOh4KAxiACAoDGIEICgMYgggKAxiDCAoDGIQICgMYhQgyJgokCgIIGxIGCAUSAggFGhYKBAoCCAUKCAoGIJesxKkGCgQaAggAEiQIABIg_vub4yDKe3X_ZYwW1OPNcQhBzm9aCFq87JuDioh3Iz4aQF-D8EMnLkyTnuqCGc7MLK7HOLcPAGNViWZc5jeQPt83SbY1K9Hot5GHelpHwLVQAUmlJwmkIgy8mkCTYZLssA8iIgogTCydeLS2B7m8L6-e5tWH0PfdDimN6JXBvDN-WP0l20Q=
-------------------------------------------------------------
The token will expire at:
2023-10-19 11:42:14Z
The token has the following permissions:
account:read
account:write
build:read
build:write
store:read
store:write
We store the token in a file to make it easier to handle with the biscuit
program:
$ echo >token EpYCCqsBCgxhY2NvdW50OnJlYWQKDWFjY291bnQ6d3JpdGUKCmJ1aWxkOnJlYWQKC2J1aWxkOndyaXRlCgpzdG9yZTpyZWFkCgtzdG9yZTp3cml0ZRgDIggKBggHEgIQBCImCiQIBBIgOh4KAxiACAoDGIEICgMYgggKAxiDCAoDGIQICgMYhQgyJgokCgIIGxIGCAUSAggFGhYKBAoCCAUKCAoGIJesxKkGCgQaAggAEiQIABIg_vub4yDKe3X_ZYwW1OPNcQhBzm9aCFq87JuDioh3Iz4aQF-D8EMnLkyTnuqCGc7MLK7HOLcPAGNViWZc5jeQPt83SbY1K9Hot5GHelpHwLVQAUmlJwmkIgy8mkCTYZLssA8iIgogTCydeLS2B7m8L6-e5tWH0PfdDimN6JXBvDN-WP0l20Q=
We can use biscuit inspect
to take a look at what's inside the token:
$ biscuit inspect ./token
Authority block:
== Datalog ==
owner(4);
right(["account:read", "account:write", "build:read", "build:write", "store:read", "store:write"]);
check if time($time), $time < 2023-10-19T11:42:15Z;
== Revocation id ==
5f83f043272e4c939eea8219cecc2caec738b70f00635589665ce637903edf3749b6352bd1e8b791877a5a47c0b5500149a52709a4220cbc9a40936192ecb00f
==========
🙈 Public key check skipped 🔑
🙈 Datalog check skipped 🛡️
We can see that the token contains an owner account identifier, a set of
permissions and an expiration check. The Authority block
is using the
Biscuit policy
language,
and that is also what you'll use to attenuate the token.
Lets attenuate the token now, and create a new token that can't be used to perform any changes to the account configuration using the administration shell:
$ biscuit attenuate ./token --block 'check if operations($ops), !($ops.contains(["account:write"]))'
EpYCCqsBCgxhY2NvdW50OnJlYWQKDWFjY291bnQ6d3JpdGUKCmJ1aWxkOnJlYWQKC2J1aWxkOndyaXRlCgpzdG9yZTpyZWFkCgtzdG9yZTp3cml0ZRgDIggKBggHEgIQBCImCiQIBBIgOh4KAxiACAoDGIEICgMYgggKAxiDCAoDGIQICgMYhQgyJgokCgIIGxIGCAUSAggFGhYKBAoCCAUKCAoGIJesxKkGCgQaAggAEiQIABIg_vub4yDKe3X_ZYwW1OPNcQhBzm9aCFq87JuDioh3Iz4aQF-D8EMnLkyTnuqCGc7MLK7HOLcPAGNViWZc5jeQPt83SbY1K9Hot5GHelpHwLVQAUmlJwmkIgy8mkCTYZLssA8atQEKSwoKb3BlcmF0aW9ucwoDb3BzGAMyNgo0CgIIGxIICIYIEgMIhwgaJAoFCgMIhwgKCQoHOgUKAxiBCAoEGgIIBQoEEgIIAQoEEgIIABIkCAASIO--7mSwDxqhhL4O6K6DtqYDfKJUH0JvYM2OErB0a2jhGkBWHj5nDRyU7w8oItWMd5A2c5SuJy-3tSqNXmPRJvuz9rfhu4BNF2YIJ9OkuMg6Ob3onzT5OlZLdYh94GiN_eIPIiIKIO6HoXcsjkDS8eE1nPsigbmq_YfTUykRL9JWqWHL9Ftj
If we use the resulting token when accessing the administration shell, then we can not run any operations that require write access:
nixbuild.net> tokens create --all-permissions
Authorization failed. You might lack one or more of these permissions:
account:write
An attenuated token can be further attenuated into new tokens, if one wishes to do so.
You may wonder where the operations()
and time()
constructs, that were used in the Biscuit policies above, came from. These are Biscuit facts and they are added by nixbuild.net during the authorization phase. You can make use of these facts to define your own access policies. Below follows the complete list of facts that you can use when authoring access policies.
It is strongly recommended to read through the Biscuit documentation to gain a deeper understanding of how Biscuit tokens work and how they can be used.
Available Permissions¶
The permissions available in nixbuild.net are the following:
account:read
¶
Grants read-only access to the administration shell.
account:write
¶
Grants read and write access to the administration shell. A user holding this permission can make any changes to the account configuration. This includes adding new public SSH keys and generating new auth tokens.
build:read
¶
Grants read access to build information, including build logs.
build:write
¶
Grants the ability to run builds on nixbuild.net. In practice,
to be able to run Nix builds, you also need the build:read
, store:read
and
store:write
permissions since Nix performs multiple different store
operations when running a build.
store:read
¶
Grants read-only access to the Nix store. A user holding this permission can download build outputs or any other store paths from nixbuild.net (as long as the paths belong to the account).
store:write
¶
Grants the ability to upload paths to nixbuild.net.
Available Biscuit Facts¶
These are the facts available to your Biscuit policies. It is expected that this list of available facts will grow in the future, to make it possible to define a wide range of access policies.
build
¶
Type: (integer)
This fact will be set for any request that concerns a specific build. It can be used to restrict a token to only access information about a specific build id.
operations
¶
Type: ([string])
The set of the permissions necessary to allow the request to be performed. This fact can be used to restrict the permissions of a token to only a subset of its initially assigned permissions.
Example attenuation block:
check if operations($ops), !($ops.contains(["account:write"]));
settings
¶
Type: (string, *)
This fact represents a subset of the settings that was in effect during the request.
The settings available in this fact are listed below.
trusted-public-keys
¶
Type: [string]
You can use this fact to restrict a token to only be allowed to trust a specific set of public signing keys. If such a token is used, there is no way for a user to use any store paths signed by other keys as build inputs, or fetch such store paths . Here is an example attenuation block that achieves this:
check if
setting("trusted-public-keys", $tpks),
(
[ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
, "nixbuild.net/AOEWUB-1:/vW9PcQO5qLaIxeWMD2WPlOfJ9itCCU9n1JcAdwee0k="
]
).contains($tpks);
Note that your build signing key and your
upload signing key are implicitly included
in the trusted-public-keys setting, and will
also be part of the setting("trusted-public-keys", $tpks)
fact. You may
therefore need to include them in your policy.
time
¶
Type: (date)
The current date and time, in RFC 3339 format. This fact can be used to create tokens with a shorter expiration time.
Example attenuation block:
check if time($time), $time <= 2022-03-30T20:00:00Z;