Project | LXD |
Status | Implemented |
Author(s) | @monstermunchkin |
Approver(s) | @stgraber |
Release | 4.23 |
Internal ID | LX012 |
Abstract
This allows adding new remotes using a token.
Rationale
Adding a new remote currently involves either setting up a trust password, or trusting the client before it adds the remote.
From a security perspective, the trust password is not ideal as it can be brute-forced, and the password itself often is weak.
If the remote needs to trust the client first, the remote needs to know the client’s certificate and trust it using lxc config trust add <cert>
. After this, the client needs to add the remote using lxc remote add <name> <url>
.
With a token based approach, the remote generates a token which the client uses to add the remote. There are no passwords, certificates or URLs needed.
Specification
Design
User level
A remote can generate a new token using lxc config trust add
(without specifying a certificate). It’s interactive and will prompt for a name, and then return a token. This token is a base64 encoded representation of a CertificateAddToken
containing the client name, server addresses, and the join secret.
A client can then use this token with lxc remote add <remote> <token>
to add the new remote.
Once the remote has been added, the token expires. It is also possible for the remote to revoke a token using lxc config trust revoke-token <name>
. A list of active tokens can shown using lxc config trust list-tokens
.
API level
When running lxc config trust add
, the POST /1.0/certificates
endpoint is called, with Token
set to true
. In this case, the Type
needs to be client
, and Certificate
needs to be empty.
LXD will then create a new token operation and put the request in its metadata, similar to what is done for the cluster token.
When consuming the token, the CLI will use a normal POST /1.0/certificates
and pass the token as the Password
field. LXD will detect it’s a token, will locate the operation and if one is found, will add the certificate to the trust store using the request information stored in the operation’s metadata.
API changes
type CertificateAddToken struct {
// The name of the new client
// Example: lxd02
ClientName string `json:"client_name" yaml:"client_name"`
// The fingerprint of the network certificate
// Example: 57bb0ff4340b5bb28517e062023101adf788c37846dc8b619eb2c3cb4ef29436
Fingerprint string `json:"fingerprint" yaml:"fingerprint"`
// The addresses of the server
// Example: ["10.98.30.229:8443"]
Addresses []string `json:"addresses" yaml:"addresses"`
// The random join secret.
// Example: 2b2284d44db32675923fe0d2020477e0e9be11801ff70c435e032b97028c35cd
Secret string `json:"secret" yaml:"secret"`
}
type CertificatesPost struct {
CertificatePut `yaml:",inline"`
// Server trust password (used to add an untrusted client)
// Example: blah
Password string `json:"password" yaml:"password"`
// Whether to use token
// Example: true
Token bool `json:"token" yaml:"token"`
}
A new function for creating and returning a join token needs to be added:
func CreateCertificateToken(certificate api.CertificatesPost) (op Operation, err error)
CLI changes
New commands:
lxc config trust list-tokens
for listing all active tokenslxc config trust revoke-token <name>
for revoking an active token
lxc config trust add
will prompt for a name if no certificate is provided, and then return a token.
lxc remote add
will support tokens.
Database changes
No database changes.
Upgrade handling
No upgrade handling.
Further information
To make the CLI consistent, lxc cluster add
will gain an interactive mode where it asks for the cluster name. The prompt can be skipped by using --name <name>
which allows for scripting.