Allow including CA signing key with JoiningBootstrap, and update docs

This commit is contained in:
Brian Picciano 2024-07-14 13:33:29 +02:00
parent d2710db8f1
commit 67d17efde0
6 changed files with 41 additions and 63 deletions

View File

@ -23,8 +23,6 @@ was configured when creating the network.
## Step 3: Create a `bootstrap.json` File
Access to an `admin.json` file is required for this step.
To create a `bootstrap.json` file for the new host, the admin should perform the
following command from their own host:
@ -32,7 +30,6 @@ following command from their own host:
isle hosts create \
--hostname <name> \
--ip <ip> \
--admin-path <path to admin.json> \
> bootstrap.json
```
@ -44,21 +41,3 @@ The user can now proceed with calling `isle network join`, as described in the
[Getting Started][getting-started] document.
[getting-started]: ../user/getting-started.md
### Encrypted `admin.json`
If `admin.json` is kept in an encrypted format on disk (it should be!) then the
decrypted form can be piped into `isle hosts create` over stdin. For example, if
GPG is being used to secure `admin.json` then the following could be used to
generate a `bootstrap.json`:
```
gpg -d <path to admin.json.gpg> | isle hosts create \
--hostname <name> \
--ip <ip> \
--admin-path - \
> bootstrap.json
```
Note that the value of `--admin-path` is `-`, indicating that `admin.json`
should be read from stdin.

View File

@ -82,44 +82,18 @@ be chosen with care.
* IP: The IP of your host, which will be the first host in the network. This IP
must be within the chosen subnet range.
## Step 3: Prepare to Encrypt `admin.json`
## Step 3: Create the Network
The `admin.json` file (which will be created in the next step) is the most
sensitive part of an isle network. If it falls into the wrong hands it can be
used to completely compromise your network, impersonate hosts on the network,
and will likely lead to someone stealing or deleting all of your data.
Therefore it is important that the file remains encrypted when it is not being
used, and that it is never stored to disk in its decrypted form.
This guide assumes that you have GPG already set up with your own secret key,
and that you are familiar with how it works. There is no requirement to use GPG,
if you care to use a different method.
## Step 4: Create the `admin.json` File
To create the network, and the `admin.json` file in the process, run:
To create the network, run:
```
sudo isle network create \
--name <name> \
--ip-net <subnet> \
--domain <domain> \
--hostname <hostname> \
| gpg -e -r <my gpg email> \
> admin.json.gpg
--hostname <hostname>
```
A couple of notes here:
* Only one gpg recipient is specified. If you intend on including other users as
network administrators you can add them to the recipients list at this step,
so they will be able to use the `admin.json` file as well. You can also
manually add them as recipients later.
The `isle network create` command may take up to a minute to complete. Once
completed you should have an `admin.json.gpg` file in your current directory.
At this point your host, and your network, are ready to go! To add other hosts
to the network you can reference the [Adding a Host to the Network][add-host]
document.

View File

@ -8,6 +8,14 @@ order they will be implemented.
These items are listed more or less in the order they need to be completed, as
they generally depend on the items previous to them.
### Windows Support + GUI
Support for Windows is a must. This requirement also includes a simple GUI,
which would essentially act as a thin layer on top of `daemon.yml` to start
with.
Depending on difficulty level, OSX support might be added at this stage as well.
### NATS
Garage is currently used to handle eventually-consistent persistent storage, but
@ -36,14 +44,6 @@ files. The bootstrap file would be stored, encrypted, in garage, with the invite
code being able to both identify and decrypt it. To instantiate a host, the user
only needs to input the network domain name and the invite code.
### Windows Support + GUI
Support for Windows is a must. This requirement also includes a simple GUI,
which would essentially act as a thin layer on top of `daemon.yml` to start
with.
Depending on difficulty level, OSX support might be added at this stage as well.
### FUSE Mount
KBFS style. Every user should be able to mount virtual directories to their host

View File

@ -33,6 +33,12 @@ var subCmdHostsCreate = subCmd{
textUnmarshalerFlag{&ip}, "ip", "i", "IP of the new host",
)
canCreateHosts := flags.Bool(
"can-create-hosts",
false,
"The new host should have the ability to create hosts too",
)
if err := flags.Parse(subCmdCtx.args); err != nil {
return fmt.Errorf("parsing flags: %w", err)
}
@ -49,6 +55,9 @@ var subCmdHostsCreate = subCmd{
daemon.CreateHostRequest{
HostName: hostName,
IP: ip,
Opts: daemon.CreateHostOpts{
CanCreateHosts: *canCreateHosts,
},
},
)
if err != nil {

View File

@ -22,6 +22,13 @@ import (
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
)
// CreateHostOpts are optional parameters to the CreateHost method.
type CreateHostOpts struct {
// CanCreateHosts indicates that the bootstrap produced by CreateHost should
// give the new host the ability to create new hosts as well.
CanCreateHosts bool
}
// Daemon presents all functionality required for client frontends to interact
// with isle, typically via the unix socket.
type Daemon interface {
@ -65,6 +72,7 @@ type Daemon interface {
ctx context.Context,
hostName nebula.HostName,
ip netip.Addr, // TODO automatically choose IP address
opts CreateHostOpts,
) (
JoiningBootstrap, error,
)
@ -670,6 +678,7 @@ func (d *daemon) CreateHost(
ctx context.Context,
hostName nebula.HostName,
ip netip.Addr,
opts CreateHostOpts,
) (
JoiningBootstrap, error,
) {
@ -700,11 +709,17 @@ func (d *daemon) CreateHost(
joiningBootstrap.Bootstrap.Hosts = currBootstrap.Hosts
secretsIDs := []secrets.ID{
garageRPCSecretSecretID,
garageS3APIGlobalBucketCredentialsSecretID,
}
if opts.CanCreateHosts {
secretsIDs = append(secretsIDs, nebulaCASigningPrivateKeySecretID)
}
if joiningBootstrap.Secrets, err = secrets.Export(
ctx, d.secretsStore, []secrets.ID{
garageRPCSecretSecretID,
garageS3APIGlobalBucketCredentialsSecretID,
},
ctx, d.secretsStore, secretsIDs,
); err != nil {
return JoiningBootstrap{}, fmt.Errorf("exporting secrets: %w", err)
}

View File

@ -131,6 +131,7 @@ func (r *RPC) RemoveHost(ctx context.Context, req RemoveHostRequest) (struct{},
type CreateHostRequest struct {
HostName nebula.HostName
IP netip.Addr
Opts CreateHostOpts
}
// CreateHostResult wraps the results from the CreateHost RPC method.
@ -146,7 +147,7 @@ func (r *RPC) CreateHost(
CreateHostResult, error,
) {
joiningBootstrap, err := r.daemon.CreateHost(
ctx, req.HostName, req.IP,
ctx, req.HostName, req.IP, req.Opts,
)
if err != nil {
return CreateHostResult{}, err